From e4ae6b5b33ab2d7fac7d1ccafaf989b6e20c6c67 Mon Sep 17 00:00:00 2001 From: Joel Spadin Date: Sun, 14 May 2023 11:55:21 -0500 Subject: [PATCH 1/3] refactor: Split endpoint to transport and instance Changed the endpoints code to rename the existing endpoint types to "transport" and add the concept of "endpoint instances". A transport is the method by which data is sent, while instances allow describing multiple endpoints that use the same transport (e.g. bluetooth profiles) Also added new APIs to get the total number of possible endpoint instances and assign each instance a unique index, which can be used for tracking separate state for each endpoint in other code files. --- .../arm/corneish_zen/widgets/output_status.c | 33 ++- app/include/zmk/endpoints.h | 62 ++++- app/include/zmk/endpoints_types.h | 32 ++- ...selection_changed.h => endpoint_changed.h} | 6 +- app/src/behaviors/behavior_outputs.c | 6 +- app/src/display/widgets/output_status.c | 29 +-- app/src/endpoints.c | 220 ++++++++++++------ app/src/events/endpoint_selection_changed.c | 4 +- 8 files changed, 268 insertions(+), 124 deletions(-) rename app/include/zmk/events/{endpoint_selection_changed.h => endpoint_changed.h} (61%) diff --git a/app/boards/arm/corneish_zen/widgets/output_status.c b/app/boards/arm/corneish_zen/widgets/output_status.c index ad0c2b1a8fb..bdf90cc3d7f 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,31 @@ 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 +83,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 +112,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/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/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/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..e208a36a312 100644 --- a/app/src/endpoints.c +++ b/app/src/endpoints.c @@ -16,29 +16,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 +46,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 + +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; +} - if (preferred_endpoint == endpoint) { +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 +108,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 +133,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 +141,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 +162,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 +170,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 +182,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 +198,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 +218,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 +226,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 +234,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; + } + + 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; } - LOG_DBG("No endpoints are ready."); - return DEFAULT_ENDPOINT; + 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 +300,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_selection_changed.c index 34bc39dd2ab..6b152156feb 100644 --- a/app/src/events/endpoint_selection_changed.c +++ b/app/src/events/endpoint_selection_changed.c @@ -5,6 +5,6 @@ */ #include -#include +#include -ZMK_EVENT_IMPL(zmk_endpoint_selection_changed); +ZMK_EVENT_IMPL(zmk_endpoint_changed); From 7f5b6cfdea0bd35cd6b5f96afb7fad016f00a5a0 Mon Sep 17 00:00:00 2001 From: Joel Spadin Date: Sun, 27 Aug 2023 18:03:06 -0500 Subject: [PATCH 2/3] fix: Address review comments --- app/CMakeLists.txt | 2 +- app/boards/arm/corneish_zen/widgets/output_status.c | 2 -- app/src/endpoints.c | 2 ++ .../events/{endpoint_selection_changed.c => endpoint_changed.c} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename app/src/events/{endpoint_selection_changed.c => endpoint_changed.c} (100%) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index efa349052cf..04fc5488b54 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -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) diff --git a/app/boards/arm/corneish_zen/widgets/output_status.c b/app/boards/arm/corneish_zen/widgets/output_status.c index bdf90cc3d7f..8e9457ebefe 100644 --- a/app/boards/arm/corneish_zen/widgets/output_status.c +++ b/app/boards/arm/corneish_zen/widgets/output_status.c @@ -41,7 +41,6 @@ struct output_status_state { 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) { @@ -50,7 +49,6 @@ static struct output_status_state get_state(const zmk_event_t *_eh) { .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) { diff --git a/app/src/endpoints.c b/app/src/endpoints.c index e208a36a312..138e790fe72 100644 --- a/app/src/endpoints.c +++ b/app/src/endpoints.c @@ -7,6 +7,8 @@ #include #include +#include + #include #include #include diff --git a/app/src/events/endpoint_selection_changed.c b/app/src/events/endpoint_changed.c similarity index 100% rename from app/src/events/endpoint_selection_changed.c rename to app/src/events/endpoint_changed.c From 396344e09a1697c5e656dbe318ce5e06bd71b9e6 Mon Sep 17 00:00:00 2001 From: Joel Spadin Date: Sun, 27 Aug 2023 18:33:29 -0500 Subject: [PATCH 3/3] fix: Fix nice_view display widgets --- .../nice_view/widgets/peripheral_status.c | 8 +- app/boards/shields/nice_view/widgets/status.c | 76 +++++++++---------- app/boards/shields/nice_view/widgets/util.c | 6 +- app/boards/shields/nice_view/widgets/util.h | 5 +- 4 files changed, 46 insertions(+), 49 deletions(-) diff --git a/app/boards/shields/nice_view/widgets/peripheral_status.c b/app/boards/shields/nice_view/widgets/peripheral_status.c index 85c2a1d8793..4c0c22637be 100644 --- a/app/boards/shields/nice_view/widgets/peripheral_status.c +++ b/app/boards/shields/nice_view/widgets/peripheral_status.c @@ -31,7 +31,7 @@ struct peripheral_status_state { bool connected; }; -static void draw_top(lv_obj_t *widget, lv_color_t cbuf[], struct status_state state) { +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; @@ -47,7 +47,7 @@ static void draw_top(lv_obj_t *widget, lv_color_t cbuf[], struct status_state st // Draw output status lv_canvas_draw_text(canvas, 0, 0, CANVAS_SIZE, &label_dsc, - state.connected ? LV_SYMBOL_WIFI : LV_SYMBOL_CLOSE); + state->connected ? LV_SYMBOL_WIFI : LV_SYMBOL_CLOSE); // Rotate canvas rotate_canvas(canvas, cbuf); @@ -61,7 +61,7 @@ static void set_battery_status(struct zmk_widget_status *widget, widget->state.battery = state.level; - draw_top(widget->obj, widget->cbuf, widget->state); + draw_top(widget->obj, widget->cbuf, &widget->state); } static void battery_status_update_cb(struct battery_status_state state) { @@ -94,7 +94,7 @@ 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); + draw_top(widget->obj, widget->cbuf, &widget->state); } static void output_status_update_cb(struct peripheral_status_state state) { diff --git a/app/boards/shields/nice_view/widgets/status.c b/app/boards/shields/nice_view/widgets/status.c index 1ad9e9207d7..c629be50f59 100644 --- a/app/boards/shields/nice_view/widgets/status.c +++ b/app/boards/shields/nice_view/widgets/status.c @@ -17,7 +17,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include #include -#include +#include #include #include #include @@ -29,10 +29,9 @@ 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; }; struct layer_status_state { @@ -44,7 +43,7 @@ struct wpm_status_state { uint8_t wpm; }; -static void draw_top(lv_obj_t *widget, lv_color_t cbuf[], struct status_state state) { +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; @@ -67,13 +66,13 @@ static void draw_top(lv_obj_t *widget, lv_color_t cbuf[], struct status_state st // Draw output status char output_text[10] = {}; - switch (state.selected_endpoint) { - case ZMK_ENDPOINT_USB: + switch (state->selected_endpoint.transport) { + case ZMK_TRANSPORT_USB: strcat(output_text, LV_SYMBOL_USB); break; - case ZMK_ENDPOINT_BLE: - if (state.active_profile_bonded) { - if (state.active_profile_connected) { + 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); @@ -91,18 +90,18 @@ static void draw_top(lv_obj_t *widget, lv_color_t cbuf[], struct status_state st 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]); + 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] > max) { + max = state->wpm[i]; } - if (state.wpm[i] < min) { - min = state.wpm[i]; + if (state->wpm[i] < min) { + min = state->wpm[i]; } } @@ -114,7 +113,7 @@ static void draw_top(lv_obj_t *widget, lv_color_t cbuf[], struct status_state st 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; + points[i].y = 60 - (state->wpm[i] - min) * 36 / range; } lv_canvas_draw_line(canvas, points, 10, &line_dsc); @@ -122,7 +121,7 @@ static void draw_top(lv_obj_t *widget, lv_color_t cbuf[], struct status_state st rotate_canvas(canvas, cbuf); } -static void draw_middle(lv_obj_t *widget, lv_color_t cbuf[], struct status_state state) { +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; @@ -147,7 +146,7 @@ static void draw_middle(lv_obj_t *widget, lv_color_t cbuf[], struct status_state }; for (int i = 0; i < 5; i++) { - bool selected = state.active_profile_index == 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); @@ -167,7 +166,7 @@ static void draw_middle(lv_obj_t *widget, lv_color_t cbuf[], struct status_state rotate_canvas(canvas, cbuf); } -static void draw_bottom(lv_obj_t *widget, lv_color_t cbuf[], struct status_state state) { +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; @@ -179,14 +178,14 @@ static void draw_bottom(lv_obj_t *widget, lv_color_t cbuf[], struct status_state lv_canvas_draw_rect(canvas, 0, 0, CANVAS_SIZE, CANVAS_SIZE, &rect_black_dsc); // Draw layer - if (state.layer_label == NULL) { + if (state->layer_label == NULL) { char text[9] = {}; - sprintf(text, "LAYER %i", state.layer_index); + 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); + lv_canvas_draw_text(canvas, 0, 5, 68, &label_dsc, state->layer_label); } // Rotate canvas @@ -201,7 +200,7 @@ static void set_battery_status(struct zmk_widget_status *widget, widget->state.battery = state.level; - draw_top(widget->obj, widget->cbuf, widget->state); + draw_top(widget->obj, widget->cbuf, &widget->state); } static void battery_status_update_cb(struct battery_status_state state) { @@ -226,33 +225,32 @@ ZMK_SUBSCRIPTION(widget_battery_status, zmk_battery_state_changed); 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, 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; - widget->state.active_profile_index = state.active_profile_index; +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); + 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); } + 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(), - .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(), + }; } 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_selection_changed); +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); @@ -265,7 +263,7 @@ static void set_layer_status(struct zmk_widget_status *widget, struct layer_stat widget->state.layer_index = state.index; widget->state.layer_label = state.label; - draw_bottom(widget->obj, widget->cbuf3, widget->state); + draw_bottom(widget->obj, widget->cbuf3, &widget->state); } static void layer_status_update_cb(struct layer_status_state state) { @@ -289,7 +287,7 @@ static void set_wpm_status(struct zmk_widget_status *widget, struct wpm_status_s } widget->state.wpm[9] = state.wpm; - draw_top(widget->obj, widget->cbuf, widget->state); + draw_top(widget->obj, widget->cbuf, &widget->state); } static void wpm_status_update_cb(struct wpm_status_state state) { diff --git a/app/boards/shields/nice_view/widgets/util.c b/app/boards/shields/nice_view/widgets/util.c index 9655f837f6e..b4915ab767f 100644 --- a/app/boards/shields/nice_view/widgets/util.c +++ b/app/boards/shields/nice_view/widgets/util.c @@ -24,7 +24,7 @@ void rotate_canvas(lv_obj_t *canvas, lv_color_t cbuf[]) { CANVAS_SIZE / 2, true); } -void draw_battery(lv_obj_t *canvas, struct status_state state) { +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; @@ -32,11 +32,11 @@ void draw_battery(lv_obj_t *canvas, struct status_state state) { 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, 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) { + 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); diff --git a/app/boards/shields/nice_view/widgets/util.h b/app/boards/shields/nice_view/widgets/util.h index e48c1082ce9..e2d2782a3f9 100644 --- a/app/boards/shields/nice_view/widgets/util.h +++ b/app/boards/shields/nice_view/widgets/util.h @@ -19,10 +19,9 @@ struct status_state { uint8_t battery; bool charging; #if !IS_ENABLED(CONFIG_ZMK_SPLIT) || IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) - enum zmk_endpoint selected_endpoint; + struct zmk_endpoint_instance selected_endpoint; bool active_profile_connected; bool active_profile_bonded; - uint8_t active_profile_index; uint8_t layer_index; const char *layer_label; uint8_t wpm[10]; @@ -39,7 +38,7 @@ struct battery_status_state { }; void rotate_canvas(lv_obj_t *canvas, lv_color_t cbuf[]); -void draw_battery(lv_obj_t *canvas, struct status_state state); +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);