Browse Source

Merge pull request #1 from zmkfirmware/main

Get up to speed
xmkb
Kellen Carey 4 years ago committed by GitHub
parent
commit
a2603d106a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      .github/workflows/build.yml
  2. 2
      README.md
  3. 4
      app/Kconfig
  4. 6
      app/boards/arm/nice_nano/Kconfig
  5. 1
      app/boards/arm/nice_nano/Kconfig.board
  6. 2
      app/boards/arm/nice_nano/board.cmake
  7. 16
      app/boards/arm/planck/planck_rev6.keymap
  8. 2
      app/boards/arm/proton_c/CMakeLists.txt
  9. 2
      app/boards/arm/proton_c/pinmux.c
  10. 16
      app/boards/shields/clueboard_california/clueboard_california.keymap
  11. 58
      app/boards/shields/corne/Kconfig.defconfig
  12. 8
      app/boards/shields/corne/Kconfig.shield
  13. 29
      app/boards/shields/corne/boards/nice_nano.overlay
  14. 6
      app/boards/shields/corne/corne.conf
  15. 79
      app/boards/shields/corne/corne.dtsi
  16. 22
      app/boards/shields/corne/corne.keymap
  17. 2
      app/boards/shields/corne/corne_left.conf
  18. 18
      app/boards/shields/corne/corne_left.overlay
  19. 2
      app/boards/shields/corne/corne_right.conf
  20. 23
      app/boards/shields/corne/corne_right.overlay
  21. 1
      app/boards/shields/kyria/boards/nice_nano.overlay
  22. 10
      app/boards/shields/kyria/kyria.conf
  23. 15
      app/boards/shields/kyria/kyria.keymap
  24. 2
      app/boards/shields/lily58/lily58.conf
  25. 22
      app/boards/shields/lily58/lily58.keymap
  26. 5
      app/drivers/zephyr/Kconfig
  27. 2
      app/drivers/zephyr/ec11_trigger.c
  28. 22
      app/dts/bindings/zmk,keymap.yaml
  29. 18
      app/dts/bindings/zmk,layers.yaml
  30. 24
      app/src/ble.c
  31. 120
      app/src/keymap.c
  32. 2
      docs/blog/2020-05-24-wip.md
  33. 52
      docs/blog/2020-08-12-zmk-sotf-1.md
  34. BIN
      docs/docs/assets/features/keymaps/layer-diagram.png
  35. BIN
      docs/docs/assets/user-setup/firmware-archive.png
  36. BIN
      docs/docs/assets/user-setup/github-actions-link.png
  37. 58
      docs/docs/behavior/key-press.md
  38. 41
      docs/docs/behavior/layers.md
  39. 50
      docs/docs/behavior/lighting.md
  40. 6
      docs/docs/dev-boards-shields-keymaps.md
  41. 63
      docs/docs/dev-guide-new-shield.md
  42. 6
      docs/docs/dev-posix-board.md
  43. 23
      docs/docs/dev-setup.md
  44. 81
      docs/docs/feature/keymaps.md
  45. 122
      docs/docs/feature/underglow.md
  46. 1
      docs/docs/hardware.md
  47. 70
      docs/docs/user-setup.md
  48. 8
      docs/docusaurus.config.js
  49. 8
      docs/sidebars.js
  50. 18
      docs/src/css/custom.css
  51. 40
      docs/static/setup.sh

5
.github/workflows/build.yml

@ -10,10 +10,15 @@ jobs:
matrix: matrix:
board: [proton_c, nice_nano] board: [proton_c, nice_nano]
shield: shield:
- corne_left
- corne_right
- kyria_left - kyria_left
- kyria_right - kyria_right
- lily58_left - lily58_left
- lily58_right - lily58_right
include:
- board: proton_c
shield: clueboard_california
steps: steps:
# To use this repository's private action, # To use this repository's private action,
# you must check out the repository # you must check out the repository

2
README.md

@ -11,4 +11,4 @@ Check out the website to learn more: https://zmkfirmware.dev/
You can also come join our [ZMK Discord Server](https://zmkfirmware.dev/community/discord/invite) You can also come join our [ZMK Discord Server](https://zmkfirmware.dev/community/discord/invite)
To review planned features, check out the [enhancement label](https://github.com/zmkfirmware/zmk/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement) in GitHub. To review planned features, check out the [enhancement label](https://github.com/zmkfirmware/zmk/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement) in GitHub. Please feel free to add 👍 to the issue description of any requests to upvote the feature.

4
app/Kconfig

@ -106,6 +106,10 @@ if ZMK_SPLIT_BLE_ROLE_CENTRAL
config BT_MAX_CONN config BT_MAX_CONN
default 5 default 5
config BT_MAX_PAIRED
# Bump this everywhere once we support switching active connections!
default 2
endif endif
config ZMK_SPLIT_BLE_ROLE_PERIPHERAL config ZMK_SPLIT_BLE_ROLE_PERIPHERAL

6
app/boards/arm/nice_nano/Kconfig

@ -0,0 +1,6 @@
config BOARD_ENABLE_DCDC
bool "Enable DCDC mode"
select SOC_DCDC_NRF52X
default y
depends on BOARD_NICE_NANO

1
app/boards/arm/nice_nano/Kconfig.board

@ -6,3 +6,4 @@
config BOARD_NICE_NANO config BOARD_NICE_NANO
bool "nice!nano" bool "nice!nano"
depends on SOC_NRF52840_QIAA depends on SOC_NRF52840_QIAA

2
app/boards/arm/nice_nano/board.cmake

@ -1,4 +1,4 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: MIT
board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset")
include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake)

16
app/boards/arm/planck/planck_rev6.keymap

@ -1,23 +1,11 @@
#include <behaviors.dtsi> #include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h> #include <dt-bindings/zmk/keys.h>
#include <dt-bindings/zmk/matrix-transform.h>
/ { / {
chosen { keymap {
zmk,keymap = &keymap0;
};
keymap0: keymap {
compatible = "zmk,keymap"; compatible = "zmk,keymap";
label ="Default Planck Keymap";
layers = <&default>;
};
layers {
compatible = "zmk,layers";
default: layer_0 { default_layer {
label = "DEFAULT";
// ----------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------
// | TAB | Q | W | E | R | T | Y | U | I | O | P | BSPC | // | TAB | Q | W | E | R | T | Y | U | I | O | P | BSPC |
// | ESC | A | S | D | F | G | H | J | K | L | ; | ' | // | ESC | A | S | D | F | G | H | J | K | L | ; | ' |

2
app/boards/arm/proton_c/CMakeLists.txt

@ -1,4 +1,4 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: MIT
if(CONFIG_PINMUX) if(CONFIG_PINMUX)
zephyr_library() zephyr_library()

2
app/boards/arm/proton_c/pinmux.c

@ -1,7 +1,7 @@
/* /*
* Copyright (c) 2017 I-SENSE group of ICCS * Copyright (c) 2017 I-SENSE group of ICCS
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: MIT
*/ */
#include <kernel.h> #include <kernel.h>

16
app/boards/shields/clueboard_california/clueboard_california.keymap

@ -1,23 +1,11 @@
#include <dt-bindings/zmk/keys.h>
#include <dt-bindings/zmk/matrix-transform.h>
#include <behaviors.dtsi> #include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
/ { / {
chosen {
zmk,keymap = &keymap0;
};
keymap0: keymap { keymap0: keymap {
compatible = "zmk,keymap"; compatible = "zmk,keymap";
label ="Default Kyria Keymap";
layers = <&default>;
};
layers {
compatible = "zmk,layers";
default: layer_0 { default_layer {
label = "DEFAULT";
bindings = < bindings = <
&kp NUM_9 &kp NUM_8 &kp NUM_9 &kp NUM_8
&kp NUM_7 &kp NUM_6 &kp NUM_7 &kp NUM_6

58
app/boards/shields/corne/Kconfig.defconfig

@ -0,0 +1,58 @@
if SHIELD_CORNE_LEFT
config ZMK_KEYBOARD_NAME
default "Corne Left"
endif
if SHIELD_CORNE_RIGHT
config ZMK_KEYBOARD_NAME
default "Corne Right"
endif
if SHIELD_CORNE_LEFT || SHIELD_CORNE_RIGHT
config ZMK_SPLIT
default y
if ZMK_DISPLAY
config I2C
default y
config SSD1306
default y
config SSD1306_REVERSE_MODE
default y
endif # ZMK_DISPLAY
if LVGL
config LVGL_HOR_RES
default 128
config LVGL_VER_RES
default 32
config LVGL_VDB_SIZE
default 64
config LVGL_DPI
default 148
config LVGL_BITS_PER_PIXEL
default 1
choice LVGL_COLOR_DEPTH
default LVGL_COLOR_DEPTH_1
endchoice
endif # LVGL
endif

8
app/boards/shields/corne/Kconfig.shield

@ -0,0 +1,8 @@
# Copyright (c) 2020 Pete Johanson
# SPDX-License-Identifier: MIT
config SHIELD_CORNE_LEFT
def_bool $(shields_list_contains,corne_left)
config SHIELD_CORNE_RIGHT
def_bool $(shields_list_contains,corne_right)

29
app/boards/shields/corne/boards/nice_nano.overlay

@ -0,0 +1,29 @@
&spi1 {
compatible = "nordic,nrf-spi";
/* Cannot be used together with i2c0. */
status = "okay";
mosi-pin = <6>;
// Unused pins, needed for SPI definition, but not used by the ws2812 driver itself.
sck-pin = <5>;
miso-pin = <7>;
led_strip: ws2812@0 {
compatible = "worldsemi,ws2812-spi";
label = "SK6812mini";
/* SPI */
reg = <0>; /* ignored, but necessary for SPI bindings */
spi-max-frequency = <4000000>;
/* WS2812 */
chain-length = <6>; /* There are per-key RGB, but the first 6 are underglow */
spi-one-frame = <0x70>;
spi-zero-frame = <0x40>;
};
};
/ {
chosen {
zmk,underglow = &led_strip;
};
};

6
app/boards/shields/corne/corne.conf

@ -0,0 +1,6 @@
# Uncomment the following lines to enable the Corne RGB Underglow
# ZMK_RGB_UNDERGLOW=y
# CONFIG_WS2812_STRIP=y
# Uncomment the following line to enable the Corne OLED Display
# CONFIG_ZMK_DISPLAY=y

79
app/boards/shields/corne/corne.dtsi

@ -0,0 +1,79 @@
/*
* Copyright (c) 2020 Pete Johanson
*
* 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 = <12>;
rows = <4>;
// | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 |
// | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 |
// | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 |
// | SW19 | SW20 | SW21 | | SW21 | SW20 | SW19 |
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,12)
RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,12)
RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,12)
RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8)
>;
};
five_column_transform: keymap_transform_1 {
compatible = "zmk,matrix-transform";
columns = <10>;
rows = <4>;
// | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 |
// | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 |
// | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 |
// | SW19 | SW20 | SW21 | | SW21 | SW20 | SW19 |
map = <
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(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10)
RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10)
RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8)
>;
};
kscan0: kscan {
compatible = "zmk,kscan-gpio-matrix";
label = "KSCAN";
diode-direction = "col2row";
row-gpios
= <&pro_micro_d 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
, <&pro_micro_d 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
, <&pro_micro_d 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
, <&pro_micro_d 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
;
};
// TODO: per-key RGB node(s)?
};
&pro_micro_i2c {
status = "okay";
ssd1306@3c {
compatible = "solomon,ssd1306fb";
reg = <0x3c>;
label = "DISPLAY";
width = <128>;
height = <32>;
segment-offset = <0>;
page-offset = <0>;
display-offset = <0>;
multiplex-ratio = <63>;
prechargep = <0x22>;
};
};

22
app/boards/shields/corne/corne.keymap

@ -0,0 +1,22 @@
#include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
/ {
keymap {
compatible = "zmk,keymap";
default_layer {
// ---------------------------------------------------------------------------------------------------------------------------------
// | ESC | Q | W | E | R | T | | Y | U | I | O | P | \ |
// | TAB | A | S | D | F | G | | H | J | K | L | ; | ' |
// | SHIFT | Z | X | C | V | B | | N | M | , | . | / | CTRL |
// | GUI | DEL | RET | | TAB | BSPC | R-ALT |
bindings = <
&kp ESC &kp Q &kp W &kp E &kp R &kp T &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 H &kp J &kp K &kp L &kp SCLN &kp QUOT
&kp LSFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp CMMA &kp DOT &kp FSLH &kp RCTL
&kp LGUI &kp DEL &kp RET &kp TAB &kp BKSP &kp RALT
>;
};
};
};

2
app/boards/shields/corne/corne_left.conf

@ -0,0 +1,2 @@
CONFIG_ZMK_SPLIT=y
CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL=y

18
app/boards/shields/corne/corne_left.overlay

@ -0,0 +1,18 @@
/*
* Copyright (c) 2020 Pete Johanson
*
* SPDX-License-Identifier: MIT
*/
#include "corne.dtsi"
&kscan0 {
col-gpios
= <&pro_micro_a 3 GPIO_ACTIVE_HIGH>
, <&pro_micro_a 2 GPIO_ACTIVE_HIGH>
, <&pro_micro_a 1 GPIO_ACTIVE_HIGH>
, <&pro_micro_a 0 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 15 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 14 GPIO_ACTIVE_HIGH>
;
};

2
app/boards/shields/corne/corne_right.conf

@ -0,0 +1,2 @@
CONFIG_ZMK_SPLIT=y
CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL=y

23
app/boards/shields/corne/corne_right.overlay

@ -0,0 +1,23 @@
/*
* Copyright (c) 2020 Pete Johanson
*
* SPDX-License-Identifier: MIT
*/
#include "corne.dtsi"
&default_transform {
col-offset = <6>;
};
&kscan0 {
col-gpios
= <&pro_micro_d 14 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 15 GPIO_ACTIVE_HIGH>
, <&pro_micro_a 0 GPIO_ACTIVE_HIGH>
, <&pro_micro_a 1 GPIO_ACTIVE_HIGH>
, <&pro_micro_a 2 GPIO_ACTIVE_HIGH>
, <&pro_micro_a 3 GPIO_ACTIVE_HIGH>
;
};

1
app/boards/shields/kyria/boards/nice_nano.overlay

@ -1,6 +1,5 @@
&spi1 { &spi1 {
compatible = "nordic,nrf-spi"; compatible = "nordic,nrf-spi";
/* Cannot be used together with i2c0. */
status = "okay"; status = "okay";
mosi-pin = <6>; mosi-pin = <6>;
// Unused pins, needed for SPI definition, but not used by the ws2812 driver itself. // Unused pins, needed for SPI definition, but not used by the ws2812 driver itself.

10
app/boards/shields/kyria/kyria.conf

@ -0,0 +1,10 @@
# Uncomment these two line to add support for encoders to your firmware
# CONFIG_EC11=y
# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y
# Uncomment the following line to enable the Kyria OLED Display
# CONFIG_ZMK_DISPLAY=y
# Uncomment the following lines to enable RGB underglow
# CONFIG_ZMK_RGB_UNDERGLOW=y
# CONFIG_WS2812_STRIP=y

15
app/boards/shields/kyria/kyria.keymap

@ -2,21 +2,10 @@
#include <dt-bindings/zmk/keys.h> #include <dt-bindings/zmk/keys.h>
/ { / {
chosen { keymap {
zmk,keymap = &keymap0;
};
keymap0: keymap {
compatible = "zmk,keymap"; compatible = "zmk,keymap";
label ="Default Kyria Keymap";
layers = <&default>;
};
layers {
compatible = "zmk,layers";
default: layer_0 { default_layer {
label = "DEFAULT";
// --------------------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------------------
// | ESC | Q | W | E | R | T | | Y | U | I | O | P | \ | // | ESC | Q | W | E | R | T | | Y | U | I | O | P | \ |
// | TAB | A | S | D | F | G | | H | J | K | L | ; | ' | // | TAB | A | S | D | F | G | | H | J | K | L | ; | ' |

2
app/boards/shields/lily58/lily58.conf

@ -0,0 +1,2 @@
# Uncomment the following line to enable the Lily58 OLED Display
# CONFIG_ZMK_DISPLAY=y

22
app/boards/shields/lily58/lily58.keymap

@ -1,23 +1,11 @@
#include <behaviors.dtsi> #include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h> #include <dt-bindings/zmk/keys.h>
#include <dt-bindings/zmk/matrix-transform.h>
/ { / {
chosen { keymap {
zmk,keymap = &keymap0;
};
keymap0: keymap {
compatible = "zmk,keymap"; compatible = "zmk,keymap";
label ="Default Lily58 Keymap";
layers = <&default &lower &raise>;
};
layers {
compatible = "zmk,layers";
default: layer_0 { default_layer {
label = "DEFAULT";
// ------------------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------------------
// | ESC | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | ` | // | ESC | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | ` |
// | TAB | Q | W | E | R | T | | Y | U | I | O | P | - | // | TAB | Q | W | E | R | T | | Y | U | I | O | P | - |
@ -33,8 +21,7 @@
>; >;
}; };
lower: layer_1 { lower_layer {
label = "LOWER";
// ------------------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------------------
// | | | | | | | | | | | | | | // | | | | | | | | | | | | | |
// | F1 | F2 | F3 | F4 | F5 | F6 | | F7 | F8 | F9 | F10 | F11 | F12 | // | F1 | F2 | F3 | F4 | F5 | F6 | | F7 | F8 | F9 | F10 | F11 | F12 |
@ -50,8 +37,7 @@
>; >;
}; };
raise: layer_3 { raise_layer {
label = "RAISE";
// ------------------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------------------
// | | | | | | | | | | | | | | // | | | | | | | | | | | | | |
// | ` | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | | // | ` | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | |

5
app/drivers/zephyr/Kconfig

@ -25,7 +25,7 @@ menuconfig EC11
if EC11 if EC11
choice EC11_TRIGGER choice
prompt "Trigger mode" prompt "Trigger mode"
default EC11_TRIGGER_NONE default EC11_TRIGGER_NONE
help help
@ -46,6 +46,9 @@ config EC11_TRIGGER_OWN_THREAD
endchoice endchoice
config EC11_TRIGGER
bool
config EC11_THREAD_PRIORITY config EC11_THREAD_PRIORITY
int "Thread priority" int "Thread priority"
depends on EC11_TRIGGER_OWN_THREAD depends on EC11_TRIGGER_OWN_THREAD

2
app/drivers/zephyr/ec11_trigger.c

@ -1,7 +1,7 @@
/* /*
* Copyright (c) 2016 Intel Corporation * Copyright (c) 2016 Intel Corporation
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: MIT
*/ */
#define DT_DRV_COMPAT alps_ec11 #define DT_DRV_COMPAT alps_ec11

22
app/dts/bindings/zmk,keymap.yaml

@ -3,15 +3,13 @@ description: |
compatible: "zmk,keymap" compatible: "zmk,keymap"
properties: child-binding:
transform: description: "A layer to be used in a keymap"
type: phandle
required: false properties:
bindings:
label: type: phandle-array
type: string required: true
required: true sensor-bindings:
type: phandle-array
layers: required: false
type: phandles
required: true

18
app/dts/bindings/zmk,layers.yaml

@ -1,18 +0,0 @@
description: |
Allows defining the various keymap layers for use.
compatible: "zmk,layers"
child-binding:
description: "A layer to be used in a keymap"
properties:
label:
type: string
required: true
bindings:
type: phandle-array
required: true
sensor-bindings:
type: phandle-array
required: false

24
app/src/ble.c

@ -31,11 +31,11 @@ static void connected(struct bt_conn *conn, u8_t err)
if (err) if (err)
{ {
printk("Failed to connect to %s (%u)\n", addr, err); LOG_WRN("Failed to connect to %s (%u)", log_strdup(addr), err);
return; return;
} }
printk("Connected %s\n", addr); LOG_DBG("Connected %s", log_strdup(addr));
bt_conn_le_param_update(conn, BT_LE_CONN_PARAM(0x0006, 0x000c, 30, 400)); bt_conn_le_param_update(conn, BT_LE_CONN_PARAM(0x0006, 0x000c, 30, 400));
@ -45,7 +45,7 @@ static void connected(struct bt_conn *conn, u8_t err)
if (bt_conn_set_security(conn, BT_SECURITY_L2)) if (bt_conn_set_security(conn, BT_SECURITY_L2))
{ {
printk("Failed to set security\n"); LOG_ERR("Failed to set security");
} }
} }
@ -55,7 +55,7 @@ static void disconnected(struct bt_conn *conn, u8_t reason)
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
printk("Disconnected from %s (reason 0x%02x)\n", addr, reason); LOG_DBG("Disconnected from %s (reason 0x%02x)", log_strdup(addr), reason);
} }
static void security_changed(struct bt_conn *conn, bt_security_t level, static void security_changed(struct bt_conn *conn, bt_security_t level,
@ -67,11 +67,11 @@ static void security_changed(struct bt_conn *conn, bt_security_t level,
if (!err) if (!err)
{ {
printk("Security changed: %s level %u\n", addr, level); LOG_DBG("Security changed: %s level %u", log_strdup(addr), level);
} }
else else
{ {
printk("Security failed: %s level %u err %d\n", addr, level, LOG_ERR("Security failed: %s level %u err %d", log_strdup(addr), level,
err); err);
} }
} }
@ -107,7 +107,7 @@ static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey)
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
printk("Passkey for %s: %06u\n", addr, passkey); LOG_DBG("Passkey for %s: %06u", log_strdup(addr), passkey);
} }
#ifdef CONFIG_ZMK_BLE_PASSKEY_ENTRY #ifdef CONFIG_ZMK_BLE_PASSKEY_ENTRY
@ -118,7 +118,7 @@ static void auth_passkey_entry(struct bt_conn *conn)
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
printk("Passkey entry requested for %s\n", addr); LOG_DBG("Passkey entry requested for %s", log_strdup(addr));
auth_passkey_entry_conn = bt_conn_ref(conn); auth_passkey_entry_conn = bt_conn_ref(conn);
} }
@ -138,7 +138,7 @@ static void auth_cancel(struct bt_conn *conn)
passkey_digit = 0; passkey_digit = 0;
printk("Pairing cancelled: %s\n", addr); LOG_DBG("Pairing cancelled: %s", log_strdup(addr));
} }
static struct bt_conn_auth_cb zmk_ble_auth_cb_display = { static struct bt_conn_auth_cb zmk_ble_auth_cb_display = {
@ -169,14 +169,14 @@ static void zmk_ble_ready(int err)
LOG_DBG("ready? %d", err); LOG_DBG("ready? %d", err);
if (err) if (err)
{ {
printk("Bluetooth init failed (err %d)\n", err); LOG_ERR("Bluetooth init failed (err %d)", err);
return; return;
} }
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0); err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0);
if (err) if (err)
{ {
printk("Advertising failed to start (err %d)\n", err); LOG_ERR("Advertising failed to start (err %d)", err);
return; return;
} }
} }
@ -187,7 +187,7 @@ static int zmk_ble_init(struct device *_arg)
if (err) if (err)
{ {
printk("BLUETOOTH FAILED"); LOG_ERR("BLUETOOTH FAILED (%d)", err);
return err; return err;
} }

120
app/src/keymap.c

@ -17,96 +17,53 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
static u32_t zmk_keymap_layer_state = 0; static u32_t zmk_keymap_layer_state = 0;
static u8_t zmk_keymap_layer_default = 0; static u8_t zmk_keymap_layer_default = 0;
#define ZMK_KEYMAP_NODE DT_CHOSEN(zmk_keymap) #define DT_DRV_COMPAT zmk_keymap
#define ZMK_KEYMAP_LAYERS_LEN DT_PROP_LEN(ZMK_KEYMAP_NODE, layers)
#define LAYER_CHILD_LEN(node) 1+
#define ZMK_KEYMAP_NODE DT_DRV_INST(0)
#define ZMK_KEYMAP_LAYERS_LEN (DT_INST_FOREACH_CHILD(0, LAYER_CHILD_LEN) 0)
#define LAYER_NODE(l) DT_PHANDLE_BY_IDX(ZMK_KEYMAP_NODE, layers, l) #define LAYER_NODE(l) DT_PHANDLE_BY_IDX(ZMK_KEYMAP_NODE, layers, l)
#define _TRANSFORM_ENTRY(idx, layer) \ #define _TRANSFORM_ENTRY(idx, layer) \
{ .behavior_dev = DT_LABEL(DT_PHANDLE_BY_IDX(DT_PHANDLE_BY_IDX(ZMK_KEYMAP_NODE, layers, layer), bindings, idx)), \ { .behavior_dev = DT_LABEL(DT_PHANDLE_BY_IDX(layer, bindings, idx)), \
.param1 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(LAYER_NODE(layer), bindings, idx, param1), (0), (DT_PHA_BY_IDX(LAYER_NODE(layer), bindings, idx, param1))), \ .param1 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, bindings, idx, param1), (0), (DT_PHA_BY_IDX(layer, bindings, idx, param1))), \
.param2 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(LAYER_NODE(layer), bindings, idx, param2), (0), (DT_PHA_BY_IDX(LAYER_NODE(layer), bindings, idx, param2))), \ .param2 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, bindings, idx, param2), (0), (DT_PHA_BY_IDX(layer, bindings, idx, param2))), \
}, },
#define TRANSFORMED_LAYER(idx) \ #define TRANSFORMED_LAYER(node) \
{ UTIL_LISTIFY(DT_PROP_LEN(DT_PHANDLE_BY_IDX(ZMK_KEYMAP_NODE, layers, idx), bindings), _TRANSFORM_ENTRY, idx) } { UTIL_LISTIFY(DT_PROP_LEN(node, bindings), _TRANSFORM_ENTRY, node) },
static struct zmk_behavior_binding zmk_keymap[ZMK_KEYMAP_LAYERS_LEN][ZMK_KEYMAP_LEN] = {
#if DT_PROP_HAS_IDX(ZMK_KEYMAP_NODE, layers, 0)
TRANSFORMED_LAYER(0),
#endif
#if DT_PROP_HAS_IDX(ZMK_KEYMAP_NODE, layers, 1)
TRANSFORMED_LAYER(1),
#endif
#if DT_PROP_HAS_IDX(ZMK_KEYMAP_NODE, layers, 2)
TRANSFORMED_LAYER(2),
#endif
#if DT_PROP_HAS_IDX(ZMK_KEYMAP_NODE, layers, 3)
TRANSFORMED_LAYER(3),
#endif
#if DT_PROP_HAS_IDX(ZMK_KEYMAP_NODE, layers, 4)
TRANSFORMED_LAYER(4),
#endif
#if DT_PROP_HAS_IDX(ZMK_KEYMAP_NODE, layers, 5)
TRANSFORMED_LAYER(5),
#endif
#if DT_PROP_HAS_IDX(ZMK_KEYMAP_NODE, layers, 6)
TRANSFORMED_LAYER(6),
#endif
#if DT_PROP_HAS_IDX(ZMK_KEYMAP_NODE, layers, 7)
TRANSFORMED_LAYER(7),
#endif
#if DT_PROP_HAS_IDX(ZMK_KEYMAP_NODE, layers, 8)
TRANSFORMED_LAYER(8),
#endif
#if DT_PROP_HAS_IDX(ZMK_KEYMAP_NODE, layers, 9)
TRANSFORMED_LAYER(9),
#endif
};
#if ZMK_KEYMAP_HAS_SENSORS #if ZMK_KEYMAP_HAS_SENSORS
#define _TRANSFORM_SENSOR_ENTRY(idx, layer) \ #define _TRANSFORM_SENSOR_ENTRY(idx, layer) \
{ .behavior_dev = DT_LABEL(DT_PHANDLE_BY_IDX(DT_PHANDLE_BY_IDX(ZMK_KEYMAP_NODE, layers, layer), sensor_bindings, idx)), \ { .behavior_dev = DT_LABEL(DT_PHANDLE_BY_IDX(layer, sensor_bindings, idx)), \
.param1 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(LAYER_NODE(layer), sensor_bindings, idx, param1), (0), (DT_PHA_BY_IDX(LAYER_NODE(layer), sensor_bindings, idx, param1))), \ .param1 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, sensor_bindings, idx, param1), (0), (DT_PHA_BY_IDX(layer, sensor_bindings, idx, param1))), \
.param2 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(LAYER_NODE(layer), sensor_bindings, idx, param2), (0), (DT_PHA_BY_IDX(LAYER_NODE(layer), sensor_bindings, idx, param2))), \ .param2 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, sensor_bindings, idx, param2), (0), (DT_PHA_BY_IDX(layer, sensor_bindings, idx, param2))), \
}, },
#define SENSOR_LAYER(idx) \ #define SENSOR_LAYER(node) \
COND_CODE_1(DT_NODE_HAS_PROP(DT_PHANDLE_BY_IDX(ZMK_KEYMAP_NODE, layers, idx), sensor_bindings), \ COND_CODE_1(DT_NODE_HAS_PROP(node, sensor_bindings), \
({ UTIL_LISTIFY(DT_PROP_LEN(DT_PHANDLE_BY_IDX(ZMK_KEYMAP_NODE, layers, idx), sensor_bindings), _TRANSFORM_SENSOR_ENTRY, idx) }), \ ({ UTIL_LISTIFY(DT_PROP_LEN(node, sensor_bindings), _TRANSFORM_SENSOR_ENTRY, node) }), \
(NULL)) ({})),
#endif /* ZMK_KEYMAP_HAS_SENSORS */
// State
// When a behavior handles a key position "down" event, we record that layer
// here so that even if that layer is deactivated before the "up", event, we
// still send the release event to the behavior in that layer also.
static u8_t zmk_keymap_active_behavior_layer[ZMK_KEYMAP_LEN];
static struct zmk_behavior_binding zmk_keymap[ZMK_KEYMAP_LAYERS_LEN][ZMK_KEYMAP_LEN] = {
DT_INST_FOREACH_CHILD(0, TRANSFORMED_LAYER)
};
#if ZMK_KEYMAP_HAS_SENSORS
static struct zmk_behavior_binding zmk_sensor_keymap[ZMK_KEYMAP_LAYERS_LEN][ZMK_KEYMAP_SENSORS_LEN] = { static struct zmk_behavior_binding zmk_sensor_keymap[ZMK_KEYMAP_LAYERS_LEN][ZMK_KEYMAP_SENSORS_LEN] = {
#if DT_PROP_HAS_IDX(ZMK_KEYMAP_NODE, layers, 0) DT_INST_FOREACH_CHILD(0, SENSOR_LAYER)
SENSOR_LAYER(0),
#endif
#if DT_PROP_HAS_IDX(ZMK_KEYMAP_NODE, layers, 1)
SENSOR_LAYER(1),
#endif
#if DT_PROP_HAS_IDX(ZMK_KEYMAP_NODE, layers, 2)
SENSOR_LAYER(2),
#endif
#if DT_PROP_HAS_IDX(ZMK_KEYMAP_NODE, layers, 3)
SENSOR_LAYER(3),
#endif
#if DT_PROP_HAS_IDX(ZMK_KEYMAP_NODE, layers, 4)
SENSOR_LAYER(4),
#endif
#if DT_PROP_HAS_IDX(ZMK_KEYMAP_NODE, layers, 5)
SENSOR_LAYER(5),
#endif
#if DT_PROP_HAS_IDX(ZMK_KEYMAP_NODE, layers, 6)
SENSOR_LAYER(6),
#endif
#if DT_PROP_HAS_IDX(ZMK_KEYMAP_NODE, layers, 7)
SENSOR_LAYER(7),
#endif
#if DT_PROP_HAS_IDX(ZMK_KEYMAP_NODE, layers, 8)
SENSOR_LAYER(8),
#endif
#if DT_PROP_HAS_IDX(ZMK_KEYMAP_NODE, layers, 9)
SENSOR_LAYER(9),
#endif
}; };
#endif /* ZMK_KEYMAP_HAS_SENSORS */ #endif /* ZMK_KEYMAP_HAS_SENSORS */
@ -129,11 +86,18 @@ int zmk_keymap_layer_deactivate(u8_t layer)
SET_LAYER_STATE(layer, false); SET_LAYER_STATE(layer, false);
}; };
bool is_active_position(u32_t position, u8_t layer)
{
return (zmk_keymap_layer_state & BIT(layer)) == BIT(layer)
|| layer == zmk_keymap_layer_default
|| zmk_keymap_active_behavior_layer[position] == layer;
}
int zmk_keymap_position_state_changed(u32_t position, bool pressed) int zmk_keymap_position_state_changed(u32_t position, bool pressed)
{ {
for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= zmk_keymap_layer_default; layer--) for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= zmk_keymap_layer_default; layer--)
{ {
if ((zmk_keymap_layer_state & BIT(layer)) == BIT(layer) || layer == zmk_keymap_layer_default) if (is_active_position(position, layer))
{ {
struct zmk_behavior_binding *binding = &zmk_keymap[layer][position]; struct zmk_behavior_binding *binding = &zmk_keymap[layer][position];
struct device *behavior; struct device *behavior;
@ -159,8 +123,10 @@ int zmk_keymap_position_state_changed(u32_t position, bool pressed)
continue; continue;
} else if (ret < 0) { } else if (ret < 0) {
LOG_DBG("Behavior returned error: %d", ret); LOG_DBG("Behavior returned error: %d", ret);
zmk_keymap_active_behavior_layer[position] = 0;
return ret; return ret;
} else { } else {
zmk_keymap_active_behavior_layer[position] = pressed ? layer : 0;
return ret; return ret;
} }
} }

2
docs/blog/2020-05-24-wip.md

@ -5,7 +5,7 @@ author: Pete Johanson
author_title: Project Creator author_title: Project Creator
author_url: https://gitlab.com/petejohanson author_url: https://gitlab.com/petejohanson
author_image_url: https://www.gravatar.com/avatar/2001ceff7e9dc753cf96fcb2e6f41110 author_image_url: https://www.gravatar.com/avatar/2001ceff7e9dc753cf96fcb2e6f41110
tags: [keyboards, firmeware, oss, ble] tags: [keyboards, firmware, oss, ble]
--- ---
This blog is a work-in-progress as I work on basic docs + blog on this nascent keyboard firmware. This blog is a work-in-progress as I work on basic docs + blog on this nascent keyboard firmware.

52
docs/blog/2020-08-12-zmk-sotf-1.md

@ -0,0 +1,52 @@
---
title: ZMK State Of The Firmware \#1
author: Pete Johanson
author_title: Project Creator
author_url: https://gitlab.com/petejohanson
author_image_url: https://www.gravatar.com/avatar/2001ceff7e9dc753cf96fcb2e6f41110
tags: [SOTF, keyboards, firmware, oss, ble]
---
Welcome to the first ZMK "State Of The Firmware"!
With interest and Discord activity growing, it seemed important to lay out the progress made recently, current major bugs/showstoppers, and planned next steps.
## Recent Activity
There's been lots of various activity in ZMK land!
- [Nicell](https://github.com/Nicell) (nice!nano creator) contributed initial [RGB Underglow](/docs/feature/underglow) ([#64](https://github.com/zmkfirmware/zmk/pull/64)) support to ZMK.
- Tons of [documentation](/docs) work.
- Refactoring ([#73](https://github.com/zmkfirmware/zmk/pull/73), [#74](https://github.com/zmkfirmware/zmk/pull/74)) of [keymaps](/docs/feature/keymaps) to make them simpler for users.
- Mod-Tap Behavior (docs coming!) is much improved ([#69](https://github.com/zmkfirmware/zmk/pull/69)) and usable now.
- An initial [`setup.sh`](http://localhost:3000/docs/user-setup#user-config-setup-script) script was created, allowing users to quickly bootstrap a "user config" setup and push it to GitHub, where GitHub Actions will build the firmware for you.
- Corne shield ([#80](https://github.com/zmkfirmware/zmk/pull/80)) shield definition was added.
- Initial [encoder](/docs/feature/encoders) support ([#61](https://github.com/zmkfirmware/zmk/pull/61)) was added.
## Bugs and Showstoppers
Despite the flurry of activity, there are still some serious bugs and show stoppers that potential ZMK users should be aware of:
- [Bluetooth Related](https://github.com/zmkfirmware/zmk/issues/58) - There are several key bugs and fixes needed, including one complete show stopper:
- Fully working split wireless is not working. In particular, both split halves can properly pair, but once they do so, pairing with the _central_ host will not work. Workaround: You can currently have both halves pair, and use USB on the central side (Left side right now for Kyria, Corne, Lily58) and receive HID events over USB.
- BT bond information is not currently stored to the devices, so after powering off or restarting your device, users need to re-pair
- USB - There is one important USB related bug which is a showstopper:
- The Zephyr USB stack does not have a built in queue for endpoint data being written. As a result, HID events sent by ZMK are sometimes [dropped, or lost](https://github.com/zmkfirmware/zmk/issues/84).
## Next Steps
There's plenty of places to go next! To help keep folks in the loop for what's next, I've created a [Core Functionality](https://github.com/zmkfirmware/zmk/projects/1) project/kanban board in GitHub, where users should be able to get some visibility into items being focused on.
Of course, at the top of that list currently is the above bugs/showstoppers, and then from there, I hope to:
- Work on power management.
- Improve our documentation on various aspects of the system, mostly around:
- End user documentation for understanding how to use ZMK, better installation docs, etc.
- Developer focused documentation, so interested contributors can start building out more behaviors and ZMK functionality.
- Implement true "hold" detection, useful for several behaviors such as Mod-Tap and Layer-Tap.
- Hopefully acquire a proper and official USB Product ID for use for the project.
- Fun things that come up along the way!
## Thanks!
A big thanks for everyone who has shown interest in the project, tested things, asked questions, and contributed PRs ([Nicell](https://github.com/Nicell), [CrossR](https://github.com/CrossR), [careyk007](https://github.com/careyk007)).

BIN
docs/docs/assets/features/keymaps/layer-diagram.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

BIN
docs/docs/assets/user-setup/firmware-archive.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
docs/docs/assets/user-setup/github-actions-link.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

58
docs/docs/behavior/key-press.md

@ -2,4 +2,60 @@
title: Key Presses title: Key Presses
--- ---
TODO: Docs on key press behavior ## Summary
The most basic of behaiors, is the ability to send certain keycode presses and releases in response to activating
a certain key.
For reference on keycode values, see the [USB HID Usage Tables](https://www.usb.org/document-library/hid-usage-tables-12).
## Keycode Defines
To make it easier to encode the HID keycode numeric values, most keymaps include
the [`dt-bindings/zmk/keys.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/keys.h) header
provided by ZMK near the top:
```
#include <dt-bindings/zmk/keys.h>
```
Doing so makes a set of defines such as `A`, `NUM_1`, etc. available for use with these behaviors
:::note
There is an [open issue](https://github.com/zmkfirmware/zmk/issues/21) to provide a more comprehensive, and
complete set of defines for the full keypad and consumer usage pages in the future for ZMK.
:::
## Keypad Key Press
The "keypad key press" behavior sends standard keypad keycodes on press/release.
### Behavior Binding
- Reference: `&kp`
- Parameter: The keycode usage ID from the keypad usage page, e.g. `4` or `A`
Example:
```
&kp A
```
## Consumer Key Press
The "consumer key press" behavior allows you to send "consumer" usage page keycodes on press/release.
These are mostly used for media and power related keycodes, such as sending "Pause", "Scan Track Next",
"Scan Track Previous", etc.
There are a subset of the full consumer usage IDs found in the `keys.h` include, prefixed with `M_`, e.g. `M_PREV`.
### Behavior Binding
- Reference: `&cp`
- Parameter: The keycode usage ID from the consumer usage page, e.g. `M_PREV` or `M_EJCT`
Example:
```
&cp M_PREV
```

41
docs/docs/behavior/layers.md

@ -0,0 +1,41 @@
---
title: Layers
---
## Summary
Often, you may want a certain key position to alter which layers are enabled, change the default layer, etc.
Some of those behaviors are still in the works; the ones that are working now are documented here.
## Defines To Refer To Layers
When working with layers, you may have several different key positions with bindings that enable/disable those layers.
To make it easier to refer to those layers in your key bindings, and to change which layers are where later, you can
add a set of `#define`s at the top of your keymap file, and use those layer in your keymap.
For example, if you have three layers, you can add the following to the top of your keymap:
```
#define DEFAULT 0
#define LOWER 1
#define RAISE 2
```
This allows you to use those defines, e.g. `LOWER` later in your keymap.
## Momentary Layer
The "momentary layer" behavior allows you to enable 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
again.
### Behavior Binding
- Reference: `&mo`
- Parameter: The layer number to enable/disable, e.g. `1`
Example:
```
&mo LOWER
```

50
docs/docs/behavior/lighting.md

@ -0,0 +1,50 @@
---
title: Lighting
---
## Summary
Lighting is often used for either aesthetics or for the practical purposes of lighting up keys in the dark.
Currently ZMK supports RGB underglow, which can be changed and configured using its behavior.
## RGB Action Defines
RGB actions defines are provided through the [`dt-bindings/zmk/rgb.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/rgb.h) header,
which is added at the top of the keymap file:
```
#include <dt-bindings/zmk/rgb.h>
```
This will allow you to reference the actions defined in this header such as `RGB_TOG`.
Here is a table describing the action for each define:
| Define | Action |
|-----------|-----------------------------------------------------------|
| `RGB_TOG` | Toggles the RGB feature on and off |
| `RGB_HUI` | Increases the hue of the RGB feature |
| `RGB_HUD` | Decreases the hue of the RGB feature |
| `RGB_SAI` | Increases the saturation of the RGB feature |
| `RGB_SAD` | Decreases the saturation of the RGB feature |
| `RGB_BRI` | Increases the brightness of the RGB feature |
| `RGB_BRD` | Decreases the brightness of the RGB feature |
| `RGB_SPI` | Increases the speed of the RGB feature effect's animation |
| `RGB_SPD` | Decreases the speed of the RGB feature effect's animation |
| `RGB_EFF` | Cycles the RGB feature's effect forwards |
| `RGB_EFR` | Cycles the RGB feature's effect reverse |
## RGB Underglow
The "RGB underglow" behavior completes an RGB action given on press.
### Behavior Binding
- Reference: `&rgb_ug`
- Parameter: The RGB action define, e.g. `RGB_TOG` or `RGB_BRI`
Example:
```
&rgb_ug RGB_TOG
```

6
docs/docs/dev-boards-shields-keymaps.md

@ -8,11 +8,11 @@ title: Boards, Shields, and Keymaps
The foundational elements needed to get a specific keyboard working with ZMK can be broken down into: The foundational elements needed to get a specific keyboard working with ZMK can be broken down into:
- A [KSCAN driver](https://docs.zephyrproject.org/2.3.0/reference/peripherals/kscan.html), which uses `compatible="zmk,kscan-gpio-matrix"` for GPIO matrix based keyboards, or uses `compatible="zmk,kscan-gpio-direct"` for small direct wires. - A [KSCAN driver](https://docs.zephyrproject.org/2.3.0/reference/peripherals/kscan.html), which uses `compatible="zmk,kscan-gpio-matrix"` for GPIO matrix based keyboards, or uses `compatible="zmk,kscan-gpio-direct"` for small direct wires.
- An optional matrix transform, which defines how the KSCAN row/column events are translated into logical "key positions". This is required for non-rectangular keyboards/matrixes, where the key positions don't naturally follow the row/columns from the GPIO matrix. - An optional matrix transform, which defines how the KSCAN row/column events are translated into logical "key positions". This is required for non-rectangular keyboards/matrices, where the key positions don't naturally follow the row/columns from the GPIO matrix.
- A keymap, which binds each key position to a behavior, e.g. key press, mod-tap, momentary layer, in a set of layers. - A keymap, which binds each key position to a behavior, e.g. key press, mod-tap, momentary layer, in a set of layers.
These three core architectural elements are defined per-keyboard, and _where_ they are defined depeneds on the specifics of how that These three core architectural elements are defined per-keyboard, and _where_ they are defined depends on the specifics of how that
keyboard works. For an overview on the general concepts of boards and shields, please see the [FAQs on boards and sheilds](/docs/faq#why-boards-and-shields--why-not-just-keyboard). keyboard works. For an overview on the general concepts of boards and shields, please see the [FAQs on boards and shields](/docs/faq#why-boards-and-shields--why-not-just-keyboard).
## Self-Contained Keyboard ## Self-Contained Keyboard

63
docs/docs/dev-guide-new-shield.md

@ -11,14 +11,14 @@ The high level steps are:
- Create a new shield directory. - Create a new shield directory.
- Add the base Kconfig files. - Add the base Kconfig files.
- Add the shield overlay file to define the [KSCAN driver]() for detecting key press/release. - Add the shield overlay file to define the [KSCAN driver]() for detecting key press/release.
- (Optional) Add the mateix transform for mapping KSCAN row/coluk values to sane key positions. This is needed for non-rectangular keyboards, or where the underlying row/column pin arrangement does not map one to one with logical locations on the keyboard. - (Optional) Add the matrix transform for mapping KSCAN row/column values to sane key positions. This is needed for non-rectangular keyboards, or where the underlying row/column pin arrangement does not map one to one with logical locations on the keyboard.
- Add a default keymap, which users can override in their own configs as needed. - Add a default keymap, which users can override in their own configs as needed.
It may be helpful to review the upstream [shields documentation](https://docs.zephyrproject.org/2.3.0/guides/porting/shields.html#shields) to get a proper understanding of the underlying system before continuing. It may be helpful to review the upstream [shields documentation](https://docs.zephyrproject.org/2.3.0/guides/porting/shields.html#shields) to get a proper understanding of the underlying system before continuing.
## New Shield Directory ## New Shield Directory
Shields for Zephyr applications go into the `boards/shields/` directory; since ZMK's Zephyr appliction linves in the `app/` subdirectory of the repository, that means the new shield directory should be: Shields for Zephyr applications go into the `boards/shields/` directory; since ZMK's Zephyr application lives in the `app/` subdirectory of the repository, that means the new shield directory should be:
```bash ```bash
mkdir app/boards/shields/<keyboard_name> mkdir app/boards/shields/<keyboard_name>
@ -60,7 +60,7 @@ endif
## Shield Overlay ## Shield Overlay
The `<shield_name>.overlay` is the devicetree description of the keyboard shield that is merged with the primary board devicetree description before the build. For ZMK, this file at a minumum should include the [chosen]() node named `zmk,kscan` that refernces a KSCAN driver instance. For a simple 3x3 macropad matrix, The `<shield_name>.overlay` is the devicetree description of the keyboard shield that is merged with the primary board devicetree description before the build. For ZMK, this file at a minimum should include the [chosen]() node named `zmk,kscan` that references a KSCAN driver instance. For a simple 3x3 macropad matrix,
this might look something like: this might look something like:
``` ```
@ -81,9 +81,9 @@ this might look something like:
; ;
row-gpios row-gpios
= <&pro_micro_a 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> = <&pro_micro_a 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
, <&pro_micro_a 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> , <&pro_micro_a 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
, <&pro_micro_a 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> , <&pro_micro_a 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
; ;
}; };
}; };
@ -97,7 +97,7 @@ Internally ZMK translates all row/column events into "key position" events to ma
1. For non rectangular keyboards with thumb clusters, non `1u` locations, etc. 1. For non rectangular keyboards with thumb clusters, non `1u` locations, etc.
A "key position" is the numeric index (zero-based) of a given key, which identifies A "key position" is the numeric index (zero-based) of a given key, which identifies
the logical key location as percieved by the end user. All _keymap_ mappings actually bind behaviors to _key positions_, not to row/column values. the logical key location as perceived by the end user. All _keymap_ mappings actually bind behaviors to _key positions_, not to row/column values.
_Without_ a matrix transform, that intentionally map each key position to the row/column pair that position corresponds to, the default equation to determine that is: _Without_ a matrix transform, that intentionally map each key position to the row/column pair that position corresponds to, the default equation to determine that is:
@ -141,57 +141,44 @@ RC(7,0) RC(7,1) RC(7,2) RC(7,3) RC(7
Some important things to note: Some important things to note:
- The `#include <dt-bindings/zmk/matrix-transform.h>` is critical. The `RC` macro is used to generate the interanl storage in the matrix transform, and is actually replaced by a C preprocessor before the final devicetree is compiled into ZMK. - The `#include <dt-bindings/zmk/matrix-transform.h>` is critical. The `RC` macro is used to generate the internal storage in the matrix transform, and is actually replaced by a C preprocessor before the final devicetree is compiled into ZMK.
- `RC(row, column)` is placed sequentially to define what row and column values that position corresponds to. - `RC(row, column)` is placed sequentially to define what row and column values that position corresponds to.
- If you have a keyboard with options for `2u` keys in certain positions, or break away portions, it is a good idea to set the chosen `zmk,matrix_transform` to the default arrangement, and include _other_ possible matrix transform nodes in the devicetree that users can select in their user config by overriding the chosen node. - If you have a keyboard with options for `2u` keys in certain positions, or break away portions, it is a good idea to set the chosen `zmk,matrix_transform` to the default arrangement, and include _other_ possible matrix transform nodes in the devicetree that users can select in their user config by overriding the chosen node.
## Default Keymap ## Default Keymap
Each keyboard should provide an OOTB default keymap to be used when building the firmware, which can be overriden and customized by user configs. For "shield keyboards", this should be placed in the `app/boards/shields/<shield_name>/keymap/keymap.overlay` file. The keymap is configured as an additional devicetree overlay that includes the following: Each keyboard should provide an OOTB default keymap to be used when building the firmware, which can be overridden and customized by user configs. For "shield keyboards", this should be placed in the `app/boards/shields/<shield_name>/<shield_name>.keymap` file. The keymap is configured as an additional devicetree overlay that includes the following:
- A node with `compatible="zmk,layers"` where each child node is a layer with a `bindings` array that binds each key position to a given behavior (e.g. key press, momentarily layer, etc). - A node with `compatible="zmk,keymap"` where each child node is a layer with a `bindings` array that binds each key position to a given behavior (e.g. key press, momentarily layer, etc).
- A node with `compatible="zmk,keymap"` that references the layers with a `layers` phandle-array property.
- A chosen node named `zmk,keymap` that references the defined keymap.
Here is an example simple keymap for the nice60, with only one layer: Here is an example simple keymap for the Kyria, with only one layer:
``` ```
#include <behaviors.dtsi> #include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h> #include <dt-bindings/zmk/keys.h>
/ { / {
chosen { keymap {
zmk,keymap = &keymap0;
};
keymap0: keymap {
compatible = "zmk,keymap"; compatible = "zmk,keymap";
label ="Default nice!60 Keymap";
layers = <&default>;
};
layers { default_layer {
compatible = "zmk,layers"; // ---------------------------------------------------------------------------------------------------------------------------------
// | ESC | Q | W | E | R | T | | Y | U | I | O | P | \ |
default: layer_0 { // | TAB | A | S | D | F | G | | H | J | K | L | ; | ' |
label = "DEFAULT"; // | SHIFT | Z | X | C | V | B | L SHIFT | L SHIFT | | L SHIFT | L SHIFT | N | M | , | . | / | CTRL |
// ------------------------------------------------------------------------------------------ // | GUI | DEL | RET | SPACE | ESC | | RET | SPACE | TAB | BSPC | R-ALT |
// | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP |
// | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | "|" |
// | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER |
// | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT |
// | CTL | WIN | ALT | SPACE | ALT | WIN | MENU | CTL |
// ------------------------------------------------------------------------------------------
bindings = < bindings = <
&kp ESC &kp NUM_1 &kp NUM_2 &kp NUM_3 &kp NUM_4 &kp NUM_5 &kp NUM_6 &kp NUM_7 &kp NUM_8 &kp NUM_9 &kp NUM_0 &kp MINUS &kp EQL &kp BKSP &kp ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSLH
&kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp TAB &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SCLN &kp QUOT
&kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SCLN &kp QUOT &kp RET &kp LSFT &kp Z &kp X &kp C &kp V &kp B &kp LSFT &kp LSFT &kp LSFT &kp LSFT &kp N &kp M &kp CMMA &kp DOT &kp FSLH &kp RCTL
&kp LSFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp CMMA &kp DOT &kp FSLH &kp RSFT &kp LGUI &kp DEL &kp RET &kp SPC &kp ESC &kp RET &kp SPC &kp TAB &kp BKSP &kp RALT
&kp LCTL &kp LGUI &kp LALT &kp SPC &kp RALT &kp RGUI &kp GUI &kp RCTL
>; >;
sensor-bindings = <&inc_dec_cp M_VOLU M_VOLD &inc_dec_kp PGUP PGDN>;
}; };
}; };
}; };
``` ```
:::note :::note

6
docs/docs/dev-posix-board.md

@ -10,7 +10,7 @@ flowing into the handler functions.
## Prerequisites ## Prerequisites
In order to build targetting the `native_posix` board, you need to setup your system In order to build targeting the `native_posix` board, you need to setup your system
with a compiler that can target 32-bit POSIX. with a compiler that can target 32-bit POSIX.
On Debian, you can do this with: On Debian, you can do this with:
@ -21,7 +21,7 @@ apt install -y gcc-multilib
## Building ## Building
To do this, you can build ZMK targetting the To do this, you can build ZMK targeting the
`native_posix` board. `native_posix` board.
``` ```
@ -36,4 +36,4 @@ Once built, you can run the firmware locally:
## Virtual Key Events ## Virtual Key Events
The virtual key presses are hardcoded in `boards/native_posix.overlay` file. should you want to change the sequence to test various actions like Mod-Tap, etc. The virtual key presses are hardcoded in `boards/native_posix.overlay` file, should you want to change the sequence to test various actions like Mod-Tap, etc.

23
docs/docs/dev-setup.md

@ -34,7 +34,7 @@ A unix-like environment with the following base packages installed:
<OsTabs> <OsTabs>
<TabItem value="debian"> <TabItem value="debian">
On Debian and Ubuntu, we'll use apt to install our base dependencies: On Debian and Ubuntu, we'll use `apt` to install our base dependencies:
First, if you haven't updated recently, or if this is a new install, First, if you haven't updated recently, or if this is a new install,
you should update to get the latest package information: you should update to get the latest package information:
@ -188,7 +188,7 @@ West can be installed by using the `pip` python package manager.
pip3 install --user -U west pip3 install --user -U west
``` ```
:::tip pip user packages :::danger pip user packages
If you haven't done so yet, you may need to add the Python Pip user package directory to your `PATH`, e.g.: If you haven't done so yet, you may need to add the Python Pip user package directory to your `PATH`, e.g.:
``` ```
@ -200,7 +200,7 @@ source ~/.bashrc
### Toolchain Installation ### Toolchain Installation
The toolchain provides the compiler, linker, etc necessary to build for the target The toolchain provides the compiler, linker, etc., necessary to build for the target
platform. platform.
<OsTabs> <OsTabs>
@ -217,7 +217,7 @@ wget -q "https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v${ZSDK_
rm "zephyr-toolchain-arm-${ZSDK_VERSION}-setup.run" rm "zephyr-toolchain-arm-${ZSDK_VERSION}-setup.run"
``` ```
The installation will prompt with several questions about installation location, and creating a default `~/.zephyrrc` for you with various variables. The defaults shouldn normally work as expected. The installation will prompt with several questions about installation location, and creating a default `~/.zephyrrc` for you with various variables. The defaults should normally work as expected.
</TabItem> </TabItem>
<TabItem value="raspberryos"> <TabItem value="raspberryos">
@ -252,7 +252,7 @@ wget -q "https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v${ZSDK_
rm "zephyr-toolchain-arm-\${ZSDK_VERSION}-setup.run" rm "zephyr-toolchain-arm-\${ZSDK_VERSION}-setup.run"
``` ```
The installation will prompt with several questions about installation location, and creating a default `~/.zephyrrc` for you with various variables. The defaults shouldn normally work as expected. The installation will prompt with several questions about installation location, and creating a default `~/.zephyrrc` for you with various variables. The defaults should normally work as expected.
</TabItem> </TabItem>
<TabItem value="win"> <TabItem value="win">
@ -275,11 +275,20 @@ wget -q "https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v${ZSDK_
rm "zephyr-toolchain-arm-\${ZSDK_VERSION}-setup.run" rm "zephyr-toolchain-arm-\${ZSDK_VERSION}-setup.run"
``` ```
The installation will prompt with several questions about installation location, and creating a default `~/.zephyrrc` for you with various variables. The defaults shouldn normally work as expected. The installation will prompt with several questions about installation location, and creating a default `~/.zephyrrc` for you with various variables. The defaults should normally work as expected.
</TabItem> </TabItem>
</OsTabs> </OsTabs>
:::note
If you intend to build firmware straight away, make sure to correctly setup the current shell.
Notes on setting this up can be found in the [Environment Variables](#environment-variables) section.
The transient instructions can be used to setup the current shell, and the automatic instructions can setup any newly made shells automatically.
The transient instructions must be run to build firmware using the current shell.
:::
### Source Code ### Source Code
Next, you'll need to clone the ZMK source repository if you haven't already: Next, you'll need to clone the ZMK source repository if you haven't already:
@ -306,7 +315,7 @@ cd zmk
west init -l app/ west init -l app/
``` ```
:::note :::caution Command Not Found?
If you encounter errors like `command not found: west` then your `PATH` environment variable is likely If you encounter errors like `command not found: west` then your `PATH` environment variable is likely
missing the Python 3 user packages directory. See the [West Build Command](#west-build-command) missing the Python 3 user packages directory. See the [West Build Command](#west-build-command)
section again for links to how to do this section again for links to how to do this

81
docs/docs/feature/keymaps.md

@ -39,11 +39,13 @@ Like many mechanical keyboard firmwares, ZMK keymaps are composed of a collectio
minimum of at least one layer that is the default, usually near the bottom of the "stack". Each layer minimum of at least one layer that is the default, usually near the bottom of the "stack". Each layer
in ZMK contains a set of bindings that bind a certain behavior to a certain key position in that layer. in ZMK contains a set of bindings that bind a certain behavior to a certain key position in that layer.
| ![Diagram of three layers](../assets/features/keymaps/layer-diagram.png) |
| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| _A simplified diagram showing three layers. The layout of each layer is the same (they all contain four keys), but the behavior bindings within each layer can be different._ |
In addition to the base default layer (which can be changed), certain bound behaviors may also In addition to the base default layer (which can be changed), certain bound behaviors may also
enable/disable additional layers "on top" of the default layer. enable/disable additional layers "on top" of the default layer.
**TODO**: A diagram to help visualize layers
When a key location is pressed/released, the stack of all active layers from "top to bottom" is used, When a key location is pressed/released, the stack of all active layers from "top to bottom" is used,
and the event is sent to the behavior bound at that position in each layer, for it to perform whatever and the event is sent to the behavior bound at that position in each layer, for it to perform whatever
actions it wants to in reaction to the event. Those behaviors can choose to "handle" the event, and stop actions it wants to in reaction to the event. Those behaviors can choose to "handle" the event, and stop
@ -102,24 +104,39 @@ ALl the remaining keymap nodes will be nested inside of the root devicetree node
}; };
``` ```
### Keymap Node
Nested under the devicetree root, is the keymap node. The node _name_ itself is not critical, but the node **MUST** have a property
`compatible = "zmk,keymap"` in order to be used by ZMK.
```
keymap {
compatible = "zmk,keymap";
// Layer nodes go here!
};
```
### Layers ### Layers
Each layer of your keymap will be nested under the keymap node. Here is a sample
that defines just one layer for this keymap:
``` ```
layers { keymap {
compatible = "zmk,layers"; compatible = "zmk,keymap";
default: layer_0 { default_layer {
label = "DEFAULT";
// --------------------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------------------
// | ESC | Q | W | E | R | T | | Y | U | I | O | P | \ | // | ESC | Q | W | E | R | T | | Y | U | I | O | P | \ |
// | TAB | A | S | D | F | G | | H | J | K | L | ; | ' | // | TAB | A | S | D | F | G | | H | J | K | L | ; | ' |
// | SHIFT | Z | X | C | V | B | L SHIFT | L SHIFT | | L SHIFT | L SHIFT | N | M | , | . | / | CTRL | // | SHIFT | Z | X | C | V | B | L SHIFT | L SHIFT | | L SHIFT | L SHIFT | N | M | , | . | / | CTRL |
// | GUI | DEL | RET | SPACE | ESC | | RET | SPACE | TAB | BSPC | R-ALT | // | GUI | DEL | RET | SPACE | ESC | | RET | SPACE | TAB | BSPC | R-ALT |
bindings = < bindings = <
&kp ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSLH &kp ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSLH
&kp TAB &kp A &kp S &mt MOD_LCTL D &mt MOD_LSFT F &kp G &kp H &mt MOD_LSFT J &mt MOD_LCTL K &kp L &kp SCLN &kp QUOT &kp TAB &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SCLN &kp QUOT
&kp LSFT &kp Z &kp X &kp C &kp V &kp B &kp LSFT &kp LSFT &kp LSFT &kp LSFT &kp N &kp M &kp CMMA &kp DOT &kp FSLH &kp RCTL &kp LSFT &kp Z &kp X &kp C &kp V &kp B &kp LSFT &kp LSFT &kp LSFT &kp LSFT &kp N &kp M &kp CMMA &kp DOT &kp FSLH &kp RCTL
&kp LGUI &kp DEL &kp RET &kp SPC &mo 1 &mo 2 &kp SPC &kp RET &kp BKSP &kp RALT &kp LGUI &kp DEL &kp RET &kp SPC &kp ESC &kp RET &kp SPC &kp TAB &kp BKSP &kp RALT
>; >;
sensor-bindings = <&inc_dec_cp M_VOLU M_VOLD &inc_dec_kp PGUP PGDN>; sensor-bindings = <&inc_dec_cp M_VOLU M_VOLD &inc_dec_kp PGUP PGDN>;
@ -127,24 +144,40 @@ ALl the remaining keymap nodes will be nested inside of the root devicetree node
}; };
``` ```
### Keymap Each layer should have:
1. A `bindings` property this will be a list of behaviour bindings, one for each key position for the keyboard.
1. (Optional) A `sensor-bindings` property that will be a list of behavior bindings for each sensor on the keyboard. (Currently, only encoders are supported as sensor hardware, but in the future devices like trackpoints would be supported the same way)
For the full set of possible behaviors, start at the [Key Press](/docs/behavior/key-press) behavior.
### Complete Example
Putting this all together, a complete [`kyria.keymap`](https://github.com/zmkfirmware/zmk/blob/main/app/boards/shields/kyria/kyria.keymap) looks like:
``` ```
keymap0: keymap { #include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
/ {
keymap {
compatible = "zmk,keymap"; compatible = "zmk,keymap";
label ="Default Kyria Keymap";
layers = <&default>;
};
```
### Chosen Keymap default_layer {
// ---------------------------------------------------------------------------------------------------------------------------------
// | ESC | Q | W | E | R | T | | Y | U | I | O | P | \ |
// | TAB | A | S | D | F | G | | H | J | K | L | ; | ' |
// | SHIFT | Z | X | C | V | B | L SHIFT | L SHIFT | | L SHIFT | L SHIFT | N | M | , | . | / | CTRL |
// | GUI | DEL | RET | SPACE | ESC | | RET | SPACE | TAB | BSPC | R-ALT |
bindings = <
&kp ESC &kp Q &kp W &kp E &kp R &kp T &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 H &kp J &kp K &kp L &kp SCLN &kp QUOT
&kp LSFT &kp Z &kp X &kp C &kp V &kp B &kp LSFT &kp LSFT &kp LSFT &kp LSFT &kp N &kp M &kp CMMA &kp DOT &kp FSLH &kp RCTL
&kp LGUI &kp DEL &kp RET &kp SPC &kp ESC &kp RET &kp SPC &kp TAB &kp BKSP &kp RALT
>;
``` sensor-bindings = <&inc_dec_cp M_VOLU M_VOLD &inc_dec_kp PGUP PGDN>;
chosen { };
zmk,keymap = &keymap0;
}; };
};
``` ```
### Complete Example
You can see a complete example if you see the [stock Kyria keymap](https://github.com/zmkfirmware/zmk/blob/main/app/boards/shields/kyria/kyria.keymap).

122
docs/docs/feature/underglow.md

@ -1,5 +1,125 @@
--- ---
title: RGB Underglow title: RGB Underglow
sidebar_label: RGB Underglow
--- ---
TODO: Documentation on RGB underglow. RGB underglow is a feature used to control "strips" of RGB LEDs. Most of the time this is called underglow and creates a glow underneath the board using a ring of LEDs around the edge, hence the name. However, this can be extended to be used to control anything from a single LED to a long string of LEDs anywhere on the keyboard.
ZMK supports all the RGB LEDs supported by Zephyr. Here's the current list supported:
- WS2812-ish (WS2812B, WS2813, SK6812, or compatible)
- APA102
- LPD880x (LPD8803, LPD8806, or compatible)
Of the compatible types, the WS2812 LED family is by far the most popular type. Currently each of these types of LEDs are expected to be run using SPI with a couple of exceptions.
Here you can see the RGB underglow feature in action using WS2812 LEDs.
<figure class="video-container">
<iframe src="//www.youtube.com/embed/2KJkq8ssDU0" frameborder="0" allowfullscreen width="100%"></iframe>
</figure>
## Enabling RGB Underglow
To enable RGB underglow on your board or shield, simply enable the `ZMK_RGB_UNDERGLOW` and `X_STRIP` configuration values in the `.conf` file of your user config directory as such:
```
CONFIG_ZMK_RGB_UNDERGLOW=y
# Use the STRIP config specific to the LEDs you're using
CONFIG_WS2812_STRIP=y
```
If your board or shield does not have RGB underglow configured, refer to [Adding RGB Underglow to a Board](#adding-rgb-underglow-to-a-board).
## Configuring RGB Underglow
There are various Kconfig options used to configure the RGB underglow feature. These can all be set in the `.conf` file.
| Option | Description | Default |
| ---------------------------- | ---------------------------------------------- | ------- |
| `ZMK_RGB_UNDERGLOW_HUE_STEP` | Hue step in degrees of 360 used by RGB actions | `10` |
| `ZMK_RGB_UNDERGLOW_SAT_STEP` | Saturation step in percent used by RGB actions | `10` |
| `ZMK_RGB_UNDERGLOW_BRT_STEP` | Brightness step in percent used by RGB actions | `10` |
## Adding RGB Underglow to a Board
RGB underglow is always added to a board, not a shield. This is a consequence of needing to configure SPI to control the LEDs.
If you have a shield with RGB underglow, you must add a `boards/` directory within your shield folder to define the RGB underglow individually for each board that supports the shield.
Inside the `boards/` folder, you define a `<board>.overlay` for each different board.
For example, the Kyria shield has a `boards/nice_nano.overlay` file that defines the RGB underglow for the `nice_nano` board specifically.
The first step to adding support for underglow is to select you SPI output. With nRF52 boards, you can just use `&spi1` and define the pins you want to use.
For other boards, you must select an SPI definition that has the `MOSI` pin as your data pin going to your LED strip.
Here's an example of an nRF52 SPI definition:
```
&spi1 {
compatible = "nordic,nrf-spi";
status = "okay";
mosi-pin = <6>;
// Unused pins, needed for SPI definition, but not used by the ws2812 driver itself.
sck-pin = <5>;
miso-pin = <7>;
led_strip: ws2812@0 {
compatible = "worldsemi,ws2812-spi";
label = "WS2812";
/* SPI */
reg = <0>; /* ignored, but necessary for SPI bindings */
spi-max-frequency = <4000000>;
/* WS2812 */
chain-length = <10>; /* number of LEDs */
spi-one-frame = <0x70>;
spi-zero-frame = <0x40>;
};
};
```
:::info
If you are configuring SPI for an nRF52840 (or other nRF52) based board, double check that you are using pins that aren't restricted to low frequency I/O.
Ignoring these restrictions may result in poor wireless performance. You can find the list of low frequency I/O pins [here](https://infocenter.nordicsemi.com/index.jsp?topic=%2Fps_nrf52840%2Fpin.html&cp=4_0_0_6_0).
:::
Here's another example for a non-nRF52 board on `spi1`:
```
&spi1 {
led_strip: ws2812@0 {
compatible = "worldsemi,ws2812-spi";
label = "WS2812";
/* SPI */
reg = <0>;
spi-max-frequency = <5250000>;
/* WS2812 */
chain-length = <10>; /* number of LEDs */
spi-one-frame = <0x70>; /* make sure to configure this properly for your SOC */
spi-zero-frame = <0x40>; /* make sure to configure this properly for your SOC */
};
};
```
Once you have your `led_strip` properly defined you need to add it to the root devicetree node `chosen` element:
```
/ {
chosen {
zmk,underglow = &led_strip;
};
};
```
Finally you need to enable the `ZMK_RGB_UNDERGLOW` and `X_STRIP` configuration values in the `.conf` file of your board (or set a default in the `Kconfig.defconfig`):
```
CONFIG_ZMK_RGB_UNDERGLOW=y
# Use the STRIP config specific to the LEDs you're using
CONFIG_WS2812_STRIP=y
```

1
docs/docs/hardware.md

@ -22,6 +22,7 @@ That being said, there are currently only a few specific [boards](/docs/faq#what
## Keyboard Shields ## Keyboard Shields
- [Kyria](https://splitkb.com/products/kyria-pcb-kit) (`kyria_left` and `kyria_right`) - [Kyria](https://splitkb.com/products/kyria-pcb-kit) (`kyria_left` and `kyria_right`)
- [Corne](https://github.com/foostan/crkbd) (`corne_left` and `corne_right`)
- [Lily58](https://github.com/kata0510/Lily58) (`lily58_left` and `lily58_right`) - [Lily58](https://github.com/kata0510/Lily58) (`lily58_left` and `lily58_right`)
## Other Hardware ## Other Hardware

70
docs/docs/user-setup.md

@ -36,11 +36,15 @@ Following the steps in this guide, you will:
## Prerequisites ## Prerequisites
The remainder of this guide assumes the following prequisites: The remainder of this guide assumes the following prerequisites:
1. You have an active, working [GitHub](https://github.com/) account. 1. You have an active, working [GitHub](https://github.com/) account.
1. You have installed and configured the [`git`](https://git-scm.com/) version control tool. 1. You have installed and configured the [`git`](https://git-scm.com/) version control tool.
:::note
If you need to, a quick read of [Learn The Basics Of Git In Under 10 Minutes](https://www.freecodecamp.org/news/learn-the-basics-of-git-in-under-10-minutes-da548267cc91/) will help you get started.
:::
## GitHub Repo ## GitHub Repo
Before running the setup script, you will first need to create a new GitHub repository to host the config. Before running the setup script, you will first need to create a new GitHub repository to host the config.
@ -64,14 +68,14 @@ values={[
<TabItem value="curl"> <TabItem value="curl">
``` ```
sh -c "$(curl -fsSL https://zmkfirmware.dev/setup.sh)" bash -c "$(curl -fsSL https://zmkfirmware.dev/setup.sh)"
``` ```
</TabItem> </TabItem>
<TabItem value="wget"> <TabItem value="wget">
``` ```
sh -c "$(wget https://zmkfirmware.dev/setup.sh -O -)" bash -c "$(wget https://zmkfirmware.dev/setup.sh -O -)"
``` ```
</TabItem> </TabItem>
@ -101,6 +105,18 @@ Keyboard Shield Selection:
Pick an keyboard: Pick an keyboard:
``` ```
### Keymap Customization
At the next prompt, you have an opportunity to decide if you want the stock keymap file copied in
for further customization:
```
Copy in the stock keymap for customization? [Yn]:
```
Hit `Enter` or type `yes`/`y` to accept this. If you want to keep the stock keymap, or write a keymap
from scratch, type in `no`/`n`.
### GitHub Details ### GitHub Details
In order to have your new configuration automatically pushed, and then built using GitHub Actions, enter In order to have your new configuration automatically pushed, and then built using GitHub Actions, enter
@ -108,8 +124,8 @@ some information about your particular GitHub info:
``` ```
GitHub Username (leave empty to skip GitHub repo creation): petejohanson GitHub Username (leave empty to skip GitHub repo creation): petejohanson
GitHub Repo Name [zmk-config]: GitHub Repo Name: zmk-config
GitHub Repo [https://github.com/petejohanson/zmk-config.git]: GitHub Repo: https://github.com/petejohanson/zmk-config.git
``` ```
Only the GitHub username is required; if you are happy with the defaults offered in the square brackets, you can simply hit `Enter`. Only the GitHub username is required; if you are happy with the defaults offered in the square brackets, you can simply hit `Enter`.
@ -137,11 +153,49 @@ push the initial commit.
::: :::
## Accessing Built Firmware ## Installing The Firmware
### Download The Archive
Once the setup script is complete and the new user config repository has been pushed, GitHub will automatically run the action Once the setup script is complete and the new user config repository has been pushed, GitHub will automatically run the action
to build your keyboard firmware files. You can view the actions by clicking on the "Actions" tab on your GitHub repository. to build your keyboard firmware files. You can view the actions by clicking on the "Actions" tab on your GitHub repository.
## Keymap Changes ![](./assets/user-setup/github-actions-link.png)
Once you have loaded the Actions tab, select the top build from the list. Once you load it, the right side panel will include
a link to download the `firmware` upload:
![](./assets/user-setup/firmware-archive.png)
Once downloaded, extract the zip and you can verify it should contain one or more `uf2` files, which will be copied to
your keyboard.
TODO: Document how to add your own keymap! ### Installing UF2 Files
To flash the firmware, first put your board into bootloader mode by double clicking the reset button (either on the MCU board itself,
or the one that is part of your keyboard). The controller should appear in your OS as a new USB storage device.
Once this happens, copy the correct UF2 file (e.g. left or right if working on a split), and paste it onto the root of that USB mass
storage device. Once the flash is complete, the controller should automatically restart, and load your newfly flashed firmware.
## Customization
### Configuration Changes
The setup script creates a `config/<shield>.conf` file that allows you to add additional configuration options to
control what features and options are built into your firmware. Opening that file with your text editor you should see
various config settings that can be commented/uncommented to modify how your firmware is built.
### Keymap
Once you have the basic user config completed, you can find the file in `config/<shield>.keymap` and customize from there.
Refer to the [Keymap](/docs/feature/keymaps) documentation to learn more.
### Publishing
After making any changes you want, you should commit the changes and then push them to GitHub. That will trigger a new
GitHub Actions job to build your firmware which you can download once it completes.
:::note
If you need to, a review of [Learn The Basics Of Git In Under 10 Minutes](https://www.freecodecamp.org/news/learn-the-basics-of-git-in-under-10-minutes-da548267cc91/) will help you get these steps right.
:::

8
docs/docusaurus.config.js

@ -7,6 +7,10 @@ module.exports = {
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.
themeConfig: { themeConfig: {
googleAnalytics: {
trackingID: "UA-145201102-2",
anonymizeIP: true,
},
// sidebarCollapsible: false, // sidebarCollapsible: false,
navbar: { navbar: {
title: "ZMK Firmware", title: "ZMK Firmware",
@ -101,12 +105,12 @@ module.exports = {
homePageId: "intro", homePageId: "intro",
sidebarPath: require.resolve("./sidebars.js"), sidebarPath: require.resolve("./sidebars.js"),
// Please change this to your repo. // Please change this to your repo.
editUrl: "https://githlab.com/zmkproject/zmk/edit/main/docs/", editUrl: "https://github.com/zmkfirmware/zmk/edit/main/docs/",
}, },
blog: { blog: {
showReadingTime: true, showReadingTime: true,
// Please change this to your repo. // Please change this to your repo.
editUrl: "https://gitlab.com/zmkproject/zmk/edit/main/docs/blog/", editUrl: "https://github.com/zmkfirmware/zmk/edit/main/docs/",
}, },
theme: { theme: {
customCss: require.resolve("./src/css/custom.css"), customCss: require.resolve("./src/css/custom.css"),

8
docs/sidebars.js

@ -1,13 +1,17 @@
module.exports = { module.exports = {
someSidebar: { someSidebar: {
"Getting Started": ["intro", "hardware", "user-setup", "faq"], "Getting Started": ["intro", "hardware", "faq", "user-setup"],
Features: [ Features: [
"feature/keymaps", "feature/keymaps",
"feature/displays", "feature/displays",
"feature/encoders", "feature/encoders",
"feature/underglow", "feature/underglow",
], ],
Behaviors: ["behavior/key-press"], Behaviors: [
"behavior/key-press",
"behavior/layers",
"behavior/lighting",
],
Development: [ Development: [
"dev-clean-room", "dev-clean-room",
"dev-setup", "dev-setup",

18
docs/src/css/custom.css

@ -23,3 +23,21 @@
margin: 0 calc(-1 * var(--ifm-pre-padding)); margin: 0 calc(-1 * var(--ifm-pre-padding));
padding: 0 var(--ifm-pre-padding); padding: 0 var(--ifm-pre-padding);
} }
.video-container {
height: 0;
margin: 0;
margin-bottom: 30px;
overflow: hidden;
padding-bottom: 56.25%;
padding-top: 30px;
position: relative;
}
.video-container iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}

40
docs/static/setup.sh vendored

@ -7,6 +7,7 @@ title="ZMK Config Setup:"
# TODO: Check for git being installed # TODO: Check for git being installed
# TODO: Check for curl being installed
# TODO: Check for user.name and user.email git configs being set # TODO: Check for user.name and user.email git configs being set
prompt="Pick an MCU board:" prompt="Pick an MCU board:"
@ -36,17 +37,18 @@ echo ""
echo "Keyboard Shield Selection:" echo "Keyboard Shield Selection:"
prompt="Pick an keyboard:" prompt="Pick an keyboard:"
options=("Kyria" "Lily58") options=("Kyria" "Lily58" "Corne")
PS3="$prompt " PS3="$prompt "
# 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.
# select opt in "${options[@]}" "Other" "Quit"; do # select opt in "${options[@]}" "Other" "Quit"; do
select opt in "${options[@]}" "Other" "Quit"; do select opt in "${options[@]}" "Quit"; do
case "$REPLY" in case "$REPLY" in
1 ) shield_title="Kyria" shield="kyria"; split="y"; break;; 1 ) shield_title="Kyria" shield="kyria"; split="y"; break;;
2 ) shield_title="Lily58" shield="lily58"; split="y"; break;; 2 ) shield_title="Lily58" shield="lily58"; split="y"; break;;
3 ) shield_title="Corne" shield="corne"; split="y"; break;;
# Add link to docs on adding your own custom shield in your ZMK config! # Add link to docs on adding your own custom shield in your ZMK config!
# $(( ${#options[@]}+1 )) ) echo "Other!"; break;; # $(( ${#options[@]}+1 )) ) echo "Other!"; break;;
@ -56,7 +58,11 @@ select opt in "${options[@]}" "Other" "Quit"; do
esac esac
done done
read -p "GitHub Username (leave empty to skip GitHub repo creation): " github_user read -e -p "Copy in the stock keymap for customization? [Yn]: " copy_keymap
if [ -z "$copy_keymap" ] || [ "$copy_keymap" == "Y" ] || [ "$copy_keymap" == "y" ]; then copy_keymap="yes"; fi
read -e -p "GitHub Username (leave empty to skip GitHub repo creation): " github_user
if [ -n "$github_user" ]; then if [ -n "$github_user" ]; then
read -p "GitHub Repo Name [zmk-config]: " repo_name read -p "GitHub Repo Name [zmk-config]: " repo_name
if [ -z "$repo_name" ]; then repo_name="zmk-config"; fi if [ -z "$repo_name" ]; then repo_name="zmk-config"; fi
@ -72,6 +78,11 @@ echo ""
echo "Preparing a user config for:" echo "Preparing a user config for:"
echo "* MCU Board: ${board}" echo "* MCU Board: ${board}"
echo "* Shield: ${shield}" echo "* Shield: ${shield}"
if [ "$copy_keymap" == "yes" ]; then
echo "* Copy Keymap?: ✓"
else
echo "* Copy Keymap?: ❌"
fi
if [ -n "$github_repo" ]; then if [ -n "$github_repo" ]; then
echo "* GitHub Repo To Push (please create this in GH first!): ${github_repo}" echo "* GitHub Repo To Push (please create this in GH first!): ${github_repo}"
fi fi
@ -79,7 +90,7 @@ fi
echo "" echo ""
read -p "Continue? [Yn]: " do_it read -p "Continue? [Yn]: " do_it
if [ -n "$do_it" ] && [ "$do_it" != "y" ]; then if [ -n "$do_it" ] && [ "$do_it" != "y" ] && [ "$do_it" != "Y" ]; then
echo "Aborting..." echo "Aborting..."
exit exit
fi fi
@ -87,13 +98,28 @@ fi
git clone --single-branch $repo_path ${repo_name} git clone --single-branch $repo_path ${repo_name}
cd ${repo_name} cd ${repo_name}
sed -i \ pushd config
curl -O "https://raw.githubusercontent.com/zmkfirmware/zmk/main/app/boards/shields/${shield}/${shield}.conf"
if [ "$copy_keymap" == "yes" ]; then
curl -O "https://raw.githubusercontent.com/zmkfirmware/zmk/main/app/boards/shields/${shield}/${shield}.keymap"
fi
popd
sed -i'.orig' \
-e "s/BOARD_NAME/$board/" \ -e "s/BOARD_NAME/$board/" \
-e "s/SHIELD_NAME/$shield/" \ -e "s/SHIELD_NAME/$shield/" \
-e "s/KEYBOARD_TITLE/$shield_title/" \ -e "s/KEYBOARD_TITLE/$shield_title/" \
.github/workflows/build.yml .github/workflows/build.yml
mv config/prj.conf "config/${shield}.conf" if [ "$board" == "proton_c" ]; then
# Proton-C board still fa
sed -i'.orig' -e "s/uf2/hex/g" .github/workflows/build.yml
fi
rm .github/workflows/*.yml.orig
rm -rf .git rm -rf .git
git init . git init .
@ -102,7 +128,7 @@ git commit -m "Initial User Config."
if [ -n "$github_repo" ]; then if [ -n "$github_repo" ]; then
git remote add origin "$github_repo" git remote add origin "$github_repo"
git push --set-upstream origin $(git branch --show-current) git push --set-upstream origin $(git symbolic-ref --short HEAD)
# TODO: Support determing the actions URL when non-https:// repo URL is used. # TODO: Support determing the actions URL when non-https:// repo URL is used.
if [ "${github_repo}" != "${github_repo#https://}" ]; then if [ "${github_repo}" != "${github_repo#https://}" ]; then

Loading…
Cancel
Save