Add picolibc, improve GCC builds, update Zephyr, ZMK, Redox

This commit is contained in:
Stefan 2024-05-19 22:22:01 +02:00
parent c03fdc6264
commit 5fce2e4987
5 changed files with 1592 additions and 787 deletions

File diff suppressed because it is too large Load diff

View file

@ -42,7 +42,7 @@
(define-public %zephyr-module "zephyr-module") (define-public %zephyr-module "zephyr-module")
(define-public zephyr (define-public zephyr
(let ((version "3.4.0")) (let ((version "3.5.0"))
(package (package
(name "zephyr") (name "zephyr")
(version version) (version version)
@ -54,7 +54,7 @@
(commit (string-append "zephyr-v" version)))) (commit (string-append "zephyr-v" version))))
(file-name (git-file-name name version)) (file-name (git-file-name name version))
(sha256 (base32 (sha256 (base32
"1gcry9fxv88js5nymi9akgrkghkwavggj3wqdgg2cz6brr5wg284")))) "0mca9ca8b2xjwjg0vl5858fd9l6h0m1jqbd3zr651zryf2897a80"))))
(build-system copy-build-system) (build-system copy-build-system)
(arguments (arguments
(list (list
@ -71,7 +71,7 @@
"if (NOT DEFINED BUILD_VERSION)\n" "if (NOT DEFINED BUILD_VERSION)\n"
" set(BUILD_VERSION " #$version ")\n" " set(BUILD_VERSION " #$version ")\n"
"elseif (DEFINED BUILD_VERSION)"))) "elseif (DEFINED BUILD_VERSION)")))
;; Avoid USER_CACHE_DIR to point to XDG_CACHE_HOME, HOME, or to ;; Avoid USER_CACHE_DIR to point to XDG_CACHE_HOME, HOME or to
;; ZEPHYR_BASE inside the store. Instead use the build dir. ;; ZEPHYR_BASE inside the store. Instead use the build dir.
(with-output-to-file (with-output-to-file
"cmake/modules/user_cache.cmake" "cmake/modules/user_cache.cmake"
@ -93,12 +93,12 @@
constrained devices, and built with security in mind.") constrained devices, and built with security in mind.")
(license license:apsl2)))) (license license:apsl2))))
(define-public zephyr-3.2+zmk-fixes (define-public zephyr-3.5+zmk-fixes
(let ((revision "1") (let ((revision "1")
(commit "0a586db7b58269fb08248b081bdc3b43452da5f4")) (commit "8f87b3be1e7631332cd8b245fb94d24d0354d0cb"))
(package/inherit zephyr (package/inherit zephyr
(name "zephyr+zmk-fixes") (name "zephyr+zmk-fixes")
(version (git-version "3.2.0" revision commit)) (version (git-version "3.5.0" revision commit))
(source (source
(origin (origin
(method git-fetch) (method git-fetch)
@ -107,7 +107,7 @@ constrained devices, and built with security in mind.")
(commit commit))) (commit commit)))
(file-name (git-file-name name version)) (file-name (git-file-name name version))
(sha256 (base32 (sha256 (base32
"04mqgzhgjb43ybryvpwrbq2g9i0gk7wd7s2ds3fsrakl4hxqss78")))) "0bgy6psg2wb4fflkz1ww5dkh5qq2yrfr3cqpi2qkwgj250m8cdfb"))))
(home-page "https://github.com/zmkfirmware/zephyr")))) (home-page "https://github.com/zmkfirmware/zephyr"))))
(define-public zephyr-build-tools (define-public zephyr-build-tools

View file

@ -40,9 +40,9 @@
(define-public (complete-zephyr-application zephyr-application (define-public (complete-zephyr-application zephyr-application
zephyr zephyr
zephyr-build-tools zephyr-build-tools
target
toolchain toolchain
c-toolchain target
additional-configure-flags
directory-to-install-from directory-to-install-from
source-prefix source-prefix
target-prefix) target-prefix)
@ -59,11 +59,12 @@ boilerplate."
(arguments (arguments
(append (append
(substitute-keyword-arguments (package-arguments zephyr-application) (substitute-keyword-arguments (package-arguments zephyr-application)
((#:configure-flags configure-flags #~(list)) ((#:configure-flags configure-flags '())
#~(append #$configure-flags #~(append
(list (list "-DZEPHYR_TOOLCHAIN_VARIANT=cross-compile"
"-DZEPHYR_TOOLCHAIN_VARIANT=cross-compile" (string-append "-DCROSS_COMPILE=" #$cross-compile-prefix))
(string-append "-DCROSS_COMPILE=" #$cross-compile-prefix))))) '#$additional-configure-flags
#$configure-flags)))
(list (list
#:tests? #f #:tests? #f
#:phases #:phases
@ -138,7 +139,7 @@ boilerplate."
(cons (package-license zephyr-application) (cons (package-license zephyr-application)
(map (compose package-license second) (map (compose package-license second)
(filter package? extended-inputs)))))) (filter package? extended-inputs))))))
c-toolchain))) (c-toolchain toolchain))))
(define*-public (make-zephyr-application-for-arm zephyr-application (define*-public (make-zephyr-application-for-arm zephyr-application
#:key #:key
@ -150,16 +151,17 @@ boilerplate."
target-prefix) target-prefix)
"Make a Zephyr application for Arm microcontrollers by completing the "Make a Zephyr application for Arm microcontrollers by completing the
incomplete ZEPHYR-APPLICATION package with Arm specific Zephyr boilerplate." incomplete ZEPHYR-APPLICATION package with Arm specific Zephyr boilerplate."
(complete-zephyr-application zephyr-application (complete-zephyr-application
zephyr-application
zephyr zephyr
zephyr-build-tools zephyr-build-tools
GCC-cross-picolibc-arm-none-eabi-toolchain
"arm-none-eabi" "arm-none-eabi"
gcc12-cross-newlib-arm-none-eabi-toolchain '("-DTOOLCHAIN_HAS_PICOLIBC=y"
gcc12-cross-newlib-arm-none-eabi-c-toolchain "-DCONFIG_TOOLCHAIN_CROSS_COMPILE_SUPPORTS_THREAD_LOCAL_STORAGE=y")
directory-to-install-from directory-to-install-from
source-prefix source-prefix
(or target-prefix (or target-prefix (package-name zephyr-application))))
(package-name zephyr-application))))
(define-public zephyr-hello-world (define-public zephyr-hello-world
(make-zephyr-application-for-arm (make-zephyr-application-for-arm
@ -171,10 +173,7 @@ incomplete ZEPHYR-APPLICATION package with Arm specific Zephyr boilerplate."
(arguments (arguments
(list (list
#:configure-flags #:configure-flags
#~(list "-DBOARD=nucleo_wb55rg" #~(list "-DBOARD=nucleo_f767zi"
"-DCONFIG_BT=y"
"-DCONFIG_BT_STM32_IPM=y"
"-DCMAKE_C_FLAGS=-DCFG_BLE_LSE_SOURCE=1"
"-DCMAKE_BUILD_TYPE=RelMinSize"))) "-DCMAKE_BUILD_TYPE=RelMinSize")))
(inputs (list zephyr-module-cmsis (inputs (list zephyr-module-cmsis
zephyr-module-hal-stm32 zephyr-module-hal-stm32

View file

@ -56,11 +56,11 @@ provides the build-system and proper arguments."
(license #f))) (license #f)))
(define-public zephyr-module-cmsis (define-public zephyr-module-cmsis
(let ((revision "1") (let ((revision "2")
(commit "74981bf893e8b10931464b9945e2143d99a3f0a3")) (commit "dc9658a1723ad911303a48b53a3e08222f10c181"))
(package/inherit zephyr-module-template (package/inherit zephyr-module-template
(name "zephyr-module-cmsis") (name "zephyr-module-cmsis")
(version (git-version "5.8.0" revision commit)) (version (git-version "5.9.0" revision commit))
(source (origin (source (origin
(method git-fetch) (method git-fetch)
(uri (git-reference (uri (git-reference
@ -69,7 +69,7 @@ provides the build-system and proper arguments."
(file-name (git-file-name name version)) (file-name (git-file-name name version))
(sha256 (sha256
(base32 (base32
"11wwcdwzi5ac8k881616p69v7cz356cwvbqsmmfw3w3v63b9dsmy")))) "0kyjmr2jvndnx1lpglg9rvcwbnb2abjksp0b9hydx366ivaza5xn"))))
(home-page "https://github.com/zephyrproject-rtos/cmsis") (home-page "https://github.com/zephyrproject-rtos/cmsis")
(synopsis "Zephyr module for CMSIS") (synopsis "Zephyr module for CMSIS")
(description "Zephyr module providing the Common Microcontroller (description "Zephyr module providing the Common Microcontroller
@ -78,10 +78,10 @@ Software Interface Standard.")
(define-public zephyr-module-hal-nordic (define-public zephyr-module-hal-nordic
(let ((revision "1") (let ((revision "1")
(commit "cf6e9fc5f7c2c98df26f2a4227a95df9a50823e7")) (commit "2947109e8dbc06ab6645d404499b6b6f6b04f3cf"))
(package/inherit zephyr-module-template (package/inherit zephyr-module-template
(name "zephyr-module-hal-nordic") (name "zephyr-module-hal-nordic")
(version (git-version "3.1.0" revision commit)) (version (git-version "3.4.0" revision commit))
(source (origin (source (origin
(method git-fetch) (method git-fetch)
(uri (git-reference (uri (git-reference
@ -90,7 +90,7 @@ Software Interface Standard.")
(file-name (git-file-name name version)) (file-name (git-file-name name version))
(sha256 (sha256
(base32 (base32
"1zbnhf7r9sg67xjhbdh6fn4gvccc71pxqcmbfnsi6a75bhfv9y55")))) "1sjhlxn866ip944a9y6lg3j2nr2nn9awzvny723cfm84xmrvq0kf"))))
(home-page "https://github.com/zephyrproject-rtos/hal_nordic") (home-page "https://github.com/zephyrproject-rtos/hal_nordic")
(synopsis "Zephyr module for Nordic Semiconductor's SoCs and SiPs") (synopsis "Zephyr module for Nordic Semiconductor's SoCs and SiPs")
(description "Zephyr module providing the Hardware Abstraction Layer for (description "Zephyr module providing the Hardware Abstraction Layer for
@ -114,12 +114,12 @@ Supported SoCs and SiPs:
") ")
(license license:bsd-3)))) (license license:bsd-3))))
(define-public zephyr-module-hal-nordic-2.11 (define-public zephyr-module-hal-nordic-3.1.0
(let ((revision "0") (let ((revision "1")
(commit "5644a13252e5d12e3e841105d106cfdeb40e59f9")) (commit "d054a315eb888ba70e09e5f6decd4097b0276d1f"))
(package/inherit zephyr-module-hal-nordic (package/inherit zephyr-module-hal-nordic
(name "zephyr-module-hal-nordic") (name "zephyr-module-hal-nordic")
(version (git-version "2.11.0" revision commit)) (version (git-version "3.1.0" revision commit))
(source (origin (source (origin
(method git-fetch) (method git-fetch)
(uri (git-reference (uri (git-reference
@ -128,11 +128,11 @@ Supported SoCs and SiPs:
(file-name (git-file-name name version)) (file-name (git-file-name name version))
(sha256 (sha256
(base32 (base32
"0lj7wlbfp9pb5pv819h9kbddmlzfbdnbmxhpm1i4xmf89z9v14sm"))))))) "0ypny416ylb2w5jg4bg55xvfg0yhqlbrakzvm0w23lnamg49kd6j")))))))
(define-public zephyr-module-hal-stm32 (define-public zephyr-module-hal-stm32
(let ((revision "1") (let ((revision "2")
(commit "d466dc8421ee0c6592bb5682aa93a671bc948107")) (commit "89ef0a3383edebf661073073bcdf6e2836fe90ee"))
(package/inherit zephyr-module-template (package/inherit zephyr-module-template
(name "zephyr-module-hal-stm32") (name "zephyr-module-hal-stm32")
;; Using highest version number listed in: ;; Using highest version number listed in:
@ -146,7 +146,7 @@ Supported SoCs and SiPs:
(file-name (git-file-name name version)) (file-name (git-file-name name version))
(sha256 (sha256
(base32 (base32
"0q0ckial6a3lvlag44zm65dklbbdnqpzr1vbh85dhwx7acpjd5ni")))) "0z7q5xg1rn9c3anjvi2kl0hgik3y3r25svwf97w1cjhjx1rhqmpv"))))
(home-page "https://github.com/zephyrproject-rtos/hal_stm32") (home-page "https://github.com/zephyrproject-rtos/hal_stm32")
(synopsis "Zephyr module for STM32 microcontrollers") (synopsis "Zephyr module for STM32 microcontrollers")
(description "Zephyr module providing the required STM32cube packages, (description "Zephyr module providing the required STM32cube packages,
@ -154,44 +154,28 @@ dtsi files and libraries needed to build a Zephyr application running on STM32
silicon.") silicon.")
(license license:bsd-3)))) (license license:bsd-3))))
(define-public zephyr-module-lvgl-8.2.0 (define-public zephyr-module-lvgl-8.3.11
(let ((revision "1") (let ((revision "1")
(commit "70a7849726be8375e3d941153dc417823ea7f355")) (commit "2b498e6f36d6b82ae1da12c8b7742e318624ecf5"))
(package/inherit zephyr-module-template (package/inherit zephyr-module-template
(name "zephyr-module-lvgl") (name "zephyr-module-lvgl")
(version (git-version "8.2.0" revision commit)) ; Taken from lvgl.h. (version (git-version "8.4.0" revision commit)) ; Taken from lvgl.h.
(source (origin (source (origin
(method git-fetch) (method git-fetch)
(uri (git-reference (uri (git-reference
(url "https://github.com/zmkfirmware/lvgl") (url "https://github.com/zephyrproject-rtos/lvgl/")
(commit commit))) (commit commit)))
(file-name (git-file-name name version)) (file-name (git-file-name name version))
(sha256 (sha256
(base32 (base32
"147mykkb72nwbjhrw4z7h0kkxw4p7kvy0w001s44rgplxhqqsg98")))) "09ch4zd0ha806jiasspvcxx526y663rw5gskyz9ikv9kcd5wdjks"))))
(home-page "https://github.com/zmkfirmware/lvgl") (home-page "https://github.com/zephyrproject-rtos/lvgl")
(synopsis "Zephyr module for LVGL") (synopsis "Zephyr module for LVGL")
(description "Zephyr module providing LVGL, the Light and Versatile (description "Zephyr module providing LVGL, the Light and Versatile
Graphics Library for an embedded GUI with graphical elements, visual effects Graphics Library for an embedded GUI with graphical elements, visual effects
and a low memory footprint.") and a low memory footprint.")
(license license:apsl2)))) (license license:apsl2))))
(define-public zephyr-module-lvgl
(let ((revision "2")
(commit "5da257f782a8f9c6e265bdc60ebc2a93fdee24de"))
(package/inherit zephyr-module-lvgl-8.2.0
(name "zephyr-module-lvgl")
(version (git-version "8.3.7" revision commit)) ; Taken from lvgl.h.
(source (origin
(method git-fetch)
(uri (git-reference
(url "https://github.com/zephyrproject-rtos/lvgl")
(commit commit)))
(file-name (git-file-name name version))
(sha256
(base32
"14isczxi36dasks1w4hwdlbzpvja4wal458i0km0hi92bbxayg0a")))))))
(define-public zephyr-module-mbedtls (define-public zephyr-module-mbedtls
(let ((revision "1") (let ((revision "1")
(commit "c38dc78d9a8dcbe43b898cc1171ab33ba3e6fc26")) (commit "c38dc78d9a8dcbe43b898cc1171ab33ba3e6fc26"))
@ -217,10 +201,10 @@ embedded systems.")
(define-public zephyr-module-mcuboot (define-public zephyr-module-mcuboot
(let ((revision "1") (let ((revision "1")
(commit "76d19b3b8885ea7ae25a6f4f5d8501f7ec646447")) (commit "02267cfdb5b368c700e3ca6bf47ecc97924c9a56"))
(package/inherit zephyr-module-template (package/inherit zephyr-module-template
(name "zephyr-module-mcuboot") (name "zephyr-module-mcuboot")
(version (git-version "1.11.0-dev" revision commit)) (version (git-version "2.0.0" revision commit))
(source (origin (source (origin
(method git-fetch) (method git-fetch)
(uri (git-reference (uri (git-reference
@ -229,7 +213,7 @@ embedded systems.")
(file-name (git-file-name name version)) (file-name (git-file-name name version))
(sha256 (sha256
(base32 (base32
"1frm9330bir1cz7h87qq26r74igy3pvrz3iqpvc7r6l7silj0fxf")))) "1xxsaz6fanv9k1gb9d9ch0klfd88daaxrdha14vhx8xfx1wdrsiv"))))
(home-page "https://github.com/zephyrproject-rtos/mcuboot") (home-page "https://github.com/zephyrproject-rtos/mcuboot")
(synopsis "Zephyr module for MCUboot") (synopsis "Zephyr module for MCUboot")
(description "Zephyr module providing the secure bootloader MCUboot for (description "Zephyr module providing the secure bootloader MCUboot for
@ -259,20 +243,19 @@ bootloader that enables easy software upgrade.")
(license (license:non-copyleft "file://README.zephyr"))))) (license (license:non-copyleft "file://README.zephyr")))))
(define-public zephyr-module-zcbor (define-public zephyr-module-zcbor
(let ((revision "1") (let ((version "0.8.1"))
(commit "67fd8bb88d3136738661fa8bb5f9989103f4599e"))
(package/inherit zephyr-module-template (package/inherit zephyr-module-template
(name "zephyr-module-zcbor") (name "zephyr-module-zcbor")
(version (git-version "0.7.0" revision commit)) (version version)
(source (origin (source (origin
(method git-fetch) (method git-fetch)
(uri (git-reference (uri (git-reference
(url "https://github.com/zephyrproject-rtos/zcbor") (url "https://github.com/zephyrproject-rtos/zcbor")
(commit commit))) (commit version)))
(file-name (git-file-name name version)) (file-name (git-file-name name version))
(sha256 (sha256
(base32 (base32
"16138k7xlahf63dfvplm8c2m0kxs1g17gcx1fa31y4gcfbi3b0k7")))) "1sc8bvqqjqyaxdmnvp7hk4js1vwa1gpxahqc1i16d5sl8gp7h8v2"))))
(home-page "https://github.com/zephyrproject-rtos/zcbor") (home-page "https://github.com/zephyrproject-rtos/zcbor")
(synopsis "Zephyr module for the zcbor library") (synopsis "Zephyr module for the zcbor library")
(description "Zephyr module providing the zcbor low footprint CBOR (description "Zephyr module providing the zcbor low footprint CBOR

View file

@ -28,6 +28,7 @@
#:use-module (ice-9 match) #:use-module (ice-9 match)
#:use-module (ice-9 optargs) #:use-module (ice-9 optargs)
#:use-module (srfi srfi-1) #:use-module (srfi srfi-1)
#:use-module (srfi srfi-26)
#:use-module (zephyr) #:use-module (zephyr)
#:use-module (zephyr apps) #:use-module (zephyr apps)
#:use-module (zephyr modules)) #:use-module (zephyr modules))
@ -49,13 +50,12 @@
(file-pattern "^config$")))) (file-pattern "^config$"))))
(home-page "https://zmk.dev/docs/config#config-file-locations") (home-page "https://zmk.dev/docs/config#config-file-locations")
(synopsis "ZMK firmware configuration") (synopsis "ZMK firmware configuration")
(description "This ZMK Firmware configuration is a helper to set the (description "This ZMK firmware configuration is a helper to set the
ZMK_CONFIG environment varibale during a ZMK Firmware package build to its ZMK_CONFIG environment varibale during a ZMK firmware package build to its
configuration input. Add a file-like object like a file-union or a package configuration input. Add a file-like object like a file-union or a package
containing a zmk-config/config folder as build input to a ZMK Firmare packege.") containing a zmk-config/config folder as build input to a ZMK firmare packege.")
(license license:expat))) (license license:expat)))
(define*-public (make-zmk board (define*-public (make-zmk board
#:key #:key
(shield "") (shield "")
@ -69,7 +69,7 @@ EXTRA-NAME with a trailing hyphen to customize the package name. Use PATCHES or
SNIPPET to modify the ZMK sources." SNIPPET to modify the ZMK sources."
(make-zephyr-application-for-arm (make-zephyr-application-for-arm
(let* ((revision "1") (let* ((revision "1")
(commit "9d714c0b69fee2098a010d29e534051aeca26386") (commit "0d3a4b7bbb199103d151ee1cadde613101859054")
(underscore->hyphen (lambda (name) (underscore->hyphen (lambda (name)
(string-map (lambda (char) (string-map (lambda (char)
(if (char=? char #\_) (if (char=? char #\_)
@ -82,7 +82,7 @@ SNIPPET to modify the ZMK sources."
(package (package
(name (string-append shield-name (if shield "-" "") (name (string-append shield-name (if shield "-" "")
extra-name board-name "-zmk")) extra-name board-name "-zmk"))
(version (git-version "2023.06.12" revision commit)) (version (git-version "2024.04.28" revision commit))
(source (origin (source (origin
(method git-fetch) (method git-fetch)
(uri (git-reference (uri (git-reference
@ -91,7 +91,7 @@ SNIPPET to modify the ZMK sources."
(file-name (git-file-name name version)) (file-name (git-file-name name version))
(sha256 (sha256
(base32 (base32
"08mihhcdlb9hh1qa0l6limggmvy98qiq6051p9qhnh6zbs8021h7")) "0i0656y83lwy2qspymy6fp7w4z68khxk9w1l7gqbv5c4ng8qjl0z"))
(patches patches) (patches patches)
(snippet snippet))) (snippet snippet)))
(build-system #f) (build-system #f)
@ -99,14 +99,15 @@ SNIPPET to modify the ZMK sources."
(list (list
#:out-of-source? #t #:out-of-source? #t
#:configure-flags #:configure-flags
#~(append (list "-S../source/app" #~(cons* "-S../source/app"
(string-append "-DBOARD=" #$board)) (string-append "-DBOARD=" #$board)
"-DCMAKE_BUILD_TYPE=RelMinSize"
(if #$shield (if #$shield
(list (string-append "-DSHIELD=" #$shield)) (list (string-append "-DSHIELD=" #$shield))
'())))) '()))))
(inputs (append extra-inputs (inputs (append extra-inputs
(list zephyr-module-cmsis (list zephyr-module-cmsis
zephyr-module-lvgl-8.2.0 zephyr-module-lvgl-8.3.11
zephyr-module-tinycrypt zephyr-module-tinycrypt
zmk-config))) zmk-config)))
(home-page "https://zmk.dev") (home-page "https://zmk.dev")
@ -115,9 +116,9 @@ SNIPPET to modify the ZMK sources."
(format #f "ZMK Firmware for a ~a keyboard" (format #f "ZMK Firmware for a ~a keyboard"
board-name))) board-name)))
(description "ZMK Firmware is an open source (MIT) keyboard firmware (description "ZMK Firmware is an open source (MIT) keyboard firmware
built on the Zephyr Project Real Time Operating System (RTOS).") built on the Zephyr Project Real Time Operating System (RTOS).")
(license license:expat))) (license license:expat)))
#:zephyr zephyr-3.2+zmk-fixes #:zephyr zephyr-3.5+zmk-fixes
#:source-prefix "zmk")) #:source-prefix "zmk"))
(define*-public (make-zmk-union zmk-packages #:key name synopsis) (define*-public (make-zmk-union zmk-packages #:key name synopsis)
@ -145,7 +146,7 @@ shield or board names."
"nrfmicro_13" "nrfmicro_13"
#:shield shield #:shield shield
#:extra-name extra-name #:extra-name extra-name
#:extra-inputs (append (list zephyr-module-hal-nordic-2.11) #:extra-inputs (append (list zephyr-module-hal-nordic-3.1.0)
(if zmk-config (list zmk-config) (if zmk-config (list zmk-config)
'())) '()))
#:snippet #:snippet
@ -153,7 +154,7 @@ shield or board names."
(use-modules (guix build utils)) (use-modules (guix build utils))
(substitute* "app/CMakeLists.txt" (substitute* "app/CMakeLists.txt"
;; Move combo.c and behaviour_tap_dance.c above all other behaviors. ;; Move combo.c and behaviour_tap_dance.c above all other behaviors.
;; This fix is needed to get working layer-tap-dance. ;; This fix is needed to get a working layer-tap-dance.
(("^ target_sources\\(app PRIVATE src/combo.c\\)\n") "") (("^ target_sources\\(app PRIVATE src/combo.c\\)\n") "")
(("^ target_sources\\(app PRIVATE src/behaviors/behavior_tap_dance.c\\)\n") (("^ target_sources\\(app PRIVATE src/behaviors/behavior_tap_dance.c\\)\n")
"") "")
@ -163,12 +164,32 @@ shield or board names."
" target_sources(app PRIVATE src/combo.c)\n" " target_sources(app PRIVATE src/combo.c)\n"
" target_sources(app PRIVATE src/behaviors/behavior_tap_dance.c)\n")))))) " target_sources(app PRIVATE src/behaviors/behavior_tap_dance.c)\n"))))))
(define-public settings-reset-nrfmicro-13-zmk
(package
(inherit (make-nrfmicro-13-zmk "settings_reset"))
(synopsis "ZMK settings reset firmware for split-keyboards with nrfmicro
1.3/1.4 boards")
(description "Pairing issues of ZMK firmware split-keyboard halves can be
resolved by flashing this settings reset firmware to both controllers.")))
(define-public redox-right-nrfmicro-13-zmk
(make-nrfmicro-13-zmk "redox_right"))
(define-public redox-nrfmicro-13-zmk
(make-zmk-union
(list (make-nrfmicro-13-zmk "redox_left")
redox-right-nrfmicro-13-zmk
settings-reset-nrfmicro-13-zmk
)
#:name "redox-nrfmicro-13-zmk"
#:synopsis "ZMK firmware for a Redox shield with nrfmicro-1.3/1.4 board"))
(define (hid-modifier modifier) (define (hid-modifier modifier)
"Map a symbol for a MODIFIER key into a macro symbol for a ZMK keymap file. "Map a symbol for a MODIFIER key into a macro symbol for a ZMK keymap file.
An unknown MODIFIER symbol is just returned." An unknown MODIFIER symbol is just returned."
(define hid-modifier->zmk-macro (define hid-modifier->zmk-macro
'(( . LS) ( . LC) ( . LA) ( . LG) '(( . LS) ( . LC) ( . LA) ( . LG) ( . LG)
(R . RG) (R . RA) (R . RC) (R . RS))) (R. RG) (R. RG) (R . RA) (R . RC) (R . RS)))
(or (assoc-ref hid-modifier->zmk-macro modifier) modifier)) (or (assoc-ref hid-modifier->zmk-macro modifier) modifier))
(define-public (special-bindings key-label) (define-public (special-bindings key-label)
@ -181,31 +202,34 @@ ZMK keymap file. An unknown KEY-LABEL symbol is just returned."
( . &none) ( . &none)
;; Fall-through to the next active lower layer. ;; Fall-through to the next active lower layer.
( . &trans) ( . &trans)
;;
( . &key_repeat)
;; Keypress on sensor, requires two parameters for up and down keycodes. ;; Keypress on sensor, requires two parameters for up and down keycodes.
( . &inc_dec_kp) ( . &inc_dec_kp)
;; Reset and bootloader, on split keyboards this is side specific. ;; Reset and bootloader, on split keyboards this is side specific.
( . &sys_reset) ( . &bootloader) ( . &sys_reset) ( . &bootloader)
;; Bluetooth, requires one or two parameters. ;; Bluetooth, requires one or two parameters.
( . &bt) ( . &bt)
;; Backlight, requires one parameter. ;; Backlight, requires one parameter.
( . &bl))) ( . &bl)))
(or (assoc-ref special-bindings->zmk-name key-label) key-label)) (or (assoc-ref special-bindings->zmk-name key-label) key-label))
(define-public (hid key-label) (define-public (hid-layout key-label)
"Map a HID KEY-LABEL into a macro symbol for a ZMK keymap file. Any other "Map a HID KEY-LABEL into a macro symbol for a ZMK keymap file. Any other
KEY-LABEL will be treated by 'special-bindings'." KEY-LABEL will be treated by 'special-bindings'."
(define hid->zmk-name (define hid->zmk-name
'(( . ESC) (. PSCRN) ( . SLCK) ( . PAUSE_BREAK) '(( . ESC) (. PSCRN) ( . SLCK) ( . PAUSE_BREAK)
(^ . GRAVE) (- . MINUS) (^ . GRAVE) (- . MINUS)
(= . EQUAL) ( . BSPC) (= . EQUAL) ( . BSPC)
( . TAB) ( . LBKT) ( . RBKT) ( . RET) ( . RET) ( . RET) ( . TAB) ( . LBKT) ( . RBKT) ( . RET) ( . RET) ( . RET)
( . CAPS) ( . SEMI) ( . SQT) ( . NUHS) ( . CAPS) ( . SEMI) ( . SQT) ( . NUHS)
( . LSHFT) (\ . NUBS) ( . LSHFT) (\ . NUBS)
( . COMMA) (· . DOT) (/ . SLASH) (R . RSHFT) ( . COMMA) (· . DOT) (/ . SLASH) (R . RSHFT)
( . LCTRL) ( . LALT) ( . LGUI) (. SPC) ( . LCTRL) ( . LALT) ( . LGUI) (. LGUI) (. SPC)
(R. RGUI) (R . RALT) (R . RCTRL) ( . K_APP) (R. RGUI) (R. RGUI) (R . RALT) (R . RCTRL) ( . K_APP)
( . INS) ( . HOME) ( . HOME) ( . PG_UP) ( . INS) ( . HOME) ( . HOME) ( . PG_UP)
( . DEL) ( . END) ( . END) ( . PG_DN) ( . DEL) ( . END) ( . END) ( . PG_DN)
(🌐 . GLOBE)
( . LEFT) ( . DOWN) ( . UP) ( . RIGHT) ( . LEFT) ( . DOWN) ( . UP) ( . RIGHT)
( . LEFT) ( . DOWN) ( . UP) ( . RIGHT) ( . LEFT) ( . DOWN) ( . UP) ( . RIGHT)
( . KP_NUMLOCK) (NUM . KP_NUMLOCK) ( . KP_NUMLOCK) (NUM . KP_NUMLOCK)
@ -216,10 +240,13 @@ KEY-LABEL will be treated by 'special-bindings'."
(P. . KP_DOT) (P, . KP_COMMA) ( . ENTER) (P. . KP_DOT) (P, . KP_COMMA) ( . ENTER)
( . C_AC_CUT) ( . C_AC_COPY) ( . C_AC_PASTE) ( . C_AC_CUT) ( . C_AC_COPY) ( . C_AC_PASTE)
( . C_AC_UNDO) ( . C_AC_REDO) ( . C_AC_UNDO) ( . C_AC_REDO)
( . C_AL_KEYBOARD_LAYOUT))) ( . C_AL_KEYBOARD_LAYOUT)
( . C_BRIGHTNESS_DEC) ( . C_BRIGHTNESS_INC)
( . C_PREVIOUS) ( . C_PLAY_PAUSE) ( . C_NEXT)
(/ . C_MUTE) ( . C_VOLUME_DOWN) ( . C_VOLUME_UP)))
(special-bindings (or (assoc-ref hid->zmk-name key-label) key-label))) (special-bindings (or (assoc-ref hid->zmk-name key-label) key-label)))
(define-public (de key-label) (define-public (de-layout key-label)
"Map a german KEY-LABEL based on the QWERTZ-layout into an international HID "Map a german KEY-LABEL based on the QWERTZ-layout into an international HID
key-label, if needed, and return a symbol for a ZMK keymap file." key-label, if needed, and return a symbol for a ZMK keymap file."
(define de->hid (define de->hid
@ -227,55 +254,27 @@ key-label, if needed, and return a symbol for a ZMK keymap file."
(Z . Y) (Ü . ) (+ . ) (Z . Y) (Ü . ) (+ . )
(Ö . ) (Ä . ) (Ö . ) (Ä . )
(< . \) (Y . Z) (- . /) (< . \) (Y . Z) (- . /)
(P+ . +) (P, . P.) (P. . P,))) (/ . ÷) (P+ . +) (P, . P.) (P. . P,)))
(hid (or (assoc-ref de->hid key-label) key-label))) (hid-layout (or (assoc-ref de->hid key-label) key-label)))
(define-public (neo key-label) (define-public (neo-layout key-label)
"Map a german KEY-LABEL based on the neo-layout into the international HID "Map a german KEY-LABEL based on the neo-layout into the international HID
key-label, if needed, and return a symbol as needed by a ZMK keymap file." key-label, if needed, and return a symbol as needed by a ZMK keymap file."
(define neo->de (define neo->de
'((T1 . ^) '((T1 . ^) (¹ . ^)
(X . Q) (V . W) (L . E) (C . R) (W . T) (X . Q) (V . W) (L . E) (C . R) (W . T)
(M3 . ) (U . A) (I . S) (A . D) (E . F) (O . G) (M3 . ) (U . A) (I . S) (A . D) (E . F) (O . G)
(M4 . <) (Ü . Y) (Ö . X) (Ä . C) (P . V) (Z . B) (M4 . <) (Ü . Y) (Ö . X) (Ä . C) (P . V) (Z . B)
(- . ß) (T2 . ´) (- . ß) (T2 . ´) (² . ´)
(K . Z) (H . U) (G . I) (F . O) (Q . P) ( . Ü) (T3 . +) (K . Z) (H . U) (G . I) (F . O) (Q . P) ( . Ü) (T3 . +) (³ . +)
(S . H) (N . J) (R . K) (T . L) (D . Ö) (Y . Ä) (RM3 . ) (S . H) (N . J) (R . K) (T . L) (D . Ö) (Y . Ä) (RM3 . )
(B . N) (J . -) (RM4 . R) (B . N) (J . -) (RM4 . R)
(P . ))) (P . ) (+ . P+)))
(de (or (assoc-ref neo->de key-label) key-label))) (de-layout (or (assoc-ref neo->de key-label) key-label)))
(define*-public (zmk-keymap #:key (properties '())
(behaviors '())
(combos '())
(conditional_layers '())
(layers '())
(macros '()))
"Generate the content of a keymap file for ZMK. Each layer in LAYERS has a
name, a layout and multiple rows, of which each contains the key-bindings. The
last row contains the bindings for sensors. The key-bindings use symbols from
the layout. The BEHAVIORS, COMBOS, MACROS and CONDITIONAL-LAYERS contain lists
of strings to inject own appropiate definitions for ZMK. PROPERTIES may contain
properties for behaviors or even C macro definitions."
(define (include file)
"Return an include statement for file"
(string-append "#include <" file ">"))
(define (include-binding file)
"Return an include statement for file defining bindings."
(include (string-append "dt-bindings/zmk/" file)))
(define (includes)
"Return all include statements offered by ZMK for keymap files."
(append (map include '("behaviors.dtsi"))
(map include-binding '("backlight.h" "bt.h" "ext_power.h"
"hid_usage.h" "hid_usage_pages.h" "keys.h"
"kscan_mock.h" "matrix_transform.h"
"modifiers.h" "outputs.h" "reset.h"
"rgb.h"))))
(define* (keymap-layer name layout rows)
"Return a string with a keymap layer definition NAME for a ZMK keymap file,
consisting of ROWS of keys with their labels based on LAYOUT."
(define-public (bindings layout keys)
"Transform a list of KEYS based on LAYOUT into ZMK behavior bindings enclosed
in \"<…>\". Any string in KEYS will be passed through."
(define (zmk-name->string zmk-name) (define (zmk-name->string zmk-name)
"Tansform a ZMK-NAME into a string." "Tansform a ZMK-NAME into a string."
(cond ((string? zmk-name) zmk-name) (cond ((string? zmk-name) zmk-name)
@ -287,7 +286,7 @@ consisting of ROWS of keys with their labels based on LAYOUT."
(zmk-name->string (layout key-label))) (zmk-name->string (layout key-label)))
(define (modified-key->zmk modified-key) (define (modified-key->zmk modified-key)
"Transform a possibly MODIFIED-KEY like '(⇧ ⌥ ⎋) into the \"LS((LA(ESC))\" "Transform a possibly MODIFIED-KEY like '(⇧ ⌥ ⎋) into the \"LS(LA(ESC))\"
respresentation of ZMK." respresentation of ZMK."
(match modified-key (match modified-key
((modifier modifier-or-key . rest) ((modifier modifier-or-key . rest)
@ -300,234 +299,557 @@ respresentation of ZMK."
(key-label (key-label
(key-label->zmk key-label)))) (key-label->zmk key-label))))
(define (behavior->zmk behavior strings-of-layers-and-modified-keys) (define (reference->zmk reference strings-of-layers-or-modified-keys)
"Join a BEHAVIOR symbol like '&mt with STRINGS-OF-LAYERS-AND-MODIFIED-KEYS "Join a reference symbol like '&mt with STRINGS-OF-LAYERS-OR-MODIFIED-KEYS
as parameters like '(\"LALT\" \"ESC\") into the \"&mt LALT ESC\" respresentation as parameters like '(\"LALT\" \"ESC\") into the \"&mt LALT ESC\" respresentation
of ZMK." of ZMK."
(string-join (cons (key-label->zmk behavior) (string-join (cons (key-label->zmk reference)
strings-of-layers-and-modified-keys))) strings-of-layers-or-modified-keys)))
(define (node->zmk node strings-of-layers-or-modified-keys)
"Join a BEHAVIOAR-NODE symbol like '/behaviors/hold-tap with
STRINGS-OF-LAYERS-OR-MODIFIED-KEYS as parameters like '(\"LALT\" \"ESC\")
into the proper node referecne \"&{/behaviors/hold-tap} LALT ESC\"
respresentation of ZMK."
(reference->zmk (string-append "&{" (key-label->zmk node) "}")
strings-of-layers-or-modified-keys))
(define (&-symbol? symbol) (define (&-symbol? symbol)
"Predicate to identify a symbol as a ZMK behavior prefixed with &." "Predicate to identify a symbol as a ZMK behavior or macro reference
(string=? "&" (string-take (key-label->zmk symbol) 1))) prefixed with &."
(string-prefix? "&" (key-label->zmk symbol)))
(define (/behaviors-or-macros-symbol? symbol)
"Predicate to identify a symbol as a ZMK behavior or macro node prefixed
with /behaviors/ or /macros/."
(any (cute string-prefix? <> (key-label->zmk symbol))
'("/behaviors/" "/macros/")))
(define (key-binding->zmk key-binding) (define (key-binding->zmk key-binding)
"Transform the KEY-BINDING, which could be a key-label, a modified key, or "Transform the KEY-BINDING, which could be a key-label, a modified key, or a
a behavior with layer and modified key parameters, into the representation of a behavior with layer and modified key parameters, into the representation of a
ZMK behavior for a keymap layer." ZMK behavior for a keymap layer."
(match key-binding (match key-binding
(((? &-symbol? behavior) . parameters) (((? &-symbol? label) . parameters)
;; A list starting with an &-symbol is a behavior with parameters. ;; A list starting with an &-symbol is a behavior or macro reference
;; The parameters themselves may be layers or modified keys. ;; with parameters. The parameters may be layers or modified keys.
(behavior->zmk behavior (map modified-key->zmk parameters))) (reference->zmk label (map modified-key->zmk parameters)))
(((? /behaviors-or-macros-symbol? node) . parameters)
;; A list starting with a /behaviors/… or /macros/… symbol is a node
;; with parameters. The parameters may be layers or modified keys.
(node->zmk node (map modified-key->zmk parameters)))
(modified-key (modified-key
(let ((modified-key (modified-key->zmk modified-key))) (let ((modified-key (modified-key->zmk modified-key)))
(if (or (string-null? modified-key) (if (or (&-symbol? modified-key)
(&-symbol? modified-key)) (and (string? modified-key)
;; There is nothing or a behavior is present, just use it. (string-null? (string-trim-both modified-key))))
;; There is a behavior present or only whitespace, just use it.
modified-key modified-key
;; Add a key-press behavior to the modified-key and start over. ;; Add a key-press behavior to the modified-key and start over.
(behavior->zmk '&kp (list modified-key))))))) (reference->zmk '&kp (list modified-key)))))))
(define (keys->zmk key-bindings) (string-append
"Transform a list of KEY-BINDINGS into ZMK behaviors for a keymap layer." "<"
(string-trim-right
(string-join (map (lambda (zmk-behavior) (string-join (map (lambda (zmk-behavior)
(string-pad-right (string-pad-right
zmk-behavior zmk-behavior
(max 12 (string-length zmk-behavior)))) (max 23 (string-length zmk-behavior))))
(map key-binding->zmk key-bindings)))) (map key-binding->zmk keys))))
">"))
(string-append " " name "_layer {" (define*-public (zmk-keymap #:key (c-defines '())
"\n bindings = <" (behaviors '())
(string-join (map keys->zmk (drop-right rows 1)) (macros '())
"\n " 'prefix) (layers '())
"\n >;" (conditional-layers '())
(combos '())
(properties '()))
"Generate the content of a keymap file for ZMK. Each layer in LAYERS has a
name, a layout and multiple rows, of which each contains the key-bindings. The
last row contains the bindings for sensors. The key-bindings use symbols from
the layout. The C-DEFINES contains a list of C pre-processor macros. The
BEHAVIORS, MACROS, CONDITIONAL-LAYERS and COMBOS contain lists of strings to
inject own appropiate definitions for ZMK. PROPERTIES may contain properties
for behaviors or other device-tree nodes."
(define (include file)
"Return an include statement for file"
(string-append "#include <" file ">"))
(define (include-binding file)
"Return an include statement for file defining bindings."
(include (string-append "dt-bindings/zmk/" file)))
(define (includes)
"Return all include statements offered by ZMK for keymap files."
(append (map include '("behaviors.dtsi"))
(map include-binding '("backlight.h" "bt.h" "ext_power.h"
"hid_usage.h" "hid_usage_pages.h" "keys.h"
"kscan_mock.h" "matrix_transform.h"
"modifiers.h" "mouse.h" "outputs.h" "reset.h"
"rgb.h"))))
(define* (keymap-layer name layer-number layout rows)
"Return a string with a keymap layer definition named NAME with a
LAYER-NUMBER suffix for a ZMK keymap file, consisting of ROWS of keys with their
labels based on LAYOUT. The last row contains the bindings for sensors."
(string-append name "-layer" (number->string layer-number) " {"
"\n bindings ="
"\n "
(string-join (map (cut bindings layout <>)
(drop-right rows 1))
",\n ")
#;(bindings layout (append-map (lambda (row)
(append '("\n ") row))
(drop-right rows 1)))
(if (null? (last rows)) (if (null? (last rows))
"" ""
(string-append (string-append
"\n sensor-bindings = <" ";\n sensor-bindings = "
(string-join (map keys->zmk (last rows)) (bindings layout (last rows))))
"\n " 'prefix) ";\n};"))
"\n >;"))
"\n };"))
(define (layer layer) (define (layer layer layer-number)
"Return a string for a ZMK keymap file containing a layer definition." "Return a string for a ZMK keymap file containing a layer definition."
(match layer (match layer
((name layout . rows) ((name layout . rows)
(keymap-layer name layout rows)))) (keymap-layer name layer-number layout rows))))
(define* (indent lines #:optional (n 4))
"Indent a list of LINES by N spaces. A line containing a list of strings
will be concatenated and a line containing a newline will be split before the indentation."
(map (cute string-append (make-string n #\space) <>)
(append-map (lambda (line)
(string-split (if (string? line)
line
(string-join line ""))
#\newline))
lines)))
(string-join (append (includes) (string-join (append (includes)
properties c-defines
(list "/ {" (list "/ {"
" behaviors {") " behaviors {")
behaviors (indent behaviors)
(list " };" (list " };"
" combos {" " macros {")
" compatible = \"zmk,combos\";") (indent macros)
combos
(list " };"
" conditional_layers {"
" compatible = \"zmk,conditional_layers\";")
conditional_layers
(list " };" (list " };"
" keymap {" " keymap {"
" compatible = \"zmk,keymap\";") " compatible = \"zmk,keymap\";")
(map layer layers) (indent (map layer layers (iota (length layers))))
(list " };" (list " };"
" macros {") " conditional_layers {"
macros " compatible = \"zmk,conditional-layers\";")
(indent conditional-layers)
(list " };" (list " };"
"};")) " combos {"
" compatible = \"zmk,combos\";")
(indent combos)
(list " };"
"};")
properties)
"\n")) "\n"))
;; This is a hold-tap behavior for a key, which momentarily activates a layer, (define-public (positions layer keys)
;; if hold, or switches to that layer, if tapped. "Return a string enclosed in \"<…>\" with the positional numbers of KEYS in
(define-public layer-hold-tap the LAYER. This is useful for combos or behaviors relying on the position of
" /omit-if-no-ref/ lht: behavior_layer_hold_tap { keys in the keyboard matrix. If the layer contains a key multiple times, then
the first key position will be returned. LAYER has a name, a layout and
multiple rows, of which each contains the key-bindings. The last row contains
the bindings for sensors."
(let* ((rows (drop-right (drop layer 2) 1))
(whitespace? (lambda (key)
(and (string? key)
(string-null? (string-trim-both key)))))
(keys-in-matrix (filter
(lambda (key)
(not (or (whitespace? key)
(eq? key '))))
(apply append rows)))
(positions (map (lambda (key)
(list-index (cut equal? key <>) keys-in-matrix))
keys)))
(when (not (null? (remove number? positions)))
(error (format #f "some keys of ~s were not found in the layer rows ~s"
keys
rows)))
(string-append "<" (string-join (map number->string positions)) ">")))
(define*-public (combo name positions bindings #:key timeout-ms
require-prior-idle-ms
slow-release
layers)
"Return a combo configuration describing a combination of key POSITIONS to
be pressed simultaneous to produce e.g. the key press in BINDNGS. Omitted
optional parameters will not be part of the configuration and make use of ZMK
defaults."
(let ((combo-begin
(format #f "combo-~a {" name))
(key-positions
(format #f " key-positions = ~a;" positions))
(bindings
(format #f " bindings = ~a;" bindings))
(timeout-ms
(if timeout-ms
(format #f " timeout-ms = <~a>;" timeout-ms)
""))
(require-prior-idle-ms
(if require-prior-idle-ms
(format #f " require-prior-idle-ms = <~a>;" require-prior-idle-ms)
""))
(slow-release
(if slow-release
" slow-release;"
""))
(layers
(if layers
(format #f " layers = <~a>;"
(string-join (map number->string layers)))
""))
(combo-end "};"))
(string-join (remove string-null? (list combo-begin
key-positions
bindings
timeout-ms
require-prior-idle-ms
slow-release
layers
combo-end))
"\n")))
(define*-public (vertical-combo name positions bindings #:key
(timeout-ms 200)
require-prior-idle-ms
(slow-release #t)
layers)
"Return a combo configuration describing a combination of key POSITIONS to
be pressed simultaneous to produce e.g. the key press in BINDNGS. Omitted
optional parameters will not be part of the configuration and make use of ZMK
defaults. The defaults for TIMEOUT-MS and SLOW-RELEASE make the combo suited
best for vertically adjacent keys to be pressed with one finger."
(combo name positions bindings #:timeout-ms timeout-ms
#:require-prior-idle-ms require-prior-idle-ms
#:slow-release slow-release
#:layers layers))
;; This is a hold-tap behavior with a balanced flavor for modifiers.
(define-public /behaviors/balanced-modifier-tap
"/omit-if-no-ref/ balanced-modifier-tap {
compatible = \"zmk,behavior-hold-tap\"; compatible = \"zmk,behavior-hold-tap\";
label = \"LAYER_HOLD_TAP\";
#binding-cells = <2>; #binding-cells = <2>;
flavor = \"balanced\"; flavor = \"balanced\";
tapping-term-ms = <200>; tapping-term-ms = <200>;
bindings = <&mo>, <&to>; quick-tap-ms = <200>;
}; bindings = <&kp &kp>;
") };")
(define-public (layer-tap-dance n) ;; This is a hold-tap behavior for modifiers and mouse-buttons.
"Give a tap-dance behavior '&ltdN', which counts the taps for the layer number (define-public /behaviors/modifier-mousebutton
and momentarily activates that layer on hold, or switches to that layer on tap. "/omit-if-no-ref/ modifier-mousebutton {
If the parameter N is 0, then taps select the layers 1, 2, 3. If N is 1, taps compatible = \"zmk,behavior-hold-tap\";
select the layers 0, 2, 3, and so on." #binding-cells = <2>;
(let ((first (if (>= n 1) "0 0" "1 1")) flavor = \"hold-preferred\";
(second (if (>= n 2) "1 1" "2 2")) tapping-term-ms = <200>;
(third (if (>= n 3) "2 2" "3 3")) bindings = <&kp &mkp>;
(n (number->string n))) };")
(string-append
" /omit-if-no-ref/ ltd" n ": behavior_layer_tap_dance" n " { ;; This is a double-tap tap-dance with two key-presses.
(define-public /behaviors/bluetooth-clear-or-clear-all
"/omit-if-no-ref/ bluetooth-clear-or-clear-all {
compatible = \"zmk,behavior-tap-dance\"; compatible = \"zmk,behavior-tap-dance\";
label = \"LAYER_TAP_DANCE" n "\";
#binding-cells = <0>; #binding-cells = <0>;
tapping-term-ms = <200>; tapping-term-ms = <200>;
bindings = <&lht " first ">, <&lht " second ">, <&lht " third ">; bindings = <&bt BT_CLR &bt BT_CLR_ALL>;
}; };")
")))
(define-public settings-reset-nrfmicro-13-zmk ;; This is a hold-tap behavior with tap-preferred flavor.
(package (define-public /behaviors/hold-tap
(inherit (make-nrfmicro-13-zmk "settings_reset")) "/omit-if-no-ref/ hold-tap {
(synopsis "ZMK settings reset firmware for split-keyboards with nrfmicro compatible = \"zmk,behavior-hold-tap\";
1.3/1.4 boards") #binding-cells = <2>;
(description "Pairing issues of ZMK firmware split-keyboard halves can be flavor = \"tap-preferred\";
resolved by flashing this settings reset firmware to both controllers."))) tapping-term-ms = <400>;
require-prior-idle-ms = <400>;
quick-tap-ms = <200>;
bindings = <&kp &kp>;
};")
(define-public redox-left-nrfmicro-13-zmk ;; This is a hold-tap behavior for a key, which momentarily activates a
(make-nrfmicro-13-zmk "redox_left")) ;; layer, if hold, or switches to that layer, if tapped.
(define-public /behaviors/layer-hold-tap
"/omit-if-no-ref/ layer-hold-tap {
compatible = \"zmk,behavior-hold-tap\";
#binding-cells = <2>;
flavor = \"balanced\";
tapping-term-ms = <200>;
bindings = <&mo &to>;
};")
(define-public redox-right-nrfmicro-13-zmk (define*-public (/behaviors/4-layer-tap-dance n #:key (start-layer 0))
(make-nrfmicro-13-zmk "redox_right")) "Give a tap-dance behavior, which counts the taps for the layer number and
momentarily activates that layer on hold, or switches to that layer on tap. If
(define-public redox-nrfmicro-13-zmk the parameter N is 0, then taps select the layers 1, 2, 3. If N is 1, taps
(make-zmk-union select the layers 0, 2, 3, and so on.
(list settings-reset-nrfmicro-13-zmk As it is not possible to momentarily activate a lower layer from an upper layer,
redox-left-nrfmicro-13-zmk it is expected that the layers 0, 1, 2 are duplicated in the layers 4, 5, 6. In
redox-right-nrfmicro-13-zmk) total seven layers are needed instead of four.
#:name "redox-nrfmicro-13-zmk" The START-LAYER defines the range of layers: START-LAYER N < START-LAYER + 4.
#:synopsis "ZMK firmware for a Redox shield with nrfmicro-1.3/1.4 board")) The examples above were given for the START-LAYER 0."
(let* ((a start-layer)
(b (1+ a))
(c (1+ b))
(d (1+ c))
(a' (+ a 4))
(b' (+ b 4))
(c' (+ c 4))
(layers (lambda (mo to)
(string-join (map number->string (list mo to)))))
(layer-n-hold-tap-i (if (<= n a) (layers b b) (layers a' a)))
(layer-n-hold-tap-j (if (<= n b) (layers c c) (layers b' b)))
(layer-n-hold-tap-k (if (<= n c) (layers d d) (layers c' c))))
(when (or (< n a)
(> n d))
(error
(format
#f
"/behaviors/4-layer-tap-dance: N = ~a is out of range ~a ≤ N ≤ ~a"
n a d)))
(string-append
"/omit-if-no-ref/ 4-layer-tap-dance-" (number->string n) " {
compatible = \"zmk,behavior-tap-dance\";
#binding-cells = <0>;
tapping-term-ms = <200>;
bindings = <&{/behaviors/layer-hold-tap} " layer-n-hold-tap-i "
&{/behaviors/layer-hold-tap} " layer-n-hold-tap-j "
&{/behaviors/layer-hold-tap} " layer-n-hold-tap-k ">;
};")))
(define-public redox-neo-keymap (define-public redox-neo-keymap
(let* ((M3Y '(&mt RM3 Y)) (let* ((M3Y '(/behaviors/balanced-modifier-tap RM3 Y))
(- '(&mt -)) (M3. '(/behaviors/balanced-modifier-tap RM3 ·))
(R '(&mt R )) (¹ '(&mt ¹))
(- '(&mt -)) ( '(&mt ))
(. '(&mt ·)) ( '(&mt ))
( '(&mt ))
(R '(&mt R ))
(R² '(&mt R ²))
(R '(/behaviors/modifier-mousebutton R MB4))
(R '(/behaviors/modifier-mousebutton R MB5))
( '(&mt ))
(R³ '(&mt R ³))
( '(&mt ))
(l1 '(&lt 1 )) (l1 '(&lt 1 ))
(l0 '(&ltd0)) ; Layer tap-dance for layer 0. (l4 '(&lt 4 ))
(l1 '(&ltd1)) ; Layer tap-dance for layer 1. (l5 '(&lt 5 ))
(l2 '(&ltd2)) ; Layer tap-dance for layer 2. (l0 '(/behaviors/4-layer-tap-dance-0))
(l3 '(&ltd3)) ; Layer tap-dance for layer 3. (l1 '(/behaviors/4-layer-tap-dance-1))
(1 '( BT_SEL 0)) (l2 '(/behaviors/4-layer-tap-dance-2))
(2 '( BT_SEL 1)) (l3 '(/behaviors/4-layer-tap-dance-3))
(3 '( BT_SEL 2)) (¹ '( BT_SEL 0))
(4 '( BT_SEL 3)) (² '( BT_SEL 1))
(5 '( BT_SEL 4)) (³ '( BT_SEL 2))
( '( BT_CLR)) ( '( BT_SEL 3))
( '( BT_SEL 4))
( '( BT_DISC 0))
( '( BT_DISC 1))
( '( BT_DISC 2))
( '( BT_DISC 3))
( '( BT_DISC 4))
( '( BT_NXT)) ( '( BT_NXT))
( '( BT_PRV)) ( '( BT_PRV))
( '(/behaviors/bluetooth-clear-or-clear-all))
(K '(/behaviors/hold-tap K))
(H '(/behaviors/hold-tap H))
(G '(/behaviors/hold-tap G))
(F '(/behaviors/hold-tap F))
(Q '(/behaviors/hold-tap Q))
(S '(/behaviors/hold-tap S))
(N '(/behaviors/hold-tap N))
(R '(/behaviors/hold-tap R))
(T '(/behaviors/hold-tap T))
(D '(/behaviors/hold-tap D))
(B '(/behaviors/hold-tap B))
(M '(/behaviors/hold-tap M))
( '(/behaviors/hold-tap ))
(· '(/behaviors/hold-tap ·))
(J '(/behaviors/hold-tap J))
( '(&mkp MB4))
( '(&mkp MB5))
(layer-0+4
`("default" ,neo-layout
( N1 N2 N3 N4 N5 N7 N8 N9 N0 - )
( X V L C W N6 ,K ,H ,G ,F ,Q )
( M3 U I A E O ,S ,N ,R ,T ,D ,M3Y)
(,¹ Ü Ö Ä P Z R R ,B ,M , ,· ,J ,R²)
(, ,l0 ,l1 M4 RM4 R ,l1 ,l0 , ,R³)
()))
(layer-1+5
`("cursor" ,neo-layout
( F1 F2 F3 F4 F5 F8 F9 F10 F11 F12 )
( F6 F7 )
( ,R)
(, R ,R)
( ,l1 , ,l4 ,l1 )
()))
(layer-2+6
`("keypad" ,neo-layout
( P= P / * )
( / , P7 P8 P9 + )
( M3 , P4 P5 P6 P, ,M3.)
(, R P1 P2 P3 ,R)
( ,l2 ,l5 M4 RM4 P0 ,l2 )
()))
(layer-3
`("zmk" ,neo-layout
( ,¹ ,² ,³ , , )
( , , , , , )
( , , )
( )
( ,l3 , ,l3 ,l3 ,l3 )
()))
(keymap (keymap
(zmk-keymap (zmk-keymap
#:layers #:behaviors (list /behaviors/balanced-modifier-tap
`(("default" ,neo /behaviors/modifier-mousebutton
( N1 N2 N3 N4 N5 N6 N7 N8 N9 N0 ) /behaviors/bluetooth-clear-or-clear-all
( X V L C W T2 K H G F Q ) /behaviors/hold-tap
( M3 U I A E O T3 S N R T D ,M3Y) /behaviors/layer-hold-tap
(,- Ü Ö Ä P Z R R B M · J ,R) (/behaviors/4-layer-tap-dance 0)
( T1 ,l0 M4 RM4 R ,l1 ,l0 ,- R ) (/behaviors/4-layer-tap-dance 1)
()) (/behaviors/4-layer-tap-dance 2)
("cursor" ,neo (/behaviors/4-layer-tap-dance 3))
( F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 ) #:layers (list layer-0+4 layer-1+5 layer-2+6 layer-3
( ) layer-0+4 layer-1+5 layer-2+6)
( ) #:combos
(,- R R ) (list (vertical-combo "lhs-shift-up"
( ,l1 R ,l1 ,- R ) (positions layer-1+5 '(F3 ))
()) (bindings neo-layout '(( )))
("keypad" ,neo #:layers '(1 5))
( F11 F12 F13 F14 F15 P ÷ * ) (vertical-combo "lhs-shift-home"
( P7 P8 P9 P+ ) (positions layer-1+5 '( ))
( M3 P4 P5 P6 P= M3 ) (bindings neo-layout '(( )))
(,- R R P1 P2 P3 R ) #:layers '(1 5))
( ,l2 M4 RM4 R P0 P, ,. R ) (vertical-combo "lhs-shift-left"
()) (positions layer-0+4 '(V I))
("zmk" ,neo (bindings neo-layout '(( )))
( ,1 ,2 ,3 ,4 ,5 ) #:layers '(1 5))
( ) (vertical-combo "lhs-shift-down"
( , , , ) (positions layer-1+5 '( ))
( ) (bindings neo-layout '(( )))
( ,l3 ,l3 ) #:layers '(1 5))
())) (vertical-combo "lhs-shift-right"
#:properties (list "&lt {quick-tap-ms = <200>;};" (positions layer-1+5 '( ))
"&mt {quick-tap-ms = <200>;};") (bindings neo-layout '(( )))
#:combos (list " combo_up {" ; G F ⇒ ↑ #:layers '(1 5))
" key-positions = <22 23>;" (vertical-combo "lhs-shift-end"
" bindings = <&kp UP>;" (positions layer-1+5 '( ))
" };" (bindings neo-layout '(( )))
" combo_left {" ; N R ⇒ ← #:layers '(1 5))
" key-positions = <35 36>;" (vertical-combo "rhs-shift-up"
" bindings = <&kp LEFT>;" (positions layer-0+4 `(N9 ,G))
" };" (bindings neo-layout '(( )))
" combo_down {" ; R T ⇒ ↓ #:layers '(1 5))
" key-positions = <36 37>;" (vertical-combo "rhs-shift-home"
" bindings = <&kp DOWN>;" (positions layer-0+4 `(,K ,S))
" };" (bindings neo-layout '(( )))
" combo_right {" ; T D ⇒ → #:layers '(1 5))
" key-positions = <37 38>;" (vertical-combo "rhs-shift-left"
" bindings = <&kp RIGHT>;" (positions layer-0+4 `(,H ,N))
" };") (bindings neo-layout '(( )))
#:behaviors (list layer-hold-tap #:layers '(1 5))
(layer-tap-dance 0) (vertical-combo "rhs-shift-down"
(layer-tap-dance 1) (positions layer-0+4 `(,G ,R))
(layer-tap-dance 2) (bindings neo-layout '(( )))
(layer-tap-dance 3))))) #:layers '(1 5))
(vertical-combo "rhs-shift-right"
(positions layer-0+4 `(,F ,T))
(bindings neo-layout '(( )))
#:layers '(1 5))
(vertical-combo "rhs-shift-end"
(positions layer-0+4 `(,Q ,D))
(bindings neo-layout '(( )))
#:layers '(1 5))
(vertical-combo "lhs-pageup"
(positions layer-1+5 '(F1 ))
(bindings neo-layout '()))
(vertical-combo "lhs-backspace"
(positions layer-0+4 '(N2 V))
(bindings neo-layout '()))
(vertical-combo "lhs-up"
(positions layer-1+5 '(F3 ))
(bindings neo-layout '()))
(vertical-combo "lhs-delete"
(positions layer-1+5 '(F4 ))
(bindings neo-layout '()))
(vertical-combo "lhs-pagedown"
(positions layer-1+5 '(F5 ))
(bindings neo-layout '()))
(vertical-combo "lhs-home"
(positions layer-1+5 '( ))
(bindings neo-layout '()))
(vertical-combo "lhs-left"
(positions layer-0+4 '(V I))
(bindings neo-layout '()))
(vertical-combo "lhs-down"
(positions layer-1+5 '( ))
(bindings neo-layout '()))
(vertical-combo "lhs-right"
(positions layer-1+5 '( ))
(bindings neo-layout '()))
(vertical-combo "lhs-end"
(positions layer-1+5 '( ))
(bindings neo-layout '()))
(vertical-combo "rhs-pageup"
(positions layer-0+4 `(N7 ,K))
(bindings neo-layout '()))
(vertical-combo "rhs-backspace"
(positions layer-0+4 `(N8 ,H))
(bindings neo-layout '()))
(vertical-combo "rhs-up"
(positions layer-0+4 `(N9 ,G))
(bindings neo-layout '()))
(vertical-combo "rhs-delete"
(positions layer-0+4 `(N0 ,F))
(bindings neo-layout '()))
(vertical-combo "rhs-pagedown"
(positions layer-0+4 `(- ,Q))
(bindings neo-layout '()))
(vertical-combo "rhs-home"
(positions layer-0+4 `(,K ,S))
(bindings neo-layout '()))
(vertical-combo "rhs-left"
(positions layer-0+4 `(,H ,N))
(bindings neo-layout '()))
(vertical-combo "rhs-down"
(positions layer-0+4 `(,G ,R))
(bindings neo-layout '()))
(vertical-combo "rhs-right"
(positions layer-0+4 `(,F ,T))
(bindings neo-layout '()))
(vertical-combo "rhs-end"
(positions layer-0+4 `(,Q ,D))
(bindings neo-layout '())))
#:properties (list "&mt {quick-tap-ms = <200>;};"
"&lt {quick-tap-ms = <200>;};"))))
(file-union "redox-config" (file-union "redox-config"
(list (list "zmk-config/config/redox.keymap" (list (list "zmk-config/config/redox.keymap"
(plain-file "redox-neo.keymap" keymap)))))) (plain-file "redox-neo.keymap" keymap))
(list "zmk-config/config/redox.conf"
(define-public redox-left-neo-nrfmicro-13-zmk (plain-file "redox-neo.conf"
(make-nrfmicro-13-zmk "redox_left" ;; Left hand options to fetch and report the battery level of the right hand.
#:zmk-config redox-neo-keymap "CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_FETCHING=y
#:extra-name "neo-")) CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_PROXY=y
CONFIG_ZMK_BLE_EXPERIMENTAL_CONN=y"))))))
(define-public redox-right-neo-nrfmicro-13-zmk
(make-nrfmicro-13-zmk "redox_right"
#:zmk-config redox-neo-keymap
#:extra-name "neo-"))
(define-public redox-neo-nrfmicro-13-zmk (define-public redox-neo-nrfmicro-13-zmk
(make-zmk-union (make-zmk-union
(list settings-reset-nrfmicro-13-zmk (list (make-nrfmicro-13-zmk "redox_left"
redox-left-neo-nrfmicro-13-zmk #:zmk-config redox-neo-keymap
redox-right-neo-nrfmicro-13-zmk) #:extra-name "neo-")
(make-nrfmicro-13-zmk "redox_right"
#:zmk-config redox-neo-keymap
#:extra-name "neo-")
settings-reset-nrfmicro-13-zmk
redox-neo-keymap)
#:name "redox-neo-nrfmicro-13-zmk" #:name "redox-neo-nrfmicro-13-zmk"
#:synopsis #:synopsis
"Neo layout ZMK firmware for a Redox shield with nrfmicro-1.3/1.4 board")) "Neo layout ZMK firmware for a Redox shield with nrfmicro-1.3/1.4 board"))