Browse Source

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.
xmkb
Joel Spadin 4 years ago
parent
commit
1d369ffa73
  1. 1
      app/CMakeLists.txt
  2. 20
      app/include/zmk/events/usb-conn-state-changed.h
  3. 12
      app/include/zmk/usb.h
  4. 140
      app/src/endpoints.c
  5. 10
      app/src/events/usb_conn_state_changed.c
  6. 9
      app/src/power.c
  7. 29
      app/src/usb.c

1
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/modifiers_state_changed.c)
target_sources(app PRIVATE src/events/sensor_event.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_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) 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_key_press.c)
target_sources(app PRIVATE src/behaviors/behavior_reset.c) target_sources(app PRIVATE src/behaviors/behavior_reset.c)

20
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 <zephyr.h>
#include <usb/usb_device.h>
#include <zmk/event-manager.h>
#include <zmk/usb.h>
struct usb_conn_state_changed {
struct zmk_event_header header;
enum zmk_usb_conn_state conn_state;
};
ZMK_EVENT_DECLARE(usb_conn_state_changed);

12
app/include/zmk/usb.h

@ -12,8 +12,18 @@
#include <zmk/keys.h> #include <zmk/keys.h>
#include <zmk/hid.h> #include <zmk/hid.h>
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 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 #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 */ #endif /* CONFIG_ZMK_USB */

140
app/src/endpoints.c

@ -8,54 +8,138 @@
#include <zmk/hid.h> #include <zmk/hid.h>
#include <zmk/usb.h> #include <zmk/usb.h>
#include <zmk/hog.h> #include <zmk/hog.h>
#include <zmk/event-manager.h>
#include <zmk/events/usb-conn-state-changed.h>
#include <logging/log.h> #include <logging/log.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
int zmk_endpoints_send_report(u8_t usage_page) { enum endpoint {
int err; ENDPOINT_USB,
struct zmk_hid_keypad_report *keypad_report; ENDPOINT_BLE,
struct zmk_hid_consumer_report *consumer_report; };
LOG_DBG("usage page 0x%02X", usage_page);
switch (usage_page) { static enum endpoint current_endpoint =
case USAGE_KEYPAD: COND_CODE_1(IS_ENABLED(CONFIG_ZMK_BLE), (ENDPOINT_BLE), (ENDPOINT_USB));
keypad_report = zmk_hid_get_keypad_report();
#ifdef CONFIG_ZMK_USB static int send_keypad_report() {
if (zmk_usb_hid_send_report((u8_t *)keypad_report, sizeof(struct zmk_hid_keypad_report)) != struct zmk_hid_keypad_report *keypad_report = zmk_hid_get_keypad_report();
0) {
LOG_DBG("USB Send Failed"); 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);
} }
#endif /* CONFIG_ZMK_USB */ return err;
}
#endif /* IS_ENABLED(CONFIG_ZMK_USB) */
#ifdef CONFIG_ZMK_BLE #if IS_ENABLED(CONFIG_ZMK_BLE)
err = zmk_hog_send_keypad_report(&keypad_report->body); case ENDPOINT_BLE: {
int err = zmk_hog_send_keypad_report(&keypad_report->body);
if (err) { if (err) {
LOG_ERR("FAILED TO SEND OVER HOG: %d", err); LOG_ERR("FAILED TO SEND OVER HOG: %d", err);
} }
#endif /* CONFIG_ZMK_BLE */ return err;
}
#endif /* IS_ENABLED(CONFIG_ZMK_BLE) */
break; default:
case USAGE_CONSUMER: LOG_ERR("Unsupported endpoint %d", current_endpoint);
consumer_report = zmk_hid_get_consumer_report(); return -ENOTSUP;
#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"); 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);
} }
#endif /* CONFIG_ZMK_USB */ return err;
}
#endif /* IS_ENABLED(CONFIG_ZMK_USB) */
#ifdef CONFIG_ZMK_BLE #if IS_ENABLED(CONFIG_ZMK_BLE)
err = zmk_hog_send_consumer_report(&consumer_report->body); case ENDPOINT_BLE: {
int err = zmk_hog_send_consumer_report(&consumer_report->body);
if (err) { if (err) {
LOG_ERR("FAILED TO SEND OVER HOG: %d", err); LOG_ERR("FAILED TO SEND OVER HOG: %d", err);
} }
#endif /* CONFIG_ZMK_BLE */ 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) {
break; LOG_DBG("usage page 0x%02X", usage_page);
switch (usage_page) {
case USAGE_KEYPAD:
return send_keypad_report();
case USAGE_CONSUMER:
return send_consumer_report();
default: default:
LOG_ERR("Unsupported usage page %d", usage_page); LOG_ERR("Unsupported usage page %d", usage_page);
return -ENOTSUP; 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; 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

10
app/src/events/usb_conn_state_changed.c

@ -0,0 +1,10 @@
/*
* Copyright (c) 2020 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <kernel.h>
#include <zmk/events/usb-conn-state-changed.h>
ZMK_EVENT_IMPL(usb_conn_state_changed);

9
app/src/power.c

@ -23,14 +23,7 @@ static u32_t power_last_uptime;
bool is_usb_power_present() { bool is_usb_power_present() {
#ifdef CONFIG_USB #ifdef CONFIG_USB
enum usb_dc_status_code usb_status = zmk_usb_get_status(); return zmk_usb_is_powered();
switch (usb_status) {
case USB_DC_DISCONNECTED:
case USB_DC_UNKNOWN:
return false;
default:
return true;
}
#else #else
return false; return false;
#endif /* CONFIG_USB */ #endif /* CONFIG_USB */

29
app/src/usb.c

@ -13,6 +13,8 @@
#include <zmk/hid.h> #include <zmk/hid.h>
#include <zmk/keymap.h> #include <zmk/keymap.h>
#include <zmk/event-manager.h>
#include <zmk/events/usb-conn-state-changed.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); 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 */ #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; } 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) { static int zmk_usb_init(struct device *_arg) {
int usb_enable_ret; int usb_enable_ret;

Loading…
Cancel
Save