From 86b35294a5301ef4a49243f15c1ad85e4d6b298d Mon Sep 17 00:00:00 2001 From: snoyer Date: Wed, 19 Oct 2022 16:26:18 +0000 Subject: [PATCH 1/5] add profile indexing --- app/src/profiles.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 app/src/profiles.c diff --git a/app/src/profiles.c b/app/src/profiles.c new file mode 100644 index 00000000..00cf2b57 --- /dev/null +++ b/app/src/profiles.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +zmk_profile_index_t zmk_profile_index(enum zmk_endpoint endpoint, uint8_t profile) { + switch (endpoint) { + case ZMK_ENDPOINT_USB: + return 0; + case ZMK_ENDPOINT_BLE: + return ZMK_USB_PROFILE_COUNT + profile; + } + + CODE_UNREACHABLE; +} + +zmk_profile_index_t zmk_current_profile_index() { + const enum zmk_endpoint endpoint = zmk_endpoints_selected(); + uint8_t profile = 0; + +#if IS_ENABLED(CONFIG_ZMK_BLE) + if (endpoint == ZMK_ENDPOINT_BLE) { + profile = zmk_ble_active_profile_index(); + } +#endif + + const zmk_profile_index_t index = zmk_profile_index(endpoint, profile); + LOG_DBG("endpoint=%d, profile=%d => profile_index=%d", endpoint, profile, index); + return index; +} From bc7df67c30c8fb8ca5df5eeb495f8eab435d9b48 Mon Sep 17 00:00:00 2001 From: snoyer Date: Wed, 19 Oct 2022 16:28:37 +0000 Subject: [PATCH 2/5] add base-layer behavior --- app/CMakeLists.txt | 1 + app/dts/behaviors.dtsi | 3 +- app/dts/behaviors/base_layer.dtsi | 15 ++++ .../behaviors/zmk,behavior-base-layer.yaml | 8 ++ app/src/behaviors/behavior_base_layer.c | 76 +++++++++++++++++++ 5 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 app/dts/behaviors/base_layer.dtsi create mode 100644 app/dts/bindings/behaviors/zmk,behavior-base-layer.yaml create mode 100644 app/src/behaviors/behavior_base_layer.c diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 793f386d..c800d1cc 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -49,6 +49,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL) target_sources(app PRIVATE src/behaviors/behavior_outputs.c) target_sources(app PRIVATE src/behaviors/behavior_toggle_layer.c) target_sources(app PRIVATE src/behaviors/behavior_to_layer.c) + target_sources(app PRIVATE src/behaviors/behavior_base_layer.c) target_sources(app PRIVATE src/behaviors/behavior_transparent.c) target_sources(app PRIVATE src/behaviors/behavior_none.c) target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE app PRIVATE src/behaviors/behavior_sensor_rotate.c) diff --git a/app/dts/behaviors.dtsi b/app/dts/behaviors.dtsi index b3502cbb..83faeacd 100644 --- a/app/dts/behaviors.dtsi +++ b/app/dts/behaviors.dtsi @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -18,4 +19,4 @@ #include #include #include -#include \ No newline at end of file +#include diff --git a/app/dts/behaviors/base_layer.dtsi b/app/dts/behaviors/base_layer.dtsi new file mode 100644 index 00000000..510829f2 --- /dev/null +++ b/app/dts/behaviors/base_layer.dtsi @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + behaviors { + /omit-if-no-ref/ base: behavior_base_layer { + compatible = "zmk,behavior-base-layer"; + label = "BASE_LAYER"; + #binding-cells = <1>; + }; + }; +}; diff --git a/app/dts/bindings/behaviors/zmk,behavior-base-layer.yaml b/app/dts/bindings/behaviors/zmk,behavior-base-layer.yaml new file mode 100644 index 00000000..91c3809b --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-base-layer.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Base Layer + +compatible: "zmk,behavior-base-layer" + +include: one_param.yaml diff --git a/app/src/behaviors/behavior_base_layer.c b/app/src/behaviors/behavior_base_layer.c new file mode 100644 index 00000000..dc472900 --- /dev/null +++ b/app/src/behaviors/behavior_base_layer.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_base_layer + +#include +#include +#include + +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +uint8_t base_layer_by_profile[ZMK_PROFILE_COUNT] = {0}; + +static int behavior_to_init(const struct device *dev) { return 0; }; + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d layer %d", event.position, binding->param1); + + const zmk_profile_index_t profile_index = zmk_current_profile_index(); + const uint8_t layer = binding->param1; + + base_layer_by_profile[profile_index] = layer; + zmk_keymap_layer_to(layer); + LOG_INF("saved base layer %d for profile %d", layer, profile_index); + + return ZMK_BEHAVIOR_OPAQUE; +} + +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d layer %d", event.position, binding->param1); + return ZMK_BEHAVIOR_OPAQUE; +} + +static int base_layer_listener(const zmk_event_t *e) { + if (e == NULL) { + return ZMK_EV_EVENT_BUBBLE; + } + + const zmk_profile_index_t profile_index = zmk_current_profile_index(); + const uint8_t layer = base_layer_by_profile[profile_index]; + + zmk_keymap_layer_to(layer); + LOG_INF("restored base layer %d for profile %d", layer, profile_index); + + return ZMK_EV_EVENT_BUBBLE; +} +static ZMK_LISTENER(base_layer_listener, base_layer_listener); + +static ZMK_SUBSCRIPTION(base_layer_listener, zmk_endpoint_selection_changed); + +#if IS_ENABLED(CONFIG_ZMK_BLE) +static ZMK_SUBSCRIPTION(base_layer_listener, zmk_ble_active_profile_changed); +#endif + +static const struct behavior_driver_api behavior_base_layer_driver_api = { + .binding_pressed = on_keymap_binding_pressed, + .binding_released = on_keymap_binding_released, +}; + +DEVICE_DT_INST_DEFINE(0, behavior_to_init, NULL, NULL, NULL, APPLICATION, + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_base_layer_driver_api); + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ From b34b7f8e8e9e39b241d2a17fc7f644de3c25f279 Mon Sep 17 00:00:00 2001 From: snoyer Date: Sat, 22 Oct 2022 04:52:35 +0000 Subject: [PATCH 3/5] persist base layer selection --- app/src/behaviors/behavior_base_layer.c | 61 +++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 5 deletions(-) diff --git a/app/src/behaviors/behavior_base_layer.c b/app/src/behaviors/behavior_base_layer.c index dc472900..314d105b 100644 --- a/app/src/behaviors/behavior_base_layer.c +++ b/app/src/behaviors/behavior_base_layer.c @@ -16,13 +16,60 @@ #include #include +#if IS_ENABLED(CONFIG_SETTINGS) +#include +#endif + LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) -uint8_t base_layer_by_profile[ZMK_PROFILE_COUNT] = {0}; +struct base_layer_state { + uint8_t base_layer_by_profile[ZMK_PROFILE_COUNT]; +}; -static int behavior_to_init(const struct device *dev) { return 0; }; +static struct base_layer_state state = {.base_layer_by_profile = {0}}; + +#if IS_ENABLED(CONFIG_SETTINGS) +static int base_layer_settings_set(const char *name, size_t len, settings_read_cb read_cb, + void *cb_arg) { + const char *next; + if (settings_name_steq(name, "state", &next) && !next) { + if (len != sizeof(state)) { + return -EINVAL; + } + int rc = read_cb(cb_arg, &state, sizeof(state)); + return MIN(rc, 0); + } + return -ENOENT; +} + +static void base_layer_save_work_handler(struct k_work *work) { + settings_save_one("base_layer/state", &state, sizeof(state)); +} + +static struct k_work_delayable base_layer_save_work; +struct settings_handler base_layer_settings_handler = {.name = "base_layer", + .h_set = base_layer_settings_set}; +#endif + +static int behavior_base_layer_init(const struct device *dev) { +#if IS_ENABLED(CONFIG_SETTINGS) + settings_subsys_init(); + + int err = settings_register(&base_layer_settings_handler); + if (err) { + LOG_ERR("Failed to register the base_layer settings handler (err %d)", err); + return err; + } + + k_work_init_delayable(&base_layer_save_work, base_layer_save_work_handler); + + settings_load_subtree("base_layer"); +#endif + + return 0; +}; static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { @@ -31,10 +78,14 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, const zmk_profile_index_t profile_index = zmk_current_profile_index(); const uint8_t layer = binding->param1; - base_layer_by_profile[profile_index] = layer; + state.base_layer_by_profile[profile_index] = layer; zmk_keymap_layer_to(layer); LOG_INF("saved base layer %d for profile %d", layer, profile_index); +#if IS_ENABLED(CONFIG_SETTINGS) + k_work_reschedule(&base_layer_save_work, K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE)); +#endif /* IS_ENABLED(CONFIG_SETTINGS) */ + return ZMK_BEHAVIOR_OPAQUE; } @@ -50,7 +101,7 @@ static int base_layer_listener(const zmk_event_t *e) { } const zmk_profile_index_t profile_index = zmk_current_profile_index(); - const uint8_t layer = base_layer_by_profile[profile_index]; + const uint8_t layer = state.base_layer_by_profile[profile_index]; zmk_keymap_layer_to(layer); LOG_INF("restored base layer %d for profile %d", layer, profile_index); @@ -70,7 +121,7 @@ static const struct behavior_driver_api behavior_base_layer_driver_api = { .binding_released = on_keymap_binding_released, }; -DEVICE_DT_INST_DEFINE(0, behavior_to_init, NULL, NULL, NULL, APPLICATION, +DEVICE_DT_INST_DEFINE(0, behavior_base_layer_init, NULL, NULL, NULL, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_base_layer_driver_api); #endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ From f332af80b8d99a6d7fb7b6b3403830f6d0f079ba Mon Sep 17 00:00:00 2001 From: snoyer Date: Wed, 19 Oct 2022 16:28:37 +0000 Subject: [PATCH 4/5] add base-layer behavior --- app/src/behaviors/behavior_base_layer.c | 59 ++++++++++++------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/app/src/behaviors/behavior_base_layer.c b/app/src/behaviors/behavior_base_layer.c index 314d105b..ffce6e74 100644 --- a/app/src/behaviors/behavior_base_layer.c +++ b/app/src/behaviors/behavior_base_layer.c @@ -1,34 +1,33 @@ /* - * Copyright (c) 2022 The ZMK Contributors + * Copyright (c) 2023 The ZMK Contributors * * SPDX-License-Identifier: MIT */ #define DT_DRV_COMPAT zmk_behavior_base_layer -#include +#include #include -#include -#include #include -#include -#include -#include +#include +#include +#include #if IS_ENABLED(CONFIG_SETTINGS) -#include +#include #endif +#include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) struct base_layer_state { - uint8_t base_layer_by_profile[ZMK_PROFILE_COUNT]; + uint8_t layer_by_enpoint[ZMK_ENDPOINT_COUNT]; }; -static struct base_layer_state state = {.base_layer_by_profile = {0}}; +static struct base_layer_state state; #if IS_ENABLED(CONFIG_SETTINGS) static int base_layer_settings_set(const char *name, size_t len, settings_read_cb read_cb, @@ -38,8 +37,7 @@ static int base_layer_settings_set(const char *name, size_t len, settings_read_c if (len != sizeof(state)) { return -EINVAL; } - int rc = read_cb(cb_arg, &state, sizeof(state)); - return MIN(rc, 0); + return MIN(read_cb(cb_arg, &state, sizeof(state)), 0); } return -ENOENT; } @@ -51,7 +49,7 @@ static void base_layer_save_work_handler(struct k_work *work) { static struct k_work_delayable base_layer_save_work; struct settings_handler base_layer_settings_handler = {.name = "base_layer", .h_set = base_layer_settings_set}; -#endif +#endif /* IS_ENABLED(CONFIG_SETTINGS) */ static int behavior_base_layer_init(const struct device *dev) { #if IS_ENABLED(CONFIG_SETTINGS) @@ -66,7 +64,7 @@ static int behavior_base_layer_init(const struct device *dev) { k_work_init_delayable(&base_layer_save_work, base_layer_save_work_handler); settings_load_subtree("base_layer"); -#endif +#endif /* IS_ENABLED(CONFIG_SETTINGS) */ return 0; }; @@ -75,12 +73,16 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { LOG_DBG("position %d layer %d", event.position, binding->param1); - const zmk_profile_index_t profile_index = zmk_current_profile_index(); + const struct zmk_endpoint_instance endpoint = zmk_endpoints_selected(); + const int endpoint_index = zmk_endpoint_instance_to_index(endpoint); const uint8_t layer = binding->param1; - state.base_layer_by_profile[profile_index] = layer; + state.layer_by_enpoint[endpoint_index] = layer; zmk_keymap_layer_to(layer); - LOG_INF("saved base layer %d for profile %d", layer, profile_index); + + char endpoint_str[ZMK_ENDPOINT_STR_LEN]; + zmk_endpoint_instance_to_str(endpoint, endpoint_str, sizeof(endpoint_str)); + LOG_INF("saved base layer %d for endpoint %s", layer, endpoint_str); #if IS_ENABLED(CONFIG_SETTINGS) k_work_reschedule(&base_layer_save_work, K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE)); @@ -96,25 +98,22 @@ static int on_keymap_binding_released(struct zmk_behavior_binding *binding, } static int base_layer_listener(const zmk_event_t *e) { - if (e == NULL) { - return ZMK_EV_EVENT_BUBBLE; + struct zmk_endpoint_changed *data = as_zmk_endpoint_changed(e); + if (data != NULL) { + const int endpoint_index = zmk_endpoint_instance_to_index(data->endpoint); + const uint8_t layer = state.layer_by_enpoint[endpoint_index]; + zmk_keymap_layer_to(layer); + + char endpoint_str[ZMK_ENDPOINT_STR_LEN]; + zmk_endpoint_instance_to_str(data->endpoint, endpoint_str, sizeof(endpoint_str)); + LOG_INF("restored base layer %d for endpoint %s", layer, endpoint_str); } - const zmk_profile_index_t profile_index = zmk_current_profile_index(); - const uint8_t layer = state.base_layer_by_profile[profile_index]; - - zmk_keymap_layer_to(layer); - LOG_INF("restored base layer %d for profile %d", layer, profile_index); - return ZMK_EV_EVENT_BUBBLE; } static ZMK_LISTENER(base_layer_listener, base_layer_listener); -static ZMK_SUBSCRIPTION(base_layer_listener, zmk_endpoint_selection_changed); - -#if IS_ENABLED(CONFIG_ZMK_BLE) -static ZMK_SUBSCRIPTION(base_layer_listener, zmk_ble_active_profile_changed); -#endif +static ZMK_SUBSCRIPTION(base_layer_listener, zmk_endpoint_changed); static const struct behavior_driver_api behavior_base_layer_driver_api = { .binding_pressed = on_keymap_binding_pressed, From f737d087b5bbbd369b6602ea7430738c18acf649 Mon Sep 17 00:00:00 2001 From: snoyer Date: Sun, 5 Nov 2023 11:27:27 +0400 Subject: [PATCH 5/5] cleanup --- app/dts/behaviors/base_layer.dtsi | 14 ++++++------ app/src/profiles.c | 38 ------------------------------- 2 files changed, 7 insertions(+), 45 deletions(-) delete mode 100644 app/src/profiles.c diff --git a/app/dts/behaviors/base_layer.dtsi b/app/dts/behaviors/base_layer.dtsi index 510829f2..f9e60729 100644 --- a/app/dts/behaviors/base_layer.dtsi +++ b/app/dts/behaviors/base_layer.dtsi @@ -5,11 +5,11 @@ */ / { - behaviors { - /omit-if-no-ref/ base: behavior_base_layer { - compatible = "zmk,behavior-base-layer"; - label = "BASE_LAYER"; - #binding-cells = <1>; - }; - }; + behaviors { + /omit-if-no-ref/ base: behavior_base_layer { + compatible = "zmk,behavior-base-layer"; + label = "BASE_LAYER"; + #binding-cells = <1>; + }; + }; }; diff --git a/app/src/profiles.c b/app/src/profiles.c deleted file mode 100644 index 00cf2b57..00000000 --- a/app/src/profiles.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2022 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#include -#include -#include - -#include -LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); - -zmk_profile_index_t zmk_profile_index(enum zmk_endpoint endpoint, uint8_t profile) { - switch (endpoint) { - case ZMK_ENDPOINT_USB: - return 0; - case ZMK_ENDPOINT_BLE: - return ZMK_USB_PROFILE_COUNT + profile; - } - - CODE_UNREACHABLE; -} - -zmk_profile_index_t zmk_current_profile_index() { - const enum zmk_endpoint endpoint = zmk_endpoints_selected(); - uint8_t profile = 0; - -#if IS_ENABLED(CONFIG_ZMK_BLE) - if (endpoint == ZMK_ENDPOINT_BLE) { - profile = zmk_ble_active_profile_index(); - } -#endif - - const zmk_profile_index_t index = zmk_profile_index(endpoint, profile); - LOG_DBG("endpoint=%d, profile=%d => profile_index=%d", endpoint, profile, index); - return index; -}