diff --git a/README.md b/README.md index 50cb2817b8f..f112b0f9705 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,10 @@ [![Build](https://github.com/zmkfirmware/zmk/workflows/Build/badge.svg)](https://github.com/zmkfirmware/zmk/actions) [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg)](CODE_OF_CONDUCT.md) -[ZMK Firmware](https://zmk.dev/) is an open source (MIT) keyboard firmware built on the [Zephyr™ Project](https://www.zephyrproject.org/) Real Time Operating System (RTOS). ZMK's goal is to provide a modern, wireless, and powerful firmware free of licensing issues. +[ZMK Firmware](https://zmk.dev/) is an open source ([MIT](LICENSE)) keyboard firmware built on the [Zephyr™ Project](https://www.zephyrproject.org/) Real Time Operating System (RTOS). ZMK's goal is to provide a modern, wireless, and powerful firmware free of licensing issues. -Check out the website to learn more: https://zmk.dev/ +Check out the website to learn more: https://zmk.dev/. -You can also come join our [ZMK Discord Server](https://zmk.dev/community/discord/invite) +You can also come join our [ZMK Discord Server](https://zmk.dev/community/discord/invite). To review features, check out the [feature overview](https://zmk.dev/docs/). ZMK is under active development, and new features are listed with 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. diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 4c1c63c2cfa..793f386dbe3 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -8,7 +8,7 @@ list(APPEND DTS_ROOT ${CMAKE_SOURCE_DIR}/drivers/zephyr) set(ZephyrBuildConfiguration_ROOT ${CMAKE_SOURCE_DIR}/cmake) list(APPEND ZEPHYR_EXTRA_MODULES - ${CMAKE_CURRENT_SOURCE_DIR}/drivers + ${CMAKE_CURRENT_SOURCE_DIR}/module ) # Find Zephyr. This also loads Zephyr's build system. @@ -59,7 +59,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL) target_sources(app PRIVATE src/behavior_queue.c) target_sources(app PRIVATE src/conditional_layer.c) target_sources(app PRIVATE src/endpoints.c) - target_sources(app PRIVATE src/events/endpoint_selection_changed.c) + target_sources(app PRIVATE src/events/endpoint_changed.c) target_sources(app PRIVATE src/hid_listener.c) target_sources(app PRIVATE src/keymap.c) target_sources(app PRIVATE src/events/layer_state_changed.c) @@ -87,6 +87,7 @@ target_sources_ifdef(CONFIG_USB_DEVICE_STACK app PRIVATE src/usb.c) target_sources_ifdef(CONFIG_ZMK_USB app PRIVATE src/usb_hid.c) target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/rgb_underglow.c) target_sources_ifdef(CONFIG_ZMK_BACKLIGHT app PRIVATE src/backlight.c) +target_sources(app PRIVATE src/workqueue.c) target_sources(app PRIVATE src/main.c) add_subdirectory(src/display/) diff --git a/app/Kconfig b/app/Kconfig index 92641c14ed0..0dd9316a2a7 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -403,14 +403,18 @@ endif #Initialization Priorities endmenu -menu "KSCAN Settings" +menuconfig ZMK_KSCAN + bool "ZMK KScan Integration" + default y + select KSCAN + +if ZMK_KSCAN config ZMK_KSCAN_EVENT_QUEUE_SIZE int "Size of the event queue for KSCAN events to buffer events" default 4 -#KSCAN Settings -endmenu +endif # ZMK_KSCAN menu "Logging" @@ -500,10 +504,18 @@ config ZMK_SETTINGS_SAVE_DEBOUNCE endif config ZMK_BATTERY_REPORT_INTERVAL - depends on ZMK_BLE + depends on ZMK_BATTERY_REPORTING int "Battery level report interval in seconds" default 60 +config ZMK_LOW_PRIORITY_THREAD_STACK_SIZE + int "Low priority thread stack size" + default 768 + +config ZMK_LOW_PRIORITY_THREAD_PRIORITY + int "Low priority thread priority" + default 10 + #Advanced endmenu diff --git a/app/boards/arm/corneish_zen/widgets/output_status.c b/app/boards/arm/corneish_zen/widgets/output_status.c index ad0c2b1a8fb..8e9457ebefe 100644 --- a/app/boards/arm/corneish_zen/widgets/output_status.c +++ b/app/boards/arm/corneish_zen/widgets/output_status.c @@ -14,9 +14,8 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include "output_status.h" #include -#include #include -#include +#include #include #include #include @@ -39,31 +38,29 @@ LV_IMG_DECLARE(USB_connected); static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); struct output_status_state { - enum zmk_endpoint selected_endpoint; + struct zmk_endpoint_instance selected_endpoint; bool active_profile_connected; bool active_profile_bonded; - uint8_t active_profile_index; }; static struct output_status_state get_state(const zmk_event_t *_eh) { - return (struct output_status_state){.selected_endpoint = zmk_endpoints_selected(), - .active_profile_connected = - zmk_ble_active_profile_is_connected(), - .active_profile_bonded = !zmk_ble_active_profile_is_open(), - .active_profile_index = zmk_ble_active_profile_index()}; - ; + return (struct output_status_state){ + .selected_endpoint = zmk_endpoints_selected(), + .active_profile_connected = zmk_ble_active_profile_is_connected(), + .active_profile_bonded = !zmk_ble_active_profile_is_open(), + }; } static void set_status_symbol(lv_obj_t *icon, struct output_status_state state) { - switch (state.selected_endpoint) { - case ZMK_ENDPOINT_USB: + switch (state.selected_endpoint.transport) { + case ZMK_TRANSPORT_USB: lv_img_set_src(icon, &USB_connected); break; - case ZMK_ENDPOINT_BLE: + case ZMK_TRANSPORT_BLE: if (state.active_profile_bonded) { if (state.active_profile_connected) { // sprintf(text, LV_SYMBOL_BLUETOOTH "%i " LV_SYMBOL_OK, active_profile_index); - switch (state.active_profile_index) { + switch (state.selected_endpoint.ble.profile_index) { case 0: lv_img_set_src(icon, &bluetooth_connected_1); break; @@ -84,7 +81,7 @@ static void set_status_symbol(lv_obj_t *icon, struct output_status_state state) lv_img_set_src(icon, &bluetooth_disconnected_right); } } else { - switch (state.active_profile_index) { + switch (state.selected_endpoint.ble.profile_index) { case 0: lv_img_set_src(icon, &bluetooth_advertising_1); break; @@ -113,11 +110,9 @@ static void output_status_update_cb(struct output_status_state state) { ZMK_DISPLAY_WIDGET_LISTENER(widget_output_status, struct output_status_state, output_status_update_cb, get_state) -ZMK_SUBSCRIPTION(widget_output_status, zmk_endpoint_selection_changed); - -#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) -ZMK_SUBSCRIPTION(widget_output_status, zmk_usb_conn_state_changed); -#endif +ZMK_SUBSCRIPTION(widget_output_status, zmk_endpoint_changed); +// We don't get an endpoint changed event when the active profile connects/disconnects +// but there wasn't another endpoint to switch from/to, so update on BLE events too. #if defined(CONFIG_ZMK_BLE) ZMK_SUBSCRIPTION(widget_output_status, zmk_ble_active_profile_changed); #endif diff --git a/app/boards/seeeduino_xiao_ble.overlay b/app/boards/seeeduino_xiao_ble.overlay index 51671a803b4..e6a5b62c738 100644 --- a/app/boards/seeeduino_xiao_ble.overlay +++ b/app/boards/seeeduino_xiao_ble.overlay @@ -32,3 +32,6 @@ }; }; +&qspi { + status = "disabled"; +}; diff --git a/app/boards/shields/cradio/cradio.keymap b/app/boards/shields/cradio/cradio.keymap index 3f6670da725..47bf0422a5a 100644 --- a/app/boards/shields/cradio/cradio.keymap +++ b/app/boards/shields/cradio/cradio.keymap @@ -18,7 +18,7 @@ flavor = "tap-preferred"; tapping-term-ms = <220>; quick-tap-ms = <150>; - global-quick-tap; + require-prior-idle-ms = <100>; bindings = <&kp>, <&kp>; }; }; diff --git a/app/boards/shields/kyria/kyria.keymap b/app/boards/shields/kyria/kyria.keymap index 9a2163db549..a11c13259e1 100644 --- a/app/boards/shields/kyria/kyria.keymap +++ b/app/boards/shields/kyria/kyria.keymap @@ -5,6 +5,7 @@ */ #include +#include #include / { @@ -15,15 +16,30 @@ // --------------------------------------------------------------------------------------------------------------------------------- // | 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 | +// | SHIFT | Z | X | C | V | B | L SHIFT | L SHIFT | | LAYER 1 | 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 SEMI &kp SQT - &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LSHFT &kp LSHFT &kp LSHFT &kp LSHFT &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RCTRL + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LSHFT &kp LSHFT &mo 1 &kp LSHFT &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RCTRL &kp LGUI &kp DEL &kp RET &kp SPACE &kp ESC &kp RET &kp SPACE &kp TAB &kp BSPC &kp RALT >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + function_layer { +// --------------------------------------------------------------------------------------------------------------------------------- +// | | |BT_CLR|BTSEL0|BTSEL1|BTSEL2| | | | | | | | +// | | | |BTSEL3|BTSEL4| | | | | | | | | +// | | | | | | | | | | | | | | | | | | | +// | | | | | | | | | | | | | + bindings = < + &trans &trans &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &trans &trans &trans &trans &trans &trans + &trans &trans &trans &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; }; }; diff --git a/app/boards/shields/kyria/kyria_rev2.keymap b/app/boards/shields/kyria/kyria_rev2.keymap index 9a2163db549..a11c13259e1 100644 --- a/app/boards/shields/kyria/kyria_rev2.keymap +++ b/app/boards/shields/kyria/kyria_rev2.keymap @@ -5,6 +5,7 @@ */ #include +#include #include / { @@ -15,15 +16,30 @@ // --------------------------------------------------------------------------------------------------------------------------------- // | 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 | +// | SHIFT | Z | X | C | V | B | L SHIFT | L SHIFT | | LAYER 1 | 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 SEMI &kp SQT - &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LSHFT &kp LSHFT &kp LSHFT &kp LSHFT &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RCTRL + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LSHFT &kp LSHFT &mo 1 &kp LSHFT &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RCTRL &kp LGUI &kp DEL &kp RET &kp SPACE &kp ESC &kp RET &kp SPACE &kp TAB &kp BSPC &kp RALT >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + function_layer { +// --------------------------------------------------------------------------------------------------------------------------------- +// | | |BT_CLR|BTSEL0|BTSEL1|BTSEL2| | | | | | | | +// | | | |BTSEL3|BTSEL4| | | | | | | | | +// | | | | | | | | | | | | | | | | | | | +// | | | | | | | | | | | | | + bindings = < + &trans &trans &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &trans &trans &trans &trans &trans &trans + &trans &trans &trans &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; }; }; diff --git a/app/boards/shields/kyria/kyria_rev3.keymap b/app/boards/shields/kyria/kyria_rev3.keymap index d74757cad7d..ac2fc044e73 100644 --- a/app/boards/shields/kyria/kyria_rev3.keymap +++ b/app/boards/shields/kyria/kyria_rev3.keymap @@ -5,6 +5,7 @@ */ #include +#include #include /* Uncomment this block if using RGB @@ -23,13 +24,28 @@ // --------------------------------------------------------------------------------------------------------------------------------- // | 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 | + // | SHIFT | Z | X | C | V | B | L SHIFT | L SHIFT | | LAYER 1 | 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 SEMI &kp SQT - &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LSHFT &kp LSHFT &kp LSHFT &kp LSHFT &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RCTRL - &kp LGUI &kp DEL &kp RET &kp SPACE &kp ESC &kp RET &kp SPACE &kp TAB &kp BSPC &kp RALT + &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 SEMI &kp SQT + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LSHFT &kp LSHFT &mo 1 &kp LSHFT &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RCTRL + &kp LGUI &kp DEL &kp RET &kp SPACE &kp ESC &kp RET &kp SPACE &kp TAB &kp BSPC &kp RALT + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + function_layer { + // --------------------------------------------------------------------------------------------------------------------------------- + // | | |BT_CLR|BTSEL0|BTSEL1|BTSEL2| | | | | | | | + // | | | |BTSEL3|BTSEL4| | | | | | | | | + // | | | | | | | | | | | | | | | | | | | + // | | | | | | | | | | | | | + bindings = < + &trans &trans &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &trans &trans &trans &trans &trans &trans + &trans &trans &trans &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans >; sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; diff --git a/app/boards/shields/leeloo/Kconfig.defconfig b/app/boards/shields/leeloo/Kconfig.defconfig index 7388a4b9af0..046bd49a3dd 100644 --- a/app/boards/shields/leeloo/Kconfig.defconfig +++ b/app/boards/shields/leeloo/Kconfig.defconfig @@ -1,6 +1,16 @@ -# Copyright (c) 2022 The ZMK Contributors +# Copyright (c) 2023 The ZMK Contributors # SPDX-License-Identifier: MIT +if SHIELD_LEELOO_REV2_LEFT + +config ZMK_KEYBOARD_NAME + default "Leeloo v2" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + if SHIELD_LEELOO_LEFT config ZMK_KEYBOARD_NAME @@ -11,7 +21,7 @@ config ZMK_SPLIT_ROLE_CENTRAL endif -if SHIELD_LEELOO_LEFT || SHIELD_LEELOO_RIGHT +if SHIELD_LEELOO config ZMK_SPLIT default y @@ -31,7 +41,6 @@ endif # ZMK_DISPLAY if LVGL - config LV_Z_VDB_SIZE default 64 diff --git a/app/boards/shields/leeloo/Kconfig.shield b/app/boards/shields/leeloo/Kconfig.shield index 46ea96400fb..1d7843957e5 100644 --- a/app/boards/shields/leeloo/Kconfig.shield +++ b/app/boards/shields/leeloo/Kconfig.shield @@ -1,8 +1,21 @@ -# Copyright (c) 2022 The ZMK Contributors +# Copyright (c) 2023 The ZMK Contributors # SPDX-License-Identifier: MIT +config SHIELD_LEELOO + bool + config SHIELD_LEELOO_LEFT def_bool $(shields_list_contains,leeloo_left) + select SHIELD_LEELOO config SHIELD_LEELOO_RIGHT def_bool $(shields_list_contains,leeloo_right) + select SHIELD_LEELOO + +config SHIELD_LEELOO_REV2_LEFT + def_bool $(shields_list_contains,leeloo_rev2_left) + select SHIELD_LEELOO + +config SHIELD_LEELOO_REV2_RIGHT + def_bool $(shields_list_contains,leeloo_rev2_right) + select SHIELD_LEELOO \ No newline at end of file diff --git a/app/boards/shields/leeloo/README.md b/app/boards/shields/leeloo/README.md index a807843f08f..27d5e872b5a 100644 --- a/app/boards/shields/leeloo/README.md +++ b/app/boards/shields/leeloo/README.md @@ -1,41 +1,123 @@ -# Clickety Split | Leeloo +# Clickety Split | Leeloo v2 -![Leeloo](https://cdn.shopify.com/s/files/1/0599/3460/5491/files/Leeloo-rev1.0-w.jpg?v=1646798726) +![Leeloo v2](https://github.com/ClicketySplit/build-guides/blob/main/leeloo/images/gallery/Leeloo-v2-ZMK.jpg) Keyboard Designer: [clicketysplit.ca](https://clicketysplit.ca) GitHub: [ClicketySplit](https://github.com/ClicketySplit) -Hardware Supported: Pro Micro, Elite-C, nice!nano v2 +Hardware Supported: Pro Micro, Elite-C, and nice!nano v2 -Albeit, there is no doubt where Leeloo's heritage is derived from—Lily58, and Corne. It is not a copy-paste-modify implementation. +Leeloo v2 has been designed from scratch—again. Everything from the wiring schematic to its case. Leeloo v2 still keeps the column stagger that it's known for, along with its low profile design. -Leeloo has been designed from scratch; everything from the schematic to its PCB footprints, and column stagger. There are some subtle differences that may not be apparent; however, its subtle changes enable an interesting future. +## Features/Differences from Leeloo v1 -Features: +- Support for Kailh Low Profile Choc switches with 18mm x 18mm spacing. + - A version for Kailh Box/MX switches with 19.05mm x 19.05mm spacing will be available in the future. +- All switch locations are socketed. +- Rotary encoder locations are socketed. + - One of two locations on each side can be used for a rotary encoder. +- OLED Displays and nice!view Displays are natively supported, socketed, and no extra wiring is required. +- Support for per-switch RGB underglow. +- Better location for 110mAh or 700mAh batteries. + - Different location for soldering battery leads. +- Support for Alps Alpine Micro On/off switches. + +# Leeloo v1 + +![Leeloo](https://github.com/ClicketySplit/build-guides/blob/main/leeloo/images/gallery/Leeloo-v1.jpg) + +## Features - 4x6x5m Split Keyboard -- Support for MX/Box or Low Profile Choc switches. -- 90% of the switches are socketed; with the exception to the rotary encoder positions—6 positions require soldering. -- Support for 128x32 OLED Displays. -- The option to select one of three positions for an EC11 rotary encoder on each half. -- Support for Alps Alpine Micro Switch -- Support for 3.7v 301230 LiPo Battery +- Support for both Low Profile Choc switches, and Box/MX switches; 19.05mm x 19.05mm spacing. +- 90% of the switches are socketed; with the exception to the rotary encoder positions. +- Support for Alps Alpine EC11 Rotary Encoders—one on each side, in one of three locations. +- Support for OLED Displays or nice!view Displays. + - nice!view displays require a wire to be soldered from the CS Pin on nice!view display to P0.22 or D4 on the nice!nano. +- Support for both 110mAh or 700mAh batteries. +- Solder pads for battery leads. +- Support for Alps Alpine Micro On/off switches. -# Building Your Firmware +# Building Leeloo's ZMK Firmware ZMK Firmware: [Introduction to ZMK](https://zmk.dev/docs/) Installation: [Installing ZMK](https://zmk.dev/docs/user-setup) Customization: [Customizing ZMK](https://zmk.dev/docs/customization) Development Environment: [Basic Setup](https://zmk.dev/docs/development/setup) -Build command for the default keymap of Leeloo: +Build commands for the default keymap of Leeloo v1: + +``` +west build -d build/left -p -b nice_nano_v2 -- -DSHIELD=leeloo_left +west build -d build/right -p -b nice_nano_v2 -- -DSHIELD=leeloo_right +``` + +Build commands for the default keymap of Leeloo v2: + +``` +west build -d build/left_v2 -p -b nice_nano_v2 -- -DSHIELD=leeloo_rev2_left +west build -d build/right_v2 -p -b nice_nano_v2 -- -DSHIELD=leeloo_rev2_right +``` + +Build commands for your custom keymap of Leeloo v1: + +``` +west build -d build/right -p -b nice_nano_v2 -- -DSHIELD=leeloo_right -DZMK_CONFIG="C:/dev/zmk/[yourName]/leeloo/config" +west build -d build/left -p -b nice_nano_v2 -- -DSHIELD=leeloo_left -DZMK_CONFIG="C:/dev/zmk/[yourName]/leeloo/config" +``` + +Build commands for your custom keymap of Leeloo v2: + +``` +west build -d build/right_v2 -p -b nice_nano_v2 -- -DSHIELD=leeloo_rev2_right -DZMK_CONFIG="C:/dev/zmk/[yourName]/leeloo_v2/config" +west build -d build/left_v2 -p -b nice_nano_v2 -- -DSHIELD=leeloo_rev2_left -DZMK_CONFIG="C:/dev/zmk/[yourName]/leeloo_v2/config" +``` + +## Building Leeloo's ZMK Firmware with nice!view Displays + +There are a couple of files that need to be adjusted before the build commands can be run. + +### Edit the leeloo[_rev2].keymap File + +Near the top 3rd of the leeloo[_rev2].keymap file, locate the following code block: + +``` +//nice_view_spi: &spi0 { +// cs-gpios = <&pro_micro 4 GPIO_ACTIVE_HIGH>; +//}; +``` + +Remove the forward slashes to resemble the following: + +``` +nice_view_spi: &spi0 { + cs-gpios = <&pro_micro 4 GPIO_ACTIVE_HIGH>; +}; +``` + +Save your changes and close the file. + +### Sample Build Commands for nice!view Displays + +Build commands for the default keymap of Leeloo v1: + +``` +west build -d build/left -p -b nice_nano_v2 -- -DSHIELD="leeloo_left nice_view_adapter nice_view" +west build -d build/right -p -b nice_nano_v2 -- -DSHIELD="leeloo_right nice_view_adapter nice_view" +``` + +Build commands for the default keymap of Leeloo v2: - west build -d build/left -p -b nice_nano_v2 -- -DSHIELD=leeloo_left - west build -d build/right -p -b nice_nano_v2 -- -DSHIELD=leeloo_right +``` +west build -d build/left_v2 -p -b nice_nano_v2 -- -DSHIELD="leeloo_rev2_left nice_view_adapter nice_view" +west build -d build/right_v2 -p -b nice_nano_v2 -- -DSHIELD="leeloo_rev2_right nice_view_adapter nice_view" +``` -Build command for your custom keymap of Leeloo: +Build commands for your custom keymap of Leeloo v2: - west build -d build/right -p -b nice_nano_v2 -- -DSHIELD=leeloo_right -DZMK_CONFIG="C:/dev/zmk/[yourNmae]/leeloo/config" - west build -d build/left -p -b nice_nano_v2 -- -DSHIELD=leeloo_left -DZMK_CONFIG="C:/dev/zmk/[yourName]/leeloo/config" +``` +west build -d build/left -p -b nice_nano_v2 -- -DSHIELD="leeloo_rev2_left nice_view_adapter nice_view" -DZMK_CONFIG="/workspaces/zmk-config/[yourName]/leeloo_v2/config" +west build -d build/right -p -b nice_nano_v2 -- -DSHIELD="leeloo_rev2_right nice_view_adapter nice_view" -DZMK_CONFIG="/workspaces/zmk-config/[yourName]/leeloo_v2/config" +``` # Support diff --git a/app/boards/shields/leeloo/boards/nice_nano_v2.overlay b/app/boards/shields/leeloo/boards/nice_nano_v2.overlay new file mode 100644 index 00000000000..5c451b73eaf --- /dev/null +++ b/app/boards/shields/leeloo/boards/nice_nano_v2.overlay @@ -0,0 +1,47 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + 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 = <37>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/leeloo/leeloo.conf b/app/boards/shields/leeloo/leeloo.conf index a652bb65144..466279a33e3 100644 --- a/app/boards/shields/leeloo/leeloo.conf +++ b/app/boards/shields/leeloo/leeloo.conf @@ -1,9 +1,16 @@ -# Copyright (c) 2022 The ZMK Contributors +# Copyright (c) 2023 The ZMK Contributors # SPDX-License-Identifier: MIT # Uncomment the following line to enable the OLED Display # CONFIG_ZMK_DISPLAY=y +# Uncomment to turn off WPM Status. +# CONFIG_ZMK_WIDGET_WPM_STATUS=n + +# Uncomment to invert colour when using nice!view Displays +# CONFIG_ZMK_DISPLAY_INVERT=y + + # Uncomment these two lines to add support for encoders # CONFIG_EC11=y -# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y \ No newline at end of file diff --git a/app/boards/shields/leeloo/leeloo.dtsi b/app/boards/shields/leeloo/leeloo.dtsi index 438f9a9d924..dad05c55c6e 100644 --- a/app/boards/shields/leeloo/leeloo.dtsi +++ b/app/boards/shields/leeloo/leeloo.dtsi @@ -1,87 +1,6 @@ /* - * Copyright (c) 2022 The ZMK Contributors - * + * Copyright (c) 2023 The ZMK Contributors * SPDX-License-Identifier: MIT */ -#include -/ { - chosen { - zephyr,display = &oled; - zmk,kscan = &kscan0; - zmk,matrix_transform = &default_transform; - }; - - default_transform: keymap_transform_0 { - compatible = "zmk,matrix-transform"; - columns = <12>; - rows = <5>; -// | 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 | SW22 | SW23 | SW24 | SW29 | | SW29 | SW24 | SW23 | SW22 | SW21 | SW20 | SW19 | -// | SW25 | SW26 | SW27 | SW28 | | SW28 | SW27 | SW26 | SW25 | - map = < -RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) -RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) -RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) -RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) - RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) RC(4,9) RC(4,10) - >; - }; - - kscan0: kscan { - compatible = "zmk,kscan-gpio-matrix"; - label = "KSCAN"; - - diode-direction = "col2row"; - row-gpios - = <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - , <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - ; - }; - - left_encoder: encoder_left { - compatible = "alps,ec11"; - label = "LEFT_ENCODER"; - a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; - b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; - resolution = <4>; - }; - - right_encoder: encoder_right { - compatible = "alps,ec11"; - label = "RIGHT_ENCODER"; - a-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; - b-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; - resolution = <4>; - }; - - sensors { - compatible = "zmk,keymap-sensors"; - sensors = <&left_encoder &right_encoder>; - }; -}; - -&pro_micro_i2c { - status = "okay"; - - oled: ssd1306@3c { - compatible = "solomon,ssd1306fb"; - reg = <0x3c>; - label = "DISPLAY"; - width = <128>; - height = <32>; - segment-offset = <0>; - page-offset = <0>; - display-offset = <0>; - multiplex-ratio = <31>; - segment-remap; - com-invdir; - com-sequential; - prechargep = <0x22>; - }; -}; +#include "leeloo_common.dtsi" \ No newline at end of file diff --git a/app/boards/shields/leeloo/leeloo.keymap b/app/boards/shields/leeloo/leeloo.keymap index fc3b25e03e2..bdbf8988cc8 100644 --- a/app/boards/shields/leeloo/leeloo.keymap +++ b/app/boards/shields/leeloo/leeloo.keymap @@ -1,17 +1,23 @@ /* - * Copyright (c) 2022 The ZMK Contributors - * + * Copyright (c) 2023 The ZMK Contributors * SPDX-License-Identifier: MIT */ + #include #include #include #include -// Layers -#define DEFAULT 0 // default_layer -#define LOWER 1 // lower_layer -#define RAISE 2 // raise_layer +/* + * Assign the cs-gpios pin to 4. + * Uncomment these next few lines if implementing nice!view Displays + * A wire from the nice!view CS display needs to be connected to the + * High Frequency P0.22, also known as D4 if you choose to refer to + * the pins with Arduino Labels. + */ +//nice_view_spi: &spi0 { +// cs-gpios = <&pro_micro 4 GPIO_ACTIVE_HIGH>; +//}; / { @@ -19,40 +25,43 @@ compatible = "zmk,keymap"; default_layer { + label = " QWERTY"; bindings = < &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &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 GRAV &kp CAPS &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT -&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT - &kp LALT &kp LCTRL < 1 RET < 2 MINUS &kp LGUI &kp LGUI < 2 EQUAL < 1 SPACE &kp BSPC &kp DEL +&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LGUI &kp LGUI &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LALT &kp LCTRL < 1 RET < 2 MINUS < 2 EQUAL < 1 SPACE &kp BSPC &kp DEL >; sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; }; lower_layer { + label = " Lower"; bindings = < &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &trans &trans &trans &trans &trans &trans &kp PG_UP &kp HOME &kp UP &kp END &trans &kp F12 &trans &trans &trans &trans &trans &trans &kp PG_DN &kp LEFT &kp DOWN &kp RIGHT &trans &trans -&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans - &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans >; sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; }; raise_layer { + label = " Raise"; bindings = < &trans &trans &trans &trans &trans &trans &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans -&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &sys_reset &bootloader -&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &sys_reset &bootloader &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans - &trans &trans &trans &trans &trans &trans &trans &trans &bt BT_CLR &trans +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &bt BT_CLR &trans >; sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; }; }; -}; +}; \ No newline at end of file diff --git a/app/boards/shields/leeloo/leeloo_common.dtsi b/app/boards/shields/leeloo/leeloo_common.dtsi new file mode 100644 index 00000000000..ef775cfbe61 --- /dev/null +++ b/app/boards/shields/leeloo/leeloo_common.dtsi @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zephyr,display = &oled; + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <12>; + rows = <5>; +// | 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 | SW22 | SW23 | SW24 | SW29 | | SW29 | SW24 | SW23 | SW22 | SW21 | SW20 | SW19 | +// | SW25 | SW26 | SW27 | SW28 | | SW28 | SW27 | SW26 | SW25 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5) RC(4,6) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) + RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,7) RC(4,8) RC(4,9) RC(4,10) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + + diode-direction = "col2row"; + + row-gpios + = <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; + + left_encoder: left_encoder { + compatible = "alps,ec11"; + label = "LEFT_ENCODER"; + a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <120>; + status = "disabled"; + }; + + right_encoder: right_encoder { + compatible = "alps,ec11"; + label = "RIGHT_ENCODER"; + a-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + steps = <120>; + status = "disabled"; + }; + + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + triggers-per-rotation = <30>; + }; + +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + label = "DISPLAY"; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/leeloo/leeloo_left.overlay b/app/boards/shields/leeloo/leeloo_left.overlay index 59fce1b0e5b..4421e1124ef 100644 --- a/app/boards/shields/leeloo/leeloo_left.overlay +++ b/app/boards/shields/leeloo/leeloo_left.overlay @@ -1,8 +1,8 @@ /* - * Copyright (c) 2022 The ZMK Contributors - * + * Copyright (c) 2023 The ZMK Contributors * SPDX-License-Identifier: MIT */ + #include "leeloo.dtsi" &kscan0 { @@ -18,4 +18,4 @@ &left_encoder { status = "okay"; -}; +}; \ No newline at end of file diff --git a/app/boards/shields/leeloo/leeloo_rev2.conf b/app/boards/shields/leeloo/leeloo_rev2.conf new file mode 100644 index 00000000000..8c1cf3eed7b --- /dev/null +++ b/app/boards/shields/leeloo/leeloo_rev2.conf @@ -0,0 +1,43 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Uncomment the following line to enable the OLED Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment to turn off WPM Status. +# CONFIG_ZMK_WIDGET_WPM_STATUS=n + +# Uncomment to invert colour when using nice!view Displays +# CONFIG_ZMK_DISPLAY_INVERT=y + + +# Uncomment the following line to enable per-key lighting +# CONFIG_ZMK_RGB_UNDERGLOW=y + +# Use the STRIP config specific to the LEDs you're using +# CONFIG_WS2812_STRIP=y + +# Keep OLED or nice!view Displays on even when toggling off LEDs +# Change to y if you wish to toggle Displays on and off with LEDs +# CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER=n + +# Turn off LEDs when idle. +# Change to n if you wish to keep LEDs on even when idle. +# CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_IDLE=y + +# When USB is disconnected, turn off LEDs +# Change to n if you wish to keep LEDs on even when USB is unpluged. +# CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_USB=y + +# Start LEDs off at 75% +# CONFIG_ZMK_RGB_UNDERGLOW_BRT_START=75 + + +# Uncomment these two lines to add support for encoders +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + + +# Uncomment if you are experiencing connectivity issues; this +# configuration item boosts the BLE transmit power. +# CONFIG_BT_CTLR_TX_PWR_PLUS_8=y \ No newline at end of file diff --git a/app/boards/shields/leeloo/leeloo_rev2.dtsi b/app/boards/shields/leeloo/leeloo_rev2.dtsi new file mode 100644 index 00000000000..dad05c55c6e --- /dev/null +++ b/app/boards/shields/leeloo/leeloo_rev2.dtsi @@ -0,0 +1,6 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +#include "leeloo_common.dtsi" \ No newline at end of file diff --git a/app/boards/shields/leeloo/leeloo_rev2.keymap b/app/boards/shields/leeloo/leeloo_rev2.keymap new file mode 100644 index 00000000000..a66205b64cc --- /dev/null +++ b/app/boards/shields/leeloo/leeloo_rev2.keymap @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +// Short versions +#define RGBON &rgb_ug RGB_ON +#define RGBOFF &rgb_ug RGB_OFF +#define RGBTOG &rgb_ug RGB_TOG +#define RGBHUI &rgb_ug RGB_HUI +#define RGBHUD &rgb_ug RGB_HUD +#define RGBSAI &rgb_ug RGB_SAI +#define RGBSAD &rgb_ug RGB_SAD +#define RGBBRI &rgb_ug RGB_BRI +#define RGBBRD &rgb_ug RGB_BRD +#define RGBEFF &rgb_ug RGB_EFF + + +/* + * Assign the cs-gpios pin to 4. + * Uncomment these next few lines if implementing nice!view Displays + */ +//nice_view_spi: &spi0 { +// cs-gpios = <&pro_micro 4 GPIO_ACTIVE_HIGH>; +//}; + + +/ { + + keymap { + compatible = "zmk,keymap"; + + default_layer { + label = " QWERTY"; + bindings = < +&kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &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 GRAV +&kp CAPS &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT +&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LGUI &kp RGUI &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LALT &kp LCTRL < 1 RET < 2 MINUS < 2 EQUAL < 1 SPACE &kp BSPC &kp DEL + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + lower_layer { + label = " Lower"; + bindings = < +&trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 +&trans &trans &trans &trans &trans &trans &kp PG_UP &kp HOME &kp UP &kp END &trans &kp F12 +&trans &trans &trans &trans &trans &trans &kp PG_DN &kp LEFT &kp DOWN &kp RIGHT &trans &trans +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + raise_layer { + label = " Raise"; + bindings = < +&trans &trans &trans &trans &trans &trans &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &sys_reset &bootloader +RGBON RGBTOG RGBHUI RGBSAI RGBBRI &trans &trans &trans &trans &trans &trans &trans +RGBOFF RGBEFF RGBHUD RGBSAD RGBBRD &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &bt BT_CLR &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + }; +}; \ No newline at end of file diff --git a/app/boards/shields/leeloo/leeloo_rev2.zmk.yml b/app/boards/shields/leeloo/leeloo_rev2.zmk.yml new file mode 100644 index 00000000000..5e0a4db3dc5 --- /dev/null +++ b/app/boards/shields/leeloo/leeloo_rev2.zmk.yml @@ -0,0 +1,15 @@ +file_format: "1" +id: leeloo_rev2 +name: Leeloo v2 +type: shield +url: https://clicketysplit.ca/pages/leeloo +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder + - underglow +siblings: + - leeloo_rev2_left + - leeloo_rev2_right diff --git a/app/boards/shields/leeloo/leeloo_rev2_left.overlay b/app/boards/shields/leeloo/leeloo_rev2_left.overlay new file mode 100644 index 00000000000..14ddc0eceb1 --- /dev/null +++ b/app/boards/shields/leeloo/leeloo_rev2_left.overlay @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +#include "leeloo_rev2.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + ; +}; + +&left_encoder { + status = "okay"; +}; \ No newline at end of file diff --git a/app/boards/shields/leeloo/leeloo_rev2_right.overlay b/app/boards/shields/leeloo/leeloo_rev2_right.overlay new file mode 100644 index 00000000000..afca41b474b --- /dev/null +++ b/app/boards/shields/leeloo/leeloo_rev2_right.overlay @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +#include "leeloo_rev2.dtsi" + +&default_transform { + col-offset = <6>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + ; +}; + +&right_encoder { + status = "okay"; +}; \ No newline at end of file diff --git a/app/boards/shields/leeloo/leeloo_right.overlay b/app/boards/shields/leeloo/leeloo_right.overlay index 80e89529566..b860c2ca651 100644 --- a/app/boards/shields/leeloo/leeloo_right.overlay +++ b/app/boards/shields/leeloo/leeloo_right.overlay @@ -1,8 +1,8 @@ /* - * Copyright (c) 2022 The ZMK Contributors - * + * Copyright (c) 2023 The ZMK Contributors * SPDX-License-Identifier: MIT */ + #include "leeloo.dtsi" &default_transform { @@ -22,4 +22,4 @@ &right_encoder { status = "okay"; -}; +}; \ No newline at end of file diff --git a/app/boards/shields/leeloo_micro/Kconfig.defconfig b/app/boards/shields/leeloo_micro/Kconfig.defconfig new file mode 100644 index 00000000000..26256120a76 --- /dev/null +++ b/app/boards/shields/leeloo_micro/Kconfig.defconfig @@ -0,0 +1,49 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_LEELOO_MICRO_LEFT + +config ZMK_KEYBOARD_NAME + default "Leeloo-Micro" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif + +if SHIELD_LEELOO_MICRO + +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 LV_Z_VDB_SIZE + default 64 + +config LV_Z_DPI + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif diff --git a/app/boards/shields/leeloo_micro/Kconfig.shield b/app/boards/shields/leeloo_micro/Kconfig.shield new file mode 100644 index 00000000000..c622f16dfcd --- /dev/null +++ b/app/boards/shields/leeloo_micro/Kconfig.shield @@ -0,0 +1,13 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_LEELOO_MICRO + bool + +config SHIELD_LEELOO_MICRO_LEFT + def_bool $(shields_list_contains,leeloo_micro_left) + select SHIELD_LEELOO_MICRO + +config SHIELD_LEELOO_MICRO_RIGHT + def_bool $(shields_list_contains,leeloo_micro_right) + select SHIELD_LEELOO_MICRO \ No newline at end of file diff --git a/app/boards/shields/leeloo_micro/README.md b/app/boards/shields/leeloo_micro/README.md new file mode 100644 index 00000000000..c1827f82b72 --- /dev/null +++ b/app/boards/shields/leeloo_micro/README.md @@ -0,0 +1,89 @@ +# Clickety Split | Leeloo-Micro + +![Leeloo-Micro v1 Wireless](https://github.com/ClicketySplit/build-guides/blob/main/leeloo/images/gallery/Leeloo-Micro-v1-ZMK.jpg) + +Keyboard Designer: [clicketysplit.ca](https://clicketysplit.ca) +GitHub: [ClicketySplit](https://github.com/ClicketySplit) +Hardware Supported: nice!nano v2, nice!view v1 + +Leeloo-Micro is a 3x5x5m derivative of Leeloo v2; inheriting the column stagger and modifiers row, yet, reducing the number of switches by removing the top row and outside columns. With Leeloo-Micro's inaugural release being wireless, it leverages nice!nanos and nice!views for its microcontrollers and displays. + +## Features + +- 3x5x5m Split Keyboard +- Support for Kailh Low Profile Choc switches with 18mm x 18mm spacing. +- All switch locations are socketed. +- Support for Alps Alpine EC11 Rotary Encoders—one on each side, in one of two locations. + - Rotary encoder locations are socketed. +- nice!view Displays are inherently supported, socketed, and no extra wiring is required. +- Support for per-switch RGB underglow. +- Support for both 110mAh or 700mAh batteries. +- Support for Alps Alpine Micro On/off switches. + +# Building Leeloo-Micro ZMK Firmware + +ZMK Firmware: [Introduction to ZMK](https://zmk.dev/docs/) +Installation: [Installing ZMK](https://zmk.dev/docs/user-setup) +Customization: [Customizing ZMK](https://zmk.dev/docs/customization) +Development Environment: [Basic Setup](https://zmk.dev/docs/development/setup) + +Build commands for the default keymap of Leeloo-Micro: + +``` +west build -d build/left -p -b nice_nano_v2 -- -DSHIELD=leeloo_micro_left +west build -d build/right -p -b nice_nano_v2 -- -DSHIELD=leeloo_micro_right +``` + +Build commands for your custom keymap of Leeloo-Micro: + +``` +west build -d build/right -p -b nice_nano_v2 -- -DSHIELD=leeloo_micro_right -DZMK_CONFIG="C:/dev/zmk/[yourName]/leeloo_micro/config" +west build -d build/left -p -b nice_nano_v2 -- -DSHIELD=leeloo_micro_left -DZMK_CONFIG="C:/dev/zmk/[yourName]/leeloo_micro/config" +``` + +## Building Leeloo-Micro's ZMK Firmware with nice!view Displays + +There are a couple of files that need to be adjusted before the build commands can be run. + +### Edit the leeloo_micro.keymap File + +Near the top 3rd of the leeloo_micro.keymap file, locate the following code block: + +``` +//nice_view_spi: &spi0 { +// cs-gpios = <&pro_micro 4 GPIO_ACTIVE_HIGH>; +//}; +``` + +Remove the forward slashes to resemble the following: + +``` +nice_view_spi: &spi0 { + cs-gpios = <&pro_micro 4 GPIO_ACTIVE_HIGH>; +}; +``` + +Save your changes and close the file. + +### Sample Build Commands for nice!view Displays + +Build commands for the default keymap of Leeloo-Micro: + +``` +west build -d build/left -p -b nice_nano_v2 -- -DSHIELD="leeloo_micro_left nice_view_adapter nice_view" +west build -d build/right -p -b nice_nano_v2 -- -DSHIELD="leeloo_micro_right nice_view_adapter nice_view" +``` + +Build commands for your custom keymap of Leeloo-Micro: + +``` +west build -d build/left -p -b nice_nano_v2 -- -DSHIELD="leeloo_micro_left nice_view_adapter nice_view" -DZMK_CONFIG="/workspaces/zmk-config/[yourName]/leeloo_micro/config" +west build -d build/right -p -b nice_nano_v2 -- -DSHIELD="leeloo_micro_right nice_view_adapter nice_view" -DZMK_CONFIG="/workspaces/zmk-config/[yourName]/leeloo_micro/config" +``` + +# Support + +If you have any questions with regards to Leeloo-Micro, please [Contact Us](https://clicketysplit.ca/pages/contact-us). + +Clickety Split +For the love of split keyboards. diff --git a/app/boards/shields/leeloo_micro/boards/nice_nano_v2.overlay b/app/boards/shields/leeloo_micro/boards/nice_nano_v2.overlay new file mode 100644 index 00000000000..be5dc54ec29 --- /dev/null +++ b/app/boards/shields/leeloo_micro/boards/nice_nano_v2.overlay @@ -0,0 +1,47 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + 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 = <20>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/leeloo_micro/leeloo_micro.conf b/app/boards/shields/leeloo_micro/leeloo_micro.conf new file mode 100644 index 00000000000..02c1d60587b --- /dev/null +++ b/app/boards/shields/leeloo_micro/leeloo_micro.conf @@ -0,0 +1,38 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Uncomment the following line to enable the OLED Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment to turn off WPM Status. +# CONFIG_ZMK_WIDGET_WPM_STATUS=n + +# Uncomment to invert colour, if using nice!view Displays +# CONFIG_ZMK_DISPLAY_INVERT=y + + +# Uncomment the following line to enable per-key lighting +# CONFIG_ZMK_RGB_UNDERGLOW=y + +# Use the STRIP config specific to the LEDs you're using +# CONFIG_WS2812_STRIP=y + +# Keep OLED or nice!view Displays on even when toggling off LEDs +# Change to y if you wish to toggle Displays on and off with LEDs +# CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER=n + +# Turn off LEDs when idle. +# Change to n if you wish to keep LEDs on even when idle. +# CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_IDLE=y + +# When USB is disconnected, turn off LEDs +# Change to n if you wish to keep LEDs on even when USB is unpluged. +# CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_USB=y + +# Start LEDs off at 75% +# CONFIG_ZMK_RGB_UNDERGLOW_BRT_START=75 + + +# Uncomment these two lines to add support for encoders +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y \ No newline at end of file diff --git a/app/boards/shields/leeloo_micro/leeloo_micro.dtsi b/app/boards/shields/leeloo_micro/leeloo_micro.dtsi new file mode 100644 index 00000000000..ab68a6153f1 --- /dev/null +++ b/app/boards/shields/leeloo_micro/leeloo_micro.dtsi @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zephyr,display = &oled; + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <10>; + rows = <4>; +// +// | SW1 | SW2 | SW3 | SW4 | SW5 | | SW15 | SW4 | SW3 | SW2 | SW1 | +// | SW6 | SW7 | SW8 | SW9 | SW10 | | SW10 | SW9 | SW8 | SW7 | SW6 | +// | SW11 | SW12 | SW13 | SW14 | SW15 | SW20 | | SW20 | SW15 | SW14 | SW13 | SW12 | SW11 | +// | SW16 | SW17 | SW18 | SW19 | | SW19 | SW18 | SW17 | SW16 | + 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(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(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(3,4) RC(3,5) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,6) RC(3,7) RC(3,8) RC(3,9) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + + diode-direction = "col2row"; + + row-gpios + = <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; + + left_encoder: left_encoder { + compatible = "alps,ec11"; + label = "LEFT_ENCODER"; + a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + status = "disabled"; + steps = <60>; + }; + + right_encoder: right_encoder { + compatible = "alps,ec11"; + label = "RIGHT_ENCODER"; + a-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + status = "disabled"; + steps = <60>; + }; + + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + triggers-per-rotation = <30>; + }; + +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + label = "DISPLAY"; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/leeloo_micro/leeloo_micro.keymap b/app/boards/shields/leeloo_micro/leeloo_micro.keymap new file mode 100644 index 00000000000..8526f5ac2a8 --- /dev/null +++ b/app/boards/shields/leeloo_micro/leeloo_micro.keymap @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +// Layers +#define QW_M 0 // Main +#define QW_L 1 // Lower +#define QW_R 2 // Raise +#define QW_A 3 // Adjust + +#define QC_N 4 // Number Pad +#define QC_B 5 // Firmware + + +// Short versions +#define BT0 BT_SEL 0 +#define BT1 BT_SEL 1 +#define BT2 BT_SEL 2 +#define BT3 BT_SEL 3 +#define BT4 BT_SEL 4 + +#define BOOTLDR &bootloader + +#define RGBON &rgb_ug RGB_ON +#define RGBOFF &rgb_ug RGB_OFF +#define RGBTOG &rgb_ug RGB_TOG +#define RGBHUI &rgb_ug RGB_HUI +#define RGBHUD &rgb_ug RGB_HUD +#define RGBSAI &rgb_ug RGB_SAI +#define RGBSAD &rgb_ug RGB_SAD +#define RGBBRI &rgb_ug RGB_BRI +#define RGBBRD &rgb_ug RGB_BRD +#define RGBEFF &rgb_ug RGB_EFF + + +/* + * Assign the cs-gpios pin to 4. + * Uncomment these next few lines if implementing nice!view Displays. + */ +//nice_view_spi: &spi0 { +// cs-gpios = <&pro_micro 4 GPIO_ACTIVE_HIGH>; +//}; + + +/ { + conditional_layers { + compatible = "zmk,conditional-layers"; + adjust_layer { + if-layers = ; + then-layer = ; + }; + }; + + combos { + compatible = "zmk,combos"; + + combo_esc { + timeout-ms = <50>; + key-positions = <0 1>; + layers = ; + bindings = <&kp ESC>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + label = " QWERTY"; + bindings = < +&kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P +&kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI +&mt LSFT Z &kp X &kp C &kp V &kp B &mo QC_N &kp RGUI &kp N &kp M &kp COMMA &kp DOT &mt RSFT FSLH + &kp LALT &kp LCTRL < 1 RET < 2 MINUS < 2 EQUAL < 1 SPACE &kp BSPC &mo QC_B + >; + + sensor-bindings = <&inc_dec_kp C_VOL_DN C_VOL_UP>; + }; + + lower_layer { + label = " Lower"; + bindings = < +&kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 +&trans &trans &trans &trans &trans &trans &trans &trans &trans &kp QUOT +&kp LSHFT &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &kp RSHFT + &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_DN C_VOL_UP>; + }; + + raise_layer { + label = " Raise"; + bindings = < +&kp TAB &trans &trans &trans &trans &kp PG_UP &kp HOME &kp UP &kp END &kp BSLH +&kp CAPS &trans &trans &trans &trans &kp PG_DN &kp LEFT &kp DOWN &kp RIGHT &kp GRAVE +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &mt RSFT TILDE + &trans &trans &trans &trans &trans &trans &kp DEL &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_DN C_VOL_UP>; + }; + + adjust_layer { + label = " Adjust"; + bindings = < + +&kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &trans &trans &trans &trans &trans +&kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &trans &trans &trans &trans &trans +&kp F11 &kp F12 &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_DN C_VOL_UP>; + }; + + numpad_layer { + label = " NumPad"; + bindings = < + +&trans &none &none &none &none &kp SLASH &kp N7 &kp N8 &kp N9 &kp MINUS +RGBON RGBTOG RGBHUI RGBSAI RGBBRI &kp ASTRK &kp N4 &kp N5 &kp N6 &kp PLUS +RGBOFF RGBEFF RGBHUD RGBSAD RGBBRD &trans &trans &none &kp N1 &kp N2 &kp N3 &kp EQUAL + &trans &trans &trans &trans &trans &kp N0 &kp DOT &none + >; + + sensor-bindings = <&inc_dec_kp C_VOL_DN C_VOL_UP>; + }; + + ble_layer { + label = " BLE"; + bindings = < + +&bt BT0 &bt BT1 &bt BT2 &bt BT3 &bt BT4 &bt BT0 &bt BT1 &bt BT2 &bt BT3 &bt BT4 +BOOTLDR &sys_reset &trans &trans &trans &trans &trans &trans &sys_reset BOOTLDR +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &bt BT_CLR &trans &trans &trans &trans &bt BT_CLR &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_DN C_VOL_UP>; + }; + + }; +}; \ No newline at end of file diff --git a/app/boards/shields/leeloo_micro/leeloo_micro.zmk.yml b/app/boards/shields/leeloo_micro/leeloo_micro.zmk.yml new file mode 100644 index 00000000000..e78ce0a3530 --- /dev/null +++ b/app/boards/shields/leeloo_micro/leeloo_micro.zmk.yml @@ -0,0 +1,15 @@ +file_format: "1" +id: leeloo_micro +name: Leeloo-Micro +type: shield +url: https://clicketysplit.ca/pages/leeloo-micro +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder + - underglow +siblings: + - leeloo_micro_left + - leeloo_micro_right diff --git a/app/boards/shields/leeloo_micro/leeloo_micro_left.overlay b/app/boards/shields/leeloo_micro/leeloo_micro_left.overlay new file mode 100644 index 00000000000..d31fcf2c0fd --- /dev/null +++ b/app/boards/shields/leeloo_micro/leeloo_micro_left.overlay @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +#include "leeloo_micro.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + ; +}; + +&left_encoder { + status = "okay"; +}; \ No newline at end of file diff --git a/app/boards/shields/leeloo_micro/leeloo_micro_right.overlay b/app/boards/shields/leeloo_micro/leeloo_micro_right.overlay new file mode 100644 index 00000000000..a3f347fb9c3 --- /dev/null +++ b/app/boards/shields/leeloo_micro/leeloo_micro_right.overlay @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +#include "leeloo_micro.dtsi" + +&default_transform { + col-offset = <5>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + ; +}; + +&right_encoder { + status = "okay"; +}; \ No newline at end of file diff --git a/app/boards/shields/microdox/Kconfig.defconfig b/app/boards/shields/microdox/Kconfig.defconfig index d05ae045803..e355c6411ee 100644 --- a/app/boards/shields/microdox/Kconfig.defconfig +++ b/app/boards/shields/microdox/Kconfig.defconfig @@ -1,7 +1,7 @@ # Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT -if SHIELD_MICRODOX_LEFT +if SHIELD_MICRODOX_LEFT || SHIELD_MICRODOX_V2_LEFT config ZMK_KEYBOARD_NAME default "Microdox" @@ -11,7 +11,7 @@ config ZMK_SPLIT_ROLE_CENTRAL endif -if SHIELD_MICRODOX_LEFT || SHIELD_MICRODOX_RIGHT +if SHIELD_MICRODOX_LEFT || SHIELD_MICRODOX_RIGHT || SHIELD_MICRODOX_V2_LEFT || SHIELD_MICRODOX_V2_RIGHT config ZMK_SPLIT default y diff --git a/app/boards/shields/microdox/Kconfig.shield b/app/boards/shields/microdox/Kconfig.shield index 47543760b6a..e0f461ff56f 100644 --- a/app/boards/shields/microdox/Kconfig.shield +++ b/app/boards/shields/microdox/Kconfig.shield @@ -6,3 +6,9 @@ config SHIELD_MICRODOX_LEFT config SHIELD_MICRODOX_RIGHT def_bool $(shields_list_contains,microdox_right) + +config SHIELD_MICRODOX_V2_LEFT + def_bool $(shields_list_contains,microdox_v2_left) + +config SHIELD_MICRODOX_V2_RIGHT + def_bool $(shields_list_contains,microdox_v2_right) diff --git a/app/boards/shields/microdox/README.md b/app/boards/shields/microdox/README.md new file mode 100644 index 00000000000..f92807bb7eb --- /dev/null +++ b/app/boards/shields/microdox/README.md @@ -0,0 +1,8 @@ +# Microdox + +Microdox is a 36 key split keyboard by Boardsource. + +Two variants are defined for this shield – V1 and V2. The layout is exactly the same between the +two. Per [help documentation](https://www.boardsource.xyz/help/6129be4a9c85c6050be190d2), if you +purchased your PCB before April 2022, use `microdox_left`/`microdox_right`. Otherwise, use +`microdox_v2_left`/`microdox_v2_right`. diff --git a/app/boards/shields/microdox/microdox.dtsi b/app/boards/shields/microdox/microdox.dtsi index e02aa5546f4..57247e68159 100644 --- a/app/boards/shields/microdox/microdox.dtsi +++ b/app/boards/shields/microdox/microdox.dtsi @@ -4,35 +4,12 @@ * SPDX-License-Identifier: MIT */ -#include +#include "microdox_common.dtsi" / { - chosen { - zephyr,display = &oled; - zmk,kscan = &kscan0; - zmk,matrix_transform = &default_transform; - }; - - default_transform: keymap_transform_0 { - compatible = "zmk,matrix-transform"; - columns = <10>; - rows = <4>; -// | SW1 | SW2 | SW3 | SW4 | SW5 | | SW5 | SW4 | SW3 | SW2 | SW1 | -// | SW6 | SW7 | SW8 | SW9 | SW10 | | SW10 | SW9 | SW8 | SW7 | SW6 | -// | SW11 | SW12 | SW13 | SW14 | SW15 | | SW15 | SW14 | SW13 | SW12 | SW11 | -// | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | - 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(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(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(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) - >; - }; - kscan0: kscan { compatible = "zmk,kscan-gpio-matrix"; label = "KSCAN"; - diode-direction = "col2row"; row-gpios = <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> @@ -40,26 +17,5 @@ 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) , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> , <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> ; - - }; - - // TODO: per-key RGB node(s)? -}; - -&pro_micro_i2c { - status = "okay"; - - oled: ssd1306@3c { - compatible = "solomon,ssd1306fb"; - reg = <0x3c>; - label = "DISPLAY"; - width = <128>; - height = <32>; - segment-offset = <0>; - page-offset = <0>; - display-offset = <0>; - multiplex-ratio = <31>; - com-sequential; - prechargep = <0x22>; }; }; diff --git a/app/boards/shields/microdox/microdox_common.dtsi b/app/boards/shields/microdox/microdox_common.dtsi new file mode 100644 index 00000000000..0460e012287 --- /dev/null +++ b/app/boards/shields/microdox/microdox_common.dtsi @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zephyr,display = &oled; + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <10>; + rows = <4>; +// | SW1 | SW2 | SW3 | SW4 | SW5 | | SW5 | SW4 | SW3 | SW2 | SW1 | +// | SW6 | SW7 | SW8 | SW9 | SW10 | | SW10 | SW9 | SW8 | SW7 | SW6 | +// | SW11 | SW12 | SW13 | SW14 | SW15 | | SW15 | SW14 | SW13 | SW12 | SW11 | +// | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | + 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(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(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(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) + >; + }; + + // TODO: per-key RGB node(s)? +}; + +&pro_micro_i2c { + status = "okay"; + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + label = "DISPLAY"; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/microdox/microdox_v2.conf b/app/boards/shields/microdox/microdox_v2.conf new file mode 100644 index 00000000000..0d38398c029 --- /dev/null +++ b/app/boards/shields/microdox/microdox_v2.conf @@ -0,0 +1,6 @@ +# Uncomment the following lines to enable the Microdox RGB Underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y +# CONFIG_WS2812_STRIP=y + +# Uncomment the following line to enable the Microdox OLED Display +# CONFIG_ZMK_DISPLAY=y diff --git a/app/boards/shields/microdox/microdox_v2.dtsi b/app/boards/shields/microdox/microdox_v2.dtsi new file mode 100644 index 00000000000..93fa44459db --- /dev/null +++ b/app/boards/shields/microdox/microdox_v2.dtsi @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "microdox_common.dtsi" + +/ { + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + diode-direction = "col2row"; + }; +}; diff --git a/app/boards/shields/microdox/microdox_v2.zmk.yml b/app/boards/shields/microdox/microdox_v2.zmk.yml new file mode 100644 index 00000000000..1b9b65b33e4 --- /dev/null +++ b/app/boards/shields/microdox/microdox_v2.zmk.yml @@ -0,0 +1,13 @@ +file_format: "1" +id: microdox_v2 +name: Microdox V2 +type: shield +url: https://boardsource.xyz/store/5f2e7e4a2902de7151494f92 +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display +siblings: + - microdox_v2_left + - microdox_v2_right diff --git a/app/boards/shields/microdox/microdox_v2_left.conf b/app/boards/shields/microdox/microdox_v2_left.conf new file mode 100644 index 00000000000..e69de29bb2d diff --git a/app/boards/shields/microdox/microdox_v2_left.overlay b/app/boards/shields/microdox/microdox_v2_left.overlay new file mode 100644 index 00000000000..83326f6fdc2 --- /dev/null +++ b/app/boards/shields/microdox/microdox_v2_left.overlay @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "microdox_v2.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 4 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + ; + row-gpios + = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; +}; diff --git a/app/boards/shields/microdox/microdox_v2_right.conf b/app/boards/shields/microdox/microdox_v2_right.conf new file mode 100644 index 00000000000..e69de29bb2d diff --git a/app/boards/shields/microdox/microdox_v2_right.overlay b/app/boards/shields/microdox/microdox_v2_right.overlay new file mode 100644 index 00000000000..412c42f63f4 --- /dev/null +++ b/app/boards/shields/microdox/microdox_v2_right.overlay @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "microdox.dtsi" + +&default_transform { + col-offset = <5>; +}; + +&oled { + segment-remap; + com-invdir; +}; + +&kscan0 { + col-gpios + = <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 21 GPIO_ACTIVE_HIGH> + ; + row-gpios + = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; +}; diff --git a/app/boards/shields/nice_view/CMakeLists.txt b/app/boards/shields/nice_view/CMakeLists.txt new file mode 100644 index 00000000000..694242b2ec1 --- /dev/null +++ b/app/boards/shields/nice_view/CMakeLists.txt @@ -0,0 +1,13 @@ +if(CONFIG_ZMK_DISPLAY AND CONFIG_NICE_VIEW_WIDGET_STATUS) + zephyr_library_include_directories(${CMAKE_SOURCE_DIR}/include) + zephyr_library_sources(custom_status_screen.c) + zephyr_library_sources(widgets/bolt.c) + zephyr_library_sources(widgets/util.c) + + if(NOT CONFIG_ZMK_SPLIT OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL) + zephyr_library_sources(widgets/status.c) + else() + zephyr_library_sources(widgets/art.c) + zephyr_library_sources(widgets/peripheral_status.c) + endif() +endif() diff --git a/app/boards/shields/nice_view/Kconfig.defconfig b/app/boards/shields/nice_view/Kconfig.defconfig index d2378409612..53edc1ccc7f 100644 --- a/app/boards/shields/nice_view/Kconfig.defconfig +++ b/app/boards/shields/nice_view/Kconfig.defconfig @@ -1,21 +1,13 @@ -# Copyright (c) 2022 The ZMK Contributors +# Copyright (c) 2023 The ZMK Contributors # SPDX-License-Identifier: MIT if SHIELD_NICE_VIEW -config ZMK_DISPLAY - select LV_FONT_MONTSERRAT_26 - -if ZMK_DISPLAY - -config SPI - default y - -config LS0XX - default y +config LV_Z_VDB_SIZE + default 100 -config ZMK_WIDGET_WPM_STATUS - default y if !ZMK_SPLIT || ZMK_SPLIT_ROLE_CENTRAL +config LV_Z_DPI + default 161 config LV_Z_BITS_PER_PIXEL default 1 @@ -24,6 +16,37 @@ choice LV_COLOR_DEPTH default LV_COLOR_DEPTH_1 endchoice -endif # ZMK_DISPLAY +choice ZMK_DISPLAY_WORK_QUEUE + default ZMK_DISPLAY_WORK_QUEUE_DEDICATED +endchoice + +choice ZMK_DISPLAY_STATUS_SCREEN + default ZMK_DISPLAY_STATUS_SCREEN_CUSTOM +endchoice + +config ZMK_DISPLAY_STATUS_SCREEN_CUSTOM + imply NICE_VIEW_WIDGET_STATUS + +config NICE_VIEW_WIDGET_STATUS + bool "Custom nice!view status widget" + select LV_FONT_MONTSERRAT_16 + select LV_USE_IMG + select LV_USE_CANVAS + +config NICE_VIEW_WIDGET_INVERTED + bool "Invert custom status widget colors" + +if !ZMK_SPLIT || ZMK_SPLIT_ROLE_CENTRAL + +config NICE_VIEW_WIDGET_STATUS + select LV_FONT_MONTSERRAT_18 + select LV_FONT_MONTSERRAT_14 + select LV_FONT_UNSCII_8 + select ZMK_WPM + +endif # !ZMK_SPLIT || ZMK_SPLIT_ROLE_CENTRAL + +config ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN + select LV_FONT_MONTSERRAT_26 -endif +endif # SHIELD_NICE_VIEW diff --git a/app/boards/shields/nice_view/README.md b/app/boards/shields/nice_view/README.md index e3dffa3446e..00abfbfab1e 100644 --- a/app/boards/shields/nice_view/README.md +++ b/app/boards/shields/nice_view/README.md @@ -1,5 +1,15 @@ # nice!view -The nice!view is a low power, high refresh rate display meant to replace I2C OLEDs traditionally used. +The nice!view is a low-power, high refresh rate display meant to replace I2C OLEDs traditionally used. -This shield requires that an `&nice_view_spi` labelled SPI bus is provided with _at least_ MOSI, SCK, and CS pins defined. +This shield requires that an `&nice_view_spi` labeled SPI bus is provided with _at least_ MOSI, SCK, and CS pins defined. + +## Disable custom widget + +The nice!view shield includes a custom vertical widget. To use the built-in ZMK one, add the following item to your `.conf` file: + +``` +CONFIG_ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN=y +CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_26=y +CONFIG_LV_FONT_DEFAULT_MONTSERRAT_26=y +``` diff --git a/app/boards/shields/nice_view/custom_status_screen.c b/app/boards/shields/nice_view/custom_status_screen.c new file mode 100644 index 00000000000..c08da0eb511 --- /dev/null +++ b/app/boards/shields/nice_view/custom_status_screen.c @@ -0,0 +1,28 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#include "widgets/status.h" + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if IS_ENABLED(CONFIG_NICE_VIEW_WIDGET_STATUS) +static struct zmk_widget_status status_widget; +#endif + +lv_obj_t *zmk_display_status_screen() { + + lv_obj_t *screen; + screen = lv_obj_create(NULL); + +#if IS_ENABLED(CONFIG_NICE_VIEW_WIDGET_STATUS) + zmk_widget_status_init(&status_widget, screen); + lv_obj_align(zmk_widget_status_obj(&status_widget), LV_ALIGN_TOP_LEFT, 0, 0); +#endif + + return screen; +} diff --git a/app/boards/shields/nice_view/nice_view.conf b/app/boards/shields/nice_view/nice_view.conf index ff57c07c9aa..e6f9158f137 100644 --- a/app/boards/shields/nice_view/nice_view.conf +++ b/app/boards/shields/nice_view/nice_view.conf @@ -1,5 +1,4 @@ # Enable nice!view CONFIG_ZMK_DISPLAY=y -CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_26=y -CONFIG_LV_FONT_DEFAULT_MONTSERRAT_26=y +# Disable idle blanking CONFIG_ZMK_DISPLAY_BLANK_ON_IDLE=n diff --git a/app/boards/shields/nice_view/widgets/art.c b/app/boards/shields/nice_view/widgets/art.c new file mode 100644 index 00000000000..56c8914629f --- /dev/null +++ b/app/boards/shields/nice_view/widgets/art.c @@ -0,0 +1,229 @@ +/* + * + * Copyright (c) 2023 Collin Hodge + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BALLOON +#define LV_ATTRIBUTE_IMG_BALLOON +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BALLOON uint8_t + balloon_map[] = { +#if CONFIG_NICE_VIEW_WIDGET_INVERTED + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ +#else + 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ + 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ +#endif + + 0xfe, 0xaa, 0x0a, 0x2a, 0x9f, 0xff, 0xff, 0xff, 0xfa, 0xea, 0xaa, 0xae, 0xba, 0xff, 0xff, + 0xfb, 0xff, 0xf0, 0xf1, 0x55, 0x05, 0x15, 0x47, 0xff, 0xff, 0xff, 0xf5, 0xd5, 0x55, 0x5f, + 0x7f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xa4, 0xaa, 0x8a, 0x8a, 0xa1, 0xff, 0xff, 0xfb, 0xea, + 0xaa, 0xaa, 0xbe, 0xbf, 0xef, 0xfb, 0xfb, 0xff, 0xf0, 0x54, 0x55, 0x05, 0x45, 0x54, 0xff, + 0xff, 0x7d, 0x55, 0xd5, 0x75, 0x7f, 0x7f, 0xdf, 0xff, 0xff, 0xff, 0xf0, 0xae, 0x2a, 0x82, + 0xa0, 0xaa, 0x3f, 0xff, 0xfe, 0xaa, 0xea, 0xbb, 0xfe, 0xbf, 0xff, 0xfb, 0xfb, 0xfe, 0xf0, + 0x5f, 0x55, 0x01, 0x50, 0x54, 0x1f, 0xff, 0x7f, 0x55, 0xd5, 0x7f, 0xff, 0x7f, 0xd7, 0xff, + 0xfd, 0xfd, 0xf0, 0x2f, 0xff, 0x20, 0x28, 0x00, 0x0f, 0xff, 0xae, 0xaa, 0xaa, 0xbf, 0xff, + 0xff, 0xeb, 0xfb, 0xff, 0xff, 0xf0, 0x0e, 0x01, 0x50, 0x14, 0x00, 0x3f, 0xff, 0x57, 0x55, + 0xd5, 0x7f, 0xff, 0x7f, 0xd7, 0xfd, 0xff, 0xfd, 0xf0, 0x1e, 0x01, 0xa8, 0x0a, 0x00, 0xff, + 0xff, 0xaf, 0xaa, 0xaa, 0xff, 0xff, 0xff, 0xaf, 0xfb, 0xff, 0xff, 0xf0, 0x1f, 0xf9, 0x50, + 0x01, 0x03, 0xff, 0xff, 0x57, 0x55, 0xd5, 0x7d, 0xff, 0x7f, 0xdf, 0xfd, 0xff, 0xfd, 0xf0, + 0x9f, 0xf9, 0xa8, 0x00, 0x8f, 0xff, 0xfe, 0xaf, 0xaa, 0xaa, 0xff, 0xff, 0xfd, 0xbf, 0xfb, + 0xff, 0xfb, 0xf0, 0x5a, 0x01, 0x54, 0x00, 0x3f, 0xff, 0xff, 0x7f, 0x5d, 0xd5, 0xfd, 0xff, + 0xfd, 0xdf, 0xfd, 0xff, 0xfd, 0xf0, 0x8e, 0x01, 0xaa, 0x00, 0x7f, 0xff, 0xfe, 0xbf, 0xae, + 0xef, 0xff, 0xff, 0xfb, 0xef, 0xfb, 0xff, 0xfa, 0xf0, 0xcf, 0xff, 0xf4, 0x00, 0xf7, 0xff, + 0xff, 0x7f, 0x5d, 0xff, 0xff, 0xff, 0xfd, 0xdf, 0xff, 0xff, 0xfd, 0xf0, 0xae, 0x01, 0x2a, + 0x00, 0xfb, 0xff, 0xff, 0xbf, 0xae, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfa, 0xf0, + 0xde, 0x01, 0x35, 0x01, 0xfb, 0xff, 0xff, 0x7f, 0x5d, 0xfd, 0xbf, 0xff, 0xff, 0xdf, 0xfd, + 0xff, 0xdd, 0xf0, 0xa7, 0xff, 0xea, 0x81, 0xfc, 0xff, 0x7f, 0xbe, 0xbe, 0xff, 0xe3, 0xff, + 0xff, 0xef, 0xff, 0xf9, 0x3e, 0xf0, 0x56, 0x01, 0x55, 0x41, 0xff, 0x7f, 0xff, 0xff, 0xfd, + 0xfd, 0xfc, 0x1f, 0xff, 0xff, 0xff, 0xfc, 0x7d, 0xf0, 0xa6, 0x01, 0x2a, 0x88, 0xfe, 0xff, + 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xfc, 0xfe, 0xf0, 0x52, 0x79, 0x15, + 0x44, 0x7d, 0xff, 0xff, 0xfd, 0x7f, 0xbd, 0xff, 0xff, 0xfc, 0x00, 0x07, 0xf8, 0xfd, 0xf0, + 0x22, 0x69, 0x2a, 0xa0, 0x3d, 0xff, 0xff, 0xfa, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xe2, 0x48, + 0xfa, 0xff, 0xf0, 0x42, 0x59, 0x15, 0x54, 0x1b, 0xff, 0xff, 0xf7, 0xff, 0xbd, 0xf7, 0xff, + 0xff, 0x95, 0x55, 0x37, 0x7d, 0xf0, 0x02, 0x69, 0x0a, 0xa2, 0x1f, 0xfe, 0xff, 0xee, 0xff, + 0xff, 0xfc, 0xff, 0xff, 0x2a, 0x4a, 0x9f, 0xff, 0xf0, 0x03, 0xff, 0x55, 0x11, 0x4f, 0xff, + 0xff, 0x55, 0x7f, 0xfd, 0xff, 0x00, 0xfc, 0x55, 0x55, 0x4f, 0xff, 0xf0, 0x02, 0x01, 0xaa, + 0x88, 0x8f, 0xde, 0xff, 0xaa, 0xbf, 0xfe, 0xff, 0xff, 0x00, 0xa8, 0x02, 0xa7, 0xff, 0xf0, + 0x02, 0x01, 0x55, 0x55, 0x47, 0xff, 0x7f, 0xd5, 0x5f, 0xff, 0xff, 0xff, 0xc8, 0x47, 0x5c, + 0x53, 0xff, 0xf0, 0x82, 0x49, 0xaa, 0x8a, 0xa7, 0xfe, 0xff, 0xea, 0xbf, 0xff, 0xff, 0xff, + 0xb0, 0x3f, 0x5f, 0x89, 0xff, 0xf0, 0xc2, 0x49, 0x55, 0x45, 0x53, 0xff, 0xff, 0xf5, 0x5f, + 0xff, 0xff, 0xfe, 0x70, 0x7f, 0x5f, 0xe5, 0xff, 0xf0, 0xe2, 0x41, 0xa2, 0xa2, 0xab, 0xfe, + 0xfb, 0xfa, 0xaf, 0xef, 0xff, 0xf9, 0xe2, 0xbf, 0x5f, 0xfa, 0xff, 0xf0, 0xe2, 0x41, 0x51, + 0x51, 0x51, 0xff, 0x77, 0xfd, 0x57, 0xf9, 0xff, 0xe7, 0x85, 0x7f, 0x5f, 0xfc, 0xff, 0xf0, + 0xe3, 0xff, 0xf2, 0xa0, 0xa8, 0xff, 0xfb, 0xbe, 0xaf, 0xfe, 0x1e, 0x80, 0x6a, 0x80, 0x00, + 0x7e, 0xff, 0xb0, 0xe2, 0x60, 0x11, 0x50, 0x54, 0x7f, 0xff, 0xfd, 0x57, 0xff, 0xe0, 0x1f, + 0xc4, 0x15, 0x55, 0x06, 0x7f, 0x70, 0xee, 0x60, 0x18, 0xa8, 0x2a, 0x1f, 0xff, 0xfe, 0xaf, + 0xff, 0xe8, 0xf0, 0x00, 0x0a, 0x4a, 0xa8, 0x7f, 0xf0, 0xdf, 0xff, 0xf1, 0x54, 0x15, 0x43, + 0xff, 0xff, 0x5f, 0xff, 0xe8, 0x7b, 0xc0, 0x05, 0x55, 0x55, 0x7f, 0x70, 0xff, 0x81, 0x28, + 0xaa, 0x0a, 0xa1, 0xff, 0xfe, 0xbf, 0xf7, 0xea, 0x09, 0xe0, 0x0a, 0x4a, 0xaa, 0x7f, 0xf0, + 0xff, 0x81, 0x50, 0x54, 0x05, 0x54, 0x7f, 0xff, 0x7f, 0xfc, 0xe8, 0x4b, 0xc0, 0x05, 0x55, + 0x55, 0x7f, 0x70, 0xfe, 0x7f, 0x28, 0xaa, 0x00, 0xa8, 0xff, 0xfe, 0xbf, 0xff, 0x0a, 0xf0, + 0x00, 0x02, 0x4a, 0xa8, 0x7e, 0xb0, 0xfe, 0x7f, 0x14, 0x55, 0x00, 0x03, 0xff, 0xf7, 0x5f, + 0x7f, 0xe0, 0x1f, 0xc4, 0x01, 0x55, 0x06, 0x7f, 0x70, 0xff, 0x81, 0x08, 0x2a, 0x80, 0x07, + 0xff, 0xf6, 0xaf, 0xff, 0xfe, 0x80, 0x6a, 0x80, 0x00, 0x7e, 0xff, 0xb0, 0x7f, 0x81, 0x14, + 0x55, 0x40, 0x0f, 0xff, 0xed, 0x57, 0x7f, 0xff, 0xe7, 0x85, 0x55, 0x5f, 0xfc, 0xff, 0x70, + 0xbf, 0xff, 0xe8, 0x2a, 0xa8, 0x1f, 0xff, 0xf6, 0xae, 0xff, 0xff, 0xf9, 0xea, 0xaa, 0x5f, + 0xfa, 0xff, 0xf0, 0x5e, 0x01, 0x24, 0x15, 0x54, 0x3f, 0xff, 0xf5, 0x57, 0x7f, 0xfb, 0xfe, + 0xf0, 0x55, 0x5f, 0xe5, 0xff, 0x70, 0xbe, 0x01, 0x22, 0x2a, 0xa0, 0xff, 0xff, 0xba, 0xae, + 0xff, 0xfe, 0x1f, 0x30, 0x2a, 0x0f, 0x89, 0xbf, 0xf0, 0x5f, 0xff, 0xe5, 0x15, 0x41, 0xff, + 0xff, 0xd5, 0x57, 0x7f, 0xff, 0xe0, 0x48, 0x05, 0x54, 0x53, 0xff, 0xf0, 0xbe, 0x01, 0xa2, + 0x02, 0x03, 0xff, 0xff, 0xea, 0xaa, 0xbf, 0xff, 0xff, 0x80, 0x00, 0x02, 0xa7, 0xbf, 0xf0, + 0x5e, 0x01, 0x41, 0x00, 0x06, 0xfd, 0xff, 0xd5, 0x55, 0x5f, 0xff, 0xff, 0xfc, 0x00, 0x40, + 0x4f, 0xff, 0xf0, 0xbe, 0x49, 0x20, 0x80, 0x0f, 0x7f, 0xfe, 0xea, 0xaa, 0xbe, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x1f, 0xbf, 0xf0, 0x7e, 0x49, 0x50, 0x00, 0x0f, 0x7f, 0xff, 0xd5, 0x55, + 0x5f, 0x83, 0xff, 0xff, 0x80, 0x40, 0x3f, 0xff, 0xf0, 0xfe, 0x41, 0x28, 0x00, 0x0f, 0xbf, + 0xff, 0xeb, 0xaa, 0xbf, 0xfc, 0x00, 0x03, 0xe0, 0x00, 0xff, 0xbf, 0xf0, 0xfe, 0x41, 0x14, + 0x00, 0x1f, 0xdf, 0xff, 0xd5, 0xd5, 0x57, 0xff, 0xff, 0xfc, 0x00, 0x07, 0xff, 0xdf, 0xf0, + 0xff, 0xff, 0x08, 0x00, 0x1f, 0x3f, 0xdf, 0xeb, 0xaa, 0xab, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xbf, 0xf0, 0xfe, 0x01, 0x14, 0x40, 0x3e, 0xff, 0xbf, 0xf5, 0x55, 0x57, 0xdf, 0xff, + 0xf9, 0xff, 0xff, 0xff, 0xdf, 0xf0, 0xfe, 0x01, 0x0a, 0x20, 0x3f, 0xff, 0xdf, 0xfa, 0xaa, + 0xab, 0xbf, 0xff, 0xf3, 0xff, 0xff, 0xdf, 0xbf, 0xf0, 0xde, 0x7f, 0x05, 0x10, 0x7f, 0xff, + 0xff, 0xfd, 0x55, 0x55, 0xdf, 0xff, 0xe4, 0xff, 0xff, 0xbf, 0x7f, 0xf0, 0xee, 0x7e, 0x02, + 0x88, 0x7f, 0xff, 0xff, 0xfa, 0xaa, 0xab, 0xbf, 0xff, 0xe3, 0xff, 0xbf, 0xbf, 0xbf, 0xf0, + 0xde, 0x05, 0x41, 0x54, 0x3f, 0xff, 0xff, 0xdd, 0x55, 0x55, 0xff, 0xff, 0xd7, 0xff, 0xdf, + 0x7f, 0x7f, 0xf0, 0xee, 0x06, 0xa2, 0xaa, 0x3f, 0xff, 0xff, 0xbe, 0xaa, 0xab, 0xbf, 0xff, + 0xf7, 0xff, 0xbf, 0x3f, 0xbf, 0xf0, 0xde, 0x7d, 0x55, 0x55, 0x1f, 0xfb, 0xff, 0xff, 0x55, + 0x55, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xbf, 0xff, 0xf0, 0xfe, 0x7f, 0xaa, 0xaa, 0x8f, 0xff, + 0xff, 0xba, 0xaa, 0xab, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xdf, 0xbf, 0xf0, 0xfe, 0x01, 0x55, + 0x55, 0x47, 0xff, 0xff, 0xf7, 0xd5, 0x57, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xfe, 0x01, 0xaa, 0xaa, 0xa1, 0xff, 0xff, 0xbf, 0xea, 0xab, 0xff, 0xff, 0xff, 0xff, 0xbf, + 0xff, 0xff, 0xf0, 0xff, 0xff, 0x55, 0x55, 0x54, 0xff, 0xff, 0x5f, 0xf5, 0x57, 0xff, 0xfd, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xda, 0xaa, 0xaa, 0xaa, 0x7f, 0xff, 0xbf, 0xfa, + 0xab, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0x9d, 0x55, 0x55, 0x00, 0xff, + 0xff, 0x7f, 0xfd, 0x57, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xbf, 0xa2, + 0xa8, 0x03, 0xff, 0xfb, 0xbf, 0xfa, 0xaa, 0xbf, 0xfb, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0x3f, 0xc0, 0x00, 0x07, 0xff, 0xff, 0x5f, 0xfd, 0x57, 0x57, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf0, 0xff, 0x3f, 0x80, 0x00, 0x0f, 0xff, 0xfb, 0xaf, 0xfe, 0xae, 0xaa, 0xfb, + 0xff, 0xbf, 0xff, 0xff, 0xff, 0xf0, 0xf6, 0x7f, 0xc0, 0x00, 0x0f, 0xff, 0xff, 0x57, 0xfd, + 0x55, 0x55, 0x77, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xf0, +}; + +const lv_img_dsc_t balloon = { + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .header.always_zero = 0, + .header.reserved = 0, + .header.w = 140, + .header.h = 68, + .data_size = 1232, + .data = balloon_map, +}; + +#ifndef LV_ATTRIBUTE_IMG_MOUNTAIN +#define LV_ATTRIBUTE_IMG_MOUNTAIN +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_MOUNTAIN uint8_t + mountain_map[] = { +#if CONFIG_NICE_VIEW_WIDGET_INVERTED + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ +#else + 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ + 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ +#endif + + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x90, 0x00, 0x30, 0x80, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xa0, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x10, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf4, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0x10, 0x80, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x40, 0x00, 0x00, 0x01, 0xfe, 0x03, 0xe0, 0x0f, 0x9e, 0x01, 0x90, + 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe8, 0x00, 0x00, 0x00, 0xff, 0x07, 0xe0, 0x1f, + 0x9e, 0x00, 0x90, 0x80, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x80, 0x00, 0x00, 0x7f, + 0x8f, 0xe0, 0x1f, 0xbe, 0x00, 0x90, 0x80, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, + 0x00, 0x00, 0x3f, 0xcf, 0xf0, 0x1f, 0xbc, 0x00, 0x90, 0x80, 0x7f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xcf, 0xf0, 0x3f, 0xbc, 0x00, 0x90, 0x80, 0x7f, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe8, 0x00, 0x00, 0x1f, 0xe7, 0xf0, 0x7f, 0x3c, 0x00, 0x90, + 0x80, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x0f, 0xe7, 0xf8, 0x7f, + 0x78, 0x01, 0xb0, 0x80, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xec, 0x00, 0x00, 0x00, 0x07, + 0xf3, 0xf8, 0x3f, 0x78, 0x03, 0xd0, 0x80, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xc0, 0x00, + 0x00, 0x00, 0x07, 0xfb, 0xf8, 0x3f, 0xf8, 0x0f, 0x90, 0xc0, 0x1f, 0xff, 0xff, 0xff, 0xff, + 0xec, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfd, 0xfc, 0x3f, 0xf8, 0x0f, 0x10, 0xc0, 0x1e, 0xff, + 0xff, 0xff, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xfc, 0x3f, 0xf0, 0x0e, 0x10, + 0xc0, 0x0c, 0x27, 0xff, 0xff, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x7f, + 0xf0, 0x1e, 0x30, 0xc0, 0x00, 0x1f, 0xff, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0xfe, 0x7f, 0xf3, 0xfc, 0x50, 0xe0, 0x00, 0x3f, 0xff, 0xfa, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x7f, 0xf7, 0xf8, 0x90, 0xe0, 0x00, 0x7f, 0xfe, 0xb0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x7f, 0xe7, 0xf1, 0x90, 0xe0, 0x00, 0x7f, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0x7f, 0xef, 0xe3, 0x90, + 0xf0, 0x00, 0x7f, 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0x7f, + 0xff, 0xe7, 0x90, 0xb0, 0x10, 0xff, 0xff, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xff, 0xbf, 0xff, 0xcf, 0x90, 0xf0, 0x30, 0xff, 0xff, 0xff, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0xff, 0xf9, 0xff, 0x9f, 0x90, 0xb0, 0x30, 0xff, 0xff, 0xff, 0xf2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf6, 0xff, 0x3e, 0x90, 0xf8, 0x70, 0xff, + 0xff, 0xff, 0xff, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf6, 0xfe, 0x7c, 0x90, + 0xf8, 0x78, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf9, + 0xfe, 0xf8, 0x90, 0xa8, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0xff, 0xfd, 0xf3, 0x90, 0xdc, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xe8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xfb, 0xef, 0x90, 0xf5, 0xac, 0xff, 0xff, 0xff, 0xfe, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x90, 0xff, 0xd6, 0x7f, + 0xff, 0xff, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0x90, + 0xff, 0xfa, 0x7f, 0xff, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0xff, 0x90, 0xdd, 0xff, 0x7f, 0xff, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0xea, 0xbf, 0x3f, 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xf0, 0x10, 0xff, 0x4f, 0xbf, 0xf5, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x10, 0xff, 0xff, 0x9f, + 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf0, + 0xff, 0xb0, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0xff, 0xff, 0x90, 0xcd, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x1f, 0xff, 0xff, 0x90, 0xb2, 0xe0, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x7f, 0xff, 0xff, 0x90, 0xff, 0xc0, 0x3f, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xff, 0xff, 0xff, 0x90, 0xfe, 0xc0, 0x7f, + 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0xff, 0xff, 0x7c, 0x90, + 0xfd, 0x80, 0xff, 0xfd, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc3, 0xff, + 0xff, 0xb8, 0x90, 0xff, 0x80, 0xff, 0xff, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3f, 0x87, 0xff, 0xff, 0xc8, 0x90, 0x9f, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7f, 0x1f, 0xff, 0xff, 0xe0, 0x90, 0x86, 0x01, 0xff, 0xff, 0xd0, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xfe, 0x3f, 0xff, 0xff, 0xe0, 0x90, 0x80, 0x01, 0xff, + 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x06, 0x19, 0x83, 0xfe, 0x7f, 0xff, 0xff, 0xf0, 0x90, + 0x80, 0x01, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x7f, 0xc7, 0xee, 0x7f, 0xff, + 0xff, 0xf8, 0x90, 0x80, 0x1a, 0xbf, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x98, 0xff, 0xff, + 0xc6, 0x7f, 0xff, 0xff, 0xfc, 0x90, 0x80, 0x3f, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0xf1, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xff, 0xfe, 0x90, 0x80, 0x3f, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0xe3, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x90, 0x80, 0x7f, 0xfe, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc7, 0xff, 0xfe, 0x18, 0xff, 0xef, 0xff, 0xff, 0x90, + 0x80, 0x7f, 0xff, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x8f, 0xff, 0xfc, 0x7f, 0xff, 0xef, + 0xfd, 0xff, 0x90, 0x80, 0xff, 0xff, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x9f, 0xff, 0xf8, + 0xff, 0xff, 0xef, 0xfc, 0xf7, 0x90, 0x80, 0xff, 0xff, 0xff, 0x60, 0x00, 0x00, 0x00, 0x3f, + 0x1f, 0xff, 0xf1, 0xff, 0xff, 0xcf, 0xfc, 0xe1, 0x90, 0x80, 0xff, 0xff, 0xff, 0xf4, 0x00, + 0x00, 0x00, 0x7f, 0x3f, 0xff, 0xe3, 0xff, 0xff, 0xcf, 0xfe, 0x60, 0x90, 0x81, 0xff, 0xff, + 0xff, 0xfe, 0x80, 0x00, 0x00, 0x7f, 0x3f, 0xff, 0xc7, 0xff, 0xff, 0xdf, 0xfe, 0x40, 0x90, + 0x81, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x01, 0xfe, 0x3f, 0xff, 0xcf, 0xbf, 0xff, 0xdf, + 0xfe, 0x00, 0x90, 0x81, 0xff, 0xff, 0xff, 0xff, 0x40, 0x00, 0x07, 0xfe, 0x7f, 0xff, 0x8f, + 0x7f, 0xff, 0x9f, 0xfe, 0x00, 0x90, 0x80, 0xff, 0xff, 0xff, 0xe6, 0x00, 0x00, 0x1f, 0xfe, + 0x7f, 0xff, 0x1e, 0xff, 0xff, 0x91, 0xfe, 0x00, 0x90, 0x80, 0xff, 0xff, 0xfe, 0xc0, 0x00, + 0x00, 0x3f, 0xfc, 0x7f, 0xfe, 0x3c, 0xff, 0xff, 0x81, 0xff, 0x00, 0x90, 0x80, 0x7f, 0xff, + 0xec, 0x00, 0x00, 0x3c, 0xff, 0xf8, 0xff, 0xfc, 0x79, 0xfd, 0xff, 0x80, 0xff, 0x00, 0x90, + 0x80, 0x27, 0xff, 0x80, 0x00, 0x00, 0x7f, 0xff, 0xf9, 0xff, 0xfc, 0xf3, 0xfb, 0xff, 0x00, + 0xff, 0x00, 0x90, 0x80, 0x5f, 0xff, 0xd8, 0x00, 0x00, 0xff, 0xff, 0xf1, 0xff, 0xc8, 0xe7, + 0xf3, 0xff, 0x00, 0x7f, 0x00, 0x90, 0x80, 0xff, 0xff, 0xfd, 0x80, 0x01, 0xff, 0xff, 0xe3, + 0xff, 0x81, 0xcf, 0xf7, 0xff, 0x00, 0x7f, 0x00, 0x90, 0x80, 0xff, 0xff, 0xff, 0xd8, 0x03, + 0xff, 0xff, 0x87, 0xff, 0x03, 0x8f, 0xe7, 0xff, 0x00, 0x3f, 0x81, 0x90, 0x81, 0xff, 0xff, + 0xff, 0xfe, 0x83, 0xff, 0xfe, 0x0f, 0xfe, 0x3f, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0x10, + 0x80, 0x00, 0x00, 0x00, 0x2f, 0xc6, 0x00, 0x00, 0x38, 0x00, 0x60, 0x00, 0x48, 0x00, 0x00, + 0x00, 0x00, 0x10, 0xc0, 0x00, 0x00, 0x00, 0x17, 0xf4, 0x00, 0x00, 0xe0, 0x00, 0xc0, 0x00, + 0x88, 0x00, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, +}; + +const lv_img_dsc_t mountain = { + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .header.always_zero = 0, + .header.reserved = 0, + .header.w = 140, + .header.h = 68, + .data_size = 1232, + .data = mountain_map, +}; diff --git a/app/boards/shields/nice_view/widgets/bolt.c b/app/boards/shields/nice_view/widgets/bolt.c new file mode 100644 index 00000000000..74dcc2b00c6 --- /dev/null +++ b/app/boards/shields/nice_view/widgets/bolt.c @@ -0,0 +1,45 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BOLT +#define LV_ATTRIBUTE_IMG_BOLT +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BOLT uint8_t bolt_map[] = { +#if CONFIG_NICE_VIEW_WIDGET_INVERTED + 0x00, 0x00, 0x00, 0x00, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + 0xff, 0xff, 0xff, 0xff, /*Color of index 2*/ + 0x00, 0x00, 0x00, 0x00, /*Color of index 3*/ +#else + 0x00, 0x00, 0x00, 0x00, /*Color of index 0*/ + 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 2*/ + 0x00, 0x00, 0x00, 0x00, /*Color of index 3*/ +#endif + + 0x00, 0x14, 0x00, 0x00, 0x64, 0x00, 0x00, 0x64, 0x00, 0x01, 0xa4, 0x00, 0x01, 0xa4, + 0x00, 0x06, 0xa4, 0x00, 0x06, 0xa4, 0x00, 0x1a, 0xa5, 0x54, 0x1a, 0xaa, 0xa4, 0x6a, + 0xaa, 0x90, 0x55, 0x6a, 0x90, 0x00, 0x6a, 0x40, 0x00, 0x6a, 0x40, 0x00, 0x69, 0x00, + 0x00, 0x69, 0x00, 0x00, 0x64, 0x00, 0x00, 0x64, 0x00, 0x00, 0x50, 0x00, +}; + +const lv_img_dsc_t bolt = { + .header.cf = LV_IMG_CF_INDEXED_2BIT, + .header.always_zero = 0, + .header.reserved = 0, + .header.w = 11, + .header.h = 18, + .data_size = 70, + .data = bolt_map, +}; diff --git a/app/boards/shields/nice_view/widgets/peripheral_status.c b/app/boards/shields/nice_view/widgets/peripheral_status.c new file mode 100644 index 00000000000..4c0c22637be --- /dev/null +++ b/app/boards/shields/nice_view/widgets/peripheral_status.c @@ -0,0 +1,128 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#include +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include "peripheral_status.h" +#include +#include +#include +#include +#include +#include +#include + +LV_IMG_DECLARE(balloon); +LV_IMG_DECLARE(mountain); + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); + +struct peripheral_status_state { + bool connected; +}; + +static void draw_top(lv_obj_t *widget, lv_color_t cbuf[], const struct status_state *state) { + lv_obj_t *canvas = lv_obj_get_child(widget, 0); + + lv_draw_label_dsc_t label_dsc; + init_label_dsc(&label_dsc, LVGL_FOREGROUND, &lv_font_montserrat_16, LV_TEXT_ALIGN_RIGHT); + lv_draw_rect_dsc_t rect_black_dsc; + init_rect_dsc(&rect_black_dsc, LVGL_BACKGROUND); + + // Fill background + lv_canvas_draw_rect(canvas, 0, 0, CANVAS_SIZE, CANVAS_SIZE, &rect_black_dsc); + + // Draw battery + draw_battery(canvas, state); + + // Draw output status + lv_canvas_draw_text(canvas, 0, 0, CANVAS_SIZE, &label_dsc, + state->connected ? LV_SYMBOL_WIFI : LV_SYMBOL_CLOSE); + + // Rotate canvas + rotate_canvas(canvas, cbuf); +} + +static void set_battery_status(struct zmk_widget_status *widget, + struct battery_status_state state) { +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + widget->state.charging = state.usb_present; +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + + widget->state.battery = state.level; + + draw_top(widget->obj, widget->cbuf, &widget->state); +} + +static void battery_status_update_cb(struct battery_status_state state) { + struct zmk_widget_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_battery_status(widget, state); } +} + +static struct battery_status_state battery_status_get_state(const zmk_event_t *eh) { + return (struct battery_status_state) { + .level = bt_bas_get_battery_level(), +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + .usb_present = zmk_usb_is_powered(), +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + }; +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_battery_status, struct battery_status_state, + battery_status_update_cb, battery_status_get_state) + +ZMK_SUBSCRIPTION(widget_battery_status, zmk_battery_state_changed); +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) +ZMK_SUBSCRIPTION(widget_battery_status, zmk_usb_conn_state_changed); +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + +static struct peripheral_status_state get_state(const zmk_event_t *_eh) { + return (struct peripheral_status_state){.connected = zmk_split_bt_peripheral_is_connected()}; +} + +static void set_connection_status(struct zmk_widget_status *widget, + struct peripheral_status_state state) { + widget->state.connected = state.connected; + + draw_top(widget->obj, widget->cbuf, &widget->state); +} + +static void output_status_update_cb(struct peripheral_status_state state) { + struct zmk_widget_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_connection_status(widget, state); } +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_peripheral_status, struct peripheral_status_state, + output_status_update_cb, get_state) +ZMK_SUBSCRIPTION(widget_peripheral_status, zmk_split_peripheral_status_changed); + +int zmk_widget_status_init(struct zmk_widget_status *widget, lv_obj_t *parent) { + widget->obj = lv_obj_create(parent); + lv_obj_set_size(widget->obj, 160, 68); + lv_obj_t *top = lv_canvas_create(widget->obj); + lv_obj_align(top, LV_ALIGN_TOP_RIGHT, 0, 0); + lv_canvas_set_buffer(top, widget->cbuf, CANVAS_SIZE, CANVAS_SIZE, LV_IMG_CF_TRUE_COLOR); + + lv_obj_t *art = lv_img_create(widget->obj); + bool random = sys_rand32_get() & 1; + lv_img_set_src(art, random ? &balloon : &mountain); + lv_obj_align(art, LV_ALIGN_TOP_LEFT, 0, 0); + + sys_slist_append(&widgets, &widget->node); + widget_battery_status_init(); + widget_peripheral_status_init(); + + return 0; +} + +lv_obj_t *zmk_widget_status_obj(struct zmk_widget_status *widget) { return widget->obj; } diff --git a/app/boards/shields/nice_view/widgets/peripheral_status.h b/app/boards/shields/nice_view/widgets/peripheral_status.h new file mode 100644 index 00000000000..815963572b4 --- /dev/null +++ b/app/boards/shields/nice_view/widgets/peripheral_status.h @@ -0,0 +1,22 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include +#include +#include "util.h" + +struct zmk_widget_status { + sys_snode_t node; + lv_obj_t *obj; + lv_color_t cbuf[CANVAS_SIZE * CANVAS_SIZE]; + struct status_state state; +}; + +int zmk_widget_status_init(struct zmk_widget_status *widget, lv_obj_t *parent); +lv_obj_t *zmk_widget_status_obj(struct zmk_widget_status *widget); diff --git a/app/boards/shields/nice_view/widgets/status.c b/app/boards/shields/nice_view/widgets/status.c new file mode 100644 index 00000000000..c629be50f59 --- /dev/null +++ b/app/boards/shields/nice_view/widgets/status.c @@ -0,0 +1,328 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include "status.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); + +struct output_status_state { + struct zmk_endpoint_instance selected_endpoint; + bool active_profile_connected; + bool active_profile_bonded; +}; + +struct layer_status_state { + uint8_t index; + const char *label; +}; + +struct wpm_status_state { + uint8_t wpm; +}; + +static void draw_top(lv_obj_t *widget, lv_color_t cbuf[], const struct status_state *state) { + lv_obj_t *canvas = lv_obj_get_child(widget, 0); + + lv_draw_label_dsc_t label_dsc; + init_label_dsc(&label_dsc, LVGL_FOREGROUND, &lv_font_montserrat_16, LV_TEXT_ALIGN_RIGHT); + lv_draw_label_dsc_t label_dsc_wpm; + init_label_dsc(&label_dsc_wpm, LVGL_FOREGROUND, &lv_font_unscii_8, LV_TEXT_ALIGN_RIGHT); + lv_draw_rect_dsc_t rect_black_dsc; + init_rect_dsc(&rect_black_dsc, LVGL_BACKGROUND); + lv_draw_rect_dsc_t rect_white_dsc; + init_rect_dsc(&rect_white_dsc, LVGL_FOREGROUND); + lv_draw_line_dsc_t line_dsc; + init_line_dsc(&line_dsc, LVGL_FOREGROUND, 1); + + // Fill background + lv_canvas_draw_rect(canvas, 0, 0, CANVAS_SIZE, CANVAS_SIZE, &rect_black_dsc); + + // Draw battery + draw_battery(canvas, state); + + // Draw output status + char output_text[10] = {}; + + switch (state->selected_endpoint.transport) { + case ZMK_TRANSPORT_USB: + strcat(output_text, LV_SYMBOL_USB); + break; + case ZMK_TRANSPORT_BLE: + if (state->active_profile_bonded) { + if (state->active_profile_connected) { + strcat(output_text, LV_SYMBOL_WIFI); + } else { + strcat(output_text, LV_SYMBOL_CLOSE); + } + } else { + strcat(output_text, LV_SYMBOL_SETTINGS); + } + break; + } + + lv_canvas_draw_text(canvas, 0, 0, CANVAS_SIZE, &label_dsc, output_text); + + // Draw WPM + lv_canvas_draw_rect(canvas, 0, 21, 68, 42, &rect_white_dsc); + lv_canvas_draw_rect(canvas, 1, 22, 66, 40, &rect_black_dsc); + + char wpm_text[6] = {}; + snprintf(wpm_text, sizeof(wpm_text), "%d", state->wpm[9]); + lv_canvas_draw_text(canvas, 42, 52, 24, &label_dsc_wpm, wpm_text); + + int max = 0; + int min = 256; + + for (int i = 0; i < 10; i++) { + if (state->wpm[i] > max) { + max = state->wpm[i]; + } + if (state->wpm[i] < min) { + min = state->wpm[i]; + } + } + + int range = max - min; + if (range == 0) { + range = 1; + } + + lv_point_t points[10]; + for (int i = 0; i < 10; i++) { + points[i].x = 2 + i * 7; + points[i].y = 60 - (state->wpm[i] - min) * 36 / range; + } + lv_canvas_draw_line(canvas, points, 10, &line_dsc); + + // Rotate canvas + rotate_canvas(canvas, cbuf); +} + +static void draw_middle(lv_obj_t *widget, lv_color_t cbuf[], const struct status_state *state) { + lv_obj_t *canvas = lv_obj_get_child(widget, 1); + + lv_draw_rect_dsc_t rect_black_dsc; + init_rect_dsc(&rect_black_dsc, LVGL_BACKGROUND); + lv_draw_rect_dsc_t rect_white_dsc; + init_rect_dsc(&rect_white_dsc, LVGL_FOREGROUND); + lv_draw_arc_dsc_t arc_dsc; + init_arc_dsc(&arc_dsc, LVGL_FOREGROUND, 2); + lv_draw_arc_dsc_t arc_dsc_filled; + init_arc_dsc(&arc_dsc_filled, LVGL_FOREGROUND, 9); + lv_draw_label_dsc_t label_dsc; + init_label_dsc(&label_dsc, LVGL_FOREGROUND, &lv_font_montserrat_18, LV_TEXT_ALIGN_CENTER); + lv_draw_label_dsc_t label_dsc_black; + init_label_dsc(&label_dsc_black, LVGL_BACKGROUND, &lv_font_montserrat_18, LV_TEXT_ALIGN_CENTER); + + // Fill background + lv_canvas_draw_rect(canvas, 0, 0, CANVAS_SIZE, CANVAS_SIZE, &rect_black_dsc); + + // Draw circles + int circle_offsets[5][2] = { + {13, 13}, {55, 13}, {34, 34}, {13, 55}, {55, 55}, + }; + + for (int i = 0; i < 5; i++) { + bool selected = state->selected_endpoint.ble.profile_index == i; + + lv_canvas_draw_arc(canvas, circle_offsets[i][0], circle_offsets[i][1], 13, 0, 359, + &arc_dsc); + + if (selected) { + lv_canvas_draw_arc(canvas, circle_offsets[i][0], circle_offsets[i][1], 9, 0, 359, + &arc_dsc_filled); + } + + char label[2]; + snprintf(label, sizeof(label), "%d", i + 1); + lv_canvas_draw_text(canvas, circle_offsets[i][0] - 8, circle_offsets[i][1] - 10, 16, + (selected ? &label_dsc_black : &label_dsc), label); + } + + // Rotate canvas + rotate_canvas(canvas, cbuf); +} + +static void draw_bottom(lv_obj_t *widget, lv_color_t cbuf[], const struct status_state *state) { + lv_obj_t *canvas = lv_obj_get_child(widget, 2); + + lv_draw_rect_dsc_t rect_black_dsc; + init_rect_dsc(&rect_black_dsc, LVGL_BACKGROUND); + lv_draw_label_dsc_t label_dsc; + init_label_dsc(&label_dsc, LVGL_FOREGROUND, &lv_font_montserrat_14, LV_TEXT_ALIGN_CENTER); + + // Fill background + lv_canvas_draw_rect(canvas, 0, 0, CANVAS_SIZE, CANVAS_SIZE, &rect_black_dsc); + + // Draw layer + if (state->layer_label == NULL) { + char text[9] = {}; + + sprintf(text, "LAYER %i", state->layer_index); + + lv_canvas_draw_text(canvas, 0, 5, 68, &label_dsc, text); + } else { + lv_canvas_draw_text(canvas, 0, 5, 68, &label_dsc, state->layer_label); + } + + // Rotate canvas + rotate_canvas(canvas, cbuf); +} + +static void set_battery_status(struct zmk_widget_status *widget, + struct battery_status_state state) { +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + widget->state.charging = state.usb_present; +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + + widget->state.battery = state.level; + + draw_top(widget->obj, widget->cbuf, &widget->state); +} + +static void battery_status_update_cb(struct battery_status_state state) { + struct zmk_widget_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_battery_status(widget, state); } +} + +static struct battery_status_state battery_status_get_state(const zmk_event_t *eh) { + return (struct battery_status_state) { + .level = bt_bas_get_battery_level(), +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + .usb_present = zmk_usb_is_powered(), +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + }; +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_battery_status, struct battery_status_state, + battery_status_update_cb, battery_status_get_state) + +ZMK_SUBSCRIPTION(widget_battery_status, zmk_battery_state_changed); +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) +ZMK_SUBSCRIPTION(widget_battery_status, zmk_usb_conn_state_changed); +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + +static void set_output_status(struct zmk_widget_status *widget, + const struct output_status_state *state) { + widget->state.selected_endpoint = state->selected_endpoint; + widget->state.active_profile_connected = state->active_profile_connected; + widget->state.active_profile_bonded = state->active_profile_bonded; + + draw_top(widget->obj, widget->cbuf, &widget->state); + draw_middle(widget->obj, widget->cbuf2, &widget->state); +} + +static void output_status_update_cb(struct output_status_state state) { + struct zmk_widget_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_output_status(widget, &state); } +} + +static struct output_status_state output_status_get_state(const zmk_event_t *_eh) { + return (struct output_status_state){ + .selected_endpoint = zmk_endpoints_selected(), + .active_profile_connected = zmk_ble_active_profile_is_connected(), + .active_profile_bonded = !zmk_ble_active_profile_is_open(), + }; +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_output_status, struct output_status_state, + output_status_update_cb, output_status_get_state) +ZMK_SUBSCRIPTION(widget_output_status, zmk_endpoint_changed); + +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) +ZMK_SUBSCRIPTION(widget_output_status, zmk_usb_conn_state_changed); +#endif +#if defined(CONFIG_ZMK_BLE) +ZMK_SUBSCRIPTION(widget_output_status, zmk_ble_active_profile_changed); +#endif + +static void set_layer_status(struct zmk_widget_status *widget, struct layer_status_state state) { + widget->state.layer_index = state.index; + widget->state.layer_label = state.label; + + draw_bottom(widget->obj, widget->cbuf3, &widget->state); +} + +static void layer_status_update_cb(struct layer_status_state state) { + struct zmk_widget_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_layer_status(widget, state); } +} + +static struct layer_status_state layer_status_get_state(const zmk_event_t *eh) { + uint8_t index = zmk_keymap_highest_layer_active(); + return (struct layer_status_state){.index = index, .label = zmk_keymap_layer_label(index)}; +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_layer_status, struct layer_status_state, layer_status_update_cb, + layer_status_get_state) + +ZMK_SUBSCRIPTION(widget_layer_status, zmk_layer_state_changed); + +static void set_wpm_status(struct zmk_widget_status *widget, struct wpm_status_state state) { + for (int i = 0; i < 9; i++) { + widget->state.wpm[i] = widget->state.wpm[i + 1]; + } + widget->state.wpm[9] = state.wpm; + + draw_top(widget->obj, widget->cbuf, &widget->state); +} + +static void wpm_status_update_cb(struct wpm_status_state state) { + struct zmk_widget_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_wpm_status(widget, state); } +} + +struct wpm_status_state wpm_status_get_state(const zmk_event_t *eh) { + return (struct wpm_status_state){.wpm = zmk_wpm_get_state()}; +}; + +ZMK_DISPLAY_WIDGET_LISTENER(widget_wpm_status, struct wpm_status_state, wpm_status_update_cb, + wpm_status_get_state) +ZMK_SUBSCRIPTION(widget_wpm_status, zmk_wpm_state_changed); + +int zmk_widget_status_init(struct zmk_widget_status *widget, lv_obj_t *parent) { + widget->obj = lv_obj_create(parent); + lv_obj_set_size(widget->obj, 160, 68); + lv_obj_t *top = lv_canvas_create(widget->obj); + lv_obj_align(top, LV_ALIGN_TOP_RIGHT, 0, 0); + lv_canvas_set_buffer(top, widget->cbuf, CANVAS_SIZE, CANVAS_SIZE, LV_IMG_CF_TRUE_COLOR); + lv_obj_t *middle = lv_canvas_create(widget->obj); + lv_obj_align(middle, LV_ALIGN_TOP_LEFT, 24, 0); + lv_canvas_set_buffer(middle, widget->cbuf2, CANVAS_SIZE, CANVAS_SIZE, LV_IMG_CF_TRUE_COLOR); + lv_obj_t *bottom = lv_canvas_create(widget->obj); + lv_obj_align(bottom, LV_ALIGN_TOP_LEFT, -44, 0); + lv_canvas_set_buffer(bottom, widget->cbuf3, CANVAS_SIZE, CANVAS_SIZE, LV_IMG_CF_TRUE_COLOR); + + sys_slist_append(&widgets, &widget->node); + widget_battery_status_init(); + widget_output_status_init(); + widget_layer_status_init(); + widget_wpm_status_init(); + + return 0; +} + +lv_obj_t *zmk_widget_status_obj(struct zmk_widget_status *widget) { return widget->obj; } diff --git a/app/boards/shields/nice_view/widgets/status.h b/app/boards/shields/nice_view/widgets/status.h new file mode 100644 index 00000000000..53a22518d73 --- /dev/null +++ b/app/boards/shields/nice_view/widgets/status.h @@ -0,0 +1,24 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include +#include +#include "util.h" + +struct zmk_widget_status { + sys_snode_t node; + lv_obj_t *obj; + lv_color_t cbuf[CANVAS_SIZE * CANVAS_SIZE]; + lv_color_t cbuf2[CANVAS_SIZE * CANVAS_SIZE]; + lv_color_t cbuf3[CANVAS_SIZE * CANVAS_SIZE]; + struct status_state state; +}; + +int zmk_widget_status_init(struct zmk_widget_status *widget, lv_obj_t *parent); +lv_obj_t *zmk_widget_status_obj(struct zmk_widget_status *widget); diff --git a/app/boards/shields/nice_view/widgets/util.c b/app/boards/shields/nice_view/widgets/util.c new file mode 100644 index 00000000000..b4915ab767f --- /dev/null +++ b/app/boards/shields/nice_view/widgets/util.c @@ -0,0 +1,69 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#include +#include "util.h" + +LV_IMG_DECLARE(bolt); + +void rotate_canvas(lv_obj_t *canvas, lv_color_t cbuf[]) { + static lv_color_t cbuf_tmp[CANVAS_SIZE * CANVAS_SIZE]; + memcpy(cbuf_tmp, cbuf, sizeof(cbuf_tmp)); + lv_img_dsc_t img; + img.data = (void *)cbuf_tmp; + img.header.cf = LV_IMG_CF_TRUE_COLOR; + img.header.w = CANVAS_SIZE; + img.header.h = CANVAS_SIZE; + + lv_canvas_fill_bg(canvas, LVGL_BACKGROUND, LV_OPA_COVER); + lv_canvas_transform(canvas, &img, 900, LV_IMG_ZOOM_NONE, -1, 0, CANVAS_SIZE / 2, + CANVAS_SIZE / 2, true); +} + +void draw_battery(lv_obj_t *canvas, const struct status_state *state) { + lv_draw_rect_dsc_t rect_black_dsc; + init_rect_dsc(&rect_black_dsc, LVGL_BACKGROUND); + lv_draw_rect_dsc_t rect_white_dsc; + init_rect_dsc(&rect_white_dsc, LVGL_FOREGROUND); + + lv_canvas_draw_rect(canvas, 0, 2, 29, 12, &rect_white_dsc); + lv_canvas_draw_rect(canvas, 1, 3, 27, 10, &rect_black_dsc); + lv_canvas_draw_rect(canvas, 2, 4, (state->battery + 2) / 4, 8, &rect_white_dsc); + lv_canvas_draw_rect(canvas, 30, 5, 3, 6, &rect_white_dsc); + lv_canvas_draw_rect(canvas, 31, 6, 1, 4, &rect_black_dsc); + + if (state->charging) { + lv_draw_img_dsc_t img_dsc; + lv_draw_img_dsc_init(&img_dsc); + lv_canvas_draw_img(canvas, 9, -1, &bolt, &img_dsc); + } +} + +void init_label_dsc(lv_draw_label_dsc_t *label_dsc, lv_color_t color, const lv_font_t *font, + lv_text_align_t align) { + lv_draw_label_dsc_init(label_dsc); + label_dsc->color = color; + label_dsc->font = font; + label_dsc->align = align; +} + +void init_rect_dsc(lv_draw_rect_dsc_t *rect_dsc, lv_color_t bg_color) { + lv_draw_rect_dsc_init(rect_dsc); + rect_dsc->bg_color = bg_color; +} + +void init_line_dsc(lv_draw_line_dsc_t *line_dsc, lv_color_t color, uint8_t width) { + lv_draw_line_dsc_init(line_dsc); + line_dsc->color = color; + line_dsc->width = width; +} + +void init_arc_dsc(lv_draw_arc_dsc_t *arc_dsc, lv_color_t color, uint8_t width) { + lv_draw_arc_dsc_init(arc_dsc); + arc_dsc->color = color; + arc_dsc->width = width; +} diff --git a/app/boards/shields/nice_view/widgets/util.h b/app/boards/shields/nice_view/widgets/util.h new file mode 100644 index 00000000000..e2d2782a3f9 --- /dev/null +++ b/app/boards/shields/nice_view/widgets/util.h @@ -0,0 +1,46 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#include +#include + +#define CANVAS_SIZE 68 + +#define LVGL_BACKGROUND \ + IS_ENABLED(CONFIG_NICE_VIEW_WIDGET_INVERTED) ? lv_color_black() : lv_color_white() +#define LVGL_FOREGROUND \ + IS_ENABLED(CONFIG_NICE_VIEW_WIDGET_INVERTED) ? lv_color_white() : lv_color_black() + +struct status_state { + uint8_t battery; + bool charging; +#if !IS_ENABLED(CONFIG_ZMK_SPLIT) || IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) + struct zmk_endpoint_instance selected_endpoint; + bool active_profile_connected; + bool active_profile_bonded; + uint8_t layer_index; + const char *layer_label; + uint8_t wpm[10]; +#else + bool connected; +#endif +}; + +struct battery_status_state { + uint8_t level; +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + bool usb_present; +#endif +}; + +void rotate_canvas(lv_obj_t *canvas, lv_color_t cbuf[]); +void draw_battery(lv_obj_t *canvas, const struct status_state *state); +void init_label_dsc(lv_draw_label_dsc_t *label_dsc, lv_color_t color, const lv_font_t *font, + lv_text_align_t align); +void init_rect_dsc(lv_draw_rect_dsc_t *rect_dsc, lv_color_t bg_color); +void init_line_dsc(lv_draw_line_dsc_t *line_dsc, lv_color_t color, uint8_t width); +void init_arc_dsc(lv_draw_arc_dsc_t *arc_dsc, lv_color_t color, uint8_t width); diff --git a/app/boards/shields/settings_reset/settings_reset.keymap b/app/boards/shields/settings_reset/settings_reset.keymap index 0afdcc2bf35..1206ef1e363 100644 --- a/app/boards/shields/settings_reset/settings_reset.keymap +++ b/app/boards/shields/settings_reset/settings_reset.keymap @@ -12,9 +12,7 @@ compatible = "zmk,keymap"; default_layer { - bindings = < - &sys_reset - >; + bindings = <&sys_reset>; }; }; }; diff --git a/app/boards/shields/settings_reset/settings_reset.overlay b/app/boards/shields/settings_reset/settings_reset.overlay index 77a9d85871d..48a5f223b65 100644 --- a/app/boards/shields/settings_reset/settings_reset.overlay +++ b/app/boards/shields/settings_reset/settings_reset.overlay @@ -12,12 +12,12 @@ }; kscan0: kscan { - compatible = "zmk,kscan-gpio-direct"; + compatible = "zmk,kscan-mock"; label = "KSCAN"; + columns = <1>; + rows = <0>; - input-gpios - = <&pro_micro 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - ; + events = <>; }; }; diff --git a/app/boards/shields/sofle/Kconfig.defconfig b/app/boards/shields/sofle/Kconfig.defconfig index cc598d6720f..4e7bf88488e 100644 --- a/app/boards/shields/sofle/Kconfig.defconfig +++ b/app/boards/shields/sofle/Kconfig.defconfig @@ -46,4 +46,10 @@ endchoice endif # LVGL +if ZMK_RGB_UNDERGLOW + +config WS2812_STRIP + default y +endif + endif diff --git a/app/boards/shields/sofle/boards/nice_nano.overlay b/app/boards/shields/sofle/boards/nice_nano.overlay new file mode 100644 index 00000000000..336be4b0d96 --- /dev/null +++ b/app/boards/shields/sofle/boards/nice_nano.overlay @@ -0,0 +1,51 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + 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 = <36>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = < + LED_COLOR_ID_GREEN + LED_COLOR_ID_RED + LED_COLOR_ID_BLUE + >; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/sofle/boards/nice_nano_v2.overlay b/app/boards/shields/sofle/boards/nice_nano_v2.overlay new file mode 100644 index 00000000000..336be4b0d96 --- /dev/null +++ b/app/boards/shields/sofle/boards/nice_nano_v2.overlay @@ -0,0 +1,51 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + 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 = <36>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = < + LED_COLOR_ID_GREEN + LED_COLOR_ID_RED + LED_COLOR_ID_BLUE + >; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/sofle/boards/nrfmicro_11.overlay b/app/boards/shields/sofle/boards/nrfmicro_11.overlay new file mode 100644 index 00000000000..336be4b0d96 --- /dev/null +++ b/app/boards/shields/sofle/boards/nrfmicro_11.overlay @@ -0,0 +1,51 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + 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 = <36>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = < + LED_COLOR_ID_GREEN + LED_COLOR_ID_RED + LED_COLOR_ID_BLUE + >; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/sofle/boards/nrfmicro_13.overlay b/app/boards/shields/sofle/boards/nrfmicro_13.overlay new file mode 100644 index 00000000000..336be4b0d96 --- /dev/null +++ b/app/boards/shields/sofle/boards/nrfmicro_13.overlay @@ -0,0 +1,51 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + 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 = <36>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = < + LED_COLOR_ID_GREEN + LED_COLOR_ID_RED + LED_COLOR_ID_BLUE + >; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/sofle/sofle.conf b/app/boards/shields/sofle/sofle.conf index fe3f0f4f8a7..1f74aa339fc 100644 --- a/app/boards/shields/sofle/sofle.conf +++ b/app/boards/shields/sofle/sofle.conf @@ -7,3 +7,11 @@ # Uncomment these two lines to add support for encoders # CONFIG_EC11=y # CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y + +# Uncomment this line below to add rgb underglow / backlight support +# CONFIG_ZMK_RGB_UNDERGLOW=y + +# Uncomment the line below to disable external power toggling by the underglow. +# By default toggling the underglow on and off also toggles external power +# on and off. This also causes the display to turn off. +# CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER=n diff --git a/app/boards/shields/sofle/sofle.keymap b/app/boards/shields/sofle/sofle.keymap index 395ecf1ddd7..fbb0af7fb00 100644 --- a/app/boards/shields/sofle/sofle.keymap +++ b/app/boards/shields/sofle/sofle.keymap @@ -7,34 +7,53 @@ #include #include #include +#include +#include + +#define BASE 0 +#define LOWER 1 +#define RAISE 2 +#define ADJUST 3 / { + + // Activate ADJUST layer by pressing raise and lower + conditional_layers { + compatible = "zmk,conditional-layers"; + adjust_layer { + if-layers = ; + then-layer = ; + }; + }; + keymap { compatible = "zmk,keymap"; default_layer { + label = "default"; // ------------------------------------------------------------------------------------------------------------ -// | ` | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | | +// | ` | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | | // | ESC | Q | W | E | R | T | | Y | U | I | O | P | BKSPC | // | TAB | A | S | D | F | G | | H | J | K | L | ; | ' | // | SHIFT | Z | X | C | V | B | MUTE | | | N | M | , | . | / | SHIFT | // | GUI | ALT | CTRL | LOWER| ENTER | | SPACE | RAISE| CTRL | ALT | GUI | bindings = < -&kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &none -&kp ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSPC -&kp TAB &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT -&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp C_MUTE &none &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT - &kp LGUI &kp LALT &kp LCTRL &mo 1 &kp RET &kp SPACE &mo 2 &kp RCTRL &kp RALT &kp RGUI +&kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &none +&kp ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSPC +&kp TAB &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT +&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp C_MUTE &none &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LGUI &kp LALT &kp LCTRL &mo LOWER &kp RET &kp SPACE &mo RAISE &kp RCTRL &kp RALT &kp RGUI >; sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; }; lower_layer { + label = "lower"; // TODO: Some binds are waiting for shifted keycode support. // ------------------------------------------------------------------------------------------------------------ // | | F1 | F2 | F3 | F4 | F5 | | F6 | F7 | F8 | F9 | F10 | F11 | -// | ` | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | F12 | +// | ` | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | F12 | // | | ! | @ | # | $ | % | | ^ | & | * | ( | ) | | | // | | = | - | + | { | } | | | | [ | ] | ; | : | \ | | // | | | | | | | | | | | | @@ -42,29 +61,48 @@ &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp F12 &trans &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp KP_MULTIPLY &kp LPAR &kp RPAR &kp PIPE -&trans &kp EQUAL &kp MINUS &kp KP_PLUS &kp LBRC &kp RBRC &trans &trans &kp LBKT &kp RBKT &kp SEMI &kp COLON &kp BSLH &trans - &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans +&trans &kp EQUAL &kp MINUS &kp KP_PLUS &kp LBRC &kp RBRC &trans &trans &kp LBKT &kp RBKT &kp SEMI &kp COLON &kp BSLH &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans >; sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; }; raise_layer { + label = "raise"; // ------------------------------------------------------------------------------------------------------------ -// |BTCLR| BT1 | BT2 | BT3 | BT4 | BT5 | | | | | | | | -// | | INS | PSCR | GUI | | | | PGUP | | ^ | | | | -// | | ALT | CTRL | SHIFT | | CAPS | | PGDN | <- | v | -> | DEL | BKSPC | -// | | UNDO | CUT | COPY | PASTE | | | | | | | | | | | -// | | | | | | | | | | | | +// | BTCLR | BT1 | BT2 | BT3 | BT4 | BT5 | | | | | | | | +// | | INS | PSCR | GUI | | | | PGUP | | ^ | | | | +// | | ALT | CTRL | SHIFT | | CAPS | | PGDN | <- | v | -> | DEL | BKSPC | +// | | UNDO | CUT | COPY | PASTE | | | | | | | | | | | +// | | | | | | | | | | | | bindings = < -&bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans -&trans &kp INS &kp PSCRN &kp K_CMENU &trans &trans &kp PG_UP &trans &kp UP &trans &kp N0 &trans -&trans &kp LALT &kp LCTRL &kp LSHFT &trans &kp CLCK &kp PG_DN &kp LEFT &kp DOWN &kp RIGHT &kp DEL &kp BSPC -&trans &kp K_UNDO &kp K_CUT &kp K_COPY &kp K_PASTE &trans &trans &trans &trans &trans &trans &trans &trans &trans - &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans +&bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans +&trans &kp INS &kp PSCRN &kp K_CMENU &trans &trans &kp PG_UP &trans &kp UP &trans &kp N0 &trans +&trans &kp LALT &kp LCTRL &kp LSHFT &trans &kp CLCK &kp PG_DN &kp LEFT &kp DOWN &kp RIGHT &kp DEL &kp BSPC +&trans &kp K_UNDO &kp K_CUT &kp K_COPY &kp K_PASTE &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans >; sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; }; + + adjust_layer { +// ---------------------------------------------------------------------------------------------------------------------------- +// | BTCLR | BT1 | BT2 | BT3 | BT4 | BT5 | | | | | | | | +// | EXTPWR | RGB_HUD | RGB_HUI | RGB_SAD | RGB_SAI | RGB_EFF | | | | | | | | +// | | RGB_BRD | RGB_BRI | | | | | | | | | | | +// | | | | | | | RGB_TOG | | | | | | | | | +// | | | | | | | | | | | | + label = "adjust"; + bindings = < +&bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &none &none &none &none &none &none +&ext_power EP_TOG &rgb_ug RGB_HUD &rgb_ug RGB_HUI &rgb_ug RGB_SAD &rgb_ug RGB_SAI &rgb_ug RGB_EFF &none &none &none &none &none &none +&none &rgb_ug RGB_BRD &rgb_ug RGB_BRI &none &none &none &none &none &none &none &none &none +&none &none &none &none &none &none &rgb_ug RGB_TOG &none &none &none &none &none &none &none + &none &none &none &none &none &none &none &none &none &none + >; + }; + }; }; diff --git a/app/boards/shields/sofle/sofle.zmk.yml b/app/boards/shields/sofle/sofle.zmk.yml index 5f6f99c3fed..47b66d6777c 100644 --- a/app/boards/shields/sofle/sofle.zmk.yml +++ b/app/boards/shields/sofle/sofle.zmk.yml @@ -9,6 +9,7 @@ features: - keys - display - encoder + - underglow siblings: - sofle_left - sofle_right diff --git a/app/boards/shields/splitkb_aurora_helix/Kconfig.defconfig b/app/boards/shields/splitkb_aurora_helix/Kconfig.defconfig new file mode 100644 index 00000000000..6d7a55691e2 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_helix/Kconfig.defconfig @@ -0,0 +1,53 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_SPLITKB_AURORA_HELIX_LEFT + +config ZMK_KEYBOARD_NAME + default "Aurora Helix" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif # SHIELD_SPLITKB_AURORA_HELIX_LEFT + +if SHIELD_SPLITKB_AURORA_HELIX_LEFT || SHIELD_SPLITKB_AURORA_HELIX_RIGHT + +config ZMK_SPLIT + default y + +config ZMK_RGB_UNDERGLOW + select WS2812_STRIP + select SPI + +if ZMK_DISPLAY + +config SSD1306 + default y + +config I2C + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_DPI_DEF + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif # SHIELD_SPLITKB_AURORA_HELIX_LEFT || SHIELD_SPLITKB_AURORA_HELIX_RIGHT diff --git a/app/boards/shields/splitkb_aurora_helix/Kconfig.shield b/app/boards/shields/splitkb_aurora_helix/Kconfig.shield new file mode 100644 index 00000000000..c64ef8798e1 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_helix/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_SPLITKB_AURORA_HELIX_LEFT + def_bool $(shields_list_contains,splitkb_aurora_helix_left) + +config SHIELD_SPLITKB_AURORA_HELIX_RIGHT + def_bool $(shields_list_contains,splitkb_aurora_helix_right) diff --git a/app/boards/shields/splitkb_aurora_helix/boards/nice_nano.overlay b/app/boards/shields/splitkb_aurora_helix/boards/nice_nano.overlay new file mode 100644 index 00000000000..8f1629ced14 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_helix/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + 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 = <6>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_helix/boards/nice_nano_v2.overlay b/app/boards/shields/splitkb_aurora_helix/boards/nice_nano_v2.overlay new file mode 100644 index 00000000000..8f1629ced14 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_helix/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + 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 = <6>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.conf b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.conf new file mode 100644 index 00000000000..af482abcc4b --- /dev/null +++ b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.conf @@ -0,0 +1,9 @@ +# 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 OLED Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment the following line to enable RGB underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y diff --git a/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.dtsi b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.dtsi new file mode 100644 index 00000000000..e580e87daba --- /dev/null +++ b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.dtsi @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + + chosen { + zephyr,display = &oled; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <14>; + rows = <5>; + // | 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 | SW22 | SW23 | SW24 | SW25 | | SW25 | SW24 | SW23 | SW22 | SW21 | SW20 | SW19 | + // | SW26 | SW27 | SW28 | SW29 | SW30 | SW31 | SW32 | | SW32 | SW31 | SW30 | SW29 | SW28 | SW27 | SW26 | + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,12) RC(3,13) + RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) RC(4,12) RC(4,13) + >; + }; + + left_encoder: left_encoder { + compatible = "alps,ec11"; + label = "L_ENCODER"; + steps = <144>; + status = "disabled"; + + a-gpios = <&pro_micro 7 GPIO_PULL_UP>; + b-gpios = <&pro_micro 8 GPIO_PULL_UP>; + }; + + right_encoder: right_encoder { + compatible = "alps,ec11"; + label = "R_ENCODER"; + steps = <144>; + status = "disabled"; + + a-gpios = <&pro_micro 16 GPIO_PULL_UP>; + b-gpios = <&pro_micro 14 GPIO_PULL_UP>; + }; + + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + triggers-per-rotation = <36>; + }; +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + label = "DISPLAY"; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.keymap b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.keymap new file mode 100644 index 00000000000..edec8fec306 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.keymap @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include +#include + +#define DEFAULT 0 +#define LOWER 1 +#define RAISE 2 +#define ADJUST 3 + +/* Uncomment this block if using RGB +&led_strip { + chain-length = <6>; + // chain-length = <38>; // Uncomment if using both per-key and underglow LEDs + // chain-length = <32>; // Uncomment if using only per-key LEDs. +}; + */ + +/* NOTE: At the time of the creation of this keymap, there are no specified codes for 'eisuu' and 'kana' input in ZMK. +However, 'LANG1' and 'LANG2' are fully-functioning candidates for 'kana' and 'eisuu' input respectively. +As such, those are in use within the default layer at this time.*/ + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + // --------------------------------------------------------------------------------------------------------------------------------- + // | GRAVE | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | DEL | + // | TAB | Q | W | E | R | T | | Y | U | I | O | P | BSPC | + // | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' | + // | SHIFT | Z | X | C | V | B | LBKT | | RBKT | N | M | , | . | / | RET | + // | ADJUST | ESC | ALT | LGUI | EISUU | LOWER | SPACE | | SPACE | RAISE | KANA | LEFT | DOWN | UP | RIGHT | + bindings = < + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp DEL + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSPC + &kp LCTRL &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LBKT &kp RBKT &kp N &kp M &kp COMMA &kp PERIOD &kp SLASH &kp RET + &mo ADJUST &kp ESC &kp LALT &kp LGUI &kp LANG2 &mo LOWER &kp SPACE &kp SPACE &mo RAISE &kp LANG1 &kp LEFT &kp DOWN &kp UP &kp RIGHT + >; + }; + lower_layer { + // --------------------------------------------------------------------------------------------------------------------------------- + // | | | | | | | | | | | | | | + // | ~ | ! | @ | # | $ | % | | ^ | & | * | ( | ) | | + // | | | | | | | | | _ | + | { | } | PIPE | + // | | | | | | | ( | | ) | | | | HOME | END | | + // | | | | | | | | | | | | | | | | + bindings = < + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &kp TILDE &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp ASTRK &kp LPAR &kp RPAR &trans + &trans &trans &trans &trans &trans &trans &trans &kp UNDER &kp PLUS &kp LBRC &kp RBRC &kp PIPE + &trans &trans &trans &trans &trans &trans &kp LPAR &kp RPAR &trans &trans &trans &kp HOME &kp END &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + }; + raise_layer { + // --------------------------------------------------------------------------------------------------------------------------------- + // | | | | | | | | | | | | | | + // | ` | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | DEL | + // | | F1 | F2 | F3 | F4 | F5 | | F6 | - | = | [ | ] | \ | + // | | F7 | F8 | F9 | F10 | F11 | | | | F12 | | PSCRN | PG_DN | PG_UP | | + // | | | | | | | | | | | | NEXT | VOL- | VOL+ | PLAY | + bindings = < + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp DEL + &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp BSLH + &trans &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &trans &trans &kp F12 &trans &kp PSCRN &kp PG_DN &kp PG_UP &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &kp C_NEXT &kp C_VOL_DN &kp C_VOL_UP &kp C_PP + >; + }; + adjust_layer { + // --------------------------------------------------------------------------------------------------------------------------------- + // | ` | ! | @ | # | $ | % | | ^ | & | * | ( | ) | EP TOG | + // | BT CLR | BT SEL0 | BT SEL1 | BT SEL2 | BGT SEL3 | BT SEL4 | | RGB EFF+ | RGB HUE+ | RGB SAT+ | RGB SPD+ | RGB BRI+ | RGB TOG | + // | BT NXT | OUT TOG | OUT USB | OUT BLE | | | | RGB EFF- | RGB HUE- | RGB SAT- | RGB SPD- | RGB BRI- | | + // | BT PRV | | | | | | { | | } | | | | | | | + // | | | | | | | | | | | | | | | | + bindings = < + &kp GRAVE &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp ASTRK &kp LPAR &kp RPAR &ext_power EP_TOG + &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &rgb_ug RGB_EFF &rgb_ug RGB_HUI &rgb_ug RGB_SAI &rgb_ug RGB_SPI &rgb_ug RGB_BRI &rgb_ug RGB_TOG + &bt BT_NXT &out OUT_TOG &out OUT_USB &out OUT_BLE &trans &trans &rgb_ug RGB_EFR &rgb_ug RGB_HUD &rgb_ug RGB_SAD &rgb_ug RGB_SPD &rgb_ug RGB_BRD &trans + &bt BT_PRV &trans &trans &trans &trans &trans &kp LBRC &kp RBRC &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + }; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.zmk.yml b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.zmk.yml new file mode 100644 index 00000000000..d83c74ecca8 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.zmk.yml @@ -0,0 +1,15 @@ +file_format: "1" +id: splitkb_aurora_helix +name: splitkb.com Aurora Helix +type: shield +url: https://splitkb.com/products/aurora-helix-pcb-kit +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder + - underglow +siblings: + - splitkb_aurora_helix_left + - splitkb_aurora_helix_right diff --git a/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix_left.overlay b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix_left.overlay new file mode 100644 index 00000000000..c9830658b00 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix_left.overlay @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "splitkb_aurora_helix.dtsi" + +/ { + chosen { + zmk,kscan = &kscan; + }; + + kscan: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + label = "KSCAN"; + diode-direction = "col2row"; + + row-gpios + = <&pro_micro 21 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 20 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 4 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 5 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 6 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + ; + + col-gpios + = <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + ; + }; +}; + +&left_encoder { + status = "okay"; +}; diff --git a/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix_right.overlay b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix_right.overlay new file mode 100644 index 00000000000..48572de902d --- /dev/null +++ b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix_right.overlay @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "splitkb_aurora_helix.dtsi" + +/ { + chosen { + zmk,kscan = &kscan; + }; + + kscan: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + label = "KSCAN"; + diode-direction = "col2row"; + + row-gpios + = <&pro_micro 21 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 20 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 19 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 18 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 15 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + ; + + col-gpios + = <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 4 GPIO_ACTIVE_HIGH> + ; + }; +}; + +&right_encoder { + status = "okay"; +}; + +&default_transform { + col-offset = <7>; +}; diff --git a/app/boards/shields/splitkb_aurora_sofle/Kconfig.defconfig b/app/boards/shields/splitkb_aurora_sofle/Kconfig.defconfig new file mode 100644 index 00000000000..b53c4c8dc16 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sofle/Kconfig.defconfig @@ -0,0 +1,53 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_SPLITKB_AURORA_SOFLE_LEFT + +config ZMK_KEYBOARD_NAME + default "Aurora Sofle" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +endif # SHIELD_SPLITKB_AURORA_SOFLE_LEFT + +if SHIELD_SPLITKB_AURORA_SOFLE_LEFT || SHIELD_SPLITKB_AURORA_SOFLE_RIGHT + +config ZMK_SPLIT + default y + +config ZMK_RGB_UNDERGLOW + select WS2812_STRIP + select SPI + +if ZMK_DISPLAY + +config SSD1306 + default y + +config I2C + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LV_Z_VDB_SIZE + default 64 + +config LV_DPI_DEF + default 148 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif # SHIELD_SPLITKB_AURORA_SOFLE_LEFT || SHIELD_SPLITKB_AURORA_SOFLE_RIGHT diff --git a/app/boards/shields/splitkb_aurora_sofle/Kconfig.shield b/app/boards/shields/splitkb_aurora_sofle/Kconfig.shield new file mode 100644 index 00000000000..c72e95d9d0f --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sofle/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_SPLITKB_AURORA_SOFLE_LEFT + def_bool $(shields_list_contains,splitkb_aurora_sofle_left) + +config SHIELD_SPLITKB_AURORA_SOFLE_RIGHT + def_bool $(shields_list_contains,splitkb_aurora_sofle_right) diff --git a/app/boards/shields/splitkb_aurora_sofle/boards/nice_nano.overlay b/app/boards/shields/splitkb_aurora_sofle/boards/nice_nano.overlay new file mode 100644 index 00000000000..8f1629ced14 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sofle/boards/nice_nano.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + 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 = <6>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_sofle/boards/nice_nano_v2.overlay b/app/boards/shields/splitkb_aurora_sofle/boards/nice_nano_v2.overlay new file mode 100644 index 00000000000..8f1629ced14 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sofle/boards/nice_nano_v2.overlay @@ -0,0 +1,46 @@ +#include + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + 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 = <6>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + color-mapping = ; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.conf b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.conf new file mode 100644 index 00000000000..d456100ab74 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.conf @@ -0,0 +1,9 @@ +# 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 OLED Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment the following lines to enable RGB underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y diff --git a/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.dtsi b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.dtsi new file mode 100644 index 00000000000..798cd84e5f3 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.dtsi @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + + chosen { + zephyr,display = &oled; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <14>; + rows = <5>; +// | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | +// | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | +// | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | +// | SW24 | SW23 | SW22 | SW21 | SW20 | SW19 | SW25 | | SW25 | SW19 | SW20 | SW21 | SW22 | SW23 | SW24 | +// | SW30 | SW29 | SW28 | SW27 | SW26 | | SW26 | SW27 | SW28 | SW29 | SW30 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5) RC(4,6) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) + RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) + >; + }; + + left_encoder: left_encoder { + compatible = "alps,ec11"; + label = "L_ENCODER"; + steps = <144>; + status = "disabled"; + + a-gpios = <&pro_micro 16 GPIO_PULL_UP>; + b-gpios = <&pro_micro 10 GPIO_PULL_UP>; + }; + + right_encoder: right_encoder { + compatible = "alps,ec11"; + label = "R_ENCODER"; + steps = <144>; + status = "disabled"; + + a-gpios = <&pro_micro 16 GPIO_PULL_UP>; + b-gpios = <&pro_micro 10 GPIO_PULL_UP>; + }; + + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + triggers-per-rotation = <36>; + }; +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + label = "DISPLAY"; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.keymap b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.keymap new file mode 100644 index 00000000000..23127416762 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.keymap @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +/* Uncomment this block if using RGB +&led_strip { + chain-length = <6>; + // chain-length = <35>; // Uncomment if using both per-key and underglow LEDs + // chain-length = <29>; // Uncomment if using only per-key LEDs. +}; + */ + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// ------------------------------------------------------------------------------------------------------------ +// | ESC | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | ` | +// | TAB | Q | W | E | R | T | | Y | U | I | O | P | - | +// | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' | +// | SHIFT | Z | X | C | V | B | "[" | | "]" | N | M | , | . | / | SHIFT | +// |CTRL | ALT | GUI | LOWER| SPACE | | ENTER | RAISE| BSPC | GUI | RALT | + bindings = < +&kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp GRAVE +&kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp MINUS +&kp LCTRL &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT +&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LBKT &kp RBKT &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LCTRL &kp LALT &kp LGUI &mo 1 &kp SPACE &kp RET &mo 2 &kp BSPC &kp RGUI &kp RALT + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + lower_layer { +// ------------------------------------------------------------------------------------------------------------ +// | BTCLR | BT1 | BT2 | BT3 | BT4 | BT5 | | | | | | | | +// | F1 | F2 | F3 | F4 | F5 | F6 | | F7 | F8 | F9 | F10 | F11 | F12 | +// | ` | ! | @ | # | $ | % | | ^ | & | * | ( | ) | ~ | +// | | | | | | | | | | | _ | + | { | } | "|" | +// | | | | | | | | | | | | + bindings = < +&bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans +&kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 +&kp GRAVE &kp EXCL &kp AT &kp HASH &kp DOLLAR &kp PRCNT &kp CARET &kp AMPS &kp STAR &kp LPAR &kp RPAR &kp TILDE +&trans &ext_power EP_ON &ext_power EP_OFF &ext_power EP_TOG &trans &trans &trans &trans &trans &kp MINUS &kp PLUS &kp LBRC &kp RBRC &kp PIPE + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + raise_layer { +// ------------------------------------------------------------------------------------------------------------ +// | | | | | | | | | | | | | | +// | ` | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | | +// | F1 | F2 | F3 | F4 | F5 | F6 | | | <- | v | ^ | -> | | +// | F7 | F8 | F9 | F10 | F11 | F12 | | | | + | - | = | [ | ] | \ | +// | | | | | | | | | | | | + bindings = < +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans +&kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &trans +&kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &trans &kp LEFT &kp DOWN &kp UP &kp RIGHT &trans +&kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &trans &trans &kp KP_PLUS &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp BSLH + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + }; +}; diff --git a/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.zmk.yml b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.zmk.yml new file mode 100644 index 00000000000..d832d3e1053 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.zmk.yml @@ -0,0 +1,15 @@ +file_format: "1" +id: splitkb_aurora_sofle +name: splitkb.com Aurora Sofle +type: shield +url: https://splitkb.com/products/aurora-sofle-pcb-kit +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder + - underglow +siblings: + - splitkb_aurora_sofle_left + - splitkb_aurora_sofle_right diff --git a/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle_left.overlay b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle_left.overlay new file mode 100644 index 00000000000..1adaf401563 --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle_left.overlay @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "splitkb_aurora_sofle.dtsi" + +/ { + chosen { + zmk,kscan = &kscan; + }; + + kscan: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + label = "KSCAN"; + diode-direction = "col2row"; + + row-gpios + = <&pro_micro 20 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 15 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 18 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 19 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 14 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + ; + + col-gpios + = <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + , <&pro_micro 4 GPIO_ACTIVE_HIGH> + ; + }; +}; + +&left_encoder { + status = "okay"; +}; + + diff --git a/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle_right.overlay b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle_right.overlay new file mode 100644 index 00000000000..3249b94193c --- /dev/null +++ b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle_right.overlay @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "splitkb_aurora_sofle.dtsi" + +/ { + chosen { + zmk,kscan = &kscan; + }; + + kscan: kscan { + compatible = "zmk,kscan-gpio-matrix"; + + label = "KSCAN"; + diode-direction = "col2row"; + + row-gpios + = <&pro_micro 14 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 15 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 18 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 19 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + , <&pro_micro 20 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)> + ; + + col-gpios + = <&pro_micro 6 GPIO_ACTIVE_HIGH> + , <&pro_micro 7 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 4 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + ; + }; +}; + +&right_encoder { + status = "okay"; +}; + +&default_transform { + col-offset = <6>; +}; diff --git a/app/drivers/CMakeLists.txt b/app/drivers/CMakeLists.txt deleted file mode 100644 index 44d69ac37a2..00000000000 --- a/app/drivers/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) 2020 The ZMK Contributors -# SPDX-License-Identifier: MIT - -add_subdirectory_ifdef(CONFIG_ZMK_DRIVERS_GPIO gpio) -add_subdirectory(kscan) -add_subdirectory(sensor) -add_subdirectory(display) diff --git a/app/drivers/display/CMakeLists.txt b/app/drivers/display/CMakeLists.txt deleted file mode 100644 index d5e83c1dc4e..00000000000 --- a/app/drivers/display/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright (c) 2021 The ZMK Contributors -# SPDX-License-Identifier: MIT - -zephyr_sources_ifdef(CONFIG_IL0323 il0323.c) \ No newline at end of file diff --git a/app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml b/app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml index a2affbf2147..575754116b1 100644 --- a/app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml +++ b/app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml @@ -13,15 +13,21 @@ properties: required: true tapping-term-ms: type: int - tapping_term_ms: # deprecated + tapping_term_ms: type: int + deprecated: true quick-tap-ms: type: int default: -1 - quick_tap_ms: # deprecated + quick_tap_ms: type: int + deprecated: true global-quick-tap: type: boolean + deprecated: true + require-prior-idle-ms: + type: int + default: -1 flavor: type: string required: false diff --git a/app/dts/bindings/zmk,combos.yaml b/app/dts/bindings/zmk,combos.yaml index d094b5c42af..f146ab7a230 100644 --- a/app/dts/bindings/zmk,combos.yaml +++ b/app/dts/bindings/zmk,combos.yaml @@ -18,6 +18,9 @@ child-binding: timeout-ms: type: int default: 50 + require-prior-idle-ms: + type: int + default: -1 slow-release: type: boolean layers: diff --git a/app/include/dt-bindings/zmk/keys.h b/app/include/dt-bindings/zmk/keys.h index 3e67c402470..364ffa8647a 100644 --- a/app/include/dt-bindings/zmk/keys.h +++ b/app/include/dt-bindings/zmk/keys.h @@ -1439,3 +1439,7 @@ #define C_KEYBOARD_INPUT_ASSIST_CANCEL \ (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_KEYBOARD_INPUT_ASSIST_CANCEL)) #define C_KBIA_CANCEL (C_KEYBOARD_INPUT_ASSIST_CANCEL) + +/* Apple Globe key */ +#define C_AC_NEXT_KEYBOARD_LAYOUT_SELECT (ZMK_HID_USAGE(HID_USAGE_CONSUMER, 0x029D)) +#define GLOBE (C_AC_NEXT_KEYBOARD_LAYOUT_SELECT) diff --git a/app/include/dt-bindings/zmk/kscan-mock.h b/app/include/dt-bindings/zmk/kscan-mock.h deleted file mode 100644 index 4ed666c61ca..00000000000 --- a/app/include/dt-bindings/zmk/kscan-mock.h +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright (c) 2020 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#warning "kscan-mock.h has been deprecated and superseded by kscan_mock.h" - -#include "kscan_mock.h" \ No newline at end of file diff --git a/app/include/zmk/endpoints.h b/app/include/zmk/endpoints.h index c8860533e1d..c5964ff8535 100644 --- a/app/include/zmk/endpoints.h +++ b/app/include/zmk/endpoints.h @@ -6,10 +6,66 @@ #pragma once +#include #include -int zmk_endpoints_select(enum zmk_endpoint endpoint); -int zmk_endpoints_toggle(); -enum zmk_endpoint zmk_endpoints_selected(); +/** + * Recommended length of string buffer for printing endpoint identifiers. + */ +#define ZMK_ENDPOINT_STR_LEN 10 + +#ifdef CONFIG_ZMK_USB +#define ZMK_ENDPOINT_USB_COUNT 1 +#else +#define ZMK_ENDPOINT_USB_COUNT 0 +#endif + +#ifdef CONFIG_ZMK_BLE +#define ZMK_ENDPOINT_BLE_COUNT ZMK_BLE_PROFILE_COUNT +#else +#define ZMK_ENDPOINT_BLE_COUNT 0 +#endif + +/** + * The total number of different (struct zmk_endpoint_instance) values that can + * be selected. + * + * Note that this value may change between firmware versions, so it should not + * be used in any persistent storage. + */ +#define ZMK_ENDPOINT_COUNT (ZMK_ENDPOINT_USB_COUNT + ZMK_ENDPOINT_BLE_COUNT) + +bool zmk_endpoint_instance_eq(struct zmk_endpoint_instance a, struct zmk_endpoint_instance b); + +/** + * Writes a string identifying an endpoint instance. + * + * @param str Address of output string buffer + * @param len Length of string buffer. See ZMK_ENDPOINT_STR_LEN for recommended length. + * + * @returns Number of characters written. + */ +int zmk_endpoint_instance_to_str(struct zmk_endpoint_instance endpoint, char *str, size_t len); + +/** + * Gets a unique index for an endpoint instance. This can be used together with + * ZMK_ENDPOINT_COUNT to manage separate state for each endpoint instance. + * + * Note that the index for a specific instance may change between firmware versions, + * so it should not be used in any persistent storage. + */ +int zmk_endpoint_instance_to_index(struct zmk_endpoint_instance endpoint); + +/** + * Sets the preferred endpoint transport to use. (If the preferred endpoint is + * not available, a different one may automatically be selected.) + */ +int zmk_endpoints_select_transport(enum zmk_transport transport); +int zmk_endpoints_toggle_transport(void); + +/** + * Gets the currently-selected endpoint. + */ +struct zmk_endpoint_instance zmk_endpoints_selected(void); int zmk_endpoints_send_report(uint16_t usage_page); diff --git a/app/include/zmk/endpoints_types.h b/app/include/zmk/endpoints_types.h index 70804a613d8..ea51c8aa93d 100644 --- a/app/include/zmk/endpoints_types.h +++ b/app/include/zmk/endpoints_types.h @@ -6,7 +6,33 @@ #pragma once -enum zmk_endpoint { - ZMK_ENDPOINT_USB, - ZMK_ENDPOINT_BLE, +/** + * The method by which data is sent. + */ +enum zmk_transport { + ZMK_TRANSPORT_USB, + ZMK_TRANSPORT_BLE, +}; + +/** + * Configuration to select an endpoint on ZMK_TRANSPORT_USB. + */ +struct zmk_transport_usb_data {}; + +/** + * Configuration to select an endpoint on ZMK_TRANSPORT_BLE. + */ +struct zmk_transport_ble_data { + int profile_index; +}; + +/** + * A specific endpoint to which data may be sent. + */ +struct zmk_endpoint_instance { + enum zmk_transport transport; + union { + struct zmk_transport_usb_data usb; // ZMK_TRANSPORT_USB + struct zmk_transport_ble_data ble; // ZMK_TRANSPORT_BLE + }; }; diff --git a/app/include/zmk/events/endpoint_selection_changed.h b/app/include/zmk/events/endpoint_changed.h similarity index 61% rename from app/include/zmk/events/endpoint_selection_changed.h rename to app/include/zmk/events/endpoint_changed.h index 198fe5a1688..2147009b84b 100644 --- a/app/include/zmk/events/endpoint_selection_changed.h +++ b/app/include/zmk/events/endpoint_changed.h @@ -11,8 +11,8 @@ #include #include -struct zmk_endpoint_selection_changed { - enum zmk_endpoint endpoint; +struct zmk_endpoint_changed { + struct zmk_endpoint_instance endpoint; }; -ZMK_EVENT_DECLARE(zmk_endpoint_selection_changed); +ZMK_EVENT_DECLARE(zmk_endpoint_changed); diff --git a/app/include/zmk/keymap.h b/app/include/zmk/keymap.h index a47cd505643..9ce140bfa27 100644 --- a/app/include/zmk/keymap.h +++ b/app/include/zmk/keymap.h @@ -8,6 +8,10 @@ #include +#define ZMK_LAYER_CHILD_LEN_PLUS_ONE(node) 1 + +#define ZMK_KEYMAP_LAYERS_LEN \ + (DT_FOREACH_CHILD(DT_INST(0, zmk_keymap), ZMK_LAYER_CHILD_LEN_PLUS_ONE) 0) + typedef uint32_t zmk_keymap_layers_state_t; uint8_t zmk_keymap_layer_default(); diff --git a/app/include/zmk/sensors.h b/app/include/zmk/sensors.h index 8ac1c283cb6..1919d4ce647 100644 --- a/app/include/zmk/sensors.h +++ b/app/include/zmk/sensors.h @@ -24,7 +24,9 @@ struct zmk_sensor_config { uint16_t triggers_per_rotation; }; +// This struct is also used for data transfer for splits, so any changes to the size, layout, etc +// is a breaking change for the split GATT service protocol. struct zmk_sensor_channel_data { - enum sensor_channel channel; struct sensor_value value; -}; + enum sensor_channel channel; +} __packed; diff --git a/app/include/zmk/split/bluetooth/service.h b/app/include/zmk/split/bluetooth/service.h index f0c1d79ff7d..112cd552942 100644 --- a/app/include/zmk/split/bluetooth/service.h +++ b/app/include/zmk/split/bluetooth/service.h @@ -6,8 +6,18 @@ #pragma once +#include +#include + #define ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN 9 +struct sensor_event { + uint8_t sensor_index; + + uint8_t channel_data_size; + struct zmk_sensor_channel_data channel_data[ZMK_SENSOR_EVENT_MAX_CHANNELS]; +} __packed; + struct zmk_split_run_behavior_data { uint8_t position; uint8_t state; @@ -21,4 +31,7 @@ struct zmk_split_run_behavior_payload { } __packed; int zmk_split_bt_position_pressed(uint8_t position); -int zmk_split_bt_position_released(uint8_t position); \ No newline at end of file +int zmk_split_bt_position_released(uint8_t position); +int zmk_split_bt_sensor_triggered(uint8_t sensor_index, + const struct zmk_sensor_channel_data channel_data[], + size_t channel_data_size); diff --git a/app/include/zmk/split/bluetooth/uuid.h b/app/include/zmk/split/bluetooth/uuid.h index cbdb17723cd..c38131dd83e 100644 --- a/app/include/zmk/split/bluetooth/uuid.h +++ b/app/include/zmk/split/bluetooth/uuid.h @@ -16,3 +16,4 @@ #define ZMK_SPLIT_BT_SERVICE_UUID ZMK_BT_SPLIT_UUID(0x00000000) #define ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID ZMK_BT_SPLIT_UUID(0x00000001) #define ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID ZMK_BT_SPLIT_UUID(0x00000002) +#define ZMK_SPLIT_BT_CHAR_SENSOR_STATE_UUID ZMK_BT_SPLIT_UUID(0x00000003) diff --git a/app/include/zmk/workqueue.h b/app/include/zmk/workqueue.h new file mode 100644 index 00000000000..41e94580846 --- /dev/null +++ b/app/include/zmk/workqueue.h @@ -0,0 +1 @@ +struct k_work_q *zmk_workqueue_lowprio_work_q(); diff --git a/app/module/CMakeLists.txt b/app/module/CMakeLists.txt new file mode 100644 index 00000000000..db886ac6987 --- /dev/null +++ b/app/module/CMakeLists.txt @@ -0,0 +1,4 @@ +zephyr_include_directories(include) + +add_subdirectory(drivers) +add_subdirectory(lib) \ No newline at end of file diff --git a/app/module/Kconfig b/app/module/Kconfig new file mode 100644 index 00000000000..52c013151a9 --- /dev/null +++ b/app/module/Kconfig @@ -0,0 +1,3 @@ + +rsource "drivers/Kconfig" +rsource "lib/Kconfig" \ No newline at end of file diff --git a/app/module/drivers/CMakeLists.txt b/app/module/drivers/CMakeLists.txt new file mode 100644 index 00000000000..5281c3dcb21 --- /dev/null +++ b/app/module/drivers/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +add_subdirectory_ifdef(CONFIG_GPIO gpio) +add_subdirectory_ifdef(CONFIG_KSCAN kscan) +add_subdirectory_ifdef(CONFIG_SENSOR sensor) +add_subdirectory_ifdef(CONFIG_DISPLAY display) diff --git a/app/drivers/Kconfig b/app/module/drivers/Kconfig similarity index 100% rename from app/drivers/Kconfig rename to app/module/drivers/Kconfig diff --git a/app/module/drivers/display/CMakeLists.txt b/app/module/drivers/display/CMakeLists.txt new file mode 100644 index 00000000000..6fc98c95a9d --- /dev/null +++ b/app/module/drivers/display/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +zephyr_library_amend() + +zephyr_library_sources_ifdef(CONFIG_IL0323 il0323.c) \ No newline at end of file diff --git a/app/drivers/display/Kconfig b/app/module/drivers/display/Kconfig similarity index 58% rename from app/drivers/display/Kconfig rename to app/module/drivers/display/Kconfig index efa064d4f6b..d70aff7c40a 100644 --- a/app/drivers/display/Kconfig +++ b/app/module/drivers/display/Kconfig @@ -1,4 +1,8 @@ # Copyright (c) 2021 The ZMK Contributors # SPDX-License-Identifier: MIT -rsource "Kconfig.il0323" \ No newline at end of file +if DISPLAY + +rsource "Kconfig.il0323" + +endif # DISPLAY \ No newline at end of file diff --git a/app/drivers/display/Kconfig.il0323 b/app/module/drivers/display/Kconfig.il0323 similarity index 100% rename from app/drivers/display/Kconfig.il0323 rename to app/module/drivers/display/Kconfig.il0323 diff --git a/app/drivers/display/il0323.c b/app/module/drivers/display/il0323.c similarity index 100% rename from app/drivers/display/il0323.c rename to app/module/drivers/display/il0323.c diff --git a/app/drivers/display/il0323_regs.h b/app/module/drivers/display/il0323_regs.h similarity index 100% rename from app/drivers/display/il0323_regs.h rename to app/module/drivers/display/il0323_regs.h diff --git a/app/drivers/gpio/CMakeLists.txt b/app/module/drivers/gpio/CMakeLists.txt similarity index 65% rename from app/drivers/gpio/CMakeLists.txt rename to app/module/drivers/gpio/CMakeLists.txt index 0756ed386b4..b5647e87bd7 100644 --- a/app/drivers/gpio/CMakeLists.txt +++ b/app/module/drivers/gpio/CMakeLists.txt @@ -1,8 +1,7 @@ # Copyright (c) 2022 The ZMK Contributors # SPDX-License-Identifier: MIT -zephyr_library_named(zmk__drivers__gpio) -zephyr_library_include_directories(${CMAKE_SOURCE_DIR}/include) +zephyr_library_amend() zephyr_library_sources_ifdef(CONFIG_GPIO_595 gpio_595.c) zephyr_library_sources_ifdef(CONFIG_GPIO_MAX7318 gpio_max7318.c) diff --git a/app/drivers/gpio/Kconfig b/app/module/drivers/gpio/Kconfig similarity index 52% rename from app/drivers/gpio/Kconfig rename to app/module/drivers/gpio/Kconfig index 54b30590e1c..a6c7b4a19ef 100644 --- a/app/drivers/gpio/Kconfig +++ b/app/module/drivers/gpio/Kconfig @@ -1,5 +1,7 @@ -menuconfig ZMK_DRIVERS_GPIO - bool "GPIO" + +if GPIO rsource "Kconfig.max7318" rsource "Kconfig.595" + +endif # GPIO \ No newline at end of file diff --git a/app/drivers/gpio/Kconfig.595 b/app/module/drivers/gpio/Kconfig.595 similarity index 95% rename from app/drivers/gpio/Kconfig.595 rename to app/module/drivers/gpio/Kconfig.595 index b4b6bdcc2d8..7ebdc0cc54c 100644 --- a/app/drivers/gpio/Kconfig.595 +++ b/app/module/drivers/gpio/Kconfig.595 @@ -10,7 +10,6 @@ menuconfig GPIO_595 default $(dt_compat_enabled,$(DT_COMPAT_ZMK_GPIO_595)) depends on SPI select HAS_DTS_GPIO - select ZMK_DRIVERS_GPIO help Enable driver for 595 shift register chip using SPI. diff --git a/app/drivers/gpio/Kconfig.max7318 b/app/module/drivers/gpio/Kconfig.max7318 similarity index 95% rename from app/drivers/gpio/Kconfig.max7318 rename to app/module/drivers/gpio/Kconfig.max7318 index d572b97090f..b54e1dba465 100644 --- a/app/drivers/gpio/Kconfig.max7318 +++ b/app/module/drivers/gpio/Kconfig.max7318 @@ -10,7 +10,6 @@ menuconfig GPIO_MAX7318 default $(dt_compat_enabled,$(DT_COMPAT_MAXIM_MAX7318)) depends on I2C select HAS_DTS_GPIO - select ZMK_DRIVERS_GPIO help Enable driver for MAX7318 I2C-based GPIO chip. diff --git a/app/drivers/gpio/gpio_595.c b/app/module/drivers/gpio/gpio_595.c similarity index 100% rename from app/drivers/gpio/gpio_595.c rename to app/module/drivers/gpio/gpio_595.c diff --git a/app/drivers/gpio/gpio_max7318.c b/app/module/drivers/gpio/gpio_max7318.c similarity index 98% rename from app/drivers/gpio/gpio_max7318.c rename to app/module/drivers/gpio/gpio_max7318.c index 04424b48b09..1842ce7b2d6 100644 --- a/app/drivers/gpio/gpio_max7318.c +++ b/app/module/drivers/gpio/gpio_max7318.c @@ -12,16 +12,15 @@ #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #define LOG_LEVEL CONFIG_GPIO_LOG_LEVEL -#include +#include LOG_MODULE_REGISTER(gpio_max7318); diff --git a/app/drivers/kscan/CMakeLists.txt b/app/module/drivers/kscan/CMakeLists.txt similarity index 75% rename from app/drivers/kscan/CMakeLists.txt rename to app/module/drivers/kscan/CMakeLists.txt index 8fc7ed58d50..7ae9524c75f 100644 --- a/app/drivers/kscan/CMakeLists.txt +++ b/app/module/drivers/kscan/CMakeLists.txt @@ -1,10 +1,8 @@ # Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT -zephyr_library_named(zmk__drivers__kscan) -zephyr_library_include_directories(${CMAKE_SOURCE_DIR}/include) +zephyr_library_amend() -zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DRIVER debounce.c) zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DRIVER kscan_gpio.c) zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_MATRIX kscan_gpio_matrix.c) zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DIRECT kscan_gpio_direct.c) diff --git a/app/drivers/kscan/Kconfig b/app/module/drivers/kscan/Kconfig similarity index 95% rename from app/drivers/kscan/Kconfig rename to app/module/drivers/kscan/Kconfig index 1d1656694dc..6f60b3f919f 100644 --- a/app/drivers/kscan/Kconfig +++ b/app/module/drivers/kscan/Kconfig @@ -7,6 +7,8 @@ DT_COMPAT_ZMK_KSCAN_GPIO_DIRECT := zmk,kscan-gpio-direct DT_COMPAT_ZMK_KSCAN_GPIO_MATRIX := zmk,kscan-gpio-matrix DT_COMPAT_ZMK_KSCAN_MOCK := zmk,kscan-mock +if KSCAN + config ZMK_KSCAN_COMPOSITE_DRIVER bool default $(dt_compat_enabled,$(DT_COMPAT_ZMK_KSCAN_COMPOSITE)) @@ -14,6 +16,7 @@ config ZMK_KSCAN_COMPOSITE_DRIVER config ZMK_KSCAN_GPIO_DRIVER bool select GPIO + select ZMK_DEBOUNCE config ZMK_KSCAN_GPIO_DEMUX bool @@ -87,8 +90,4 @@ config ZMK_KSCAN_DEBOUNCE_RELEASE_MS endif -config ZMK_KSCAN_INIT_PRIORITY - int "Keyboard scan driver init priority" - default 40 - help - Keyboard scan device driver initialization priority. +endif # KSCAN diff --git a/app/drivers/kscan/kscan_composite.c b/app/module/drivers/kscan/kscan_composite.c similarity index 97% rename from app/drivers/kscan/kscan_composite.c rename to app/module/drivers/kscan/kscan_composite.c index 9909a4cfcfa..97311ef8e52 100644 --- a/app/drivers/kscan/kscan_composite.c +++ b/app/module/drivers/kscan/kscan_composite.c @@ -109,4 +109,4 @@ static const struct kscan_composite_config kscan_composite_config = {}; static struct kscan_composite_data kscan_composite_data; DEVICE_DT_INST_DEFINE(0, kscan_composite_init, NULL, &kscan_composite_data, &kscan_composite_config, - APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &mock_driver_api); + POST_KERNEL, CONFIG_KSCAN_INIT_PRIORITY, &mock_driver_api); diff --git a/app/drivers/kscan/kscan_gpio.c b/app/module/drivers/kscan/kscan_gpio.c similarity index 100% rename from app/drivers/kscan/kscan_gpio.c rename to app/module/drivers/kscan/kscan_gpio.c diff --git a/app/drivers/kscan/kscan_gpio.h b/app/module/drivers/kscan/kscan_gpio.h similarity index 100% rename from app/drivers/kscan/kscan_gpio.h rename to app/module/drivers/kscan/kscan_gpio.h diff --git a/app/drivers/kscan/kscan_gpio_demux.c b/app/module/drivers/kscan/kscan_gpio_demux.c similarity index 99% rename from app/drivers/kscan/kscan_gpio_demux.c rename to app/module/drivers/kscan/kscan_gpio_demux.c index 812a899d89c..2cbe116d9f2 100644 --- a/app/drivers/kscan/kscan_gpio_demux.c +++ b/app/module/drivers/kscan/kscan_gpio_demux.c @@ -201,7 +201,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); }; \ \ DEVICE_DT_INST_DEFINE(n, kscan_gpio_init_##n, NULL, &kscan_gpio_data_##n, \ - &kscan_gpio_config_##n, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY, \ + &kscan_gpio_config_##n, POST_KERNEL, CONFIG_KSCAN_INIT_PRIORITY, \ &gpio_driver_api_##n); DT_INST_FOREACH_STATUS_OKAY(GPIO_INST_INIT) diff --git a/app/drivers/kscan/kscan_gpio_direct.c b/app/module/drivers/kscan/kscan_gpio_direct.c similarity index 94% rename from app/drivers/kscan/kscan_gpio_direct.c rename to app/module/drivers/kscan/kscan_gpio_direct.c index d43d716bf64..5b227784dad 100644 --- a/app/drivers/kscan/kscan_gpio_direct.c +++ b/app/module/drivers/kscan/kscan_gpio_direct.c @@ -4,7 +4,6 @@ * SPDX-License-Identifier: MIT */ -#include "debounce.h" #include "kscan_gpio.h" #include @@ -15,6 +14,8 @@ #include #include +#include + LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #define DT_DRV_COMPAT zmk_kscan_gpio_direct @@ -61,11 +62,11 @@ struct kscan_direct_data { /** Timestamp of the current or scheduled scan. */ int64_t scan_time; /** Current state of the inputs as an array of length config->inputs.len */ - struct debounce_state *pin_state; + struct zmk_debounce_state *pin_state; }; struct kscan_direct_config { - struct debounce_config debounce_config; + struct zmk_debounce_config debounce_config; int32_t debounce_scan_period_ms; int32_t poll_period_ms; bool toggle_mode; @@ -182,8 +183,8 @@ static int kscan_direct_read(const struct device *dev) { return active; } - debounce_update(&data->pin_state[gpio->index], active, config->debounce_scan_period_ms, - &config->debounce_config); + zmk_debounce_update(&data->pin_state[gpio->index], active, config->debounce_scan_period_ms, + &config->debounce_config); } // Process the new state. @@ -191,10 +192,10 @@ static int kscan_direct_read(const struct device *dev) { for (int i = 0; i < data->inputs.len; i++) { const struct kscan_gpio *gpio = &data->inputs.gpios[i]; - struct debounce_state *state = &data->pin_state[gpio->index]; + struct zmk_debounce_state *state = &data->pin_state[gpio->index]; - if (debounce_get_changed(state)) { - const bool pressed = debounce_is_pressed(state); + if (zmk_debounce_get_changed(state)) { + const bool pressed = zmk_debounce_is_pressed(state); LOG_DBG("Sending event at 0,%i state %s", gpio->index, pressed ? "on" : "off"); data->callback(dev, 0, gpio->index, pressed); @@ -203,7 +204,7 @@ static int kscan_direct_read(const struct device *dev) { } } - continue_scan = continue_scan || debounce_is_active(state); + continue_scan = continue_scan || zmk_debounce_is_active(state); } if (continue_scan) { @@ -332,7 +333,7 @@ static const struct kscan_driver_api kscan_direct_api = { static struct kscan_gpio kscan_direct_inputs_##n[] = { \ LISTIFY(INST_INPUTS_LEN(n), KSCAN_DIRECT_INPUT_CFG_INIT, (, ), n)}; \ \ - static struct debounce_state kscan_direct_state_##n[INST_INPUTS_LEN(n)]; \ + static struct zmk_debounce_state kscan_direct_state_##n[INST_INPUTS_LEN(n)]; \ \ COND_INTERRUPTS( \ (static struct kscan_direct_irq_callback kscan_direct_irqs_##n[INST_INPUTS_LEN(n)];)) \ @@ -354,7 +355,7 @@ static const struct kscan_driver_api kscan_direct_api = { }; \ \ DEVICE_DT_INST_DEFINE(n, &kscan_direct_init, NULL, &kscan_direct_data_##n, \ - &kscan_direct_config_##n, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY, \ + &kscan_direct_config_##n, POST_KERNEL, CONFIG_KSCAN_INIT_PRIORITY, \ &kscan_direct_api); DT_INST_FOREACH_STATUS_OKAY(KSCAN_DIRECT_INIT); diff --git a/app/drivers/kscan/kscan_gpio_matrix.c b/app/module/drivers/kscan/kscan_gpio_matrix.c similarity index 95% rename from app/drivers/kscan/kscan_gpio_matrix.c rename to app/module/drivers/kscan/kscan_gpio_matrix.c index b8e72044928..0d8a3190659 100644 --- a/app/drivers/kscan/kscan_gpio_matrix.c +++ b/app/module/drivers/kscan/kscan_gpio_matrix.c @@ -4,7 +4,6 @@ * SPDX-License-Identifier: MIT */ -#include "debounce.h" #include "kscan_gpio.h" #include @@ -16,6 +15,8 @@ #include #include +#include + LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #define DT_DRV_COMPAT zmk_kscan_gpio_matrix @@ -80,12 +81,12 @@ struct kscan_matrix_data { * Current state of the matrix as a flattened 2D array of length * (config->rows * config->cols) */ - struct debounce_state *matrix_state; + struct zmk_debounce_state *matrix_state; }; struct kscan_matrix_config { struct kscan_gpio_list outputs; - struct debounce_config debounce_config; + struct zmk_debounce_config debounce_config; size_t rows; size_t cols; int32_t debounce_scan_period_ms; @@ -242,8 +243,8 @@ static int kscan_matrix_read(const struct device *dev) { return active; } - debounce_update(&data->matrix_state[index], active, config->debounce_scan_period_ms, - &config->debounce_config); + zmk_debounce_update(&data->matrix_state[index], active, config->debounce_scan_period_ms, + &config->debounce_config); } err = gpio_pin_set_dt(&out_gpio->spec, 0); @@ -263,16 +264,16 @@ static int kscan_matrix_read(const struct device *dev) { for (int r = 0; r < config->rows; r++) { for (int c = 0; c < config->cols; c++) { const int index = state_index_rc(config, r, c); - struct debounce_state *state = &data->matrix_state[index]; + struct zmk_debounce_state *state = &data->matrix_state[index]; - if (debounce_get_changed(state)) { - const bool pressed = debounce_is_pressed(state); + if (zmk_debounce_get_changed(state)) { + const bool pressed = zmk_debounce_is_pressed(state); LOG_DBG("Sending event at %i,%i state %s", r, c, pressed ? "on" : "off"); data->callback(dev, r, c, pressed); } - continue_scan = continue_scan || debounce_is_active(state); + continue_scan = continue_scan || zmk_debounce_is_active(state); } } @@ -438,7 +439,7 @@ static const struct kscan_driver_api kscan_matrix_api = { static struct kscan_gpio kscan_matrix_cols_##n[] = { \ LISTIFY(INST_COLS_LEN(n), KSCAN_GPIO_COL_CFG_INIT, (, ), n)}; \ \ - static struct debounce_state kscan_matrix_state_##n[INST_MATRIX_LEN(n)]; \ + static struct zmk_debounce_state kscan_matrix_state_##n[INST_MATRIX_LEN(n)]; \ \ COND_INTERRUPTS( \ (static struct kscan_matrix_irq_callback kscan_matrix_irqs_##n[INST_INPUTS_LEN(n)];)) \ @@ -465,7 +466,7 @@ static const struct kscan_driver_api kscan_matrix_api = { }; \ \ DEVICE_DT_INST_DEFINE(n, &kscan_matrix_init, NULL, &kscan_matrix_data_##n, \ - &kscan_matrix_config_##n, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY, \ + &kscan_matrix_config_##n, POST_KERNEL, CONFIG_KSCAN_INIT_PRIORITY, \ &kscan_matrix_api); DT_INST_FOREACH_STATUS_OKAY(KSCAN_MATRIX_INIT); diff --git a/app/drivers/kscan/kscan_mock.c b/app/module/drivers/kscan/kscan_mock.c similarity index 96% rename from app/drivers/kscan/kscan_mock.c rename to app/module/drivers/kscan/kscan_mock.c index 57862b0d6f4..604e164cbc5 100644 --- a/app/drivers/kscan/kscan_mock.c +++ b/app/module/drivers/kscan/kscan_mock.c @@ -89,7 +89,7 @@ static int kscan_mock_configure(const struct device *dev, kscan_callback_t callb static const struct kscan_mock_config_##n kscan_mock_config_##n = { \ .events = DT_INST_PROP(n, events), .exit_after = DT_INST_PROP(n, exit_after)}; \ DEVICE_DT_INST_DEFINE(n, kscan_mock_init_##n, NULL, &kscan_mock_data_##n, \ - &kscan_mock_config_##n, APPLICATION, \ - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &mock_driver_api_##n); + &kscan_mock_config_##n, POST_KERNEL, CONFIG_KSCAN_INIT_PRIORITY, \ + &mock_driver_api_##n); DT_INST_FOREACH_STATUS_OKAY(MOCK_INST_INIT) diff --git a/app/drivers/sensor/CMakeLists.txt b/app/module/drivers/sensor/CMakeLists.txt similarity index 59% rename from app/drivers/sensor/CMakeLists.txt rename to app/module/drivers/sensor/CMakeLists.txt index b549320f121..9654600a756 100644 --- a/app/drivers/sensor/CMakeLists.txt +++ b/app/module/drivers/sensor/CMakeLists.txt @@ -2,4 +2,5 @@ # SPDX-License-Identifier: MIT add_subdirectory_ifdef(CONFIG_ZMK_BATTERY battery) -add_subdirectory_ifdef(CONFIG_EC11 ec11) \ No newline at end of file +add_subdirectory_ifdef(CONFIG_EC11 ec11) +add_subdirectory_ifdef(CONFIG_MAX17048 max17048) diff --git a/app/drivers/sensor/Kconfig b/app/module/drivers/sensor/Kconfig similarity index 56% rename from app/drivers/sensor/Kconfig rename to app/module/drivers/sensor/Kconfig index a828f6c63ab..ad570c58c94 100644 --- a/app/drivers/sensor/Kconfig +++ b/app/module/drivers/sensor/Kconfig @@ -1,5 +1,10 @@ # Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT +if SENSOR + rsource "battery/Kconfig" -rsource "ec11/Kconfig" \ No newline at end of file +rsource "ec11/Kconfig" +rsource "max17048/Kconfig" + +endif # SENSOR diff --git a/app/drivers/sensor/battery/CMakeLists.txt b/app/module/drivers/sensor/battery/CMakeLists.txt similarity index 100% rename from app/drivers/sensor/battery/CMakeLists.txt rename to app/module/drivers/sensor/battery/CMakeLists.txt diff --git a/app/drivers/sensor/battery/Kconfig b/app/module/drivers/sensor/battery/Kconfig similarity index 94% rename from app/drivers/sensor/battery/Kconfig rename to app/module/drivers/sensor/battery/Kconfig index a9d7189e58a..703adebd44e 100644 --- a/app/drivers/sensor/battery/Kconfig +++ b/app/module/drivers/sensor/battery/Kconfig @@ -14,6 +14,7 @@ config ZMK_BATTERY_NRF_VDDH default $(dt_compat_enabled,$(DT_COMPAT_ZMK_BATTERY_NRF_VDDH)) select ADC select ZMK_BATTERY + depends on SENSOR help Enable ZMK nRF VDDH voltage driver for battery monitoring. @@ -22,5 +23,6 @@ config ZMK_BATTERY_VOLTAGE_DIVIDER default $(dt_compat_enabled,$(DT_COMPAT_ZMK_BATTERY_VOLTAGE_DIVIDER)) select ADC select ZMK_BATTERY + depends on SENSOR help Enable ZMK battery voltage divider driver for battery monitoring. diff --git a/app/drivers/sensor/battery/battery_common.c b/app/module/drivers/sensor/battery/battery_common.c similarity index 100% rename from app/drivers/sensor/battery/battery_common.c rename to app/module/drivers/sensor/battery/battery_common.c diff --git a/app/drivers/sensor/battery/battery_common.h b/app/module/drivers/sensor/battery/battery_common.h similarity index 100% rename from app/drivers/sensor/battery/battery_common.h rename to app/module/drivers/sensor/battery/battery_common.h diff --git a/app/drivers/sensor/battery/battery_nrf_vddh.c b/app/module/drivers/sensor/battery/battery_nrf_vddh.c similarity index 99% rename from app/drivers/sensor/battery/battery_nrf_vddh.c rename to app/module/drivers/sensor/battery/battery_nrf_vddh.c index 3f230812f4b..32c7c61eb82 100644 --- a/app/drivers/sensor/battery/battery_nrf_vddh.c +++ b/app/module/drivers/sensor/battery/battery_nrf_vddh.c @@ -93,7 +93,7 @@ static int vddh_init(const struct device *dev) { #ifdef CONFIG_ADC_NRFX_SAADC drv_data->acc = (struct adc_channel_cfg){ - .gain = ADC_GAIN_1_5, + .gain = ADC_GAIN_1_2, .reference = ADC_REF_INTERNAL, .acquisition_time = ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 40), .input_positive = SAADC_CH_PSELN_PSELN_VDDHDIV5, diff --git a/app/drivers/sensor/battery/battery_voltage_divider.c b/app/module/drivers/sensor/battery/battery_voltage_divider.c similarity index 99% rename from app/drivers/sensor/battery/battery_voltage_divider.c rename to app/module/drivers/sensor/battery/battery_voltage_divider.c index 655af3dbd74..62a02e9c3df 100644 --- a/app/drivers/sensor/battery/battery_voltage_divider.c +++ b/app/module/drivers/sensor/battery/battery_voltage_divider.c @@ -140,7 +140,7 @@ static int bvd_init(const struct device *dev) { #ifdef CONFIG_ADC_NRFX_SAADC drv_data->acc = (struct adc_channel_cfg){ - .gain = ADC_GAIN_1_5, + .gain = ADC_GAIN_1_6, .reference = ADC_REF_INTERNAL, .acquisition_time = ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 40), .input_positive = SAADC_CH_PSELP_PSELP_AnalogInput0 + drv_cfg->io_channel.channel, diff --git a/app/drivers/sensor/ec11/CMakeLists.txt b/app/module/drivers/sensor/ec11/CMakeLists.txt similarity index 100% rename from app/drivers/sensor/ec11/CMakeLists.txt rename to app/module/drivers/sensor/ec11/CMakeLists.txt diff --git a/app/drivers/sensor/ec11/Kconfig b/app/module/drivers/sensor/ec11/Kconfig similarity index 100% rename from app/drivers/sensor/ec11/Kconfig rename to app/module/drivers/sensor/ec11/Kconfig diff --git a/app/drivers/sensor/ec11/ec11.c b/app/module/drivers/sensor/ec11/ec11.c similarity index 100% rename from app/drivers/sensor/ec11/ec11.c rename to app/module/drivers/sensor/ec11/ec11.c diff --git a/app/drivers/sensor/ec11/ec11.h b/app/module/drivers/sensor/ec11/ec11.h similarity index 100% rename from app/drivers/sensor/ec11/ec11.h rename to app/module/drivers/sensor/ec11/ec11.h diff --git a/app/drivers/sensor/ec11/ec11_trigger.c b/app/module/drivers/sensor/ec11/ec11_trigger.c similarity index 100% rename from app/drivers/sensor/ec11/ec11_trigger.c rename to app/module/drivers/sensor/ec11/ec11_trigger.c diff --git a/app/module/drivers/sensor/max17048/CMakeLists.txt b/app/module/drivers/sensor/max17048/CMakeLists.txt new file mode 100644 index 00000000000..e895fa11fb8 --- /dev/null +++ b/app/module/drivers/sensor/max17048/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +zephyr_include_directories(.) + +zephyr_library() + +zephyr_library_sources_ifdef(CONFIG_MAX17048 max17048.c) +zephyr_library_sources_ifndef(CONFIG_MAX17048 ${ZEPHYR_BASE}/misc/empty_file.c) diff --git a/app/module/drivers/sensor/max17048/Kconfig b/app/module/drivers/sensor/max17048/Kconfig new file mode 100644 index 00000000000..8a7ec16e85d --- /dev/null +++ b/app/module/drivers/sensor/max17048/Kconfig @@ -0,0 +1,23 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +DT_COMPAT_MAXIM_MAX17048 := maxim,max17048 + +menuconfig MAX17048 + bool "MAX17048/9 I2C-based Fuel Gauge" + default $(dt_compat_enabled,$(DT_COMPAT_MAXIM_MAX17048)) + depends on I2C + select ZMK_BATTERY + help + Enable driver for MAX17048/9 I2C-based Fuel Gauge. Supports measuring + battery voltage and state-of-charge. + +if MAX17048 + +config SENSOR_MAX17048_INIT_PRIORITY + int "Init priority" + default 75 + help + Device driver initialization priority. + +endif #MAX17048 diff --git a/app/module/drivers/sensor/max17048/max17048.c b/app/module/drivers/sensor/max17048/max17048.c new file mode 100644 index 00000000000..24cfe093f4a --- /dev/null +++ b/app/module/drivers/sensor/max17048/max17048.c @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT maxim_max17048 + +#include +#include +#include +#include +#include +#include + +#include "max17048.h" + +#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL +#include +LOG_MODULE_REGISTER(sensor_max17048); + +static int read_register(const struct device *dev, uint8_t reg, uint16_t *value) { + + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + struct max17048_config *config = (struct max17048_config *)dev->config; + + uint8_t data[2] = {0}; + int ret = i2c_burst_read_dt(&config->i2c_bus, reg, &data[0], sizeof(data)); + if (ret != 0) { + LOG_DBG("i2c_write_read FAIL %d\n", ret); + return ret; + } + + // the register values are returned in big endian (MSB first) + *value = sys_get_be16(data); + return 0; +} + +static int write_register(const struct device *dev, uint8_t reg, uint16_t value) { + + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + struct max17048_config *config = (struct max17048_config *)dev->config; + + uint8_t data[2] = {0}; + sys_put_be16(value, &data[0]); + + return i2c_burst_write_dt(&config->i2c_bus, reg, &data[0], sizeof(data)); +} + +static int set_rcomp_value(const struct device *dev, uint8_t rcomp_value) { + + struct max17048_drv_data *const drv_data = (struct max17048_drv_data *const)dev->data; + k_sem_take(&drv_data->lock, K_FOREVER); + + uint16_t tmp = 0; + int err = read_register(dev, REG_CONFIG, &tmp); + if (err != 0) { + goto done; + } + + tmp = ((uint16_t)rcomp_value << 8) | (tmp & 0xFF); + err = write_register(dev, REG_CONFIG, tmp); + if (err != 0) { + goto done; + } + + LOG_DBG("set RCOMP to %d", rcomp_value); + +done: + k_sem_give(&drv_data->lock); + return err; +} + +static int set_sleep_enabled(const struct device *dev, bool sleep) { + + struct max17048_drv_data *const drv_data = (struct max17048_drv_data *const)dev->data; + k_sem_take(&drv_data->lock, K_FOREVER); + + uint16_t tmp = 0; + int err = read_register(dev, REG_CONFIG, &tmp); + if (err != 0) { + goto done; + } + + if (sleep) { + tmp |= 0x80; + } else { + tmp &= ~0x0080; + } + + err = write_register(dev, REG_CONFIG, tmp); + if (err != 0) { + goto done; + } + + LOG_DBG("sleep mode %s", sleep ? "enabled" : "disabled"); + +done: + k_sem_give(&drv_data->lock); + return err; +} + +static int max17048_sample_fetch(const struct device *dev, enum sensor_channel chan) { + + struct max17048_drv_data *const drv_data = dev->data; + k_sem_take(&drv_data->lock, K_FOREVER); + + int err = 0; + + if (chan == SENSOR_CHAN_GAUGE_STATE_OF_CHARGE || chan == SENSOR_CHAN_ALL) { + err = read_register(dev, REG_STATE_OF_CHARGE, &drv_data->raw_state_of_charge); + if (err != 0) { + LOG_WRN("failed to read state-of-charge: %d", err); + goto done; + } + LOG_DBG("read soc: %d", drv_data->raw_state_of_charge); + + } else if (chan == SENSOR_CHAN_GAUGE_VOLTAGE || chan == SENSOR_CHAN_ALL) { + err = read_register(dev, REG_VCELL, &drv_data->raw_vcell); + if (err != 0) { + LOG_WRN("failed to read vcell: %d", err); + goto done; + } + LOG_DBG("read vcell: %d", drv_data->raw_vcell); + + } else { + LOG_DBG("unsupported channel %d", chan); + err = -ENOTSUP; + } + +done: + k_sem_give(&drv_data->lock); + return err; +} + +static int max17048_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) { + int err = 0; + + struct max17048_drv_data *const drv_data = dev->data; + k_sem_take(&drv_data->lock, K_FOREVER); + + struct max17048_drv_data *const data = dev->data; + unsigned int tmp = 0; + + switch (chan) { + case SENSOR_CHAN_GAUGE_VOLTAGE: + // 1250 / 16 = 78.125 + tmp = data->raw_vcell * 1250 / 16; + val->val1 = tmp / 1000000; + val->val2 = tmp % 1000000; + break; + + case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE: + val->val1 = (data->raw_state_of_charge >> 8); + val->val2 = (data->raw_state_of_charge & 0xFF) * 1000000 / 256; + break; + + default: + err = -ENOTSUP; + break; + } + + k_sem_give(&drv_data->lock); + return err; +} + +static int max17048_init(const struct device *dev) { + struct max17048_drv_data *drv_data = dev->data; + const struct max17048_config *config = dev->config; + + if (!device_is_ready(config->i2c_bus.bus)) { + LOG_WRN("i2c bus not ready!"); + return -EINVAL; + } + + uint16_t ic_version = 0; + int err = read_register(dev, REG_VERSION, &ic_version); + if (err != 0) { + LOG_WRN("could not get IC version!"); + return err; + } + + // the functions below need the semaphore, so initialise it here + k_sem_init(&drv_data->lock, 1, 1); + + // bring the device out of sleep + set_sleep_enabled(dev, false); + + // set the default rcomp value -- 0x97, as stated in the datasheet + set_rcomp_value(dev, 0x97); + + LOG_INF("device initialised at 0x%x (version %d)", config->i2c_bus.addr, ic_version); + + return 0; +} + +static const struct sensor_driver_api max17048_api_table = {.sample_fetch = max17048_sample_fetch, + .channel_get = max17048_channel_get}; + +#define MAX17048_INIT(inst) \ + static struct max17048_config max17048_##inst##_config = {.i2c_bus = \ + I2C_DT_SPEC_INST_GET(inst)}; \ + \ + static struct max17048_drv_data max17048_##inst##_drvdata = { \ + .raw_state_of_charge = 0, \ + .raw_charge_rate = 0, \ + .raw_vcell = 0, \ + }; \ + \ + /* This has to init after SPI master */ \ + DEVICE_DT_INST_DEFINE(inst, max17048_init, NULL, &max17048_##inst##_drvdata, \ + &max17048_##inst##_config, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ + &max17048_api_table); + +DT_INST_FOREACH_STATUS_OKAY(MAX17048_INIT) diff --git a/app/module/drivers/sensor/max17048/max17048.h b/app/module/drivers/sensor/max17048/max17048.h new file mode 100644 index 00000000000..984f5c70f4e --- /dev/null +++ b/app/module/drivers/sensor/max17048/max17048.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define REG_VCELL 0x02 +#define REG_STATE_OF_CHARGE 0x04 +#define REG_MODE 0x06 +#define REG_VERSION 0x08 +#define REG_HIBERNATE 0x0A +#define REG_CONFIG 0x0C +#define REG_VALERT 0x14 +#define REG_CHARGE_RATE 0x16 +#define REG_VRESET 0x18 +#define REG_STATUS 0x1A + +struct max17048_config { + struct i2c_dt_spec i2c_bus; +}; + +struct max17048_drv_data { + struct k_sem lock; + + uint16_t raw_state_of_charge; + uint16_t raw_charge_rate; + uint16_t raw_vcell; +}; + +#ifdef __cplusplus +} +#endif diff --git a/app/dts/bindings/display/gooddisplay,il0323.yaml b/app/module/dts/bindings/display/gooddisplay,il0323.yaml similarity index 100% rename from app/dts/bindings/display/gooddisplay,il0323.yaml rename to app/module/dts/bindings/display/gooddisplay,il0323.yaml diff --git a/app/drivers/zephyr/dts/bindings/gpio/maxim,max7318.yaml b/app/module/dts/bindings/gpio/maxim,max7318.yaml similarity index 93% rename from app/drivers/zephyr/dts/bindings/gpio/maxim,max7318.yaml rename to app/module/dts/bindings/gpio/maxim,max7318.yaml index 94952813edd..6c309768d44 100644 --- a/app/drivers/zephyr/dts/bindings/gpio/maxim,max7318.yaml +++ b/app/module/dts/bindings/gpio/maxim,max7318.yaml @@ -12,9 +12,6 @@ compatible: "maxim,max7318" include: [gpio-controller.yaml, i2c-device.yaml] properties: - label: - required: true - "#gpio-cells": const: 2 diff --git a/app/drivers/zephyr/dts/bindings/gpio/zmk,gpio-595.yaml b/app/module/dts/bindings/gpio/zmk,gpio-595.yaml similarity index 100% rename from app/drivers/zephyr/dts/bindings/gpio/zmk,gpio-595.yaml rename to app/module/dts/bindings/gpio/zmk,gpio-595.yaml diff --git a/app/drivers/zephyr/dts/bindings/kscan/zmk,kscan-gpio-demux.yaml b/app/module/dts/bindings/kscan/zmk,kscan-gpio-demux.yaml similarity index 100% rename from app/drivers/zephyr/dts/bindings/kscan/zmk,kscan-gpio-demux.yaml rename to app/module/dts/bindings/kscan/zmk,kscan-gpio-demux.yaml diff --git a/app/drivers/zephyr/dts/bindings/kscan/zmk,kscan-gpio-direct.yaml b/app/module/dts/bindings/kscan/zmk,kscan-gpio-direct.yaml similarity index 100% rename from app/drivers/zephyr/dts/bindings/kscan/zmk,kscan-gpio-direct.yaml rename to app/module/dts/bindings/kscan/zmk,kscan-gpio-direct.yaml diff --git a/app/drivers/zephyr/dts/bindings/kscan/zmk,kscan-gpio-matrix.yaml b/app/module/dts/bindings/kscan/zmk,kscan-gpio-matrix.yaml similarity index 100% rename from app/drivers/zephyr/dts/bindings/kscan/zmk,kscan-gpio-matrix.yaml rename to app/module/dts/bindings/kscan/zmk,kscan-gpio-matrix.yaml diff --git a/app/drivers/zephyr/dts/bindings/sensor/alps,ec11.yaml b/app/module/dts/bindings/sensor/alps,ec11.yaml similarity index 100% rename from app/drivers/zephyr/dts/bindings/sensor/alps,ec11.yaml rename to app/module/dts/bindings/sensor/alps,ec11.yaml diff --git a/app/module/dts/bindings/sensor/maxim,max17048.yml b/app/module/dts/bindings/sensor/maxim,max17048.yml new file mode 100644 index 00000000000..786f4b8686d --- /dev/null +++ b/app/module/dts/bindings/sensor/maxim,max17048.yml @@ -0,0 +1,12 @@ +# +# Copyright (c) 2022 The ZMK Contributors +# +# SPDX-License-Identifier: MIT +# + +description: > + This is a representation of the Maxim max17048 I2C Fuel Gauge. + +compatible: "maxim,max17048" + +include: [i2c-device.yaml] diff --git a/app/drivers/zephyr/dts/bindings/sensor/zmk,battery-nrf-vddh.yaml b/app/module/dts/bindings/sensor/zmk,battery-nrf-vddh.yaml similarity index 100% rename from app/drivers/zephyr/dts/bindings/sensor/zmk,battery-nrf-vddh.yaml rename to app/module/dts/bindings/sensor/zmk,battery-nrf-vddh.yaml diff --git a/app/drivers/zephyr/dts/bindings/sensor/zmk,battery-voltage-divider.yaml b/app/module/dts/bindings/sensor/zmk,battery-voltage-divider.yaml similarity index 100% rename from app/drivers/zephyr/dts/bindings/sensor/zmk,battery-voltage-divider.yaml rename to app/module/dts/bindings/sensor/zmk,battery-voltage-divider.yaml diff --git a/app/include/dt-bindings/zmk/kscan_mock.h b/app/module/include/dt-bindings/zmk/kscan_mock.h similarity index 100% rename from app/include/dt-bindings/zmk/kscan_mock.h rename to app/module/include/dt-bindings/zmk/kscan_mock.h diff --git a/app/drivers/kscan/debounce.h b/app/module/include/zmk/debounce.h similarity index 73% rename from app/drivers/kscan/debounce.h rename to app/module/include/zmk/debounce.h index 6e9faa66818..afa775a023d 100644 --- a/app/drivers/kscan/debounce.h +++ b/app/module/include/zmk/debounce.h @@ -13,13 +13,13 @@ #define DEBOUNCE_COUNTER_BITS 14 #define DEBOUNCE_COUNTER_MAX BIT_MASK(DEBOUNCE_COUNTER_BITS) -struct debounce_state { +struct zmk_debounce_state { bool pressed : 1; bool changed : 1; uint16_t counter : DEBOUNCE_COUNTER_BITS; }; -struct debounce_config { +struct zmk_debounce_config { /** Duration a switch must be pressed to latch as pressed. */ uint32_t debounce_press_ms; /** Duration a switch must be released to latch as released. */ @@ -34,23 +34,23 @@ struct debounce_config { * @param elapsed_ms Time elapsed since the previous update in milliseconds. * @param config Debounce settings. */ -void debounce_update(struct debounce_state *state, const bool active, const int elapsed_ms, - const struct debounce_config *config); +void zmk_debounce_update(struct zmk_debounce_state *state, const bool active, const int elapsed_ms, + const struct zmk_debounce_config *config); /** * @returns whether the switch is either latched as pressed or it is potentially * pressed but the debouncer has not yet made a decision. If this returns true, * the kscan driver should continue to poll quickly. */ -bool debounce_is_active(const struct debounce_state *state); +bool zmk_debounce_is_active(const struct zmk_debounce_state *state); /** * @returns whether the switch is latched as pressed. */ -bool debounce_is_pressed(const struct debounce_state *state); +bool zmk_debounce_is_pressed(const struct zmk_debounce_state *state); /** * @returns whether the pressed state of the switch changed in the last call to * debounce_update. */ -bool debounce_get_changed(const struct debounce_state *state); +bool zmk_debounce_get_changed(const struct zmk_debounce_state *state); diff --git a/app/module/lib/CMakeLists.txt b/app/module/lib/CMakeLists.txt new file mode 100644 index 00000000000..146b3637b68 --- /dev/null +++ b/app/module/lib/CMakeLists.txt @@ -0,0 +1,2 @@ + +add_subdirectory_ifdef(CONFIG_ZMK_DEBOUNCE zmk_debounce) \ No newline at end of file diff --git a/app/module/lib/Kconfig b/app/module/lib/Kconfig new file mode 100644 index 00000000000..8f2f06017d3 --- /dev/null +++ b/app/module/lib/Kconfig @@ -0,0 +1,2 @@ + +rsource "zmk_debounce/Kconfig" \ No newline at end of file diff --git a/app/module/lib/zmk_debounce/CMakeLists.txt b/app/module/lib/zmk_debounce/CMakeLists.txt new file mode 100644 index 00000000000..0a65dde1109 --- /dev/null +++ b/app/module/lib/zmk_debounce/CMakeLists.txt @@ -0,0 +1,3 @@ + +zephyr_library() +zephyr_library_sources(debounce.c) \ No newline at end of file diff --git a/app/module/lib/zmk_debounce/Kconfig b/app/module/lib/zmk_debounce/Kconfig new file mode 100644 index 00000000000..cd0321e8569 --- /dev/null +++ b/app/module/lib/zmk_debounce/Kconfig @@ -0,0 +1,3 @@ + +config ZMK_DEBOUNCE + bool "Debounce Support" \ No newline at end of file diff --git a/app/drivers/kscan/debounce.c b/app/module/lib/zmk_debounce/debounce.c similarity index 62% rename from app/drivers/kscan/debounce.c rename to app/module/lib/zmk_debounce/debounce.c index b38782267e8..6f4885b745c 100644 --- a/app/drivers/kscan/debounce.c +++ b/app/module/lib/zmk_debounce/debounce.c @@ -4,14 +4,14 @@ * SPDX-License-Identifier: MIT */ -#include "debounce.h" +#include -static uint32_t get_threshold(const struct debounce_state *state, - const struct debounce_config *config) { +static uint32_t get_threshold(const struct zmk_debounce_state *state, + const struct zmk_debounce_config *config) { return state->pressed ? config->debounce_release_ms : config->debounce_press_ms; } -static void increment_counter(struct debounce_state *state, const int elapsed_ms) { +static void increment_counter(struct zmk_debounce_state *state, const int elapsed_ms) { if (state->counter + elapsed_ms > DEBOUNCE_COUNTER_MAX) { state->counter = DEBOUNCE_COUNTER_MAX; } else { @@ -19,7 +19,7 @@ static void increment_counter(struct debounce_state *state, const int elapsed_ms } } -static void decrement_counter(struct debounce_state *state, const int elapsed_ms) { +static void decrement_counter(struct zmk_debounce_state *state, const int elapsed_ms) { if (state->counter < elapsed_ms) { state->counter = 0; } else { @@ -27,8 +27,8 @@ static void decrement_counter(struct debounce_state *state, const int elapsed_ms } } -void debounce_update(struct debounce_state *state, const bool active, const int elapsed_ms, - const struct debounce_config *config) { +void zmk_debounce_update(struct zmk_debounce_state *state, const bool active, const int elapsed_ms, + const struct zmk_debounce_config *config) { // This uses a variation of the integrator debouncing described at // https://www.kennethkuhn.com/electronics/debounce.c // Every update where "active" does not match the current state, we increment @@ -53,10 +53,10 @@ void debounce_update(struct debounce_state *state, const bool active, const int state->changed = true; } -bool debounce_is_active(const struct debounce_state *state) { +bool zmk_debounce_is_active(const struct zmk_debounce_state *state) { return state->pressed || state->counter > 0; } -bool debounce_is_pressed(const struct debounce_state *state) { return state->pressed; } +bool zmk_debounce_is_pressed(const struct zmk_debounce_state *state) { return state->pressed; } -bool debounce_get_changed(const struct debounce_state *state) { return state->changed; } \ No newline at end of file +bool zmk_debounce_get_changed(const struct zmk_debounce_state *state) { return state->changed; } \ No newline at end of file diff --git a/app/drivers/zephyr/module.yml b/app/module/zephyr/module.yml similarity index 56% rename from app/drivers/zephyr/module.yml rename to app/module/zephyr/module.yml index 0b6605945e5..219b2cfd201 100644 --- a/app/drivers/zephyr/module.yml +++ b/app/module/zephyr/module.yml @@ -1,3 +1,5 @@ build: cmake: . kconfig: Kconfig + settings: + dts_root: . diff --git a/app/src/battery.c b/app/src/battery.c index 540f7c3eab0..87a25e08a2d 100644 --- a/app/src/battery.c +++ b/app/src/battery.c @@ -18,6 +18,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include #include +#include static uint8_t last_state_of_charge = 0; @@ -77,7 +78,9 @@ static void zmk_battery_work(struct k_work *work) { K_WORK_DEFINE(battery_work, zmk_battery_work); -static void zmk_battery_timer(struct k_timer *timer) { k_work_submit(&battery_work); } +static void zmk_battery_timer(struct k_timer *timer) { + k_work_submit_to_queue(zmk_workqueue_lowprio_work_q(), &battery_work); +} K_TIMER_DEFINE(battery_timer, zmk_battery_timer, NULL); @@ -97,14 +100,7 @@ static int zmk_battery_init(const struct device *_arg) { return -ENODEV; } - int rc = zmk_battery_update(battery); - - if (rc != 0) { - LOG_DBG("Failed to update battery value: %d.", rc); - return rc; - } - - k_timer_start(&battery_timer, K_MINUTES(1), K_SECONDS(CONFIG_ZMK_BATTERY_REPORT_INTERVAL)); + k_timer_start(&battery_timer, K_NO_WAIT, K_SECONDS(CONFIG_ZMK_BATTERY_REPORT_INTERVAL)); return 0; } diff --git a/app/src/behaviors/behavior_hold_tap.c b/app/src/behaviors/behavior_hold_tap.c index 30350ef24ce..d4aa0dce036 100644 --- a/app/src/behaviors/behavior_hold_tap.c +++ b/app/src/behaviors/behavior_hold_tap.c @@ -57,7 +57,7 @@ struct behavior_hold_tap_config { char *hold_behavior_dev; char *tap_behavior_dev; int quick_tap_ms; - bool global_quick_tap; + int require_prior_idle_ms; enum flavor flavor; bool retro_tap; bool hold_trigger_on_release; @@ -97,7 +97,9 @@ struct last_tapped { int64_t timestamp; }; -struct last_tapped last_tapped = {INT32_MIN, INT64_MIN}; +// Set time stamp to large negative number initially for test suites, but not +// int64 min since it will overflow if -1 is added +struct last_tapped last_tapped = {INT32_MIN, INT32_MIN}; static void store_last_tapped(int64_t timestamp) { if (timestamp > last_tapped.timestamp) { @@ -112,10 +114,11 @@ static void store_last_hold_tapped(struct active_hold_tap *hold_tap) { } static bool is_quick_tap(struct active_hold_tap *hold_tap) { - if (hold_tap->config->global_quick_tap || last_tapped.position == hold_tap->position) { - return (last_tapped.timestamp + hold_tap->config->quick_tap_ms) > hold_tap->timestamp; + if ((last_tapped.timestamp + hold_tap->config->require_prior_idle_ms) > hold_tap->timestamp) { + return true; } else { - return false; + return (last_tapped.position == hold_tap->position) && + (last_tapped.timestamp + hold_tap->config->quick_tap_ms) > hold_tap->timestamp; } } @@ -703,7 +706,9 @@ static int behavior_hold_tap_init(const struct device *dev) { .hold_behavior_dev = DT_PROP(DT_INST_PHANDLE_BY_IDX(n, bindings, 0), label), \ .tap_behavior_dev = DT_PROP(DT_INST_PHANDLE_BY_IDX(n, bindings, 1), label), \ .quick_tap_ms = DT_INST_PROP(n, quick_tap_ms), \ - .global_quick_tap = DT_INST_PROP(n, global_quick_tap), \ + .require_prior_idle_ms = DT_INST_PROP(n, global_quick_tap) \ + ? DT_INST_PROP(n, quick_tap_ms) \ + : DT_INST_PROP(n, require_prior_idle_ms), \ .flavor = DT_ENUM_IDX(DT_DRV_INST(n), flavor), \ .retro_tap = DT_INST_PROP(n, retro_tap), \ .hold_trigger_on_release = DT_INST_PROP(n, hold_trigger_on_release), \ diff --git a/app/src/behaviors/behavior_outputs.c b/app/src/behaviors/behavior_outputs.c index 7aab8ee32c0..6ae81a0fdd7 100644 --- a/app/src/behaviors/behavior_outputs.c +++ b/app/src/behaviors/behavior_outputs.c @@ -24,11 +24,11 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { switch (binding->param1) { case OUT_TOG: - return zmk_endpoints_toggle(); + return zmk_endpoints_toggle_transport(); case OUT_USB: - return zmk_endpoints_select(ZMK_ENDPOINT_USB); + return zmk_endpoints_select_transport(ZMK_TRANSPORT_USB); case OUT_BLE: - return zmk_endpoints_select(ZMK_ENDPOINT_BLE); + return zmk_endpoints_select_transport(ZMK_TRANSPORT_BLE); default: LOG_ERR("Unknown output command: %d", binding->param1); } diff --git a/app/src/behaviors/behavior_sensor_rotate_common.c b/app/src/behaviors/behavior_sensor_rotate_common.c index 586cac3fdf2..98b4aec1267 100644 --- a/app/src/behaviors/behavior_sensor_rotate_common.c +++ b/app/src/behaviors/behavior_sensor_rotate_common.c @@ -28,7 +28,7 @@ int zmk_behavior_sensor_rotate_common_accept_data( if (value.val1 == 0) { triggers = value.val2; } else { - struct sensor_value remainder = data->remainder[sensor_index]; + struct sensor_value remainder = data->remainder[sensor_index][event.layer]; remainder.val1 += value.val1; remainder.val2 += value.val2; @@ -42,15 +42,16 @@ int zmk_behavior_sensor_rotate_common_accept_data( triggers = remainder.val1 / trigger_degrees; remainder.val1 %= trigger_degrees; - data->remainder[sensor_index] = remainder; + data->remainder[sensor_index][event.layer] = remainder; } LOG_DBG( "val1: %d, val2: %d, remainder: %d/%d triggers: %d inc keycode 0x%02X dec keycode 0x%02X", - value.val1, value.val2, data->remainder[sensor_index].val1, - data->remainder[sensor_index].val2, triggers, binding->param1, binding->param2); + value.val1, value.val2, data->remainder[sensor_index][event.layer].val1, + data->remainder[sensor_index][event.layer].val2, triggers, binding->param1, + binding->param2); - data->triggers[sensor_index] = triggers; + data->triggers[sensor_index][event.layer] = triggers; return 0; } @@ -64,11 +65,11 @@ int zmk_behavior_sensor_rotate_common_process(struct zmk_behavior_binding *bindi const int sensor_index = ZMK_SENSOR_POSITION_FROM_VIRTUAL_KEY_POSITION(event.position); if (mode != BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_TRIGGER) { - data->triggers[sensor_index] = 0; + data->triggers[sensor_index][event.layer] = 0; return ZMK_BEHAVIOR_TRANSPARENT; } - int triggers = data->triggers[sensor_index]; + int triggers = data->triggers[sensor_index][event.layer]; struct zmk_behavior_binding triggered_binding; if (triggers > 0) { diff --git a/app/src/behaviors/behavior_sensor_rotate_common.h b/app/src/behaviors/behavior_sensor_rotate_common.h index d354b67937c..c92ac3d5e5f 100644 --- a/app/src/behaviors/behavior_sensor_rotate_common.h +++ b/app/src/behaviors/behavior_sensor_rotate_common.h @@ -6,6 +6,7 @@ #include #include +#include #include struct behavior_sensor_rotate_config { @@ -16,8 +17,8 @@ struct behavior_sensor_rotate_config { }; struct behavior_sensor_rotate_data { - struct sensor_value remainder[ZMK_KEYMAP_SENSORS_LEN]; - int triggers[ZMK_KEYMAP_SENSORS_LEN]; + struct sensor_value remainder[ZMK_KEYMAP_SENSORS_LEN][ZMK_KEYMAP_LAYERS_LEN]; + int triggers[ZMK_KEYMAP_SENSORS_LEN][ZMK_KEYMAP_LAYERS_LEN]; }; int zmk_behavior_sensor_rotate_common_accept_data( diff --git a/app/src/ble.c b/app/src/ble.c index ff82f3cf40a..483bc9d79c1 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -281,14 +281,19 @@ int zmk_ble_put_peripheral_addr(const bt_addr_le_t *addr) { for (int i = 0; i < ZMK_SPLIT_BLE_PERIPHERAL_COUNT; i++) { // If the address is recognized and already stored in settings, return // index and no additional action is necessary. - if (!bt_addr_le_cmp(&peripheral_addrs[i], addr)) { + if (bt_addr_le_cmp(&peripheral_addrs[i], addr) == 0) { + LOG_DBG("Found existing peripheral address in slot %d", i); return i; + } else { + char addr_str[BT_ADDR_LE_STR_LEN]; + bt_addr_le_to_str(&peripheral_addrs[i], addr_str, sizeof(addr_str)); + LOG_DBG("peripheral slot %d occupied by %s", i, addr_str); } // If the peripheral address slot is open, store new peripheral in the // slot and return index. This compares against BT_ADDR_LE_ANY as that // is the zero value. - if (!bt_addr_le_cmp(&peripheral_addrs[i], BT_ADDR_LE_ANY)) { + if (bt_addr_le_cmp(&peripheral_addrs[i], BT_ADDR_LE_ANY) == 0) { char addr_str[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); LOG_DBG("Storing peripheral %s in slot %d", addr_str, i); @@ -606,7 +611,7 @@ static int zmk_ble_init(const struct device *_arg) { bt_unpair(BT_ID_DEFAULT, NULL); - for (int i = 0; i < ZMK_BLE_PROFILE_COUNT; i++) { + for (int i = 0; i < 8; i++) { char setting_name[15]; sprintf(setting_name, "ble/profiles/%d", i); @@ -615,7 +620,20 @@ static int zmk_ble_init(const struct device *_arg) { LOG_ERR("Failed to delete setting: %d", err); } } -#endif + + // Hardcoding a reasonable hardcoded value of peripheral addresses + // to clear so we properly clear a split central as well. + for (int i = 0; i < 8; i++) { + char setting_name[32]; + sprintf(setting_name, "ble/peripheral_addresses/%d", i); + + err = settings_delete(setting_name); + if (err) { + LOG_ERR("Failed to delete setting: %d", err); + } + } + +#endif // IS_ENABLED(CONFIG_ZMK_BLE_CLEAR_BONDS_ON_START) bt_conn_cb_register(&conn_callbacks); bt_conn_auth_cb_register(&zmk_ble_auth_cb_display); diff --git a/app/src/combo.c b/app/src/combo.c index 90c89c15e73..0d5c2a6e237 100644 --- a/app/src/combo.c +++ b/app/src/combo.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,7 @@ struct combo_cfg { int32_t key_position_len; struct zmk_behavior_binding behavior; int32_t timeout_ms; + int32_t require_prior_idle_ms; // if slow release is set, the combo releases when the last key is released. // otherwise, the combo releases when the first key is released. bool slow_release; @@ -72,6 +74,17 @@ int active_combo_count = 0; struct k_work_delayable timeout_task; int64_t timeout_task_timeout_at; +// this keeps track of the last non-combo, non-mod key tap +int64_t last_tapped_timestamp = INT32_MIN; +// this keeps track of the last time a combo was pressed +int64_t last_combo_timestamp = INT32_MIN; + +static void store_last_tapped(int64_t timestamp) { + if (timestamp > last_combo_timestamp) { + last_tapped_timestamp = timestamp; + } +} + // Store the combo key pointer in the combos array, one pointer for each key position // The combos are sorted shortest-first, then by virtual-key-position. static int initialize_combo(struct combo_cfg *new_combo) { @@ -122,6 +135,10 @@ static bool combo_active_on_layer(struct combo_cfg *combo, uint8_t layer) { return false; } +static bool is_quick_tap(struct combo_cfg *combo, int64_t timestamp) { + return (last_tapped_timestamp + combo->require_prior_idle_ms) > timestamp; +} + static int setup_candidates_for_first_keypress(int32_t position, int64_t timestamp) { int number_of_combo_candidates = 0; uint8_t highest_active_layer = zmk_keymap_highest_layer_active(); @@ -130,7 +147,7 @@ static int setup_candidates_for_first_keypress(int32_t position, int64_t timesta if (combo == NULL) { return number_of_combo_candidates; } - if (combo_active_on_layer(combo, highest_active_layer)) { + if (combo_active_on_layer(combo, highest_active_layer) && !is_quick_tap(combo, timestamp)) { candidates[number_of_combo_candidates].combo = combo; candidates[number_of_combo_candidates].timeout_at = timestamp + combo->timeout_ms; number_of_combo_candidates++; @@ -204,22 +221,34 @@ static inline bool candidate_is_completely_pressed(struct combo_cfg *candidate) static int cleanup(); static int filter_timed_out_candidates(int64_t timestamp) { - int num_candidates = 0; + int remaining_candidates = 0; for (int i = 0; i < CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY; i++) { struct combo_candidate *candidate = &candidates[i]; if (candidate->combo == NULL) { break; } if (candidate->timeout_at > timestamp) { - // reorder candidates so they're contiguous - candidates[num_candidates].combo = candidate->combo; - candidates[num_candidates].timeout_at = candidate->timeout_at; - num_candidates++; + bool need_to_bubble_up = remaining_candidates != i; + if (need_to_bubble_up) { + // bubble up => reorder candidates so they're contiguous + candidates[remaining_candidates].combo = candidate->combo; + candidates[remaining_candidates].timeout_at = candidate->timeout_at; + // clear the previous location + candidates[i].combo = NULL; + candidates[i].timeout_at = 0; + } + + remaining_candidates++; } else { candidate->combo = NULL; } } - return num_candidates; + + LOG_DBG( + "after filtering out timed out combo candidates: remaining_candidates=%d timestamp=%lld", + remaining_candidates, timestamp); + + return remaining_candidates; } static int clear_candidates() { @@ -240,7 +269,7 @@ static int capture_pressed_key(const zmk_event_t *ev) { pressed_keys[i] = ev; return ZMK_EV_EVENT_CAPTURED; } - return 0; + return ZMK_EV_EVENT_BUBBLE; } const struct zmk_listener zmk_listener_combo; @@ -272,6 +301,8 @@ static inline int press_combo_behavior(struct combo_cfg *combo, int32_t timestam .timestamp = timestamp, }; + last_combo_timestamp = timestamp; + return behavior_keymap_binding_pressed(&combo->behavior, event); } @@ -401,7 +432,7 @@ static int position_state_down(const zmk_event_t *ev, struct zmk_position_state_ if (candidates[0].combo == NULL) { num_candidates = setup_candidates_for_first_keypress(data->position, data->timestamp); if (num_candidates == 0) { - return 0; + return ZMK_EV_EVENT_BUBBLE; } } else { filter_timed_out_candidates(data->timestamp); @@ -441,7 +472,7 @@ static int position_state_up(const zmk_event_t *ev, struct zmk_position_state_ch ZMK_EVENT_RAISE(ev); return ZMK_EV_EVENT_CAPTURED; } - return 0; + return ZMK_EV_EVENT_BUBBLE; } static void combo_timeout_handler(struct k_work *item) { @@ -449,7 +480,7 @@ static void combo_timeout_handler(struct k_work *item) { // timer was cancelled or rescheduled. return; } - if (filter_timed_out_candidates(timeout_task_timeout_at) < 2) { + if (filter_timed_out_candidates(timeout_task_timeout_at) == 0) { cleanup(); } update_timeout_task(); @@ -458,7 +489,7 @@ static void combo_timeout_handler(struct k_work *item) { static int position_state_changed_listener(const zmk_event_t *ev) { struct zmk_position_state_changed *data = as_zmk_position_state_changed(ev); if (data == NULL) { - return 0; + return ZMK_EV_EVENT_BUBBLE; } if (data->state) { // keydown @@ -468,12 +499,31 @@ static int position_state_changed_listener(const zmk_event_t *ev) { } } -ZMK_LISTENER(combo, position_state_changed_listener); +static int keycode_state_changed_listener(const zmk_event_t *eh) { + struct zmk_keycode_state_changed *ev = as_zmk_keycode_state_changed(eh); + if (ev->state && !is_mod(ev->usage_page, ev->keycode)) { + store_last_tapped(ev->timestamp); + } + return ZMK_EV_EVENT_BUBBLE; +} + +int behavior_combo_listener(const zmk_event_t *eh) { + if (as_zmk_position_state_changed(eh) != NULL) { + return position_state_changed_listener(eh); + } else if (as_zmk_keycode_state_changed(eh) != NULL) { + return keycode_state_changed_listener(eh); + } + return ZMK_EV_EVENT_BUBBLE; +} + +ZMK_LISTENER(combo, behavior_combo_listener); ZMK_SUBSCRIPTION(combo, zmk_position_state_changed); +ZMK_SUBSCRIPTION(combo, zmk_keycode_state_changed); #define COMBO_INST(n) \ static struct combo_cfg combo_config_##n = { \ .timeout_ms = DT_PROP(n, timeout_ms), \ + .require_prior_idle_ms = DT_PROP(n, require_prior_idle_ms), \ .key_positions = DT_PROP(n, key_positions), \ .key_position_len = DT_PROP_LEN(n, key_positions), \ .behavior = ZMK_KEYMAP_EXTRACT_BINDING(0, n), \ diff --git a/app/src/display/Kconfig b/app/src/display/Kconfig index 63ba968b445..a2029481080 100644 --- a/app/src/display/Kconfig +++ b/app/src/display/Kconfig @@ -7,7 +7,6 @@ menuconfig ZMK_DISPLAY select DISPLAY select LVGL select LV_CONF_MINIMAL - imply LV_USE_THEME_MONO if ZMK_DISPLAY @@ -42,6 +41,11 @@ choice ZMK_DISPLAY_STATUS_SCREEN config ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN bool "Built in status screen" select LV_OBJ_LABEL + imply LV_USE_THEME_MONO + imply ZMK_WIDGET_LAYER_STATUS + imply ZMK_WIDGET_BATTERY_STATUS + imply ZMK_WIDGET_OUTPUT_STATUS + imply ZMK_WIDGET_PERIPHERAL_STATUS config ZMK_DISPLAY_STATUS_SCREEN_CUSTOM bool "Custom status screen" diff --git a/app/src/display/widgets/Kconfig b/app/src/display/widgets/Kconfig index 4c056cf5e00..7ec20c1fe4d 100644 --- a/app/src/display/widgets/Kconfig +++ b/app/src/display/widgets/Kconfig @@ -5,14 +5,12 @@ menu "ZMK Display Widgets" config ZMK_WIDGET_LAYER_STATUS bool "Widget for highest, active layer using small icons" - default y depends on !ZMK_SPLIT || ZMK_SPLIT_ROLE_CENTRAL select LV_USE_LABEL config ZMK_WIDGET_BATTERY_STATUS bool "Widget for battery charge information, using small icons" depends on BT - default y if BT select LV_USE_LABEL if ZMK_WIDGET_BATTERY_STATUS @@ -25,13 +23,11 @@ endif config ZMK_WIDGET_OUTPUT_STATUS bool "Widget for keyboard output status icons" depends on BT && (!ZMK_SPLIT_BLE || ZMK_SPLIT_ROLE_CENTRAL) - default y if BT && (!ZMK_SPLIT_BLE || ZMK_SPLIT_ROLE_CENTRAL) select LV_USE_LABEL config ZMK_WIDGET_PERIPHERAL_STATUS bool "Widget for split peripheral status icons" depends on BT && ZMK_SPLIT_BLE && !ZMK_SPLIT_ROLE_CENTRAL - default y if BT && ZMK_SPLIT_BLE && !ZMK_SPLIT_ROLE_CENTRAL select LV_USE_LABEL config ZMK_WIDGET_WPM_STATUS diff --git a/app/src/display/widgets/output_status.c b/app/src/display/widgets/output_status.c index 1c6da4b9034..da29a95f393 100644 --- a/app/src/display/widgets/output_status.c +++ b/app/src/display/widgets/output_status.c @@ -12,9 +12,8 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include #include -#include #include -#include +#include #include #include #include @@ -22,40 +21,38 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); struct output_status_state { - enum zmk_endpoint selected_endpoint; + struct zmk_endpoint_instance selected_endpoint; bool active_profile_connected; bool active_profile_bonded; - uint8_t active_profile_index; }; static struct output_status_state get_state(const zmk_event_t *_eh) { return (struct output_status_state){.selected_endpoint = zmk_endpoints_selected(), .active_profile_connected = zmk_ble_active_profile_is_connected(), - .active_profile_bonded = !zmk_ble_active_profile_is_open(), - .active_profile_index = zmk_ble_active_profile_index()}; + .active_profile_bonded = !zmk_ble_active_profile_is_open()}; ; } static void set_status_symbol(lv_obj_t *label, struct output_status_state state) { char text[10] = {}; - switch (state.selected_endpoint) { - case ZMK_ENDPOINT_USB: + switch (state.selected_endpoint.transport) { + case ZMK_TRANSPORT_USB: strcat(text, LV_SYMBOL_USB); break; - case ZMK_ENDPOINT_BLE: + case ZMK_TRANSPORT_BLE: if (state.active_profile_bonded) { if (state.active_profile_connected) { snprintf(text, sizeof(text), LV_SYMBOL_WIFI " %i " LV_SYMBOL_OK, - state.active_profile_index + 1); + state.selected_endpoint.ble.profile_index + 1); } else { snprintf(text, sizeof(text), LV_SYMBOL_WIFI " %i " LV_SYMBOL_CLOSE, - state.active_profile_index + 1); + state.selected_endpoint.ble.profile_index + 1); } } else { snprintf(text, sizeof(text), LV_SYMBOL_WIFI " %i " LV_SYMBOL_SETTINGS, - state.active_profile_index + 1); + state.selected_endpoint.ble.profile_index + 1); } break; } @@ -70,11 +67,9 @@ static void output_status_update_cb(struct output_status_state state) { ZMK_DISPLAY_WIDGET_LISTENER(widget_output_status, struct output_status_state, output_status_update_cb, get_state) -ZMK_SUBSCRIPTION(widget_output_status, zmk_endpoint_selection_changed); - -#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) -ZMK_SUBSCRIPTION(widget_output_status, zmk_usb_conn_state_changed); -#endif +ZMK_SUBSCRIPTION(widget_output_status, zmk_endpoint_changed); +// We don't get an endpoint changed event when the active profile connects/disconnects +// but there wasn't another endpoint to switch from/to, so update on BLE events too. #if defined(CONFIG_ZMK_BLE) ZMK_SUBSCRIPTION(widget_output_status, zmk_ble_active_profile_changed); #endif diff --git a/app/src/endpoints.c b/app/src/endpoints.c index dbd1a3e6c0e..138e790fe72 100644 --- a/app/src/endpoints.c +++ b/app/src/endpoints.c @@ -7,6 +7,8 @@ #include #include +#include + #include #include #include @@ -16,29 +18,29 @@ #include #include #include -#include +#include #include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); -#define DEFAULT_ENDPOINT \ - COND_CODE_1(IS_ENABLED(CONFIG_ZMK_BLE), (ZMK_ENDPOINT_BLE), (ZMK_ENDPOINT_USB)) +#define DEFAULT_TRANSPORT \ + COND_CODE_1(IS_ENABLED(CONFIG_ZMK_BLE), (ZMK_TRANSPORT_BLE), (ZMK_TRANSPORT_USB)) -static enum zmk_endpoint current_endpoint = DEFAULT_ENDPOINT; -static enum zmk_endpoint preferred_endpoint = - ZMK_ENDPOINT_USB; /* Used if multiple endpoints are ready */ +static struct zmk_endpoint_instance current_instance = {}; +static enum zmk_transport preferred_transport = + ZMK_TRANSPORT_USB; /* Used if multiple endpoints are ready */ -static void update_current_endpoint(); +static void update_current_endpoint(void); #if IS_ENABLED(CONFIG_SETTINGS) static void endpoints_save_preferred_work(struct k_work *work) { - settings_save_one("endpoints/preferred", &preferred_endpoint, sizeof(preferred_endpoint)); + settings_save_one("endpoints/preferred", &preferred_transport, sizeof(preferred_transport)); } static struct k_work_delayable endpoints_save_work; #endif -static int endpoints_save_preferred() { +static int endpoints_save_preferred(void) { #if IS_ENABLED(CONFIG_SETTINGS) return k_work_reschedule(&endpoints_save_work, K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE)); #else @@ -46,14 +48,60 @@ static int endpoints_save_preferred() { #endif } -int zmk_endpoints_select(enum zmk_endpoint endpoint) { - LOG_DBG("Selected endpoint %d", endpoint); +bool zmk_endpoint_instance_eq(struct zmk_endpoint_instance a, struct zmk_endpoint_instance b) { + if (a.transport != b.transport) { + return false; + } + + switch (a.transport) { + case ZMK_TRANSPORT_USB: + return true; + + case ZMK_TRANSPORT_BLE: + return a.ble.profile_index == b.ble.profile_index; + } + + LOG_ERR("Invalid transport %d", a.transport); + return false; +} + +int zmk_endpoint_instance_to_str(struct zmk_endpoint_instance endpoint, char *str, size_t len) { + switch (endpoint.transport) { + case ZMK_TRANSPORT_USB: + return snprintf(str, len, "USB"); + + case ZMK_TRANSPORT_BLE: + return snprintf(str, len, "BLE:%d", endpoint.ble.profile_index); + + default: + return snprintf(str, len, "Invalid"); + } +} + +#define INSTANCE_INDEX_OFFSET_USB 0 +#define INSTANCE_INDEX_OFFSET_BLE ZMK_ENDPOINT_USB_COUNT - if (preferred_endpoint == endpoint) { +int zmk_endpoint_instance_to_index(struct zmk_endpoint_instance endpoint) { + switch (endpoint.transport) { + case ZMK_TRANSPORT_USB: + return INSTANCE_INDEX_OFFSET_USB; + + case ZMK_TRANSPORT_BLE: + return INSTANCE_INDEX_OFFSET_BLE + endpoint.ble.profile_index; + } + + LOG_ERR("Invalid transport %d", endpoint.transport); + return 0; +} + +int zmk_endpoints_select_transport(enum zmk_transport transport) { + LOG_DBG("Selected endpoint transport %d", transport); + + if (preferred_transport == transport) { return 0; } - preferred_endpoint = endpoint; + preferred_transport = transport; endpoints_save_preferred(); @@ -62,20 +110,22 @@ int zmk_endpoints_select(enum zmk_endpoint endpoint) { return 0; } -enum zmk_endpoint zmk_endpoints_selected() { return current_endpoint; } +int zmk_endpoints_toggle_transport(void) { + enum zmk_transport new_transport = + (preferred_transport == ZMK_TRANSPORT_USB) ? ZMK_TRANSPORT_BLE : ZMK_TRANSPORT_USB; + return zmk_endpoints_select_transport(new_transport); +} -int zmk_endpoints_toggle() { - enum zmk_endpoint new_endpoint = - (preferred_endpoint == ZMK_ENDPOINT_USB) ? ZMK_ENDPOINT_BLE : ZMK_ENDPOINT_USB; - return zmk_endpoints_select(new_endpoint); +struct zmk_endpoint_instance zmk_endpoints_selected(void) { + return current_instance; } -static int send_keyboard_report() { +static int send_keyboard_report(void) { struct zmk_hid_keyboard_report *keyboard_report = zmk_hid_get_keyboard_report(); - switch (current_endpoint) { + switch (current_instance.transport) { #if IS_ENABLED(CONFIG_ZMK_USB) - case ZMK_ENDPOINT_USB: { + case ZMK_TRANSPORT_USB: { int err = zmk_usb_hid_send_report((uint8_t *)keyboard_report, sizeof(*keyboard_report)); if (err) { LOG_ERR("FAILED TO SEND OVER USB: %d", err); @@ -85,7 +135,7 @@ static int send_keyboard_report() { #endif /* IS_ENABLED(CONFIG_ZMK_USB) */ #if IS_ENABLED(CONFIG_ZMK_BLE) - case ZMK_ENDPOINT_BLE: { + case ZMK_TRANSPORT_BLE: { int err = zmk_hog_send_keyboard_report(&keyboard_report->body); if (err) { LOG_ERR("FAILED TO SEND OVER HOG: %d", err); @@ -93,19 +143,18 @@ static int send_keyboard_report() { return err; } #endif /* IS_ENABLED(CONFIG_ZMK_BLE) */ - - default: - LOG_ERR("Unsupported endpoint %d", current_endpoint); - return -ENOTSUP; } + + LOG_ERR("Unsupported endpoint transport %d", current_instance.transport); + return -ENOTSUP; } -static int send_consumer_report() { +static int send_consumer_report(void) { struct zmk_hid_consumer_report *consumer_report = zmk_hid_get_consumer_report(); - switch (current_endpoint) { + switch (current_instance.transport) { #if IS_ENABLED(CONFIG_ZMK_USB) - case ZMK_ENDPOINT_USB: { + case ZMK_TRANSPORT_USB: { int err = zmk_usb_hid_send_report((uint8_t *)consumer_report, sizeof(*consumer_report)); if (err) { LOG_ERR("FAILED TO SEND OVER USB: %d", err); @@ -115,7 +164,7 @@ static int send_consumer_report() { #endif /* IS_ENABLED(CONFIG_ZMK_USB) */ #if IS_ENABLED(CONFIG_ZMK_BLE) - case ZMK_ENDPOINT_BLE: { + case ZMK_TRANSPORT_BLE: { int err = zmk_hog_send_consumer_report(&consumer_report->body); if (err) { LOG_ERR("FAILED TO SEND OVER HOG: %d", err); @@ -123,11 +172,10 @@ static int send_consumer_report() { return err; } #endif /* IS_ENABLED(CONFIG_ZMK_BLE) */ - - default: - LOG_ERR("Unsupported endpoint %d", current_endpoint); - return -ENOTSUP; } + + LOG_ERR("Unsupported endpoint transport %d", current_instance.transport); + return -ENOTSUP; } int zmk_endpoints_send_report(uint16_t usage_page) { @@ -136,12 +184,13 @@ int zmk_endpoints_send_report(uint16_t usage_page) { switch (usage_page) { case HID_USAGE_KEY: return send_keyboard_report(); + case HID_USAGE_CONSUMER: return send_consumer_report(); - default: - LOG_ERR("Unsupported usage page %d", usage_page); - return -ENOTSUP; } + + LOG_ERR("Unsupported usage page %d", usage_page); + return -ENOTSUP; } #if IS_ENABLED(CONFIG_SETTINGS) @@ -151,12 +200,12 @@ static int endpoints_handle_set(const char *name, size_t len, settings_read_cb r LOG_DBG("Setting endpoint value %s", name); if (settings_name_steq(name, "preferred", NULL)) { - if (len != sizeof(enum zmk_endpoint)) { - LOG_ERR("Invalid endpoint size (got %d expected %d)", len, sizeof(enum zmk_endpoint)); + if (len != sizeof(enum zmk_transport)) { + LOG_ERR("Invalid endpoint size (got %d expected %d)", len, sizeof(enum zmk_transport)); return -EINVAL; } - int err = read_cb(cb_arg, &preferred_endpoint, sizeof(enum zmk_endpoint)); + int err = read_cb(cb_arg, &preferred_transport, sizeof(enum zmk_transport)); if (err <= 0) { LOG_ERR("Failed to read preferred endpoint from settings (err %d)", err); return err; @@ -171,25 +220,7 @@ static int endpoints_handle_set(const char *name, size_t len, settings_read_cb r struct settings_handler endpoints_handler = {.name = "endpoints", .h_set = endpoints_handle_set}; #endif /* IS_ENABLED(CONFIG_SETTINGS) */ -static int zmk_endpoints_init(const struct device *_arg) { -#if IS_ENABLED(CONFIG_SETTINGS) - settings_subsys_init(); - - int err = settings_register(&endpoints_handler); - if (err) { - LOG_ERR("Failed to register the endpoints settings handler (err %d)", err); - return err; - } - - k_work_init_delayable(&endpoints_save_work, endpoints_save_preferred_work); - - settings_load_subtree("endpoints"); -#endif - - return 0; -} - -static bool is_usb_ready() { +static bool is_usb_ready(void) { #if IS_ENABLED(CONFIG_ZMK_USB) return zmk_usb_is_hid_ready(); #else @@ -197,7 +228,7 @@ static bool is_usb_ready() { #endif } -static bool is_ble_ready() { +static bool is_ble_ready(void) { #if IS_ENABLED(CONFIG_ZMK_BLE) return zmk_ble_active_profile_is_connected(); #else @@ -205,24 +236,62 @@ static bool is_ble_ready() { #endif } -static enum zmk_endpoint get_selected_endpoint() { +static enum zmk_transport get_selected_transport(void) { if (is_ble_ready()) { if (is_usb_ready()) { - LOG_DBG("Both endpoints are ready. Using %d", preferred_endpoint); - return preferred_endpoint; + LOG_DBG("Both endpoint transports are ready. Using %d", preferred_transport); + return preferred_transport; } LOG_DBG("Only BLE is ready."); - return ZMK_ENDPOINT_BLE; + return ZMK_TRANSPORT_BLE; } if (is_usb_ready()) { LOG_DBG("Only USB is ready."); - return ZMK_ENDPOINT_USB; + return ZMK_TRANSPORT_USB; + } + + LOG_DBG("No endpoint transports are ready."); + return DEFAULT_TRANSPORT; +} + +static struct zmk_endpoint_instance get_selected_instance(void) { + struct zmk_endpoint_instance instance = {.transport = get_selected_transport()}; + + switch (instance.transport) { +#if IS_ENABLED(CONFIG_ZMK_BLE) + case ZMK_TRANSPORT_BLE: + instance.ble.profile_index = zmk_ble_active_profile_index(); + break; +#endif // IS_ENABLED(CONFIG_ZMK_BLE) + + default: + // No extra data for this transport. + break; } - LOG_DBG("No endpoints are ready."); - return DEFAULT_ENDPOINT; + return instance; +} + +static int zmk_endpoints_init(const struct device *_arg) { +#if IS_ENABLED(CONFIG_SETTINGS) + settings_subsys_init(); + + int err = settings_register(&endpoints_handler); + if (err) { + LOG_ERR("Failed to register the endpoints settings handler (err %d)", err); + return err; + } + + k_work_init_delayable(&endpoints_save_work, endpoints_save_preferred_work); + + settings_load_subtree("endpoints"); +#endif + + current_instance = get_selected_instance(); + + return 0; } static void disconnect_current_endpoint() { @@ -233,18 +302,21 @@ static void disconnect_current_endpoint() { zmk_endpoints_send_report(HID_USAGE_CONSUMER); } -static void update_current_endpoint() { - enum zmk_endpoint new_endpoint = get_selected_endpoint(); +static void update_current_endpoint(void) { + struct zmk_endpoint_instance new_instance = get_selected_instance(); - if (new_endpoint != current_endpoint) { - /* Cancel all current keypresses so keys don't stay held on the old endpoint. */ + if (!zmk_endpoint_instance_eq(new_instance, current_instance)) { + // Cancel all current keypresses so keys don't stay held on the old endpoint. disconnect_current_endpoint(); - current_endpoint = new_endpoint; - LOG_INF("Endpoint changed: %d", current_endpoint); + current_instance = new_instance; + + char endpoint_str[ZMK_ENDPOINT_STR_LEN]; + zmk_endpoint_instance_to_str(current_instance, endpoint_str, sizeof(endpoint_str)); + LOG_INF("Endpoint changed: %s", endpoint_str); - ZMK_EVENT_RAISE(new_zmk_endpoint_selection_changed( - (struct zmk_endpoint_selection_changed){.endpoint = current_endpoint})); + ZMK_EVENT_RAISE( + new_zmk_endpoint_changed((struct zmk_endpoint_changed){.endpoint = current_instance})); } } diff --git a/app/src/events/endpoint_selection_changed.c b/app/src/events/endpoint_changed.c similarity index 53% rename from app/src/events/endpoint_selection_changed.c rename to app/src/events/endpoint_changed.c index 34bc39dd2ab..6b152156feb 100644 --- a/app/src/events/endpoint_selection_changed.c +++ b/app/src/events/endpoint_changed.c @@ -5,6 +5,6 @@ */ #include -#include +#include -ZMK_EVENT_IMPL(zmk_endpoint_selection_changed); +ZMK_EVENT_IMPL(zmk_endpoint_changed); diff --git a/app/src/hid_listener.c b/app/src/hid_listener.c index 3a11101d54f..2b8470820a1 100644 --- a/app/src/hid_listener.c +++ b/app/src/hid_listener.c @@ -19,6 +19,21 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); static int hid_listener_keycode_pressed(const struct zmk_keycode_state_changed *ev) { int err, explicit_mods_changed, implicit_mods_changed; + if (!is_mod(ev->usage_page, ev->keycode) && + zmk_hid_is_pressed(ZMK_HID_USAGE(ev->usage_page, ev->keycode))) { + LOG_DBG("unregistering usage_page 0x%02X keycode 0x%02X since it was already pressed", + ev->usage_page, ev->keycode); + err = zmk_hid_release(ZMK_HID_USAGE(ev->usage_page, ev->keycode)); + if (err < 0) { + LOG_DBG("Unable to pre-release keycode (%d)", err); + return err; + } + err = zmk_endpoints_send_report(ev->usage_page); + if (err < 0) { + LOG_ERR("Failed to send key report for pre-releasing keycode (%d)", err); + } + } + LOG_DBG("usage_page 0x%02X keycode 0x%02X implicit_mods 0x%02X explicit_mods 0x%02X", ev->usage_page, ev->keycode, ev->implicit_modifiers, ev->explicit_modifiers); err = zmk_hid_press(ZMK_HID_USAGE(ev->usage_page, ev->keycode)); diff --git a/app/src/keymap.c b/app/src/keymap.c index 020faf3f2be..bda694276c8 100644 --- a/app/src/keymap.c +++ b/app/src/keymap.c @@ -31,10 +31,6 @@ static uint8_t _zmk_keymap_layer_default = 0; #define DT_DRV_COMPAT zmk_keymap -#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 BINDING_WITH_COMMA(idx, drv_inst) ZMK_KEYMAP_EXTRACT_BINDING(idx, drv_inst) #define TRANSFORMED_LAYER(node) \ diff --git a/app/src/rgb_underglow.c b/app/src/rgb_underglow.c index 7b6491749e2..b80d403953f 100644 --- a/app/src/rgb_underglow.c +++ b/app/src/rgb_underglow.c @@ -24,6 +24,7 @@ #include #include #include +#include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); @@ -196,14 +197,14 @@ static void zmk_rgb_underglow_tick(struct k_work *work) { } } -K_WORK_DEFINE(underglow_work, zmk_rgb_underglow_tick); +K_WORK_DEFINE(underglow_tick_work, zmk_rgb_underglow_tick); static void zmk_rgb_underglow_tick_handler(struct k_timer *timer) { if (!state.on) { return; } - k_work_submit(&underglow_work); + k_work_submit_to_queue(zmk_workqueue_lowprio_work_q(), &underglow_tick_work); } K_TIMER_DEFINE(underglow_tick, zmk_rgb_underglow_tick_handler, NULL); @@ -322,6 +323,16 @@ int zmk_rgb_underglow_on() { return zmk_rgb_underglow_save_state(); } +static void zmk_rgb_underglow_off_handler(struct k_work *work) { + for (int i = 0; i < STRIP_NUM_PIXELS; i++) { + pixels[i] = (struct led_rgb){r : 0, g : 0, b : 0}; + } + + led_strip_update_rgb(led_strip, pixels, STRIP_NUM_PIXELS); +} + +K_WORK_DEFINE(underglow_off_work, zmk_rgb_underglow_off_handler); + int zmk_rgb_underglow_off() { if (!led_strip) return -ENODEV; @@ -335,11 +346,7 @@ int zmk_rgb_underglow_off() { } #endif - for (int i = 0; i < STRIP_NUM_PIXELS; i++) { - pixels[i] = (struct led_rgb){r : 0, g : 0, b : 0}; - } - - led_strip_update_rgb(led_strip, pixels, STRIP_NUM_PIXELS); + k_work_submit_to_queue(zmk_workqueue_lowprio_work_q(), &underglow_off_work); k_timer_stop(&underglow_tick); state.on = false; diff --git a/app/src/sensors.c b/app/src/sensors.c index e339afe0437..60f2bd2a33f 100644 --- a/app/src/sensors.c +++ b/app/src/sensors.c @@ -29,7 +29,7 @@ struct sensors_item_cfg { { \ .dev = DEVICE_DT_GET_OR_NULL(node), \ .trigger = {.type = SENSOR_TRIG_DATA_READY, .chan = SENSOR_CHAN_ROTATION}, \ - .config = &configs[idx] \ + .config = &configs[idx], .sensor_index = idx \ } #define SENSOR_ITEM(idx, _i) _SENSOR_ITEM(idx, ZMK_KEYMAP_SENSORS_BY_IDX(idx)) @@ -112,7 +112,7 @@ static void zmk_sensors_trigger_handler(const struct device *dev, int sensor_index = test_item - sensors; if (sensor_index < 0 || sensor_index >= ARRAY_SIZE(sensors)) { - LOG_ERR("Invalid sensor item triggered our callback"); + LOG_ERR("Invalid sensor item triggered our callback (%d)", sensor_index); return; } @@ -127,8 +127,6 @@ static void zmk_sensors_trigger_handler(const struct device *dev, static void zmk_sensors_init_item(uint8_t i) { LOG_DBG("Init sensor at index %d", i); - sensors[i].sensor_index = i; - if (!sensors[i].dev) { LOG_DBG("No local device for %d", i); return; diff --git a/app/src/split/bluetooth/Kconfig b/app/src/split/bluetooth/Kconfig index 0610b667a26..5919010ba31 100644 --- a/app/src/split/bluetooth/Kconfig +++ b/app/src/split/bluetooth/Kconfig @@ -14,6 +14,7 @@ config ZMK_SPLIT_ROLE_CENTRAL select BT_CENTRAL select BT_GATT_CLIENT select BT_GATT_AUTO_DISCOVER_CCC + select BT_SCAN_WITH_IDENTITY if ZMK_SPLIT_ROLE_CENTRAL diff --git a/app/src/split/bluetooth/central.c b/app/src/split/bluetooth/central.c index 147760ffae7..860e89a5f3e 100644 --- a/app/src/split/bluetooth/central.c +++ b/app/src/split/bluetooth/central.c @@ -21,10 +21,12 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include #include +#include #include #include #include #include +#include static int start_scanning(void); @@ -41,6 +43,7 @@ struct peripheral_slot { struct bt_conn *conn; struct bt_gatt_discover_params discover_params; struct bt_gatt_subscribe_params subscribe_params; + struct bt_gatt_subscribe_params sensor_subscribe_params; struct bt_gatt_discover_params sub_discover_params; uint16_t run_behavior_handle; uint8_t position_state[POSITION_STATE_DATA_LEN]; @@ -165,6 +168,52 @@ int confirm_peripheral_slot_conn(struct bt_conn *conn) { return 0; } +#if ZMK_KEYMAP_HAS_SENSORS +K_MSGQ_DEFINE(peripheral_sensor_event_msgq, sizeof(struct zmk_sensor_event), + CONFIG_ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE, 4); + +void peripheral_sensor_event_work_callback(struct k_work *work) { + struct zmk_sensor_event ev; + while (k_msgq_get(&peripheral_sensor_event_msgq, &ev, K_NO_WAIT) == 0) { + LOG_DBG("Trigger sensor change for %d", ev.sensor_index); + ZMK_EVENT_RAISE(new_zmk_sensor_event(ev)); + } +} + +K_WORK_DEFINE(peripheral_sensor_event_work, peripheral_sensor_event_work_callback); + +static uint8_t split_central_sensor_notify_func(struct bt_conn *conn, + struct bt_gatt_subscribe_params *params, + const void *data, uint16_t length) { + if (!data) { + LOG_DBG("[UNSUBSCRIBED]"); + params->value_handle = 0U; + return BT_GATT_ITER_STOP; + } + + LOG_DBG("[SENSOR NOTIFICATION] data %p length %u", data, length); + + if (length < offsetof(struct sensor_event, channel_data)) { + LOG_WRN("Ignoring sensor notify with insufficient data length (%d)", length); + return BT_GATT_ITER_STOP; + } + + struct sensor_event sensor_event; + memcpy(&sensor_event, data, MIN(length, sizeof(sensor_event))); + struct zmk_sensor_event ev = { + .sensor_index = sensor_event.sensor_index, + .channel_data_size = MIN(sensor_event.channel_data_size, ZMK_SENSOR_EVENT_MAX_CHANNELS), + .timestamp = k_uptime_get()}; + + memcpy(ev.channel_data, sensor_event.channel_data, + sizeof(struct zmk_sensor_channel_data) * sensor_event.channel_data_size); + k_msgq_put(&peripheral_sensor_event_msgq, &ev, K_NO_WAIT); + k_work_submit(&peripheral_sensor_event_work); + + return BT_GATT_ITER_CONTINUE; +} +#endif /* ZMK_KEYMAP_HAS_SENSORS */ + static uint8_t split_central_notify_func(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t length) { @@ -209,14 +258,8 @@ static uint8_t split_central_notify_func(struct bt_conn *conn, return BT_GATT_ITER_CONTINUE; } -static void split_central_subscribe(struct bt_conn *conn) { - struct peripheral_slot *slot = peripheral_slot_for_conn(conn); - if (slot == NULL) { - LOG_ERR("No peripheral state found for connection"); - return; - } - - int err = bt_gatt_subscribe(conn, &slot->subscribe_params); +static int split_central_subscribe(struct bt_conn *conn, struct bt_gatt_subscribe_params *params) { + int err = bt_gatt_subscribe(conn, params); switch (err) { case -EALREADY: LOG_DBG("[ALREADY SUBSCRIBED]"); @@ -228,6 +271,8 @@ static void split_central_subscribe(struct bt_conn *conn) { LOG_ERR("Subscribe failed (err %d)", err); break; } + + return err; } static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn, @@ -250,9 +295,9 @@ static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn, } LOG_DBG("[ATTRIBUTE] handle %u", attr->handle); + const struct bt_uuid *chrc_uuid = ((struct bt_gatt_chrc *)attr->user_data)->uuid; - if (!bt_uuid_cmp(((struct bt_gatt_chrc *)attr->user_data)->uuid, - BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID))) { + if (bt_uuid_cmp(chrc_uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID)) == 0) { LOG_DBG("Found position state characteristic"); slot->discover_params.uuid = NULL; slot->discover_params.start_handle = attr->handle + 2; @@ -263,14 +308,33 @@ static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn, slot->subscribe_params.value_handle = bt_gatt_attr_value_handle(attr); slot->subscribe_params.notify = split_central_notify_func; slot->subscribe_params.value = BT_GATT_CCC_NOTIFY; - split_central_subscribe(conn); - } else if (!bt_uuid_cmp(((struct bt_gatt_chrc *)attr->user_data)->uuid, - BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID))) { + split_central_subscribe(conn, &slot->subscribe_params); +#if ZMK_KEYMAP_HAS_SENSORS + } else if (bt_uuid_cmp(chrc_uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_SENSOR_STATE_UUID)) == + 0) { + slot->discover_params.uuid = NULL; + slot->discover_params.start_handle = attr->handle + 2; + slot->discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; + + slot->sensor_subscribe_params.disc_params = &slot->sub_discover_params; + slot->sensor_subscribe_params.end_handle = slot->discover_params.end_handle; + slot->sensor_subscribe_params.value_handle = bt_gatt_attr_value_handle(attr); + slot->sensor_subscribe_params.notify = split_central_sensor_notify_func; + slot->sensor_subscribe_params.value = BT_GATT_CCC_NOTIFY; + split_central_subscribe(conn, &slot->sensor_subscribe_params); +#endif /* ZMK_KEYMAP_HAS_SENSORS */ + } else if (bt_uuid_cmp(chrc_uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID)) == + 0) { LOG_DBG("Found run behavior handle"); + slot->discover_params.uuid = NULL; + slot->discover_params.start_handle = attr->handle + 2; slot->run_behavior_handle = bt_gatt_attr_value_handle(attr); } - bool subscribed = (slot->run_behavior_handle && slot->subscribe_params.value_handle); + bool subscribed = slot->run_behavior_handle && slot->subscribe_params.value_handle; +#if ZMK_KEYMAP_HAS_SENSORS + subscribed = subscribed && slot->sensor_subscribe_params.value_handle; +#endif /* ZMK_KEYMAP_HAS_SENSORS */ return subscribed ? BT_GATT_ITER_STOP : BT_GATT_ITER_CONTINUE; } @@ -292,7 +356,8 @@ static uint8_t split_central_service_discovery_func(struct bt_conn *conn, return BT_GATT_ITER_STOP; } - if (bt_uuid_cmp(slot->discover_params.uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_SERVICE_UUID))) { + if (bt_uuid_cmp(slot->discover_params.uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_SERVICE_UUID)) != + 0) { LOG_DBG("Found other service"); return BT_GATT_ITER_CONTINUE; } @@ -368,20 +433,22 @@ static int stop_scanning() { static bool split_central_eir_found(const bt_addr_le_t *addr) { LOG_DBG("Found the split service"); - // Stop scanning so we can connect to the peripheral device. - int err = stop_scanning(); - if (err < 0) { - return false; - } - + // Reserve peripheral slot. Once the central has bonded to its peripherals, + // the peripheral MAC addresses will be validated internally and the slot + // reservation will fail if there is a mismatch. int slot_idx = reserve_peripheral_slot(addr); if (slot_idx < 0) { - LOG_ERR("Failed to reserve peripheral slot (err %d)", slot_idx); + LOG_INF("Unable to reserve peripheral slot (err %d)", slot_idx); return false; } - struct peripheral_slot *slot = &peripherals[slot_idx]; + // Stop scanning so we can connect to the peripheral device. + int err = stop_scanning(); + if (err < 0) { + return false; + } + LOG_DBG("Initiating new connnection"); struct bt_le_conn_param *param = BT_LE_CONN_PARAM(CONFIG_ZMK_SPLIT_BLE_PREF_INT, CONFIG_ZMK_SPLIT_BLE_PREF_INT, @@ -418,7 +485,7 @@ static bool split_central_eir_parse(struct bt_data *data, void *user_data) { continue; } - if (bt_uuid_cmp(&uuid.uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_SERVICE_UUID))) { + if (bt_uuid_cmp(&uuid.uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_SERVICE_UUID)) != 0) { char uuid_str[BT_UUID_STR_LEN]; char service_uuid_str[BT_UUID_STR_LEN]; @@ -444,8 +511,10 @@ static void split_central_device_found(const bt_addr_le_t *addr, int8_t rssi, ui LOG_DBG("[DEVICE]: %s, AD evt type %u, AD data len %u, RSSI %i", dev, type, ad->len, rssi); /* We're only interested in connectable events */ - if (type == BT_GAP_ADV_TYPE_ADV_IND || type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND) { + if (type == BT_GAP_ADV_TYPE_ADV_IND) { bt_data_parse(ad, split_central_eir_parse, (void *)addr); + } else if (type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND) { + split_central_eir_found(addr); } } @@ -622,7 +691,7 @@ int zmk_split_bt_central_init(const struct device *_arg) { CONFIG_ZMK_BLE_THREAD_PRIORITY, NULL); bt_conn_cb_register(&conn_callbacks); - return start_scanning(); + return IS_ENABLED(CONFIG_ZMK_BLE_CLEAR_BONDS_ON_START) ? 0 : start_scanning(); } SYS_INIT(zmk_split_bt_central_init, APPLICATION, CONFIG_ZMK_BLE_INIT_PRIORITY); diff --git a/app/src/split/bluetooth/peripheral.c b/app/src/split/bluetooth/peripheral.c index 6b767baa7c1..1d649f71221 100644 --- a/app/src/split/bluetooth/peripheral.c +++ b/app/src/split/bluetooth/peripheral.c @@ -43,15 +43,49 @@ static const struct bt_data zmk_ble_ad[] = { static bool is_connected = false; -static int start_advertising() { - return bt_le_adv_start(BT_LE_ADV_CONN, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0); +static void each_bond(const struct bt_bond_info *info, void *user_data) { + bt_addr_le_t *addr = (bt_addr_le_t *)user_data; + + if (bt_addr_le_cmp(&info->addr, BT_ADDR_LE_NONE) != 0) { + bt_addr_le_copy(addr, &info->addr); + } +} + +static int start_advertising(bool low_duty) { + bt_addr_le_t central_addr = bt_addr_le_none; + + bt_foreach_bond(BT_ID_DEFAULT, each_bond, ¢ral_addr); + + if (bt_addr_le_cmp(¢ral_addr, BT_ADDR_LE_NONE) != 0) { + struct bt_le_adv_param adv_param = low_duty ? *BT_LE_ADV_CONN_DIR_LOW_DUTY(¢ral_addr) + : *BT_LE_ADV_CONN_DIR(¢ral_addr); + return bt_le_adv_start(&adv_param, NULL, 0, NULL, 0); + } else { + return bt_le_adv_start(BT_LE_ADV_CONN, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0); + } }; +static bool low_duty_advertising = false; + +static void advertising_cb(struct k_work *work) { + const int err = start_advertising(low_duty_advertising); + if (err < 0) { + LOG_ERR("Failed to start advertising (%d)", err); + } +} + +K_WORK_DEFINE(advertising_work, advertising_cb); + static void connected(struct bt_conn *conn, uint8_t err) { is_connected = (err == 0); ZMK_EVENT_RAISE(new_zmk_split_peripheral_status_changed( (struct zmk_split_peripheral_status_changed){.connected = is_connected})); + + if (err == BT_HCI_ERR_ADV_TIMEOUT) { + low_duty_advertising = true; + k_work_submit(&advertising_work); + } } static void disconnected(struct bt_conn *conn, uint8_t reason) { @@ -65,6 +99,9 @@ static void disconnected(struct bt_conn *conn, uint8_t reason) { ZMK_EVENT_RAISE(new_zmk_split_peripheral_status_changed( (struct zmk_split_peripheral_status_changed){.connected = is_connected})); + + low_duty_advertising = false; + k_work_submit(&advertising_work); } static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) { @@ -116,11 +153,12 @@ static int zmk_peripheral_ble_init(const struct device *_arg) { LOG_WRN("Clearing all existing BLE bond information from the keyboard"); bt_unpair(BT_ID_DEFAULT, NULL); -#endif - +#else bt_conn_cb_register(&conn_callbacks); - start_advertising(); + low_duty_advertising = false; + k_work_submit(&advertising_work); +#endif return 0; } diff --git a/app/src/split/bluetooth/service.c b/app/src/split/bluetooth/service.c index f7b0d587b26..620df53e11c 100644 --- a/app/src/split/bluetooth/service.c +++ b/app/src/split/bluetooth/service.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: MIT */ +#include #include #include #include @@ -20,6 +21,22 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include #include +#include +#include + +#if ZMK_KEYMAP_HAS_SENSORS +static struct sensor_event last_sensor_event; + +static ssize_t split_svc_sensor_state(struct bt_conn *conn, const struct bt_gatt_attr *attrs, + void *buf, uint16_t len, uint16_t offset) { + return bt_gatt_attr_read(conn, attrs, buf, len, offset, &last_sensor_event, + sizeof(last_sensor_event)); +} + +static void split_svc_sensor_state_ccc(const struct bt_gatt_attr *attr, uint16_t value) { + LOG_DBG("value %d", value); +} +#endif /* ZMK_KEYMAP_HAS_SENSORS */ #define POS_STATE_LEN 16 @@ -98,7 +115,14 @@ BT_GATT_SERVICE_DEFINE( BT_GATT_CHRC_WRITE_WITHOUT_RESP, BT_GATT_PERM_WRITE_ENCRYPT, NULL, split_svc_run_behavior, &behavior_run_payload), BT_GATT_DESCRIPTOR(BT_UUID_NUM_OF_DIGITALS, BT_GATT_PERM_READ, split_svc_num_of_positions, NULL, - &num_of_positions), ); + &num_of_positions), +#if ZMK_KEYMAP_HAS_SENSORS + BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_SENSOR_STATE_UUID), + BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ_ENCRYPT, + split_svc_sensor_state, NULL, &last_sensor_event), + BT_GATT_CCC(split_svc_sensor_state_ccc, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), +#endif /* ZMK_KEYMAP_HAS_SENSORS */ +); K_THREAD_STACK_DEFINE(service_q_stack, CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_STACK_SIZE); @@ -151,6 +175,58 @@ int zmk_split_bt_position_released(uint8_t position) { return send_position_state(); } +#if ZMK_KEYMAP_HAS_SENSORS +K_MSGQ_DEFINE(sensor_state_msgq, sizeof(struct sensor_event), + CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_POSITION_QUEUE_SIZE, 4); + +void send_sensor_state_callback(struct k_work *work) { + while (k_msgq_get(&sensor_state_msgq, &last_sensor_event, K_NO_WAIT) == 0) { + int err = bt_gatt_notify(NULL, &split_svc.attrs[8], &last_sensor_event, + sizeof(last_sensor_event)); + if (err) { + LOG_DBG("Error notifying %d", err); + } + } +}; + +K_WORK_DEFINE(service_sensor_notify_work, send_sensor_state_callback); + +int send_sensor_state(struct sensor_event ev) { + int err = k_msgq_put(&sensor_state_msgq, &ev, K_MSEC(100)); + if (err) { + // retry... + switch (err) { + case -EAGAIN: { + LOG_WRN("Sensor state message queue full, popping first message and queueing again"); + struct sensor_event discarded_state; + k_msgq_get(&sensor_state_msgq, &discarded_state, K_NO_WAIT); + return send_sensor_state(ev); + } + default: + LOG_WRN("Failed to queue sensor state to send (%d)", err); + return err; + } + } + + k_work_submit_to_queue(&service_work_q, &service_sensor_notify_work); + return 0; +} + +int zmk_split_bt_sensor_triggered(uint8_t sensor_index, + const struct zmk_sensor_channel_data channel_data[], + size_t channel_data_size) { + if (channel_data_size > ZMK_SENSOR_EVENT_MAX_CHANNELS) { + return -EINVAL; + } + + struct sensor_event ev = + (struct sensor_event){.sensor_index = sensor_index, .channel_data_size = channel_data_size}; + memcpy(ev.channel_data, channel_data, + channel_data_size * sizeof(struct zmk_sensor_channel_data)); + return send_sensor_state(ev); +} +#endif /* ZMK_KEYMAP_HAS_SENSORS */ + int service_init(const struct device *_arg) { static const struct k_work_queue_config queue_config = { .name = "Split Peripheral Notification Queue"}; diff --git a/app/src/split/bluetooth/split_listener.c b/app/src/split/bluetooth/split_listener.c index eb5398c42d6..9b680d2c89c 100644 --- a/app/src/split/bluetooth/split_listener.c +++ b/app/src/split/bluetooth/split_listener.c @@ -13,21 +13,35 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include +#include #include +#include #include int split_listener(const zmk_event_t *eh) { LOG_DBG(""); - const struct zmk_position_state_changed *ev = as_zmk_position_state_changed(eh); - if (ev != NULL) { - if (ev->state) { - return zmk_split_bt_position_pressed(ev->position); + const struct zmk_position_state_changed *pos_ev; + if ((pos_ev = as_zmk_position_state_changed(eh)) != NULL) { + if (pos_ev->state) { + return zmk_split_bt_position_pressed(pos_ev->position); } else { - return zmk_split_bt_position_released(ev->position); + return zmk_split_bt_position_released(pos_ev->position); } } + +#if ZMK_KEYMAP_HAS_SENSORS + const struct zmk_sensor_event *sensor_ev; + if ((sensor_ev = as_zmk_sensor_event(eh)) != NULL) { + return zmk_split_bt_sensor_triggered(sensor_ev->sensor_index, sensor_ev->channel_data, + sensor_ev->channel_data_size); + } +#endif /* ZMK_KEYMAP_HAS_SENSORS */ return ZMK_EV_EVENT_BUBBLE; } ZMK_LISTENER(split_listener, split_listener); -ZMK_SUBSCRIPTION(split_listener, zmk_position_state_changed); \ No newline at end of file +ZMK_SUBSCRIPTION(split_listener, zmk_position_state_changed); + +#if ZMK_KEYMAP_HAS_SENSORS +ZMK_SUBSCRIPTION(split_listener, zmk_sensor_event); +#endif /* ZMK_KEYMAP_HAS_SENSORS */ diff --git a/app/src/workqueue.c b/app/src/workqueue.c new file mode 100644 index 00000000000..a9a8bce5202 --- /dev/null +++ b/app/src/workqueue.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +#include + +K_THREAD_STACK_DEFINE(lowprio_q_stack, CONFIG_ZMK_LOW_PRIORITY_THREAD_STACK_SIZE); + +static struct k_work_q lowprio_work_q; + +struct k_work_q *zmk_workqueue_lowprio_work_q() { + return &lowprio_work_q; +} + +static int workqueue_init() { + static const struct k_work_queue_config queue_config = {.name = "Low Priority Work Queue"}; + k_work_queue_start(&lowprio_work_q, lowprio_q_stack, K_THREAD_STACK_SIZEOF(lowprio_q_stack), + CONFIG_ZMK_LOW_PRIORITY_THREAD_PRIORITY, &queue_config); + return 0; +} + +SYS_INIT(workqueue_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/app/tests/combo/combos-and-holdtaps-0/native_posix_64.keymap b/app/tests/combo/combos-and-holdtaps-0/native_posix_64.keymap index e6754b71128..3438f9bc77d 100644 --- a/app/tests/combo/combos-and-holdtaps-0/native_posix_64.keymap +++ b/app/tests/combo/combos-and-holdtaps-0/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include &mt { flavor = "hold-preferred"; diff --git a/app/tests/combo/combos-and-holdtaps-1/native_posix_64.keymap b/app/tests/combo/combos-and-holdtaps-1/native_posix_64.keymap index 9538243291c..9120e8c3b4a 100644 --- a/app/tests/combo/combos-and-holdtaps-1/native_posix_64.keymap +++ b/app/tests/combo/combos-and-holdtaps-1/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include &mt { flavor = "hold-preferred"; diff --git a/app/tests/combo/combos-and-holdtaps-2/native_posix_64.keymap b/app/tests/combo/combos-and-holdtaps-2/native_posix_64.keymap index d6d187e2046..a227fe4c91f 100644 --- a/app/tests/combo/combos-and-holdtaps-2/native_posix_64.keymap +++ b/app/tests/combo/combos-and-holdtaps-2/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include &mt { flavor = "hold-preferred"; diff --git a/app/tests/combo/combos-and-holdtaps-3/native_posix_64.keymap b/app/tests/combo/combos-and-holdtaps-3/native_posix_64.keymap index f1c7eee7087..4fbf24071e6 100644 --- a/app/tests/combo/combos-and-holdtaps-3/native_posix_64.keymap +++ b/app/tests/combo/combos-and-holdtaps-3/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include &mt { flavor = "hold-preferred"; diff --git a/app/tests/combo/combos-and-holdtaps-4/native_posix_64.keymap b/app/tests/combo/combos-and-holdtaps-4/native_posix_64.keymap index 134b77dfa34..59f4391f288 100644 --- a/app/tests/combo/combos-and-holdtaps-4/native_posix_64.keymap +++ b/app/tests/combo/combos-and-holdtaps-4/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include #define ZMK_COMBO(name, combo_bindings, keypos, combo_term) \ diff --git a/app/tests/combo/layer-filter-0/native_posix_64.keymap b/app/tests/combo/layer-filter-0/native_posix_64.keymap index 8d94872b658..68077849a34 100644 --- a/app/tests/combo/layer-filter-0/native_posix_64.keymap +++ b/app/tests/combo/layer-filter-0/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include /* it is useful to set timeout to a large value when attaching a debugger. */ #define TIMEOUT (60*60*1000) diff --git a/app/tests/combo/layer-filter-1/native_posix_64.keymap b/app/tests/combo/layer-filter-1/native_posix_64.keymap index 96eccea4ea8..a11b86ad4d9 100644 --- a/app/tests/combo/layer-filter-1/native_posix_64.keymap +++ b/app/tests/combo/layer-filter-1/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include /* it is useful to set timeout to a large value when attaching a debugger. */ #define TIMEOUT (60*60*1000) diff --git a/app/tests/combo/multiple-timeouts/native_posix_64.keymap b/app/tests/combo/multiple-timeouts/native_posix_64.keymap index d2176390403..a2edc32fcc3 100644 --- a/app/tests/combo/multiple-timeouts/native_posix_64.keymap +++ b/app/tests/combo/multiple-timeouts/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include / { combos { diff --git a/app/tests/combo/overlapping-combos-0/native_posix_64.keymap b/app/tests/combo/overlapping-combos-0/native_posix_64.keymap index e82846652d3..e89a3f22d33 100644 --- a/app/tests/combo/overlapping-combos-0/native_posix_64.keymap +++ b/app/tests/combo/overlapping-combos-0/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include /* combo 0 timeout inf diff --git a/app/tests/combo/overlapping-combos-1/native_posix_64.keymap b/app/tests/combo/overlapping-combos-1/native_posix_64.keymap index a695a388c66..4b0166bee15 100644 --- a/app/tests/combo/overlapping-combos-1/native_posix_64.keymap +++ b/app/tests/combo/overlapping-combos-1/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include /* combo 01 timeout 50 diff --git a/app/tests/combo/overlapping-combos-2/native_posix_64.keymap b/app/tests/combo/overlapping-combos-2/native_posix_64.keymap index 6bf0e7100cd..5c38bcfc403 100644 --- a/app/tests/combo/overlapping-combos-2/native_posix_64.keymap +++ b/app/tests/combo/overlapping-combos-2/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include /* combo 01 timeout 100 diff --git a/app/tests/combo/overlapping-combos-3/native_posix_64.keymap b/app/tests/combo/overlapping-combos-3/native_posix_64.keymap index 0a2f5ee137f..48e3397f4a6 100644 --- a/app/tests/combo/overlapping-combos-3/native_posix_64.keymap +++ b/app/tests/combo/overlapping-combos-3/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include /* combo 12 timeout 100 diff --git a/app/tests/combo/overlapping-combos-4-different-timeouts/events.patterns b/app/tests/combo/overlapping-combos-4-different-timeouts/events.patterns new file mode 100644 index 00000000000..89015deee06 --- /dev/null +++ b/app/tests/combo/overlapping-combos-4-different-timeouts/events.patterns @@ -0,0 +1 @@ +s/.*\(hid_listener_keycode_pressed\|filter_timed_out_candidates\): //p \ No newline at end of file diff --git a/app/tests/combo/overlapping-combos-4-different-timeouts/keycode_events.snapshot b/app/tests/combo/overlapping-combos-4-different-timeouts/keycode_events.snapshot new file mode 100644 index 00000000000..8fe441ff46e --- /dev/null +++ b/app/tests/combo/overlapping-combos-4-different-timeouts/keycode_events.snapshot @@ -0,0 +1,8 @@ +after filtering out timed out combo candidates: remaining_candidates=2 timestamp=71 +after filtering out timed out combo candidates: remaining_candidates=1 timestamp=81 +after filtering out timed out combo candidates: remaining_candidates=0 timestamp=91 +usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +after filtering out timed out combo candidates: remaining_candidates=2 timestamp=143 +after filtering out timed out combo candidates: remaining_candidates=1 timestamp=153 +after filtering out timed out combo candidates: remaining_candidates=1 timestamp=159 +usage_page 0x07 keycode 0x1D implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/overlapping-combos-4-different-timeouts/native_posix_64.keymap b/app/tests/combo/overlapping-combos-4-different-timeouts/native_posix_64.keymap new file mode 100644 index 00000000000..8967207987b --- /dev/null +++ b/app/tests/combo/overlapping-combos-4-different-timeouts/native_posix_64.keymap @@ -0,0 +1,98 @@ +#include +#include +#include + +#define kA 0 +#define kB 1 +#define kC 2 +#define kD 3 + +/ { + combos { + compatible = "zmk,combos"; + + // Intentionally out of order in the config, to make sure 'combo.c' handles it properly + combo_40 { + timeout-ms = <40>; + key-positions = ; + bindings = <&kp Z>; + }; + combo_20 { + timeout-ms = <20>; + key-positions = ; + bindings = <&kp X>; + }; + combo_30 { + timeout-ms = <30>; + key-positions = ; + bindings = <&kp Y>; + }; + + }; + + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &kp A &kp B + &kp C &kp D + >; + }; + }; +}; + +#define press_A_and_wait(delay_next) \ + ZMK_MOCK_PRESS(0,0,delay_next) +#define press_B_and_wait(delay_next) \ + ZMK_MOCK_PRESS(0,1,delay_next) +#define press_C_and_wait(delay_next) \ + ZMK_MOCK_PRESS(1,0,delay_next) +#define press_D_and_wait(delay_next) \ + ZMK_MOCK_PRESS(1,1,delay_next) + +#define release_A_and_wait(delay_next) \ + ZMK_MOCK_RELEASE(0,0,delay_next) +#define release_D_and_wait(delay_next) \ + ZMK_MOCK_RELEASE(1,1,delay_next) + +&kscan { + events = < + /* Note: This starts at T+50 because the ZMK_MOCK_PRESS seems to launch the first event at T+(first wait duration). So in our case T+50 */ + + + + /*** First Phase: All 3 combos expire ***/ + + /* T+50+0= T+50: Press A and wait 50ms */ + press_A_and_wait(50) + + /* T+50+20= T+70: 'combo_20' should expire */ + /* T+50+30= T+80: 'combo_30' should expire */ + /* T+50+40= T+90: 'combo_40' should expire, and we should send the keycode 'A' */ + + /* T+50+50= T+100: We release A and wait 20ms */ + release_A_and_wait(20) + + + + /*** Second Phase: 2 combo expire, 1 combo triggers ***/ + + /* T+120+0= T+120: Press A and wait 35ms */ + press_A_and_wait(35) + + /* T+120+20= T+140: 'combo_20' should expire */ + /* T+120+30= T+150: 'combo_30' should expire */ + + /* T+120+35= T+155: We press 'D', this should trigger 'combo_40' and send the keycode 'Z'. We wait 15ms */ + press_D_and_wait(15) + + + + /*** Cleanup ***/ + /* T+120+50= T+170: We release both keys */ + release_A_and_wait(20) + release_D_and_wait(0) + >; +}; \ No newline at end of file diff --git a/app/tests/combo/partially-overlapping-combos/native_posix_64.keymap b/app/tests/combo/partially-overlapping-combos/native_posix_64.keymap index 900c4af3f1e..55e8f1e77b6 100644 --- a/app/tests/combo/partially-overlapping-combos/native_posix_64.keymap +++ b/app/tests/combo/partially-overlapping-combos/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include / { combos { diff --git a/app/tests/combo/press-release-long-combo-complete/native_posix_64.keymap b/app/tests/combo/press-release-long-combo-complete/native_posix_64.keymap index dac0bd5ca4c..da2e9483ff7 100644 --- a/app/tests/combo/press-release-long-combo-complete/native_posix_64.keymap +++ b/app/tests/combo/press-release-long-combo-complete/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include / { combos { diff --git a/app/tests/combo/press-release-long-combo-incomplete/native_posix_64.keymap b/app/tests/combo/press-release-long-combo-incomplete/native_posix_64.keymap index 19bad1d0d1d..b1494cecf20 100644 --- a/app/tests/combo/press-release-long-combo-incomplete/native_posix_64.keymap +++ b/app/tests/combo/press-release-long-combo-incomplete/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include / { combos { diff --git a/app/tests/combo/press-release-long-combo-wrong-last-key/native_posix_64.keymap b/app/tests/combo/press-release-long-combo-wrong-last-key/native_posix_64.keymap index 2eb6271e2f0..8769286413b 100644 --- a/app/tests/combo/press-release-long-combo-wrong-last-key/native_posix_64.keymap +++ b/app/tests/combo/press-release-long-combo-wrong-last-key/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include / { combos { diff --git a/app/tests/combo/press-release/native_posix_64.keymap b/app/tests/combo/press-release/native_posix_64.keymap index 6bd432f9c86..26cd241b0bb 100644 --- a/app/tests/combo/press-release/native_posix_64.keymap +++ b/app/tests/combo/press-release/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include / { combos { diff --git a/app/tests/combo/press-timeout/native_posix_64.keymap b/app/tests/combo/press-timeout/native_posix_64.keymap index 6ca6487ba93..a71de45a7d2 100644 --- a/app/tests/combo/press-timeout/native_posix_64.keymap +++ b/app/tests/combo/press-timeout/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include / { combos { diff --git a/app/tests/combo/press1-press2-release1-release2/native_posix_64.keymap b/app/tests/combo/press1-press2-release1-release2/native_posix_64.keymap index 9a395a41468..2e0a67a3e7f 100644 --- a/app/tests/combo/press1-press2-release1-release2/native_posix_64.keymap +++ b/app/tests/combo/press1-press2-release1-release2/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include / { combos { diff --git a/app/tests/combo/press1-press2-release2-release1/native_posix_64.keymap b/app/tests/combo/press1-press2-release2-release1/native_posix_64.keymap index 86ca3931dce..8d4838eb511 100644 --- a/app/tests/combo/press1-press2-release2-release1/native_posix_64.keymap +++ b/app/tests/combo/press1-press2-release2-release1/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include / { combos { diff --git a/app/tests/combo/press1-release1-press2-release2/native_posix_64.keymap b/app/tests/combo/press1-release1-press2-release2/native_posix_64.keymap index 650895784ae..9c75e5705b1 100644 --- a/app/tests/combo/press1-release1-press2-release2/native_posix_64.keymap +++ b/app/tests/combo/press1-release1-press2-release2/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include / { combos { diff --git a/app/tests/combo/require-prior-idle/events.patterns b/app/tests/combo/require-prior-idle/events.patterns new file mode 100644 index 00000000000..833100f6ac4 --- /dev/null +++ b/app/tests/combo/require-prior-idle/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/combo/require-prior-idle/keycode_events.snapshot b/app/tests/combo/require-prior-idle/keycode_events.snapshot new file mode 100644 index 00000000000..ee4dd064c61 --- /dev/null +++ b/app/tests/combo/require-prior-idle/keycode_events.snapshot @@ -0,0 +1,14 @@ +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1B implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1C implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/combo/require-prior-idle/native_posix_64.keymap b/app/tests/combo/require-prior-idle/native_posix_64.keymap new file mode 100644 index 00000000000..fcd94056c4d --- /dev/null +++ b/app/tests/combo/require-prior-idle/native_posix_64.keymap @@ -0,0 +1,64 @@ +#include +#include +#include + +/ { + combos { + compatible = "zmk,combos"; + combo_one { + timeout-ms = <50>; + key-positions = <0 1>; + bindings = <&kp X>; + require-prior-idle-ms = <100>; + }; + + combo_two { + timeout-ms = <50>; + key-positions = <0 2>; + bindings = <&kp Y>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &kp A &kp B + &kp C &kp D + >; + }; + }; +}; + +&kscan { + events = < + /* Tap A */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,60) + /* Quick Tap A and B */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,200) + /* Combo One */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + /* Combo One Again (shouldn't quick tap) */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + /* Tap A */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,60) + /* Combo 2 */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; diff --git a/app/tests/combo/slowrelease-disabled/native_posix_64.keymap b/app/tests/combo/slowrelease-disabled/native_posix_64.keymap index 832e9705897..46b35be02ee 100644 --- a/app/tests/combo/slowrelease-disabled/native_posix_64.keymap +++ b/app/tests/combo/slowrelease-disabled/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include / { combos { diff --git a/app/tests/combo/slowrelease-enabled/native_posix_64.keymap b/app/tests/combo/slowrelease-enabled/native_posix_64.keymap index 7fdb012ed15..d64876da557 100644 --- a/app/tests/combo/slowrelease-enabled/native_posix_64.keymap +++ b/app/tests/combo/slowrelease-enabled/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include / { combos { diff --git a/app/tests/gresc/gresc-press-release/native_posix_64.keymap b/app/tests/gresc/gresc-press-release/native_posix_64.keymap index 5e3fac42c72..c472dd6d4ad 100644 --- a/app/tests/gresc/gresc-press-release/native_posix_64.keymap +++ b/app/tests/gresc/gresc-press-release/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include / { keymap { diff --git a/app/tests/gresc/gresc-two-instances/native_posix_64.keymap b/app/tests/gresc/gresc-two-instances/native_posix_64.keymap index 18f94da5771..14adcf45c8e 100644 --- a/app/tests/gresc/gresc-two-instances/native_posix_64.keymap +++ b/app/tests/gresc/gresc-two-instances/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include /* This test checks nothing breaks if two grave-escapes are pressed at the same time. diff --git a/app/tests/hold-tap/balanced/8-global-quick-tap/1-basic/events.patterns b/app/tests/hold-tap/balanced/8-require-prior-idle/1-basic/events.patterns similarity index 100% rename from app/tests/hold-tap/balanced/8-global-quick-tap/1-basic/events.patterns rename to app/tests/hold-tap/balanced/8-require-prior-idle/1-basic/events.patterns diff --git a/app/tests/hold-tap/balanced/8-global-quick-tap/1-basic/keycode_events.snapshot b/app/tests/hold-tap/balanced/8-require-prior-idle/1-basic/keycode_events.snapshot similarity index 100% rename from app/tests/hold-tap/balanced/8-global-quick-tap/1-basic/keycode_events.snapshot rename to app/tests/hold-tap/balanced/8-require-prior-idle/1-basic/keycode_events.snapshot diff --git a/app/tests/hold-tap/tap-preferred/8-global-quick-tap/1-basic/native_posix_64.keymap b/app/tests/hold-tap/balanced/8-require-prior-idle/1-basic/native_posix_64.keymap similarity index 89% rename from app/tests/hold-tap/tap-preferred/8-global-quick-tap/1-basic/native_posix_64.keymap rename to app/tests/hold-tap/balanced/8-require-prior-idle/1-basic/native_posix_64.keymap index 5af001f6be1..aa629498073 100644 --- a/app/tests/hold-tap/tap-preferred/8-global-quick-tap/1-basic/native_posix_64.keymap +++ b/app/tests/hold-tap/balanced/8-require-prior-idle/1-basic/native_posix_64.keymap @@ -7,7 +7,7 @@ events = < /* tap */ ZMK_MOCK_PRESS(0,0,10) - ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,0,250) /* normal quick tap */ ZMK_MOCK_PRESS(0,0,400) ZMK_MOCK_RELEASE(0,0,400) @@ -16,7 +16,7 @@ ZMK_MOCK_PRESS(1,0,10) ZMK_MOCK_RELEASE(1,0,10) ZMK_MOCK_RELEASE(0,0,400) - /* global quick tap */ + /* require-prior-idle */ ZMK_MOCK_PRESS(1,0,10) ZMK_MOCK_PRESS(0,0,400) ZMK_MOCK_RELEASE(1,0,10) diff --git a/app/tests/hold-tap/balanced/8-global-quick-tap/2-double-hold/events.patterns b/app/tests/hold-tap/balanced/8-require-prior-idle/2-double-hold/events.patterns similarity index 100% rename from app/tests/hold-tap/balanced/8-global-quick-tap/2-double-hold/events.patterns rename to app/tests/hold-tap/balanced/8-require-prior-idle/2-double-hold/events.patterns diff --git a/app/tests/hold-tap/balanced/8-global-quick-tap/2-double-hold/keycode_events.snapshot b/app/tests/hold-tap/balanced/8-require-prior-idle/2-double-hold/keycode_events.snapshot similarity index 100% rename from app/tests/hold-tap/balanced/8-global-quick-tap/2-double-hold/keycode_events.snapshot rename to app/tests/hold-tap/balanced/8-require-prior-idle/2-double-hold/keycode_events.snapshot diff --git a/app/tests/hold-tap/balanced/8-global-quick-tap/2-double-hold/native_posix_64.keymap b/app/tests/hold-tap/balanced/8-require-prior-idle/2-double-hold/native_posix_64.keymap similarity index 100% rename from app/tests/hold-tap/balanced/8-global-quick-tap/2-double-hold/native_posix_64.keymap rename to app/tests/hold-tap/balanced/8-require-prior-idle/2-double-hold/native_posix_64.keymap diff --git a/app/tests/hold-tap/balanced/8-global-quick-tap/behavior_keymap.dtsi b/app/tests/hold-tap/balanced/8-require-prior-idle/behavior_keymap.dtsi similarity index 94% rename from app/tests/hold-tap/balanced/8-global-quick-tap/behavior_keymap.dtsi rename to app/tests/hold-tap/balanced/8-require-prior-idle/behavior_keymap.dtsi index ef8efd437d7..670bdcc2650 100644 --- a/app/tests/hold-tap/balanced/8-global-quick-tap/behavior_keymap.dtsi +++ b/app/tests/hold-tap/balanced/8-require-prior-idle/behavior_keymap.dtsi @@ -11,8 +11,8 @@ flavor = "balanced"; tapping-term-ms = <300>; quick-tap-ms = <300>; + require-prior-idle-ms = <100>; bindings = <&kp>, <&kp>; - global-quick-tap; }; }; diff --git a/app/tests/hold-tap/hold-preferred/8-global-quick-tap/1-basic/events.patterns b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/1-basic/events.patterns similarity index 100% rename from app/tests/hold-tap/hold-preferred/8-global-quick-tap/1-basic/events.patterns rename to app/tests/hold-tap/hold-preferred/8-require-prior-idle/1-basic/events.patterns diff --git a/app/tests/hold-tap/hold-preferred/8-global-quick-tap/1-basic/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/1-basic/keycode_events.snapshot similarity index 100% rename from app/tests/hold-tap/hold-preferred/8-global-quick-tap/1-basic/keycode_events.snapshot rename to app/tests/hold-tap/hold-preferred/8-require-prior-idle/1-basic/keycode_events.snapshot diff --git a/app/tests/hold-tap/hold-preferred/8-global-quick-tap/1-basic/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/1-basic/native_posix_64.keymap similarity index 89% rename from app/tests/hold-tap/hold-preferred/8-global-quick-tap/1-basic/native_posix_64.keymap rename to app/tests/hold-tap/hold-preferred/8-require-prior-idle/1-basic/native_posix_64.keymap index e28eb4c37e8..6db79abc381 100644 --- a/app/tests/hold-tap/hold-preferred/8-global-quick-tap/1-basic/native_posix_64.keymap +++ b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/1-basic/native_posix_64.keymap @@ -7,7 +7,7 @@ events = < /* tap */ ZMK_MOCK_PRESS(0,0,10) - ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,0,250) /* normal quick tap */ ZMK_MOCK_PRESS(0,0,400) ZMK_MOCK_RELEASE(0,0,400) @@ -16,7 +16,7 @@ ZMK_MOCK_PRESS(1,0,10) ZMK_MOCK_RELEASE(1,0,10) ZMK_MOCK_RELEASE(0,0,400) - /* global quick tap */ + /* require-prior-idle */ ZMK_MOCK_PRESS(1,0,10) ZMK_MOCK_PRESS(0,0,400) ZMK_MOCK_RELEASE(1,0,10) diff --git a/app/tests/hold-tap/hold-preferred/8-global-quick-tap/2-double-hold/events.patterns b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/2-double-hold/events.patterns similarity index 100% rename from app/tests/hold-tap/hold-preferred/8-global-quick-tap/2-double-hold/events.patterns rename to app/tests/hold-tap/hold-preferred/8-require-prior-idle/2-double-hold/events.patterns diff --git a/app/tests/hold-tap/hold-preferred/8-global-quick-tap/2-double-hold/keycode_events.snapshot b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/2-double-hold/keycode_events.snapshot similarity index 100% rename from app/tests/hold-tap/hold-preferred/8-global-quick-tap/2-double-hold/keycode_events.snapshot rename to app/tests/hold-tap/hold-preferred/8-require-prior-idle/2-double-hold/keycode_events.snapshot diff --git a/app/tests/hold-tap/hold-preferred/8-global-quick-tap/2-double-hold/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/2-double-hold/native_posix_64.keymap similarity index 100% rename from app/tests/hold-tap/hold-preferred/8-global-quick-tap/2-double-hold/native_posix_64.keymap rename to app/tests/hold-tap/hold-preferred/8-require-prior-idle/2-double-hold/native_posix_64.keymap diff --git a/app/tests/hold-tap/hold-preferred/8-global-quick-tap/behavior_keymap.dtsi b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/behavior_keymap.dtsi similarity index 94% rename from app/tests/hold-tap/hold-preferred/8-global-quick-tap/behavior_keymap.dtsi rename to app/tests/hold-tap/hold-preferred/8-require-prior-idle/behavior_keymap.dtsi index 392a5f83435..a99eb3f56f8 100644 --- a/app/tests/hold-tap/hold-preferred/8-global-quick-tap/behavior_keymap.dtsi +++ b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/behavior_keymap.dtsi @@ -11,8 +11,8 @@ flavor = "hold-preferred"; tapping-term-ms = <300>; quick-tap-ms = <300>; + require-prior-idle-ms = <100>; bindings = <&kp>, <&kp>; - global-quick-tap; }; }; diff --git a/app/tests/hold-tap/tap-preferred/8-global-quick-tap/1-basic/events.patterns b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/1-basic/events.patterns similarity index 100% rename from app/tests/hold-tap/tap-preferred/8-global-quick-tap/1-basic/events.patterns rename to app/tests/hold-tap/tap-preferred/8-require-prior-idle/1-basic/events.patterns diff --git a/app/tests/hold-tap/tap-preferred/8-global-quick-tap/1-basic/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/1-basic/keycode_events.snapshot similarity index 100% rename from app/tests/hold-tap/tap-preferred/8-global-quick-tap/1-basic/keycode_events.snapshot rename to app/tests/hold-tap/tap-preferred/8-require-prior-idle/1-basic/keycode_events.snapshot diff --git a/app/tests/hold-tap/balanced/8-global-quick-tap/1-basic/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/1-basic/native_posix_64.keymap similarity index 89% rename from app/tests/hold-tap/balanced/8-global-quick-tap/1-basic/native_posix_64.keymap rename to app/tests/hold-tap/tap-preferred/8-require-prior-idle/1-basic/native_posix_64.keymap index 5af001f6be1..aa629498073 100644 --- a/app/tests/hold-tap/balanced/8-global-quick-tap/1-basic/native_posix_64.keymap +++ b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/1-basic/native_posix_64.keymap @@ -7,7 +7,7 @@ events = < /* tap */ ZMK_MOCK_PRESS(0,0,10) - ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,0,250) /* normal quick tap */ ZMK_MOCK_PRESS(0,0,400) ZMK_MOCK_RELEASE(0,0,400) @@ -16,7 +16,7 @@ ZMK_MOCK_PRESS(1,0,10) ZMK_MOCK_RELEASE(1,0,10) ZMK_MOCK_RELEASE(0,0,400) - /* global quick tap */ + /* require-prior-idle */ ZMK_MOCK_PRESS(1,0,10) ZMK_MOCK_PRESS(0,0,400) ZMK_MOCK_RELEASE(1,0,10) diff --git a/app/tests/hold-tap/tap-preferred/8-global-quick-tap/2-double-hold/events.patterns b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/2-double-hold/events.patterns similarity index 100% rename from app/tests/hold-tap/tap-preferred/8-global-quick-tap/2-double-hold/events.patterns rename to app/tests/hold-tap/tap-preferred/8-require-prior-idle/2-double-hold/events.patterns diff --git a/app/tests/hold-tap/tap-preferred/8-global-quick-tap/2-double-hold/keycode_events.snapshot b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/2-double-hold/keycode_events.snapshot similarity index 100% rename from app/tests/hold-tap/tap-preferred/8-global-quick-tap/2-double-hold/keycode_events.snapshot rename to app/tests/hold-tap/tap-preferred/8-require-prior-idle/2-double-hold/keycode_events.snapshot diff --git a/app/tests/hold-tap/tap-unless-interrupted/6-global-quick-tap/2-double-hold/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/2-double-hold/native_posix_64.keymap similarity index 93% rename from app/tests/hold-tap/tap-unless-interrupted/6-global-quick-tap/2-double-hold/native_posix_64.keymap rename to app/tests/hold-tap/tap-preferred/8-require-prior-idle/2-double-hold/native_posix_64.keymap index 69d691cee8e..068ae81a8c6 100644 --- a/app/tests/hold-tap/tap-unless-interrupted/6-global-quick-tap/2-double-hold/native_posix_64.keymap +++ b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/2-double-hold/native_posix_64.keymap @@ -6,7 +6,7 @@ &kscan { events = < /* hold the first mod tap */ - ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_PRESS(0,0,10) /* hold the second mod tap */ ZMK_MOCK_PRESS(0,1,400) /* press the normal key */ diff --git a/app/tests/hold-tap/tap-preferred/8-global-quick-tap/behavior_keymap.dtsi b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/behavior_keymap.dtsi similarity index 93% rename from app/tests/hold-tap/tap-preferred/8-global-quick-tap/behavior_keymap.dtsi rename to app/tests/hold-tap/tap-preferred/8-require-prior-idle/behavior_keymap.dtsi index 02362ef2b09..c66dc934092 100644 --- a/app/tests/hold-tap/tap-preferred/8-global-quick-tap/behavior_keymap.dtsi +++ b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/behavior_keymap.dtsi @@ -11,8 +11,8 @@ flavor = "tap-preferred"; tapping-term-ms = <300>; quick-tap-ms = <300>; + require-prior-idle-ms = <100>; bindings = <&kp>, <&kp>; - global-quick-tap; }; }; diff --git a/app/tests/hold-tap/tap-unless-interrupted/6-global-quick-tap/1-basic/events.patterns b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/1-basic/events.patterns similarity index 100% rename from app/tests/hold-tap/tap-unless-interrupted/6-global-quick-tap/1-basic/events.patterns rename to app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/1-basic/events.patterns diff --git a/app/tests/hold-tap/tap-unless-interrupted/6-global-quick-tap/1-basic/keycode_events.snapshot b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/1-basic/keycode_events.snapshot similarity index 100% rename from app/tests/hold-tap/tap-unless-interrupted/6-global-quick-tap/1-basic/keycode_events.snapshot rename to app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/1-basic/keycode_events.snapshot diff --git a/app/tests/hold-tap/tap-unless-interrupted/6-global-quick-tap/1-basic/native_posix_64.keymap b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/1-basic/native_posix_64.keymap similarity index 89% rename from app/tests/hold-tap/tap-unless-interrupted/6-global-quick-tap/1-basic/native_posix_64.keymap rename to app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/1-basic/native_posix_64.keymap index 5af001f6be1..aa629498073 100644 --- a/app/tests/hold-tap/tap-unless-interrupted/6-global-quick-tap/1-basic/native_posix_64.keymap +++ b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/1-basic/native_posix_64.keymap @@ -7,7 +7,7 @@ events = < /* tap */ ZMK_MOCK_PRESS(0,0,10) - ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,0,250) /* normal quick tap */ ZMK_MOCK_PRESS(0,0,400) ZMK_MOCK_RELEASE(0,0,400) @@ -16,7 +16,7 @@ ZMK_MOCK_PRESS(1,0,10) ZMK_MOCK_RELEASE(1,0,10) ZMK_MOCK_RELEASE(0,0,400) - /* global quick tap */ + /* require-prior-idle */ ZMK_MOCK_PRESS(1,0,10) ZMK_MOCK_PRESS(0,0,400) ZMK_MOCK_RELEASE(1,0,10) diff --git a/app/tests/hold-tap/tap-unless-interrupted/6-global-quick-tap/2-double-hold/events.patterns b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/2-double-hold/events.patterns similarity index 100% rename from app/tests/hold-tap/tap-unless-interrupted/6-global-quick-tap/2-double-hold/events.patterns rename to app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/2-double-hold/events.patterns diff --git a/app/tests/hold-tap/tap-unless-interrupted/6-global-quick-tap/2-double-hold/keycode_events.snapshot b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/2-double-hold/keycode_events.snapshot similarity index 100% rename from app/tests/hold-tap/tap-unless-interrupted/6-global-quick-tap/2-double-hold/keycode_events.snapshot rename to app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/2-double-hold/keycode_events.snapshot diff --git a/app/tests/hold-tap/tap-preferred/8-global-quick-tap/2-double-hold/native_posix_64.keymap b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/2-double-hold/native_posix_64.keymap similarity index 100% rename from app/tests/hold-tap/tap-preferred/8-global-quick-tap/2-double-hold/native_posix_64.keymap rename to app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/2-double-hold/native_posix_64.keymap diff --git a/app/tests/hold-tap/tap-unless-interrupted/6-global-quick-tap/behavior_keymap.dtsi b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/behavior_keymap.dtsi similarity index 94% rename from app/tests/hold-tap/tap-unless-interrupted/6-global-quick-tap/behavior_keymap.dtsi rename to app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/behavior_keymap.dtsi index 029a8128292..7aa3940833f 100644 --- a/app/tests/hold-tap/tap-unless-interrupted/6-global-quick-tap/behavior_keymap.dtsi +++ b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/behavior_keymap.dtsi @@ -11,8 +11,8 @@ flavor = "tap-unless-interrupted"; tapping-term-ms = <300>; quick-tap-ms = <300>; + require-prior-idle-ms = <100>; bindings = <&kp>, <&kp>; - global-quick-tap; }; }; diff --git a/app/tests/key-repeat/tap-when-rolling/events.patterns b/app/tests/key-repeat/tap-when-rolling/events.patterns new file mode 100644 index 00000000000..794719239fc --- /dev/null +++ b/app/tests/key-repeat/tap-when-rolling/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode_//p +s/.*hid_implicit_modifiers_//p \ No newline at end of file diff --git a/app/tests/key-repeat/tap-when-rolling/keycode_events.snapshot b/app/tests/key-repeat/tap-when-rolling/keycode_events.snapshot new file mode 100644 index 00000000000..7d54e9de9b2 --- /dev/null +++ b/app/tests/key-repeat/tap-when-rolling/keycode_events.snapshot @@ -0,0 +1,9 @@ +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x00 +pressed: unregistering usage_page 0x07 keycode 0x04 since it was already pressed +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +press: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +release: Modifiers set to 0x00 diff --git a/app/tests/key-repeat/tap-when-rolling/native_posix.keymap b/app/tests/key-repeat/tap-when-rolling/native_posix.keymap new file mode 100644 index 00000000000..bb129d14c7a --- /dev/null +++ b/app/tests/key-repeat/tap-when-rolling/native_posix.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; diff --git a/app/tests/key-repeat/tap-when-rolling/native_posix_64.keymap b/app/tests/key-repeat/tap-when-rolling/native_posix_64.keymap new file mode 100644 index 00000000000..a947f7ab0ed --- /dev/null +++ b/app/tests/key-repeat/tap-when-rolling/native_posix_64.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,1,9000) + ZMK_MOCK_PRESS(0,0,30) + ZMK_MOCK_RELEASE(0,1,30) + ZMK_MOCK_RELEASE(0,0,3000) + >; +}; diff --git a/app/tests/modifiers/explicit/kp-hyper-dn-a-dn-a-up-hyper-up/native_posix_64.keymap b/app/tests/modifiers/explicit/kp-hyper-dn-a-dn-a-up-hyper-up/native_posix_64.keymap index 621945a8218..72b218f510f 100644 --- a/app/tests/modifiers/explicit/kp-hyper-dn-a-dn-a-up-hyper-up/native_posix_64.keymap +++ b/app/tests/modifiers/explicit/kp-hyper-dn-a-dn-a-up-hyper-up/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include &kscan { diff --git a/app/tests/modifiers/implicit/kp-rolling-symbols-same-key/events.patterns b/app/tests/modifiers/implicit/kp-rolling-symbols-same-key/events.patterns new file mode 100644 index 00000000000..cbf21aff278 --- /dev/null +++ b/app/tests/modifiers/implicit/kp-rolling-symbols-same-key/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode_//p +s/.*hid_register_mod/reg/p +s/.*hid_unregister_mod/unreg/p +s/.*zmk_hid_.*Modifiers set to /mods: Modifiers set to /p \ No newline at end of file diff --git a/app/tests/modifiers/implicit/kp-rolling-symbols-same-key/keycode_events.snapshot b/app/tests/modifiers/implicit/kp-rolling-symbols-same-key/keycode_events.snapshot new file mode 100644 index 00000000000..0b06bd91d88 --- /dev/null +++ b/app/tests/modifiers/implicit/kp-rolling-symbols-same-key/keycode_events.snapshot @@ -0,0 +1,9 @@ +pressed: usage_page 0x07 keycode 0x2E implicit_mods 0x02 explicit_mods 0x00 +mods: Modifiers set to 0x02 +pressed: unregistering usage_page 0x07 keycode 0x2E since it was already pressed +pressed: usage_page 0x07 keycode 0x2E implicit_mods 0x00 explicit_mods 0x00 +mods: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x2E implicit_mods 0x02 explicit_mods 0x00 +mods: Modifiers set to 0x00 +released: usage_page 0x07 keycode 0x2E implicit_mods 0x00 explicit_mods 0x00 +mods: Modifiers set to 0x00 diff --git a/app/tests/modifiers/implicit/kp-rolling-symbols-same-key/native_posix_64.keymap b/app/tests/modifiers/implicit/kp-rolling-symbols-same-key/native_posix_64.keymap new file mode 100644 index 00000000000..3926eb57a29 --- /dev/null +++ b/app/tests/modifiers/implicit/kp-rolling-symbols-same-key/native_posix_64.keymap @@ -0,0 +1,27 @@ +#include +#include +#include + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &kp PLUS &kp EQUAL + &none &none + >; + }; + }; +}; diff --git a/app/tests/sticky-keys/10-sl-sl-kp/native_posix_64.keymap b/app/tests/sticky-keys/10-sl-sl-kp/native_posix_64.keymap index 23ceeeb6161..bafdbe38d39 100644 --- a/app/tests/sticky-keys/10-sl-sl-kp/native_posix_64.keymap +++ b/app/tests/sticky-keys/10-sl-sl-kp/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include /* sticky layers should quick-release. diff --git a/app/tests/sticky-keys/2-sl-dn-up-kcdn-kcup/native_posix_64.keymap b/app/tests/sticky-keys/2-sl-dn-up-kcdn-kcup/native_posix_64.keymap index 390207515dd..38c8fb4c91c 100644 --- a/app/tests/sticky-keys/2-sl-dn-up-kcdn-kcup/native_posix_64.keymap +++ b/app/tests/sticky-keys/2-sl-dn-up-kcdn-kcup/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include /* sticky layers should quick-release. diff --git a/app/tests/to-layer/behavior_keymap.dtsi b/app/tests/to-layer/behavior_keymap.dtsi index 663e897d74b..7dc857fe143 100644 --- a/app/tests/to-layer/behavior_keymap.dtsi +++ b/app/tests/to-layer/behavior_keymap.dtsi @@ -1,6 +1,6 @@ #include #include -#include +#include / { keymap { diff --git a/app/tests/to-layer/normal/native_posix_64.keymap b/app/tests/to-layer/normal/native_posix_64.keymap index 4cb23809452..6ccc9088bb2 100644 --- a/app/tests/to-layer/normal/native_posix_64.keymap +++ b/app/tests/to-layer/normal/native_posix_64.keymap @@ -1,6 +1,6 @@ #include #include -#include +#include #include "../behavior_keymap.dtsi" // Press key A diff --git a/docs/blog/2023-10-05-zmk-sotf-6.md b/docs/blog/2023-10-05-zmk-sotf-6.md new file mode 100644 index 00000000000..18a52a859fd --- /dev/null +++ b/docs/blog/2023-10-05-zmk-sotf-6.md @@ -0,0 +1,295 @@ +--- +title: "ZMK State Of The Firmware #6" +author: Cem Aksoylar +author_title: Documentation maintainer +author_url: https://github.com/caksoylar +author_image_url: https://avatars.githubusercontent.com/u/7876996 +tags: [SOTF, keyboards, firmware, oss, ble] +--- + +Welcome to the sixth ZMK "State Of The Firmware" (SOTF)! + +This update will cover all the major activity since [SOTF #5](/blog/2022/04/10/zmk-sotf-5). That was over a year ago (again!), so there are many new exciting features and plenty of improvements to cover! + +## Recent Activity + +Here's a summary of the various major changes since last time, broken down by theme: + +### Keymaps/Behaviors + +#### Hold-tap improvements + +[andrewjrae] added the [`require-prior-idle-ms` property](/docs/behaviors/hold-tap#require-prior-idle-ms) to the hold-tap behavior in [#1187](https://github.com/zmkfirmware/zmk/pull/1187) and [#1387](https://github.com/zmkfirmware/zmk/pull/1387), which prevents the hold behavior from triggering if it hasn't been a certain duration since the last key press. This is a useful feature to prevent accidental hold activations during quick typing and made its way into many keymaps! The same property was added to [combos](/docs/features/combos#configuration) as well to help prevent false combo activations. + +Note that an earlier iteration of this feature was supported with the `global-quick-tap` property, which did not allow customizing the timeout and used the value of `tapping-term-ms` for it. This property is now deprecated and users are encouraged to use `require-prior-idle-ms` instead. + +[urob] added the [`hold-trigger-on-release` property](/docs/behaviors/hold-tap#positional-hold-tap-and-hold-trigger-key-positions) in [#1423](https://github.com/zmkfirmware/zmk/pull/1423). This significantly increases the usefulness of positional constraints on hold-taps, since it allows combining multiple holds such as different modifiers for home row mods usage. + +#### Masking mods in mod-morphs + +[aumuell](https://github.com/aumuell), [vrinek](https://github.com/vrinek) and [urob] contributed to improving the behavior of [mod-morphs](/docs/behaviors/mod-morph) by masking the triggering modifiers and added `keep-mods` property in [#1412](https://github.com/zmkfirmware/zmk/pull/1412). This unlocks more use cases for mod-morphs, since you are no longer constrained to emitting keycodes that work well with the triggering modifier keycodes. + +As an example, you can now define a mod-morph that swaps `;` and `:` so that the former is the shifted version of the latter, which wasn't previously possible: + +```dts + col_semi: colon_semicolon { + compatible = "zmk,behavior-mod-morph"; + label = "COLON_SEMICOLON"; + #binding-cells = <0>; + bindings = <&kp COLON>, <&kp SEMI>; + mods = <(MOD_LSFT|MOD_RSFT)>; + }; +``` + +#### Parameterized macros + +[petejohanson] added [macros that can be parameterized](/docs/behaviors/macros#parameterized-macros) with one or two parameters in [#1232](https://github.com/zmkfirmware/zmk/pull/1232). This allows users to define macros in a more modular way and is a nice quality-of-life improvement. + +As a simple example, you could define a macro that puts any keycode provided between double quotes as below, then use it like `&ql A` in your keymap: + +```dts + ql: quoted_letter_macro { + #binding-cells = <1>; + label = "QUOTED_LETTER"; + compatible = "zmk,behavior-macro-one-param"; + bindings = + <&kp DQT>, + <¯o_param_1to1 &kp MACRO_PLACEHOLDER>, + <&kp DQT>; + }; +``` + +Please see the documentation page linked above for usage and more examples. + +#### Arbitrary behaviors on encoder rotation + +[nickconway](https://github.com/nickconway) and [petejohanson] added [sensor rotation behaviors](/docs/behaviors/sensor-rotate) to allow invoking arbitrary behaviors from encoders [#1758](https://github.com/zmkfirmware/zmk/pull/1758). Previously encoder rotations could only invoke the key-press behavior `&kp` through the `&inc_dec_kp` binding, whereas now you can define new sensor rotation behaviors to invoke others. + +(Note that currently behaviors that have "locality" such as `&rgb_ug` do not work as expected via encoder rotation bindings in split keyboards, due to issue [#1494](https://github.com/zmkfirmware/zmk/issues/1494).) + +#### Pre-releasing already pressed keys + +[andrewjrae] contributed a tweak to emitting keycodes in [#1828](https://github.com/zmkfirmware/zmk/pull/1828), where rolling multiple keys that involve the same keycode now releases the keycode before sending a press event again. While this might sound like a technical distinction, it leads to more correct behavior when quickly typing sequences like `+=` and makes the [key repeat behavior](/docs/behaviors/key-repeat) work properly when it is pressed before the previous key is released. + +#### Key toggle behavior + +[cgoates](https://github.com/cgoates) added the [key toggle behavior](/docs/behaviors/key-toggle) in [#1278](https://github.com/zmkfirmware/zmk/pull/1278), which can be used via its `&kt` binding to toggle the state of a keycode between pressed and released. + +#### Apple Globe key + +[ReFil] added support for the `C_AC_NEXT_KEYBOARD_LAYOUT_SELECT` keycode with alias `GLOBE` which acts as the Globe key in macOS and iOS in [#1938](https://github.com/zmkfirmware/zmk/pull/1938). Note that this keycode doesn't exactly behave like a Globe key that is present on an Apple keyboard and its limitations are documented in [this comment](https://github.com/zmkfirmware/zmk/pull/1938#issuecomment-1744579039) thanks to testing by [SethMilliken](https://github.com/SethMilliken). These limitations will be noted in the official [keycodes documentation](/docs/codes/applications) shortly. + +#### Bug fixes and other improvements + +[petejohanson], [andrewjrae] and [okke-formsma] tracked down and fixed an issue causing stuck keys when there are combos on key positions involving hold-tap behaviors in [#1411](https://github.com/zmkfirmware/zmk/pull/1411). This was an elusive bug that took a lot of effort from the community to nail down and fix! + +[nguyendown](https://github.com/nguyendown) and [joelspadin] tracked down and fixed a couple issues causing stuck keys with [sticky keys](/docs/behaviors/sticky-key) in [#1586](https://github.com/zmkfirmware/zmk/pull/1586), [#1745](https://github.com/zmkfirmware/zmk/pull/1745). + +[okke-formsma] fixed an issue allowing tap dances to be invoked by combos in [#1518](https://github.com/zmkfirmware/zmk/pull/1518). + +[petejohanson] tweaked the caps word behavior to ignore modifiers in [#1330](https://github.com/zmkfirmware/zmk/pull/1330). + +[HelloThisIsFlo](https://github.com/HelloThisIsFlo) documented a bug with combos involving overlapping keys and different timeouts, produced a reproducing unit test, then proceeded to fix it in [#1945](https://github.com/zmkfirmware/zmk/pull/1945). + +### Bluetooth and Split Improvements + +#### Multiple peripherals + +[xudongzheng] contributed to add support for more than one peripheral per keyboard in [#836](https://github.com/zmkfirmware/zmk/pull/836). This allows setups such as split keyboards with more than two halves, or enable a BLE-based "dongle mode" via a third device running ZMK that can stay connected to a computer via USB. + +Note that documentation is still lacking for utilizing more than one peripheral and there will potentially be future changes in the build system to allow for more seamless configuration. + +#### Pairing passkey requirement + +[petejohanson] added [the option to require passkey input](/docs/config/bluetooth) while pairing to new devices in [#1822](https://github.com/zmkfirmware/zmk/pull/1822). Enabling this will require you to enter a six digit passcode via the number keys on your keymap and press enter when pairing to a new device, enhancing security during the pairing procedure. + +#### Split keyboard improvements + +[petejohanson] contributed a fix to release held keys on peripheral disconnect [#1340](https://github.com/zmkfirmware/zmk/pull/1340), which makes scenarios where a split disconnects unexpectedly less painful. + +[petejohanson] also improved [the `settings_reset` shield](/docs/troubleshooting#split-keyboard-halves-unable-to-pair) by making it clear bonds more reliably, and allow it to build for all boards in [#1879](https://github.com/zmkfirmware/zmk/pull/1879). + +[petejohanson] and [xudongzheng] contributed additional split connectivity improvements, via using directed advertising in [#1913](https://github.com/zmkfirmware/zmk/pull/1913) and improving the robustness of central scanning in [#1912](https://github.com/zmkfirmware/zmk/pull/1912). + +### Hardware Support + +#### Encoders + +[petejohanson] contributed a major refactor of encoder (and more generally sensor) functionality in [#1039](https://github.com/zmkfirmware/zmk/pull/1039). While the documentation for these changes are still in progress, check out the [dedicated blog post](/blog/2023/06/18/encoder-refactors) for more details. + +This refactor paved way to implementing a long-awaited feature, encoder support in peripheral halves of split keyboards! Building upon the work by [stephen](https://github.com/stephen) in [#728](https://github.com/zmkfirmware/zmk/pull/728), [petejohanson] implemented support in [#1841](https://github.com/zmkfirmware/zmk/pull/1841). + +#### Direct GPIO driver + +[joelspadin] extended the comprehensive debouncing framework used for matrix scan driver to the [direct GPIO driver](/docs/config/kscan#direct-gpio-driver) in [#1288](https://github.com/zmkfirmware/zmk/pull/1288). + +[kurtis-lew] added toggle mode support for direct GPIO driver in [#1305](https://github.com/zmkfirmware/zmk/pull/1305). This allows for adding toggle switches to a keyboard, by properly reading their initial state on boot and making sure the power use is efficient. + +#### IO peripheral drivers + +[petejohanson] added support for the 595 shift register commonly used with smaller controllers like Seeeduino Xiaos, in [#1325](https://github.com/zmkfirmware/zmk/pull/1325). + +[zhiayang](https://github.com/zhiayang) added the driver for the MAX7318 GPIO expander in [#1295](https://github.com/zmkfirmware/zmk/pull/1295). + +#### Underglow auto-off options + +[ReFil] added two [new RGB auto off options](/docs/config/underglow), one using an idle timeout and the other USB status in [#1010](https://github.com/zmkfirmware/zmk/pull/1010). + +#### nice!view support + +[nicell] added support for nice!view, a memory display optimized for low power use in [#1462](https://github.com/zmkfirmware/zmk/pull/1462). +He also contributed a custom vertically-oriented status screen that is automatically enabled when the `nice_view` shield is used in [#1768](https://github.com/zmkfirmware/zmk/pull/1768), since the default status screen has a horizontal orientation. +Please see the instructions in the [nice!view README](https://github.com/zmkfirmware/zmk/blob/main/app/boards/shields/nice_view/README.md) if you would like to restore the stock status screen. + +#### E-paper display initialization + +[petejohanson] contributed EPD initialization improvements in [#1098](https://github.com/zmkfirmware/zmk/pull/1098), which makes the keyboards using slow refresh displays such as the Corne-ish Zen much more responsive during initial boot. + +#### Xiao BLE improvements + +Various improvements were made for the Seeeduino Xiao BLE board in [#1293](https://github.com/zmkfirmware/zmk/pull/1293), [d0176f36](https://github.com/zmkfirmware/zmk/commit/d0176f36), [#1545](https://github.com/zmkfirmware/zmk/pull/1545) and [#1927](https://github.com/zmkfirmware/zmk/pull/1927) by [petejohanson] and [caksoylar], enabling features necessary for ZMK and improving its power use. + +### Zephyr 3.2 Upgrade + +[petejohanson] once again contributed the massive work necessary for upgrading ZMK to Zephyr 3.2 in [#1499](https://github.com/zmkfirmware/zmk/pull/1499), with review help from [joelspadin] and testing by the community. This Zephyr release brings with it upgrades to the display library LVGL, adds official support for the RP2040 controllers and many internal refactors to help future development. +Check out the [dedicated blog post](/blog/2023/04/06/zephyr-3-2) for more details! + +### Documentation + +#### Configuration docs + +[joelspadin], through a massive amount of work in [#722](https://github.com/zmkfirmware/zmk/pull/722), contributed a whole new section to the documentation: [configuration](/docs/config)! It enumerates the configuration options for each ZMK feature that might be relevant to users in dedicated pages, making it a very handy reference. + +In addition, the [overview page](/docs/config) presents an overview of how configuration works in Zephyr in the context of ZMK, in terms of devicetree files (like the keymap files or shield overlays), and Kconfig ones (like the `.conf` files). It is very helpful in de-mystifying what the various files do and what syntax is expected in them. + +#### New behavior guide + +For users or future contributors that might want to dive into writing their own ZMK behaviors, [kurtis-lew] wrote a useful [guide on how to create new behaviors](/docs/development/new-behavior) in [#1268](https://github.com/zmkfirmware/zmk/pull/1268). + +#### Tap dance and hold-tap documentation improvements + +[kurtis-lew] also improved the documentation for these two behaviors in [#1298](https://github.com/zmkfirmware/zmk/pull/1298), by updating the diagrams to better clarify how their timings work and adding examples for scenarios that are frequently asked by users. + +#### Battery sensor documentation + +[joelspadin] also added documentation for setting up battery sensors, typically required for new boards, in [#868](https://github.com/zmkfirmware/zmk/pull/868). + +#### Shield interconnects + +[petejohanson] updated the [new shield guide](/docs/development/new-shield) for non-Pro Micro interconnects including Xiao, Arduino Uno and Blackpill in [#1607](https://github.com/zmkfirmware/zmk/pull/1607). + +#### Bluetooth feature page + +[petejohanson] and [caksoylar] added a new [Bluetooth feature page](/docs/features/bluetooth) as part of [#1499](https://github.com/zmkfirmware/zmk/pull/1499) and in [#1818](https://github.com/zmkfirmware/zmk/pull/1499), detailing ZMK's Bluetooth implementation and troubleshooting for common problems. + +In addition to the specific contributions listed above, various improvements and fixes to documentation are made by many users from the community, including but not limited to [kurtis-lew], [joelspadin], [filterpaper], [byran.tech](https://github.com/byran.tech), [dxmh] and [caksoylar]. These contributions are are all very appreciated! + +### Miscellaneous + +#### Reusable GitHub build workflow + +[elagil](https://github.com/elagil) helped switch the build workflow used by the [user config repos](/docs/user-setup) to a reusable one in [#1183](https://github.com/zmkfirmware/zmk/pull/1183) and it was further tweaked by [filterpaper] in [#1258](https://github.com/zmkfirmware/zmk/pull/1258). This allows any changes in the workflow to be propagated automatically to users, rather than requiring them to make the updates. The build workflow can be customized by the users [using input parameters](https://github.com/zmkfirmware/zmk/blob/main/.github/workflows/build-user-config.yml#L5) if desired. + +#### Pre-commit hooks + +[joelspadin] added various [pre-commit](https://pre-commit.com/) hooks and added checks to the repo to run them for each commit in [#1651](https://github.com/zmkfirmware/zmk/pull/1651). These hooks and resulting updates standardize formatting across devicetree and other source files, reducing busywork on both contributors and reviewers. + +#### Zephyr usage and other refactors + +[joelspadin] also contributed a few refactor PRs such as [#1269](https://github.com/zmkfirmware/zmk/pull/1269), [#1255](https://github.com/zmkfirmware/zmk/pull/1255) and [#1803](https://github.com/zmkfirmware/zmk/pull/1803), generally improving code quality and bringing the codebase in line with the latest Zephyr conventions. + +[petejohanson] refactored the drivers structure to bring it in line with the current Zephyr conventions for out-of-tree drivers in [#1919](https://github.com/zmkfirmware/zmk/pull/1919). + +#### Updated USB polling interval default + +USB HID polling interval now defaults to 1 ms, i.e. a 1000Hz polling rate, thanks to [joelspadin]'s tweak in [#1271](https://github.com/zmkfirmware/zmk/pull/1271). + +#### Additional display config options + +[caksoylar] added a couple configuration options for displays, including a setting to invert display colors in [#1754](https://github.com/zmkfirmware/zmk/pull/1754) and an option to display the battery percentage for the stock status screen in [#1563](https://github.com/zmkfirmware/zmk/pull/1563). + +## New Shields + +- Eternal keypad [#1136](https://github.com/zmkfirmware/zmk/pull/1136) - [halcyonCorsair](https://github.com/halcyonCorsair) +- nullbits SNAP [#1319](https://github.com/zmkfirmware/zmk/pull/1319) - [jaygreco](https://github.com/jaygreco) +- Aurora Sweep [#1504](https://github.com/zmkfirmware/zmk/pull/1504), Corne [#1520](https://github.com/zmkfirmware/zmk/pull/1520), Lily58 [#1553](https://github.com/zmkfirmware/zmk/pull/1553), Sofle [#1864](https://github.com/zmkfirmware/zmk/pull/1864), and Helix [#1873](https://github.com/zmkfirmware/zmk/pull/1873) - [petejohanson] +- ZMK Uno shield [#1576](https://github.com/zmkfirmware/zmk/pull/1576) - [petejohanson] +- Waterfowl [#1554](https://github.com/zmkfirmware/zmk/pull/1554) - [JW2586](https://github.com/JW2586) +- Kyria Rev 3 [#1627](https://github.com/zmkfirmware/zmk/pull/1627) - [petejohanson] +- Leeloo v2 and Leeloo-Micro [#1762](https://github.com/zmkfirmware/zmk/pull/1762) - [ClicketySplit](https://github.com/ClicketySplit) +- Spaceman Pancake [#1400](https://github.com/zmkfirmware/zmk/pull/1400) - [jasonhazel](https://github.com/jasonhazel) +- Reviung5 [#1548](https://github.com/zmkfirmware/zmk/pull/1548) - [zblesk](https://github.com/zblesk) + +## New Boards + +- RP2040 boards, including Sparkfun Pro Micro, Adafruit KB2040 and Seeeduino Xiao RP2040 were added as part of the Zephyr 3.2 upgrade in [#1499](https://github.com/zmkfirmware/zmk/pull/1499) - [petejohanson] +- Puchi BLE [#1445](https://github.com/zmkfirmware/zmk/pull/1445) - [BenRoe](https://github.com/BenRoe) +- nRFMicro 1.3/1.4 (nRF52833) [#912](https://github.com/zmkfirmware/zmk/pull/912) - [pashutk](https://github.com/pashutk) +- nRF5340 DK [#1562](https://github.com/zmkfirmware/zmk/pull/1562) - [joelspadin] +- PillBug [#1530](https://github.com/zmkfirmware/zmk/pull/1530) - [kylemccreery](https://github.com/kylemccreery) +- Preonic Rev 3 [#1575](https://github.com/zmkfirmware/zmk/pull/1575) - [jeromeOlivier](https://github.com/jeromeOlivier) +- Corne-ish Zen v2 [#1498](https://github.com/zmkfirmware/zmk/pull/1498) and v1 [#1593](https://github.com/zmkfirmware/zmk/pull/1593) - [LOWPROKB](https://github.com/LOWPROKB) and [caksoylar] +- Polarity Works CKP family of boards [#1547](https://github.com/zmkfirmware/zmk/pull/1547) - [ReFil] + +## Coming Soon! + +Some items listed in the last coming soon section are still under active development and other new exciting items are in progress: + +- Automatic/simple BLE profile management +- Soft off support for turning the keyboard "off" through firmware +- Improved automatic power management for devices with multiple peripherals, e.g. OLED displays and RGB LEDs +- Caps/Scroll/Num Lock LED support +- Mouse keys +- Wired split support +- More modular approach to external boards/shields, custom code, user keymaps, etc. +- More shields and boards + +## Statistics + +Some statistics of interest for ZMK: + +- GitHub (lifetime stats) + - 166 Contributors + - 1256 Closed PRs + - 1883 Stars + - 1949 Forks +- Discord Chat + - 8055 total registered (130% up from last SOTF!) +- Website (last 30 days) + - 52K page views + - 4.7K new users + +## Sponsorship + +While ZMK is an open source project that uses the permissive MIT license, below are opportunities for anyone who would like to show their support to the project financially. + +### Open Collective + +The ZMK project has an [Open Collective sponsorship](https://opencollective.com/zmkfirmware) that has been going for two and a half years. +This fund helps pay for project costs like domain registration or development of hardware such as the [ZMK Uno shield](https://github.com/zmkfirmware/zmk-uno). +Note that donations to this fund do _not_ pay for the work of any individual contributor directly. + +### Contributor sponsorships + +Project creator and lead Pete Johanson has a [GitHub sponsorship](https://github.com/sponsors/petejohanson) set up that you can contribute to, in order to directly support his time and efforts in developing and maintaining ZMK. +He has also been traveling full time while focusing on ZMK and keyboard hardware design for more than a year now! +If you are curious, you can check out [his blog post](https://petejohanson.dev/blog/new-journey-2022) on deciding to embark on this adventure, in addition to his thoughts on contributor vs. project sponsorship, and sustainability of open source projects in general. + +## Thanks! + +As the first person to author a State Of The Firmware post besides Pete, I'd like to take the opportunity to thank him for his efforts on leading and developing ZMK, along with fostering a great community of contributors and users around it. + +Also a big thank you to contributors that submit patches and perform reviews, testers that help validate changes, and users that take time out of their day to help out folks with ZMK usage on [Discord channels](https://zmk.dev/community/discord/invite), GitHub issues and other communities. + +[okke-formsma]: https://github.com/okke-formsma +[andrewjrae]: https://github.com/andrewjrae +[xudongzheng]: https://github.com/xudongzheng +[nicell]: https://github.com/Nicell +[petejohanson]: https://github.com/petejohanson +[kurtis-lew]: https://github.com/kurtis-lew +[joelspadin]: https://github.com/joelspadin +[dxmh]: https://github.com/dxmh +[caksoylar]: https://github.com/caksoylar +[urob]: https://github.com/urob +[filterpaper]: https://github.com/filterpaper +[ReFil]: https://github.com/ReFil diff --git a/docs/docs/behaviors/backlight.md b/docs/docs/behaviors/backlight.md index cb9a85a830e..8c613fe6bd1 100644 --- a/docs/docs/behaviors/backlight.md +++ b/docs/docs/behaviors/backlight.md @@ -36,6 +36,12 @@ Here is a table describing the action for each define: - Parameter #1: The backlight action define, e.g. `BL_TOG` or `BL_INC` - Parameter #2: Only applies to `BL_SET`and is the brightness value +:::note Backlight settings persistence +The backlight settings that are changed via the `&bl` behavior will be saved to flash storage and hence persist across restarts and firmware flashes. +They will also override the start values set by [`CONFIG_ZMK_BACKLIGHT_*_START` settings](../config/backlight.md#kconfig). +However the settings will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory. +::: + ### Examples 1. Toggle backlight on/off diff --git a/docs/docs/behaviors/bluetooth.md b/docs/docs/behaviors/bluetooth.md index 7c77c4ad2b7..89496948d50 100644 --- a/docs/docs/behaviors/bluetooth.md +++ b/docs/docs/behaviors/bluetooth.md @@ -35,6 +35,11 @@ Here is a table describing the command for each define: | `BT_PRV` | Switch to the previous profile, cycling through to the last one when the beginning is reached. | | `BT_SEL` | Select the 0-indexed profile by number. Please note: this definition must include a number as an argument in the keymap to work correctly. eg. `BT_SEL 0` | +:::note Selected profile persistence +The profile that is selected by the `BT_SEL`/`BT_PRV`/`BT_NXT` actions will be saved to flash storage and hence persist across restarts and firmware flashes. +However it will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory. +::: + ## Bluetooth Behavior The bluetooth behavior completes an bluetooth action given on press. diff --git a/docs/docs/behaviors/caps-word.md b/docs/docs/behaviors/caps-word.md index e85d7ecae98..e5d862d785b 100644 --- a/docs/docs/behaviors/caps-word.md +++ b/docs/docs/behaviors/caps-word.md @@ -7,7 +7,7 @@ sidebar_label: Caps Word The caps word behavior behaves similar to a caps lock, but will automatically deactivate when any key not in a continue list is pressed, or if the caps word key is pressed again. For smaller keyboards using [mod-taps](/docs/behaviors/mod-tap), this can help avoid repeated alternating holds when typing words in all caps. -The modifiers are applied only to to the alphabetic (`A` to `Z`) keycodes, to avoid automatically appliying them to numeric values, etc. +The modifiers are applied only to to the alphabetic (`A` to `Z`) keycodes, to avoid automatically applying them to numeric values, etc. ### Behavior Binding diff --git a/docs/docs/behaviors/hold-tap.md b/docs/docs/behaviors/hold-tap.md index 2a8489a15ab..ec66b34f2af 100644 --- a/docs/docs/behaviors/hold-tap.md +++ b/docs/docs/behaviors/hold-tap.md @@ -47,30 +47,30 @@ Defines how long a key must be pressed to trigger Hold behavior. #### `quick-tap-ms` -If you press a tapped hold-tap again within `quick-tap-ms` milliseconds, it will always trigger the tap behavior. This is useful for things like a backspace, where a quick tap+hold holds backspace pressed. Set this to a negative value to disable. The default is -1 (disabled). +If you press a tapped hold-tap again within `quick-tap-ms` milliseconds of the first press, it will always trigger the tap behavior. This is useful for things like a backspace, where a quick tap+hold holds backspace pressed. Set this to a negative value to disable. The default is -1 (disabled). -#### `global-quick-tap` +#### `require-prior-idle-ms` -If `global-quick-tap` is enabled, then `quick-tap-ms` will apply not only when the given hold-tap is tapped, but for any key tapped before it. This effectively disables the hold-tap when typing quickly, which can be quite useful for homerow mods. It can also have the effect of removing the input delay when typing quickly. +`require-prior-idle-ms` is like `quick-tap-ms` however it will apply for _any_ non-modifier key pressed before it. This effectively disables the hold-tap when typing quickly, which can be quite useful for homerow mods. It can also have the effect of removing the input delay when typing quickly. -For example, the following hold-tap configuration enables `global-quick-tap` with a 125 millisecond `quick-tap-ms` term. +For example, the following hold-tap configuration enables `require-prior-idle-ms` with a 125 millisecond term, alongside `quick-tap-ms` with a 200 millisecond term. ``` -gqt: global-quick-tap { +rpi: require_prior_idle { compatible = "zmk,behavior-hold-tap"; - label = "GLOBAL_QUICK_TAP"; + label = "REQUIRE_PRIOR_IDLE"; #binding-cells = <2>; flavor = "tap-preferred"; tapping-term-ms = <200>; - quick-tap-ms = <125>; - global-quick-tap; + quick-tap-ms = <200>; + require-prior-idle-ms = <125>; bindings = <&kp>, <&kp>; }; ``` -If you press `&kp A` and then `&gqt LEFT_SHIFT B` **within** 125 ms, then `ab` will be output. Importantly, `b` will be output immediately since it was within the `quick-tap-ms`. This quick-tap behavior will work for any key press, whether it is within a behavior like hold-tap, or a simple `&kp`. This means the `&gqt LEFT_SHIFT B` binding will only have its underlying hold-tap behavior if it is pressed 125 ms **after** a key press. +If you press `&kp A` and then `&rpi LEFT_SHIFT B` **within** 125 ms, then `ab` will be output. Importantly, `b` will be output immediately since it was within the `require-prior-idle-ms`, without waiting for a timeout or an interrupting key. In other words, the `&rpi LEFT_SHIFT B` binding will only have its underlying hold-tap behavior if it is pressed 125 ms **after** the previous key press; otherwise it will act like `&kp B`. -Note that the greater the value of `quick-tap-ms` is, the harder it will be to invoke the hold behavior, making this feature less applicable for use-cases like capitalizing letters while typing normally. However, if the hold behavior isn't used during fast typing, then it can be an effective way to mitigate misfires. +Note that the greater the value of `require-prior-idle-ms` is, the harder it will be to invoke the hold behavior, making this feature less applicable for use-cases like capitalizing letters while typing normally. However, if the hold behavior isn't used during fast typing, then it can be an effective way to mitigate misfires. #### `retro-tap` diff --git a/docs/docs/behaviors/layers.md b/docs/docs/behaviors/layers.md index cf793089be6..7d7901568f9 100644 --- a/docs/docs/behaviors/layers.md +++ b/docs/docs/behaviors/layers.md @@ -57,6 +57,22 @@ Example: < LOWER SPACE ``` +### Configuration + +You can configure a different tapping term or tweak other properties noted in the [hold-tap](hold-tap.md#advanced-configuration) documentation page in your keymap: + +``` +< { + tapping-term-ms = <200>; +}; + +/ { + keymap { + ... + }; +}; +``` + :::info Functionally, the layer-tap is a [hold-tap](hold-tap.md) of the ["tap-preferred" flavor](hold-tap.md/#flavors) and a [`tapping-term-ms`](hold-tap.md/#tapping-term-ms) of 200 that takes in a [`momentary layer`](#momentary-layer) and a [keypress](key-press.md) as its "hold" and "tap" parameters, respectively. diff --git a/docs/docs/behaviors/macros.md b/docs/docs/behaviors/macros.md index 40c333a9066..377ce7fecdb 100644 --- a/docs/docs/behaviors/macros.md +++ b/docs/docs/behaviors/macros.md @@ -49,22 +49,6 @@ For use cases involving sending a single keycode with modifiers, for instance ct with [modifier functions](../codes/modifiers.mdx#modifier-functions) can be used instead of a macro. ::: -### Parameterized Macros - -Macros can also be "parameterized", allowing them to be bound in your keymap with unique values passed into them, e.g.: - -``` - raise_layer { - bindings = <&my_cool_macro A> - }; -``` - -When defining a parameterized macro, a different `compatible` value will be used depending on how many parameters are passed into it: - -- `zmk,behavior-macro` - a parameter that takes no parameters. -- `zmk,behavior-macro-one-param` - a parameter that takes one parameter when used. -- `zmk,behavior-macro-two-param` - a parameter that takes two parameters when used. - ### Bindings Like [hold-taps](/docs/behaviors/hold-tap), macros are created by composing other behaviors, and any of those behaviors can @@ -83,30 +67,6 @@ bindings There are a set of special macro controls that can be included in the `bindings` list to modify the way the macro is processed. -### Parameters - -When creating a macro that takes parameter(s), there are macro controls that change when the parameters passed to the macro are used -within the macro itself. All of the controls are "one shot" and will change how the passed in parameters are used for the very next non-macro control behavior in the `bindings` list of the macro. - -For example, to pass the first parameter from the macro into a `&kp` used in the macro, you would use: - -``` -bindings - = <¯o_param_1to1> - , <&kp MACRO_PLACEHOLDER> - ; -``` - -Because `kp` takes one parameter, you can't simply make the second entry `<&kp>` in the `bindings` list. Whatever value you do pass in will be replaced when the macro is triggered, so you can put _any_ value there, e.g. `0`, `A` keycode, etc. To make it very obvious that the parameter there is not actually going to be used, you can use `MACRO_PLACEHOLDER` which is simply an alias for `0`. - -The available parameter controls are: - -- `¯o_param_1to1` - pass the first parameter of the macro into the first parameter of the next behavior in the `bindings` list. -- `¯o_param_1to2` - pass the first parameter of the macro into the second parameter of the next behavior in the `bindings` list. - -* `¯o_param_2to1` - pass the second parameter of the macro into the first parameter of the next behavior in the `bindings` list. -* `¯o_param_2to2` - pass the second parameter of the macro into the second parameter of the next behavior in the `bindings` list. - ### Binding Activation Mode Bindings in a macro are activated differently, depending on the current "activation mode" of the macro. @@ -151,7 +111,8 @@ bindings ### Wait Time -The wait time setting controls how long of a delay is introduced between behaviors in the `bindings` list. The initial wait time for a macro, 100ms by default, can +The wait time setting controls how long of a delay is introduced between behaviors in the `bindings` list. The initial wait time for a macro, +which is equal to the value of [`CONFIG_ZMK_MACRO_DEFAULT_WAIT_MS`](../config/behaviors.md#macro) by default, can be set by assigning a value to the `wait-ms` property of the macro, e.g. `wait-ms = <20>;`. If you want to update the wait time at any point in the macro bindings list, use `¯o_wait_time`, e.g. `¯o_wait_time 30`. A full example: @@ -166,7 +127,8 @@ bindings ### Tap Time -The tap time setting controls how long a tapped behavior is held in the `bindings` list. The initial tap time for a macro, 100ms by default, can +The tap time setting controls how long a tapped behavior is held in the `bindings` list. The initial tap time for a macro, +which is equal to the value of [`CONFIG_ZMK_MACRO_DEFAULT_TAP_MS`](../config/behaviors.md#macro) by default, can be set by assigning a value to the `tap-ms` property of the macro, e.g. `tap-ms = <20>;`. If you want to update the tap time at any point in a macro bindings list, use `¯o_tap_time`, e.g. `¯o_tap_time 30`. A full example: @@ -185,6 +147,72 @@ Macros use an internal queue to invoke each behavior in the bindings list when t To prevent issues with longer macros, you can change the size of this queue via the `CONFIG_ZMK_BEHAVIORS_QUEUE_SIZE` setting in your configuration, [typically through your `.conf` file](../config/index.md). For example, `CONFIG_ZMK_BEHAVIORS_QUEUE_SIZE=512` would allow your macro to type about 256 characters. +Another limit worth noting is that the maximum number of bindings you can pass to a `bindings` field in the [Devicetree](../config/index.md#devicetree-files) is 256, which also constrains how many behaviors can be invoked by a macro. + +## Parameterized Macros + +Macros can also be "parameterized", allowing them to be bound in your keymap with unique values passed into them, e.g.: + +``` + raise_layer { + bindings = <&my_one_param_macro A> + }; +``` + +### Defining Parameterized Macros + +Parameterized macros must be defined using specific values for the `compatible` and `#binding-cells` properties, depending on how many parameters they require (up to a maximum of two): + +```dts +/ { + macros { + // 0 params macro + my_macro: my_macro { + // ... + compatible = "zmk,behavior-macro"; + #binding-cells = <0>; // Must be 0 + bindings = /* ... */; + }; + + // 1 param macro + my_one_param_macro: my_one_param_macro { + // ... + compatible = "zmk,behavior-macro-one-param"; + #binding-cells = <1>; // Must be 1 + bindings = /* ... */; + }; + + // 2 params macro + my_two_param_macro: my_two_param_macro { + // ... + compatible = "zmk,behavior-macro-two-param"; + #binding-cells = <2>; // Must be 2 + bindings = /* ... */; + }; + }; +}; +``` + +### Parameters, Bindings and Controls + +There are special macro controls which must be used in order to forward received parameters to the macro's `bindings`. These controls are "one shot" and will determine how received parameters are used on the very next (non-macro control) behavior in the macro's `bindings` list. + +For example, to pass the first parameter received into a `&kp` binding, you would use: + +```dts +bindings = <¯o_param_1to1>, <&kp MACRO_PLACEHOLDER>; +``` + +Because `kp` takes one parameter, you can't simply make the second entry `<&kp>` in the `bindings` list. Whatever value you do pass in will be replaced when the macro is triggered, so you can put _any_ value there, e.g. `0`, `A` keycode, etc. To make it very obvious that the parameter there is not actually going to be used, you can use `MACRO_PLACEHOLDER` which is simply an alias for `0`. + +The available parameter controls are: + +- `¯o_param_1to1` - pass the first parameter of the macro into the first parameter of the next behavior in the `bindings` list. +- `¯o_param_1to2` - pass the first parameter of the macro into the second parameter of the next behavior in the `bindings` list. + +* `¯o_param_2to1` - pass the second parameter of the macro into the first parameter of the next behavior in the `bindings` list. +* `¯o_param_2to2` - pass the second parameter of the macro into the second parameter of the next behavior in the `bindings` list. + ## Common Patterns Below are some examples of how the macro behavior can be used for various useful functionality. @@ -198,12 +226,36 @@ To achieve this, a combination of a 0ms wait time and splitting the press and re #### Layer + Modifier -``` -wait-ms = <0>; -bindings - = <¯o_press &mo 1 &kp LSHFT> - , <¯o_pause_for_release> - , <¯o_release &mo 1 &kp LSHFT>; +```dts +/** + * Temporarily switches to a layer (`&mo`) while a modifier is held. + * Analogous to QMK's `LM()`, using a parameterized macro. + * + * Params: + * 1. Layer to switch to + * 2. Modifier to press while layer is active + * + * Example: + * `&lm NUM_LAYER LSHIFT` + */ +lm: lm { + label = "LAYER_MOD"; + compatible = "zmk,behavior-macro-two-param"; + wait-ms = <0>; + tap-ms = <0>; + #binding-cells = <2>; + bindings + = <¯o_param_1to1> + , <¯o_press &mo MACRO_PLACEHOLDER> + , <¯o_param_2to1> + , <¯o_press &kp MACRO_PLACEHOLDER> + , <¯o_pause_for_release> + , <¯o_param_2to1> + , <¯o_release &kp MACRO_PLACEHOLDER> + , <¯o_param_1to1> + , <¯o_release &mo MACRO_PLACEHOLDER> + ; +}; ``` #### Layer + Underglow Color @@ -252,20 +304,24 @@ bindings ## Convenience C Macro -To avoid repetition or possible typos when declaring a macro, a convenience _C_ macro, named `ZMK_MACRO(name, props)` can be used to simplify things: +To avoid repetition or possible typos when declaring a **zero parameter macro**, a convenience _C_ macro, named `ZMK_MACRO(name, props)` can be used to simplify things: ``` - ZMK_MACRO(my_macro, + ZMK_MACRO(my_zero_param_macro, wait-ms = <30>; tap-ms = <40>; bindings = <&kp Z &kp M &kp K>; ) ``` +:::note +`ZMK_MACRO()` **only supports declaring non-parameterized (zero parameter) macros**; parameterized declarations are not currently supported. +::: + This can be used instead of a complete macro definition. During the firmware build process, the example above would produce the complete macro definition below: ``` - my_macro: my_macro { + my_zero_param_macro: my_zero_param_macro { compatible = "zmk,behavior-macro"; label = "ZM_my_macro"; #binding-cells = <0>; diff --git a/docs/docs/behaviors/outputs.md b/docs/docs/behaviors/outputs.md index 198d9acc617..dad52be2ccb 100644 --- a/docs/docs/behaviors/outputs.md +++ b/docs/docs/behaviors/outputs.md @@ -44,6 +44,11 @@ The output selection behavior changes the preferred output on press. - Reference: `&out` - Parameter #1: Command, e.g. `OUT_BLE` +:::note External power state persistence +The endpoint that is selected by the `&out` behavior will be saved to flash storage and hence persist across restarts and firmware flashes. +However it will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory. +::: + ### Examples 1. Behavior binding to prefer sending keyboard output to USB diff --git a/docs/docs/behaviors/power.md b/docs/docs/behaviors/power.md index 805806095ac..11f920845a3 100644 --- a/docs/docs/behaviors/power.md +++ b/docs/docs/behaviors/power.md @@ -43,6 +43,11 @@ Here is a table describing the command for each define: - Reference: `&ext_power` - Parameter#1: Command, e.g `EP_ON` +:::note External power state persistence +The on/off state that is set by the `&ext_power` behavior will be saved to flash storage and hence persist across restarts and firmware flashes. +However it will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory. +::: + ### Example: 1. Behavior binding to enable the external power diff --git a/docs/docs/behaviors/underglow.md b/docs/docs/behaviors/underglow.md index 52429e69987..29f34c2ab0b 100644 --- a/docs/docs/behaviors/underglow.md +++ b/docs/docs/behaviors/underglow.md @@ -55,6 +55,12 @@ Value Limits: ::: +:::note RGB settings persistence +The RGB settings that are changed via the `&rgb_ug` behavior will be saved to flash storage and hence persist across restarts and firmware flashes. +They will also override the start values set by [`CONFIG_ZMK_RGB_*_START` settings](../config/underglow.md#kconfig). +However the settings will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory. +::: + ## Examples 1. Toggle underglow on/off diff --git a/docs/docs/config/behaviors.md b/docs/docs/config/behaviors.md index 2ff99d58cbb..f3f1f563ec8 100644 --- a/docs/docs/config/behaviors.md +++ b/docs/docs/config/behaviors.md @@ -58,17 +58,17 @@ Definition file: [zmk/app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml](htt Applies to: `compatible = "zmk,behavior-hold-tap"` -| Property | Type | Description | Default | -| ---------------------------- | ------------- | ----------------------------------------------------------------------------------------- | ------------------ | -| `label` | string | Unique label for the node | | -| `#binding-cells` | int | Must be `<2>` | | -| `bindings` | phandle array | A list of two behaviors (without parameters): one for hold and one for tap | | -| `flavor` | string | Adjusts how the behavior chooses between hold and tap | `"hold-preferred"` | -| `tapping-term-ms` | int | How long in milliseconds the key must be held to trigger a hold | | -| `quick-tap-ms` | int | Tap twice within this period (in milliseconds) to trigger a tap, even when held | -1 (disabled) | -| `global-quick-tap` | bool | If enabled, `quick-tap-ms` also applies when tapping another key and then this one. | false | -| `retro-tap` | bool | Triggers the tap behavior on release if no other key was pressed during a hold | false | -| `hold-trigger-key-positions` | array | If set, pressing the hold-tap and then any key position _not_ in the list triggers a tap. | | +| Property | Type | Description | Default | +| ---------------------------- | ------------- | -------------------------------------------------------------------------------------------------------------- | ------------------ | +| `label` | string | Unique label for the node | | +| `#binding-cells` | int | Must be `<2>` | | +| `bindings` | phandle array | A list of two behaviors (without parameters): one for hold and one for tap | | +| `flavor` | string | Adjusts how the behavior chooses between hold and tap | `"hold-preferred"` | +| `tapping-term-ms` | int | How long in milliseconds the key must be held to trigger a hold | | +| `quick-tap-ms` | int | Tap twice within this period (in milliseconds) to trigger a tap, even when held | -1 (disabled) | +| `require-prior-idle-ms` | int | Triggers a tap immediately if any non-modifier key was pressed within `require-prior-idle-ms` of the hold-tap. | -1 (disabled) | +| `retro-tap` | bool | Triggers the tap behavior on release if no other key was pressed during a hold | false | +| `hold-trigger-key-positions` | array | If set, pressing the hold-tap and then any key position _not_ in the list triggers a tap. | | The `flavor` property may be one of: @@ -131,26 +131,31 @@ See the [macro behavior](../behaviors/macros.md) documentation for more details Definition file: [zmk/app/dts/bindings/behaviors/zmk,behavior-macro.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-macro.yaml) -Applies to: `compatible = "zmk,behavior-macro"` +| Property | Type | Description | Default | +| ---------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | +| `label` | string | Unique label for the node | | +| `compatible` | string | Macro type, **must be _one_ of**:
• `"zmk,behavior-macro"`
• `"zmk,behavior-macro-one-param"`
• `"zmk,behavior-macro-two-param"` | | +| `#binding-cells` | int | Number of params accepted (depends on `compatible` property), **must be _one_ of**:
• `<0>`
• `<1>`
• `<2>` | | +| `bindings` | phandle array | List of behaviors to trigger | | +| `wait-ms` | int | The default time to wait (in milliseconds) before triggering the next behavior. | `CONFIG_ZMK_MACRO_DEFAULT_WAIT_MS` | +| `tap-ms` | int | The default time to wait (in milliseconds) between the press and release events of a tapped behavior. | `CONFIG_ZMK_MACRO_DEFAULT_TAP_MS` | -| Property | Type | Description | Default | -| ---------------- | ------------- | ----------------------------------------------------------------------------------------------------- | ---------------------------------- | -| `label` | string | Unique label for the node | | -| `#binding-cells` | int | Must be `<0>` | | -| `bindings` | phandle array | List of behaviors to trigger | | -| `wait-ms` | int | The default time to wait (in milliseconds) before triggering the next behavior. | `CONFIG_ZMK_MACRO_DEFAULT_WAIT_MS` | -| `tap-ms` | int | The default time to wait (in milliseconds) between the press and release events of a tapped behavior. | `CONFIG_ZMK_MACRO_DEFAULT_TAP_MS` | +### Macro Control Behaviors The following macro-specific behaviors can be added at any point in the `bindings` list to change how the macro triggers subsequent behaviors. -| Behavior | Description | -| -------------------------- | ----------------------------------------------------------------------------------------------------- | -| `¯o_tap` | Switches to tap mode | -| `¯o_press` | Switches to press mode | -| `¯o_release` | Switches to release mode | -| `¯o_pause_for_release` | Pauses the macro until the macro key itself is released | -| `¯o_wait_time TIME` | Changes the time to wait (in milliseconds) before triggering the next behavior. | -| `¯o_tap_time TIME` | Changes the time to wait (in milliseconds) between the press and release events of a tapped behavior. | +| Behavior | Description | +| -------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| `¯o_tap` | Switches to tap mode | +| `¯o_press` | Switches to press mode | +| `¯o_release` | Switches to release mode | +| `¯o_pause_for_release` | Pauses the macro until the macro key itself is released | +| `¯o_wait_time TIME` | Changes the time to wait (in milliseconds) before triggering the next behavior. | +| `¯o_tap_time TIME` | Changes the time to wait (in milliseconds) between the press and release events of a tapped behavior. | +| `¯o_param_1to1` | Forward the first parameter received by the macro to the first parameter of the next (non-macro control) behavior. | +| `¯o_param_1to2` | Forward the first parameter received by the macro to the second parameter of the next (non-macro control) behavior. | +| `¯o_param_2to1` | Forward the second parameter received by the macro to the first parameter of the next (non-macro control) behavior. | +| `¯o_param_2to2` | Forward the second parameter received by the macro to the second parameter of the next (non-macro control) behavior. | ## Mod-Morph diff --git a/docs/docs/config/combos.md b/docs/docs/config/combos.md index cd351125450..4f5ebba3d34 100644 --- a/docs/docs/config/combos.md +++ b/docs/docs/config/combos.md @@ -31,12 +31,13 @@ The `zmk,combos` node itself has no properties. It should have one child node pe Each child node can have the following properties: -| Property | Type | Description | Default | -| --------------- | ------------- | ----------------------------------------------------------------------------------------------------- | ------- | -| `bindings` | phandle-array | A [behavior](../features/keymaps.md#behaviors) to run when the combo is triggered | | -| `key-positions` | array | A list of key position indices for the keys which should trigger the combo | | -| `timeout-ms` | int | All the keys in `key-positions` must be pressed within this time in milliseconds to trigger the combo | 50 | -| `slow-release` | bool | Releases the combo when all keys are released instead of when any key is released | false | -| `layers` | array | A list of layers on which the combo may be triggered. `-1` allows all layers. | `<-1>` | +| Property | Type | Description | Default | +| ----------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ------------- | +| `bindings` | phandle-array | A [behavior](../features/keymaps.md#behaviors) to run when the combo is triggered | | +| `key-positions` | array | A list of key position indices for the keys which should trigger the combo | | +| `timeout-ms` | int | All the keys in `key-positions` must be pressed within this time in milliseconds to trigger the combo | 50 | +| `require-prior-idle-ms` | int | If any non-modifier key is pressed within `require-prior-idle-ms` before a key in the combo, the key will not be considered for the combo | -1 (disabled) | +| `slow-release` | bool | Releases the combo when all keys are released instead of when any key is released | false | +| `layers` | array | A list of layers on which the combo may be triggered. `-1` allows all layers. | `<-1>` | The `key-positions` array must not be longer than the `CONFIG_ZMK_COMBO_MAX_KEYS_PER_COMBO` setting, which defaults to 4. If you want a combo that triggers when pressing 5 keys, then you must change the setting to 5. diff --git a/docs/docs/config/kscan.md b/docs/docs/config/kscan.md index 787d513661f..296cb4a179c 100644 --- a/docs/docs/config/kscan.md +++ b/docs/docs/config/kscan.md @@ -72,21 +72,32 @@ Applies to: `compatible = "zmk,kscan-gpio-direct"` Definition file: [zmk/app/drivers/zephyr/dts/bindings/kscan/zmk,kscan-gpio-direct.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/drivers/zephyr/dts/bindings/kscan/zmk%2Ckscan-gpio-direct.yaml) -| Property | Type | Description | Default | -| ------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------- | ----------- | -| `label` | string | Unique label for the node | | -| `input-gpios` | GPIO array | Input GPIOs (one per key) | | -| `debounce-press-ms` | int | Debounce time for key press in milliseconds. Use 0 for eager debouncing. | 5 | -| `debounce-release-ms` | int | Debounce time for key release in milliseconds. | 5 | -| `debounce-scan-period-ms` | int | Time between reads in milliseconds when any key is pressed. | 1 | -| `diode-direction` | string | The direction of the matrix diodes | `"row2col"` | -| `poll-period-ms` | int | Time between reads in milliseconds when no key is pressed and `CONFIG_ZMK_KSCAN_DIRECT_POLLING` is enabled. | 10 | -| `toggle-mode` | bool | Use toggle switch mode. | n | +| Property | Type | Description | Default | +| ------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------- | ------- | +| `label` | string | Unique label for the node | | +| `input-gpios` | GPIO array | Input GPIOs (one per key) | | +| `debounce-press-ms` | int | Debounce time for key press in milliseconds. Use 0 for eager debouncing. | 5 | +| `debounce-release-ms` | int | Debounce time for key release in milliseconds. | 5 | +| `debounce-scan-period-ms` | int | Time between reads in milliseconds when any key is pressed. | 1 | +| `poll-period-ms` | int | Time between reads in milliseconds when no key is pressed and `CONFIG_ZMK_KSCAN_DIRECT_POLLING` is enabled. | 10 | +| `toggle-mode` | bool | Use toggle switch mode. | n | By default, a switch will drain current through the internal pull up/down resistor whenever it is pressed. This is not ideal for a toggle switch, where the switch may be left in the "pressed" state for a long time. Enabling `toggle-mode` will make the driver flip between pull up and down as the switch is toggled to optimize for power. `toggle-mode` applies to all switches handled by the instance of the driver. To use a toggle switch with other, non-toggle, direct GPIO switches, create two instances of the direct GPIO driver, one with `toggle-mode` and the other without. Then, use a [composite driver](#composite-driver) to combine them. +Assuming the switches connect each GPIO pin to the ground, the [GPIO flags](https://docs.zephyrproject.org/3.2.0/hardware/peripherals/gpio.html#api-reference) for the elements in `input-gpios` should be `(GPIO_ACTIVE_LOW | GPIO_PULL_UP)`: + +```devicetree + kscan0: kscan { + compatible = "zmk,kscan-gpio-direct"; + input-gpios + = <&pro_micro 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; + }; +``` + ## Matrix Driver Keyboard scan driver where keys are arranged on a matrix with one GPIO per row and column. @@ -123,6 +134,24 @@ The `diode-direction` property must be one of: | `"row2col"` | Diodes point from rows to columns (cathodes are connected to columns) | | `"col2row"` | Diodes point from columns to rows (cathodes are connected to rows) | +Given the `diode-direction`, the [GPIO flags](https://docs.zephyrproject.org/3.2.0/hardware/peripherals/gpio.html#api-reference) for the elements in `row-` and `col-gpios` should be set appropriately. +The output pins (e.g. columns for `col2row`) should have the flag `GPIO_ACTIVE_HIGH`, and input pins (e.g. rows for `col2row`) should have the flags `(GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)`: + +```devicetree + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + col-gpios + = <&pro_micro 4 GPIO_ACTIVE_HIGH> + , <&pro_micro 5 GPIO_ACTIVE_HIGH> + ; + row-gpios + = <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +``` + ## Composite Driver Keyboard scan driver which combines multiple other keyboard scan drivers. @@ -297,9 +326,7 @@ Any keyboard which is not a grid of 1 unit keys will likely have some unused pos kscan0: kscan { compatible = "zmk,kscan-gpio-matrix"; - rows = <5>; - columns = <4>; - // define the matrix... + // define row-gpios with 5 elements and col-gpios with 4... }; default_transform: matrix_transform { @@ -359,9 +386,7 @@ Consider a keyboard with a [duplex matrix](https://wiki.ai03.com/books/pcb-desig kscan0: kscan { compatible = "zmk,kscan-gpio-matrix"; - rows = <12>; - columns = <8>; - // define the matrix... + // define row-gpios with 12 elements and col-gpios with 8... }; default_transform: matrix_transform { diff --git a/docs/docs/development/usb-logging.md b/docs/docs/development/usb-logging.md index 9a2980ae6c8..87cd0e7d853 100644 --- a/docs/docs/development/usb-logging.md +++ b/docs/docs/development/usb-logging.md @@ -20,13 +20,16 @@ It is recommended to only enable logging when needed, and not leaving it on by d ## Kconfig -The `CONFIG_ZMK_USB_LOGGING` KConfig value needs to be set, either by copy and pasting into the `app/prj.conf` file, or by running -`west build -t menuconfig` and manually enabling the setting in that UI at `ZMK -> Advanced -> USB Logging`. +The `CONFIG_ZMK_USB_LOGGING` Kconfig enables USB logging. This can be set at the keyboard level, typically in the `config/.conf` +file if you are using a [user config repository](user-setup.md). It can also be enabled at the ZMK level using the `app/prj.conf` file, or other +search locations described in the [configuration overview](config/index.md#config-file-locations). + +Logging can be further configured using Kconfig described in [the Zephyr documentation](https://docs.zephyrproject.org/3.2.0/services/logging/index.html). +For instance, setting `CONFIG_LOG_PROCESS_THREAD_STARTUP_DELAY_MS` to a large value such as `8000` might help catch issues that happen near keyboard +boot, before you can connect to view the logs. :::note -If you are debugging your own keyboard in your [user config repository](user-setup.md), use -`config/boards/shields//.conf` instead of `app/prj.conf`. In Github -Actions, you can search the `Kconfig file` build log to verify the options above have been enabled +In Github Actions, you can check the ` Kconfig file` step output to verify the options above have been enabled for you successfully. ::: diff --git a/docs/docs/features/combos.md b/docs/docs/features/combos.md index 44313cc1dac..bc1353b416e 100644 --- a/docs/docs/features/combos.md +++ b/docs/docs/features/combos.md @@ -30,6 +30,7 @@ Combos configured in your `.keymap` file, but are separate from the `keymap` nod - `layers = <0 1...>` will allow limiting a combo to specific layers. This is an _optional_ parameter, when omitted it defaults to global scope. - `bindings` is the behavior that is activated when the behavior is pressed. - (advanced) you can specify `slow-release` if you want the combo binding to be released when all key-positions are released. The default is to release the combo as soon as any of the keys in the combo is released. +- (advanced) you can specify a `require-prior-idle-ms` value much like for [hold-taps](behaviors/hold-tap.md#require-prior-idle-ms). If any non-modifier key is pressed within `require-prior-idle-ms` before a key in the combo, the combo will not trigger. :::info diff --git a/docs/docs/features/encoders.md b/docs/docs/features/encoders.md index 29906c909de..0c493330cc6 100644 --- a/docs/docs/features/encoders.md +++ b/docs/docs/features/encoders.md @@ -5,10 +5,6 @@ sidebar_label: Encoders Existing support for encoders in ZMK is focused around the five pin EC11 rotary encoder with push button design used in the majority of current keyboard and macropad designs. -:::note -Encoders are currently only support on the left/central sides of splits. For progress on this, see [#728](https://github.com/zmkfirmware/zmk/pull/728). -::: - ## Enabling EC11 Encoders To enable encoders for boards that have existing encoder support, uncomment the `CONFIG_EC11=y` and `CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y` lines in your board's .conf file in your `zmk-config/config` folder. Save and push your changes, then download and flash the new firmware. diff --git a/docs/docs/features/underglow.md b/docs/docs/features/underglow.md index 00d3aa0ab8a..2b1400fc7e8 100644 --- a/docs/docs/features/underglow.md +++ b/docs/docs/features/underglow.md @@ -39,6 +39,20 @@ use Kconfig. 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). +### Modifying the number of LEDs + +A common issue when enabling underglow is that some of the installed LEDs do not illuminate. This can happen when a board's default underglow configuration accounts only for either the downward facing LEDs or the upward facing LEDs under each key. On a split keyboard, a good sign that this may be the problem is that the unilluminated LEDs on each half are symmetrical. + +The number of underglow LEDs is controlled by the `chain-length` property in the `led_strip` node. You can [change the value of this property](../config/index.md#changing-devicetree-properties) in the `.keymap` file by adding a stanza like this one outside of any other node (i.e. above or below the `/` node): + +``` +&led_strip { + chain-length = <21>; +}; +``` + +where the value is the total count of LEDs (per half, for split keyboards). + ## Configuring RGB Underglow See [RGB underglow configuration](/docs/config/underglow). diff --git a/docs/docs/intro.md b/docs/docs/intro.md index 142dcafc97e..d65ac46e405 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -23,11 +23,11 @@ ZMK is currently missing some features found in other popular firmware. This tab | Split Keyboard Support | âś… | âś… | âś… | | [Keymaps and Layers](behaviors/layers.md) | âś… | âś… | âś… | | [Hold-Tap](behaviors/hold-tap.md) (which includes [Mod-Tap](behaviors/mod-tap.md) and [Layer-Tap](behaviors/layers.md/#layer-tap)) | âś… | âś… | âś… | -| [Tap-Dance](behaviors/tap-dance.md) | âś… | âś…[^3] | âś… | +| [Tap-Dance](behaviors/tap-dance.md) | âś… | âś…[^2] | âś… | | [Keyboard Codes](codes/index.mdx#keyboard) | âś… | âś… | âś… | | [Media](codes/index.mdx#media-controls) & [Consumer](codes/index.mdx#consumer-controls) Codes | âś… | âś… | âś… | -| [Encoders](features/encoders.md)[^1] | âś… | âś… | âś… | -| [Display Support](features/displays.md)[^2] | 🚧 | 🚧 | âś… | +| [Encoders](features/encoders.md) | âś… | âś… | âś… | +| [Display Support](features/displays.md)[^1] | 🚧 | 🚧 | âś… | | [RGB Underglow](features/underglow.md) | âś… | âś… | âś… | | [Backlight](features/backlight.md) | âś… | âś… | âś… | | One Shot Keys | âś… | âś… | âś… | @@ -43,8 +43,7 @@ ZMK is currently missing some features found in other popular firmware. This tab | AVR/8 Bit | | | âś… | | [Wide Range of ARM Chips Supported](https://docs.zephyrproject.org/latest/boards/index.html) | âś… | | | -[^3]: Tap-Dances are limited to single and double-tap on BlueMicro -[^2]: Encoders are not currently supported on peripheral side splits. +[^2]: Tap-Dances are limited to single and double-tap on BlueMicro [^1]: OLEDs are currently proof of concept in ZMK. ## Code Of Conduct diff --git a/docs/docs/troubleshooting.md b/docs/docs/troubleshooting.md index d47671bce36..1418f327feb 100644 --- a/docs/docs/troubleshooting.md +++ b/docs/docs/troubleshooting.md @@ -58,10 +58,14 @@ A `devicetree_unfixed.h` error that follows with an "undeclared here" string ind In this example, the error string `DT_N_S_keymap_S_symbol_layer_P_bindings_IDX_12_PH_P_label` indicates a problem with the key binding in position `12` in the `symbol_layer` of the keymap. -:::note +:::info Key positions are numbered starting from `0` at the top left key on the keymap, incrementing horizontally, row by row. ::: +:::tip +A common mistake that leads to this error is to use [key press keycodes](behaviors/key-press.md) without the leading `&kp` binding. That is, having entries such as `SPACE` that should have been `&kp SPACE`. +::: + ### Split Keyboard Halves Unable to Pair Split keyboard halves pairing issue can be resolved by flashing a settings reset firmware to both controllers. You will first need to acquire the reset UF2 image file with one of the following options: diff --git a/docs/package-lock.json b/docs/package-lock.json index 5badb07e389..f17adc4bde9 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "@docusaurus/core": "^2.4.0", "@docusaurus/preset-classic": "^2.4.0", - "@fortawesome/fontawesome-svg-core": "^6.4.0", + "@fortawesome/fontawesome-svg-core": "^6.4.2", "@fortawesome/free-solid-svg-icons": "^6.4.0", "@fortawesome/react-fontawesome": "^0.2.0", "@mdx-js/react": "^1.6.22", @@ -34,8 +34,8 @@ "eslint": "^8.39.0", "eslint-config-prettier": "^8.8.0", "eslint-plugin-mdx": "^2.0.5", - "eslint-plugin-react": "^7.32.2", - "json-schema-to-typescript": "^12.0.0", + "eslint-plugin-react": "^7.33.2", + "json-schema-to-typescript": "^13.1.1", "mustache": "^4.2.0", "null-loader": "^4.0.0", "prebuild-webpack-plugin": "^1.1.1", @@ -251,9 +251,9 @@ } }, "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -325,9 +325,9 @@ } }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -384,9 +384,9 @@ } }, "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -1634,9 +1634,9 @@ } }, "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -1846,9 +1846,9 @@ } }, "node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -2704,17 +2704,26 @@ } }, "node_modules/@fortawesome/fontawesome-svg-core": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.0.tgz", - "integrity": "sha512-Bertv8xOiVELz5raB2FlXDPKt+m94MQ3JgDfsVbrqNpLU9+UE2E18GKjLKw+d3XbeYPqg1pzyQKGsrzbw+pPaw==", + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.2.tgz", + "integrity": "sha512-gjYDSKv3TrM2sLTOKBc5rH9ckje8Wrwgx1CxAPbN5N3Fm4prfi7NsJVWd1jklp7i5uSCVwhZS5qlhMXqLrpAIg==", "hasInstallScript": true, "dependencies": { - "@fortawesome/fontawesome-common-types": "6.4.0" + "@fortawesome/fontawesome-common-types": "6.4.2" }, "engines": { "node": ">=6" } }, + "node_modules/@fortawesome/fontawesome-svg-core/node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.2.tgz", + "integrity": "sha512-1DgP7f+XQIJbLFCTX1V2QnxVmpLdKdzzo2k8EmvDOePfchaIGQ9eCHj2up3/jNEbZuBqel5OxiaOJf37TWauRA==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, "node_modules/@fortawesome/free-solid-svg-icons": { "version": "6.4.0", "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.4.0.tgz", @@ -2959,9 +2968,9 @@ } }, "node_modules/@mdx-js/mdx/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "bin": { "semver": "bin/semver" } @@ -4172,6 +4181,19 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array-flatten": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", @@ -4235,11 +4257,40 @@ "get-intrinsic": "^1.1.3" } }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz", + "integrity": "sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" }, + "node_modules/asynciterator.prototype": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz", + "integrity": "sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + } + }, "node_modules/at-least-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", @@ -4280,6 +4331,18 @@ "postcss": "^8.1.0" } }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/axios": { "version": "0.25.0", "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", @@ -4366,9 +4429,9 @@ } }, "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -5750,9 +5813,9 @@ } }, "node_modules/define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", "dependencies": { "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" @@ -6100,35 +6163,50 @@ } }, "node_modules/es-abstract": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", - "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", + "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==", "dev": true, "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.1", + "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.3", + "get-intrinsic": "^1.2.1", "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", "has": "^1.0.3", "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.2", + "object-inspect": "^1.12.3", "object-keys": "^1.1.1", "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", + "regexp.prototype.flags": "^1.5.0", + "safe-array-concat": "^1.0.0", "safe-regex-test": "^1.0.0", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.10" }, "engines": { "node": ">= 0.4" @@ -6137,11 +6215,47 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-iterator-helpers": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.14.tgz", + "integrity": "sha512-JgtVnwiuoRuzLvqelrvN3Xu7H9bu2ap/kQ2CrM62iidP8SKuD99rWU3CJy++s7IVL2qb/AjXPGR/E7i9ngd/Cw==", + "dev": true, + "dependencies": { + "asynciterator.prototype": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-set-tostringtag": "^2.0.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.2.1", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "iterator.prototype": "^1.1.0", + "safe-array-concat": "^1.0.0" + } + }, "node_modules/es-module-lexer": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.2.1.tgz", "integrity": "sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg==" }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-shim-unscopables": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", @@ -6754,15 +6868,16 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.32.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", - "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", + "version": "7.33.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz", + "integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==", "dev": true, "dependencies": { "array-includes": "^3.1.6", "array.prototype.flatmap": "^1.3.1", "array.prototype.tosorted": "^1.1.1", "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.12", "estraverse": "^5.3.0", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", @@ -6772,7 +6887,7 @@ "object.values": "^1.1.6", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.4", - "semver": "^6.3.0", + "semver": "^6.3.1", "string.prototype.matchall": "^4.0.8" }, "engines": { @@ -6812,9 +6927,9 @@ } }, "node_modules/eslint-plugin-react/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -7454,6 +7569,15 @@ } } }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/fork-ts-checker-webpack-plugin": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.2.tgz", @@ -7651,12 +7775,13 @@ } }, "node_modules/get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", + "has-proto": "^1.0.1", "has-symbols": "^1.0.3" }, "funding": { @@ -7831,6 +7956,21 @@ "node": ">=4" } }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/globalyzer": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", @@ -7862,6 +8002,18 @@ "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", "dev": true }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/got": { "version": "9.6.0", "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", @@ -7986,6 +8138,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -8553,12 +8716,12 @@ "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" }, "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.0", + "get-intrinsic": "^1.2.0", "has": "^1.0.3", "side-channel": "^1.0.4" }, @@ -8612,11 +8775,40 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-bigint": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", @@ -8771,6 +8963,18 @@ "node": ">=0.10.0" } }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -8779,6 +8983,21 @@ "node": ">=8" } }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -8814,6 +9033,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", @@ -8941,6 +9169,15 @@ "node": ">=6" } }, + "node_modules/is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-shared-array-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", @@ -8994,11 +9231,35 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" }, + "node_modules/is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -9011,6 +9272,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-whitespace-character": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", @@ -9063,6 +9337,18 @@ "node": ">=0.10.0" } }, + "node_modules/iterator.prototype": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.1.tgz", + "integrity": "sha512-9E+nePc8C9cnQldmNl6bgpTY6zI4OPRZd97fhJ/iVZ1GifIUDVV5F6x1nEDqpe8KaMEZGT4xgrwKQDxXnjOIZQ==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.0", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.3" + } + }, "node_modules/jest-util": { "version": "29.2.1", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.2.1.tgz", @@ -9163,9 +9449,9 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "node_modules/json-schema-to-typescript": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-12.0.0.tgz", - "integrity": "sha512-Uk/BDIAo8vqepPBhM86UhNMHgCv7JulicNj/BgnQPHE1fGCoej0UTtcEYzXU/uk6lSvbZCf7pccW+dnNMrr5rg==", + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-13.1.1.tgz", + "integrity": "sha512-F3CYhtA7F3yPbb8vF7sFchk/2dnr1/yTKf8RcvoNpjnh67ZS/ZMH1ElLt5KHAtf2/bymiejLQQszszPWEeTdSw==", "dev": true, "dependencies": { "@bcherny/json-schema-ref-parser": "10.0.5-fork", @@ -9456,9 +9742,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -11088,9 +11374,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -11353,9 +11639,9 @@ } }, "node_modules/package-json/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -12794,6 +13080,26 @@ "node": ">=6.0.0" } }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", + "integrity": "sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -12824,14 +13130,14 @@ } }, "node_modules/regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" }, "engines": { "node": ">= 0.4" @@ -13008,9 +13314,9 @@ } }, "node_modules/remark-mdx/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "bin": { "semver": "bin/semver" } @@ -13424,6 +13730,30 @@ "node": ">=6" } }, + "node_modules/safe-array-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", + "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -13522,9 +13852,9 @@ } }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -13547,9 +13877,9 @@ } }, "node_modules/semver-diff/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -14063,29 +14393,46 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "node_modules/string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -14633,6 +14980,71 @@ "node": ">= 0.6" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", @@ -15839,6 +16251,72 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dev": true, + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dev": true, + "dependencies": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/widest-line": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", @@ -15859,9 +16337,9 @@ "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==" }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", "devOptional": true, "engines": { "node": ">=0.10.0" @@ -16203,9 +16681,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, @@ -16260,9 +16738,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, @@ -16303,9 +16781,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, @@ -17113,9 +17591,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, @@ -17270,9 +17748,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, @@ -17894,11 +18372,18 @@ "integrity": "sha512-HNii132xfomg5QVZw0HwXXpN22s7VBHQBv9CeOu9tfJnhsWQNd2lmTNi8CSrnw5B+5YOmzu1UoPAyxaXsJ6RgQ==" }, "@fortawesome/fontawesome-svg-core": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.0.tgz", - "integrity": "sha512-Bertv8xOiVELz5raB2FlXDPKt+m94MQ3JgDfsVbrqNpLU9+UE2E18GKjLKw+d3XbeYPqg1pzyQKGsrzbw+pPaw==", + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.2.tgz", + "integrity": "sha512-gjYDSKv3TrM2sLTOKBc5rH9ckje8Wrwgx1CxAPbN5N3Fm4prfi7NsJVWd1jklp7i5uSCVwhZS5qlhMXqLrpAIg==", "requires": { - "@fortawesome/fontawesome-common-types": "6.4.0" + "@fortawesome/fontawesome-common-types": "6.4.2" + }, + "dependencies": { + "@fortawesome/fontawesome-common-types": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.2.tgz", + "integrity": "sha512-1DgP7f+XQIJbLFCTX1V2QnxVmpLdKdzzo2k8EmvDOePfchaIGQ9eCHj2up3/jNEbZuBqel5OxiaOJf37TWauRA==" + } } }, "@fortawesome/free-solid-svg-icons": { @@ -18097,9 +18582,9 @@ } }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" }, "source-map": { "version": "0.5.7", @@ -19070,6 +19555,16 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, + "array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + } + }, "array-flatten": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", @@ -19118,11 +19613,34 @@ "get-intrinsic": "^1.1.3" } }, + "arraybuffer.prototype.slice": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz", + "integrity": "sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + } + }, "asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" }, + "asynciterator.prototype": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz", + "integrity": "sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.3" + } + }, "at-least-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", @@ -19141,6 +19659,12 @@ "postcss-value-parser": "^4.2.0" } }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true + }, "axios": { "version": "0.25.0", "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", @@ -19210,9 +19734,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, @@ -20186,9 +20710,9 @@ "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==" }, "define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", "requires": { "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" @@ -20448,35 +20972,72 @@ } }, "es-abstract": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", - "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", + "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==", "dev": true, "requires": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.1", + "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.3", + "get-intrinsic": "^1.2.1", "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", "has": "^1.0.3", "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.2", + "object-inspect": "^1.12.3", "object-keys": "^1.1.1", "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", + "regexp.prototype.flags": "^1.5.0", + "safe-array-concat": "^1.0.0", "safe-regex-test": "^1.0.0", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.10" + } + }, + "es-iterator-helpers": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.14.tgz", + "integrity": "sha512-JgtVnwiuoRuzLvqelrvN3Xu7H9bu2ap/kQ2CrM62iidP8SKuD99rWU3CJy++s7IVL2qb/AjXPGR/E7i9ngd/Cw==", + "dev": true, + "requires": { + "asynciterator.prototype": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-set-tostringtag": "^2.0.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.2.1", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "iterator.prototype": "^1.1.0", + "safe-array-concat": "^1.0.0" } }, "es-module-lexer": { @@ -20484,6 +21045,17 @@ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.2.1.tgz", "integrity": "sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg==" }, + "es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + } + }, "es-shim-unscopables": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", @@ -20956,15 +21528,16 @@ } }, "eslint-plugin-react": { - "version": "7.32.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", - "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", + "version": "7.33.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz", + "integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==", "dev": true, "requires": { "array-includes": "^3.1.6", "array.prototype.flatmap": "^1.3.1", "array.prototype.tosorted": "^1.1.1", "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.12", "estraverse": "^5.3.0", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", @@ -20974,7 +21547,7 @@ "object.values": "^1.1.6", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.4", - "semver": "^6.3.0", + "semver": "^6.3.1", "string.prototype.matchall": "^4.0.8" }, "dependencies": { @@ -20999,9 +21572,9 @@ } }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -21457,6 +22030,15 @@ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } + }, "fork-ts-checker-webpack-plugin": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.2.tgz", @@ -21587,12 +22169,13 @@ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" }, "get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", + "has-proto": "^1.0.1", "has-symbols": "^1.0.3" } }, @@ -21713,6 +22296,15 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3" + } + }, "globalyzer": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", @@ -21738,6 +22330,15 @@ "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", "dev": true }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, "got": { "version": "9.6.0", "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", @@ -21837,6 +22438,11 @@ "get-intrinsic": "^1.1.1" } }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -22255,12 +22861,12 @@ "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" }, "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", "dev": true, "requires": { - "get-intrinsic": "^1.1.0", + "get-intrinsic": "^1.2.0", "has": "^1.0.3", "side-channel": "^1.0.4" } @@ -22297,11 +22903,31 @@ "is-decimal": "^1.0.0" } }, + "is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + } + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, + "is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, "is-bigint": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", @@ -22392,11 +23018,29 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" }, + "is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, + "is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -22419,6 +23063,12 @@ "is-path-inside": "^3.0.2" } }, + "is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true + }, "is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", @@ -22498,6 +23148,12 @@ "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==" }, + "is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "dev": true + }, "is-shared-array-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", @@ -22530,11 +23186,26 @@ "has-symbols": "^1.0.2" } }, + "is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "requires": { + "which-typed-array": "^1.1.11" + } + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" }, + "is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "dev": true + }, "is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -22544,6 +23215,16 @@ "call-bind": "^1.0.2" } }, + "is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, "is-whitespace-character": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", @@ -22582,6 +23263,18 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" }, + "iterator.prototype": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.1.tgz", + "integrity": "sha512-9E+nePc8C9cnQldmNl6bgpTY6zI4OPRZd97fhJ/iVZ1GifIUDVV5F6x1nEDqpe8KaMEZGT4xgrwKQDxXnjOIZQ==", + "dev": true, + "requires": { + "define-properties": "^1.2.0", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.3" + } + }, "jest-util": { "version": "29.2.1", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.2.1.tgz", @@ -22663,9 +23356,9 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "json-schema-to-typescript": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-12.0.0.tgz", - "integrity": "sha512-Uk/BDIAo8vqepPBhM86UhNMHgCv7JulicNj/BgnQPHE1fGCoej0UTtcEYzXU/uk6lSvbZCf7pccW+dnNMrr5rg==", + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-13.1.1.tgz", + "integrity": "sha512-F3CYhtA7F3yPbb8vF7sFchk/2dnr1/yTKf8RcvoNpjnh67ZS/ZMH1ElLt5KHAtf2/bymiejLQQszszPWEeTdSw==", "dev": true, "requires": { "@bcherny/json-schema-ref-parser": "10.0.5-fork", @@ -22887,9 +23580,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, @@ -23966,9 +24659,9 @@ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" }, "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" }, "object-keys": { "version": "1.1.1", @@ -24147,9 +24840,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, @@ -25142,6 +25835,20 @@ "minimatch": "^3.0.5" } }, + "reflect.getprototypeof": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", + "integrity": "sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + } + }, "regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -25169,14 +25876,14 @@ } }, "regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" } }, "regexpu-core": { @@ -25310,9 +26017,9 @@ } }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" }, "source-map": { "version": "0.5.7", @@ -25608,6 +26315,26 @@ "mri": "^1.1.0" } }, + "safe-array-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", + "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } + } + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -25676,9 +26403,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" } @@ -25692,9 +26419,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, @@ -26111,26 +26838,37 @@ "side-channel": "^1.0.4" } }, + "string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, "string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" + "es-abstract": "^1.20.4" } }, "string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" + "es-abstract": "^1.20.4" } }, "stringify-entities": { @@ -26520,6 +27258,53 @@ } } }, + "typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + } + }, "typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", @@ -27339,6 +28124,59 @@ "is-symbol": "^1.0.3" } }, + "which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dev": true, + "requires": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } + } + }, + "which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dev": true, + "requires": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + } + }, + "which-typed-array": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, "widest-line": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", @@ -27353,9 +28191,9 @@ "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==" }, "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", "devOptional": true }, "wrap-ansi": { diff --git a/docs/package.json b/docs/package.json index d82e54ec8c9..aa48af24d3c 100644 --- a/docs/package.json +++ b/docs/package.json @@ -17,7 +17,7 @@ "dependencies": { "@docusaurus/core": "^2.4.0", "@docusaurus/preset-classic": "^2.4.0", - "@fortawesome/fontawesome-svg-core": "^6.4.0", + "@fortawesome/fontawesome-svg-core": "^6.4.2", "@fortawesome/free-solid-svg-icons": "^6.4.0", "@fortawesome/react-fontawesome": "^0.2.0", "@mdx-js/react": "^1.6.22", @@ -53,8 +53,8 @@ "eslint": "^8.39.0", "eslint-config-prettier": "^8.8.0", "eslint-plugin-mdx": "^2.0.5", - "eslint-plugin-react": "^7.32.2", - "json-schema-to-typescript": "^12.0.0", + "eslint-plugin-react": "^7.33.2", + "json-schema-to-typescript": "^13.1.1", "mustache": "^4.2.0", "null-loader": "^4.0.0", "prebuild-webpack-plugin": "^1.1.1", diff --git a/docs/src/data/groups.js b/docs/src/data/groups.js index 0eb15d27fc5..5a8dc3cfe75 100644 --- a/docs/src/data/groups.js +++ b/docs/src/data/groups.js @@ -49,6 +49,7 @@ export default { "C_AC_DESKTOP_SHOW_ALL_WINDOWS", "C_AC_DESKTOP_SHOW_ALL_APPLICATIONS", "C_VOICE_COMMAND", + "C_AC_NEXT_KEYBOARD_LAYOUT_SELECT", ], applications: [ "C_AL_NEXT_TASK", diff --git a/docs/src/data/hid.js b/docs/src/data/hid.js index 457671728f8..fc61555c8eb 100644 --- a/docs/src/data/hid.js +++ b/docs/src/data/hid.js @@ -7865,4 +7865,25 @@ export default [ }, footnotes: {}, }, + { + names: ["C_AC_NEXT_KEYBOARD_LAYOUT_SELECT", "GLOBE"], + description: "AC Next Keyboard Layout Select (Apple Globe)", + context: "Consumer AC", + clarify: true, + usages: [ + { + application: consumerApplication, + item: usage(consumerPage, 0x29d), + }, + ], + documentation: "https://usb.org/sites/default/files/hut1_2.pdf#page=153", + os: { + windows: null, + linux: null, + android: null, + macos: true, + ios: true, + }, + footnotes: {}, + }, ];