From 1d369ffa73ae63af821d012b1c2ab4a07a5dc9c7 Mon Sep 17 00:00:00 2001 From: Joel Spadin Date: Sun, 11 Oct 2020 17:03:21 -0500 Subject: [PATCH] feat: only send HID reports to one endpoint Added some utility functions and an event for tracking the state of the USB connection. Updated endpoints.c to select a single endpoint to send HID reports to based on the status of the USB and BLE connections. Partially fixes #206. Future commits will add a user setting to control which endpoint is used if both USB and BLE are ready. --- app/CMakeLists.txt | 1 + .../zmk/events/usb-conn-state-changed.h | 20 +++ app/include/zmk/usb.h | 12 +- app/src/endpoints.c | 154 ++++++++++++++---- app/src/events/usb_conn_state_changed.c | 10 ++ app/src/power.c | 9 +- app/src/usb.c | 29 +++- 7 files changed, 190 insertions(+), 45 deletions(-) create mode 100644 app/include/zmk/events/usb-conn-state-changed.h create mode 100644 app/src/events/usb_conn_state_changed.c diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 8a3971e8..bce21700 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -37,6 +37,7 @@ target_sources(app PRIVATE src/events/keycode_state_changed.c) target_sources(app PRIVATE src/events/modifiers_state_changed.c) target_sources(app PRIVATE src/events/sensor_event.c) target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/events/ble_active_profile_changed.c) +target_sources_ifdef(CONFIG_USB app PRIVATE src/events/usb_conn_state_changed.c) if (NOT CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) target_sources(app PRIVATE src/behaviors/behavior_key_press.c) target_sources(app PRIVATE src/behaviors/behavior_reset.c) diff --git a/app/include/zmk/events/usb-conn-state-changed.h b/app/include/zmk/events/usb-conn-state-changed.h new file mode 100644 index 00000000..d6cc6985 --- /dev/null +++ b/app/include/zmk/events/usb-conn-state-changed.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +#include +#include + +struct usb_conn_state_changed { + struct zmk_event_header header; + enum zmk_usb_conn_state conn_state; +}; + +ZMK_EVENT_DECLARE(usb_conn_state_changed); \ No newline at end of file diff --git a/app/include/zmk/usb.h b/app/include/zmk/usb.h index 452fd54d..30461de2 100644 --- a/app/include/zmk/usb.h +++ b/app/include/zmk/usb.h @@ -12,8 +12,18 @@ #include #include +enum zmk_usb_conn_state { + ZMK_USB_CONN_NONE, + ZMK_USB_CONN_POWERED, + ZMK_USB_CONN_HID, +}; + enum usb_dc_status_code zmk_usb_get_status(); +enum zmk_usb_conn_state zmk_usb_get_conn_state(); + +static inline bool zmk_usb_is_powered() { return zmk_usb_get_conn_state() != ZMK_USB_CONN_NONE; } +static inline bool zmk_usb_is_hid_ready() { return zmk_usb_get_conn_state() == ZMK_USB_CONN_HID; } #ifdef CONFIG_ZMK_USB -int zmk_usb_hid_send_report(u8_t *report, size_t len); +int zmk_usb_hid_send_report(const u8_t *report, size_t len); #endif /* CONFIG_ZMK_USB */ \ No newline at end of file diff --git a/app/src/endpoints.c b/app/src/endpoints.c index 79d294ef..4f56aa5c 100644 --- a/app/src/endpoints.c +++ b/app/src/endpoints.c @@ -8,54 +8,138 @@ #include #include #include +#include +#include #include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); +enum endpoint { + ENDPOINT_USB, + ENDPOINT_BLE, +}; + +static enum endpoint current_endpoint = + COND_CODE_1(IS_ENABLED(CONFIG_ZMK_BLE), (ENDPOINT_BLE), (ENDPOINT_USB)); + +static int send_keypad_report() { + struct zmk_hid_keypad_report *keypad_report = zmk_hid_get_keypad_report(); + + switch (current_endpoint) { +#if IS_ENABLED(CONFIG_ZMK_USB) + case ENDPOINT_USB: { + int err = zmk_usb_hid_send_report((u8_t *)keypad_report, sizeof(*keypad_report)); + if (err) { + LOG_ERR("FAILED TO SEND OVER USB: %d", err); + } + return err; + } +#endif /* IS_ENABLED(CONFIG_ZMK_USB) */ + +#if IS_ENABLED(CONFIG_ZMK_BLE) + case ENDPOINT_BLE: { + int err = zmk_hog_send_keypad_report(&keypad_report->body); + if (err) { + LOG_ERR("FAILED TO SEND OVER HOG: %d", err); + } + return err; + } +#endif /* IS_ENABLED(CONFIG_ZMK_BLE) */ + + default: + LOG_ERR("Unsupported endpoint %d", current_endpoint); + return -ENOTSUP; + } +} + +static int send_consumer_report() { + struct zmk_hid_consumer_report *consumer_report = zmk_hid_get_consumer_report(); + + switch (current_endpoint) { +#if IS_ENABLED(CONFIG_ZMK_USB) + case ENDPOINT_USB: { + int err = zmk_usb_hid_send_report((u8_t *)consumer_report, sizeof(*consumer_report)); + if (err) { + LOG_ERR("FAILED TO SEND OVER USB: %d", err); + } + return err; + } +#endif /* IS_ENABLED(CONFIG_ZMK_USB) */ + +#if IS_ENABLED(CONFIG_ZMK_BLE) + case ENDPOINT_BLE: { + int err = zmk_hog_send_consumer_report(&consumer_report->body); + if (err) { + LOG_ERR("FAILED TO SEND OVER HOG: %d", err); + } + return err; + } +#endif /* IS_ENABLED(CONFIG_ZMK_BLE) */ + + default: + LOG_ERR("Unsupported endpoint %d", current_endpoint); + return -ENOTSUP; + } +} + int zmk_endpoints_send_report(u8_t usage_page) { - int err; - struct zmk_hid_keypad_report *keypad_report; - struct zmk_hid_consumer_report *consumer_report; + LOG_DBG("usage page 0x%02X", usage_page); switch (usage_page) { case USAGE_KEYPAD: - keypad_report = zmk_hid_get_keypad_report(); -#ifdef CONFIG_ZMK_USB - if (zmk_usb_hid_send_report((u8_t *)keypad_report, sizeof(struct zmk_hid_keypad_report)) != - 0) { - LOG_DBG("USB Send Failed"); - } -#endif /* CONFIG_ZMK_USB */ - -#ifdef CONFIG_ZMK_BLE - err = zmk_hog_send_keypad_report(&keypad_report->body); - if (err) { - LOG_ERR("FAILED TO SEND OVER HOG: %d", err); - } -#endif /* CONFIG_ZMK_BLE */ - - break; + return send_keypad_report(); case USAGE_CONSUMER: - consumer_report = zmk_hid_get_consumer_report(); -#ifdef CONFIG_ZMK_USB - if (zmk_usb_hid_send_report((u8_t *)consumer_report, - sizeof(struct zmk_hid_consumer_report)) != 0) { - LOG_DBG("USB Send Failed"); - } -#endif /* CONFIG_ZMK_USB */ - -#ifdef CONFIG_ZMK_BLE - err = zmk_hog_send_consumer_report(&consumer_report->body); - if (err) { - LOG_ERR("FAILED TO SEND OVER HOG: %d", err); - } -#endif /* CONFIG_ZMK_BLE */ - - break; + return send_consumer_report(); default: LOG_ERR("Unsupported usage page %d", usage_page); return -ENOTSUP; } +} + +static bool is_usb_ready() { +#if IS_ENABLED(CONFIG_ZMK_USB) + return zmk_usb_is_hid_ready(); +#else + return false; +#endif +} + +static bool is_ble_ready() { +#if IS_ENABLED(CONFIG_ZMK_BLE) + return zmk_ble_active_profile_is_connected(); +#else + return false; +#endif +} + +static enum endpoint get_selected_endpoint() { + if (is_ble_ready()) { + if (is_usb_ready()) { + LOG_DBG("Both endpoints ready. Selecting USB"); + // TODO: add user setting to control this + return ENDPOINT_USB; + } + + return ENDPOINT_BLE; + } + + return ENDPOINT_USB; +} + +static int endpoint_listener(const struct zmk_event_header *eh) { + enum endpoint new_endpoint = get_selected_endpoint(); + + if (new_endpoint != current_endpoint) { + // TODO: send null report on previous endpoint + current_endpoint = new_endpoint; + LOG_INF("Endpoint changed: %d", current_endpoint); + } return 0; } + +ZMK_LISTENER(endpoint_listener, endpoint_listener); +#if IS_ENABLED(CONFIG_USB) +ZMK_SUBSCRIPTION(endpoint_listener, usb_conn_state_changed); +#endif +// TODO: add BLE state subscription \ No newline at end of file diff --git a/app/src/events/usb_conn_state_changed.c b/app/src/events/usb_conn_state_changed.c new file mode 100644 index 00000000..d845f6d7 --- /dev/null +++ b/app/src/events/usb_conn_state_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(usb_conn_state_changed); \ No newline at end of file diff --git a/app/src/power.c b/app/src/power.c index 73b3f123..bad54d28 100644 --- a/app/src/power.c +++ b/app/src/power.c @@ -23,14 +23,7 @@ static u32_t power_last_uptime; bool is_usb_power_present() { #ifdef CONFIG_USB - enum usb_dc_status_code usb_status = zmk_usb_get_status(); - switch (usb_status) { - case USB_DC_DISCONNECTED: - case USB_DC_UNKNOWN: - return false; - default: - return true; - } + return zmk_usb_is_powered(); #else return false; #endif /* CONFIG_USB */ diff --git a/app/src/usb.c b/app/src/usb.c index 434b3d4d..d4bc2e41 100644 --- a/app/src/usb.c +++ b/app/src/usb.c @@ -13,6 +13,8 @@ #include #include +#include +#include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); @@ -53,9 +55,34 @@ int zmk_usb_hid_send_report(const u8_t *report, size_t len) { #endif /* CONFIG_ZMK_USB */ +static void raise_usb_status_changed_event() { + struct usb_conn_state_changed *ev = new_usb_conn_state_changed(); + ev->conn_state = zmk_usb_get_conn_state(); + + ZMK_EVENT_RAISE(ev); +} + enum usb_dc_status_code zmk_usb_get_status() { return usb_status; } -void usb_status_cb(enum usb_dc_status_code status, const u8_t *params) { usb_status = status; }; +enum zmk_usb_conn_state zmk_usb_get_conn_state() { + switch (usb_status) { + case USB_DC_DISCONNECTED: + case USB_DC_UNKNOWN: + return ZMK_USB_CONN_NONE; + + case USB_DC_ERROR: + case USB_DC_RESET: + return ZMK_USB_CONN_POWERED; + + default: + return ZMK_USB_CONN_HID; + } +} + +void usb_status_cb(enum usb_dc_status_code status, const u8_t *params) { + usb_status = status; + raise_usb_status_changed_event(); +}; static int zmk_usb_init(struct device *_arg) { int usb_enable_ret;