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.
This commit is contained in:
parent
dfb69d8727
commit
1d369ffa73
7 changed files with 190 additions and 45 deletions
|
@ -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
Normal file
20
app/include/zmk/events/usb-conn-state-changed.h
Normal file
|
@ -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,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 */
|
|
@ -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);
|
||||||
|
|
||||||
|
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 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);
|
LOG_DBG("usage page 0x%02X", usage_page);
|
||||||
switch (usage_page) {
|
switch (usage_page) {
|
||||||
case USAGE_KEYPAD:
|
case USAGE_KEYPAD:
|
||||||
keypad_report = zmk_hid_get_keypad_report();
|
return send_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;
|
|
||||||
case USAGE_CONSUMER:
|
case USAGE_CONSUMER:
|
||||||
consumer_report = zmk_hid_get_consumer_report();
|
return send_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;
|
|
||||||
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
Normal file
10
app/src/events/usb_conn_state_changed.c
Normal file
|
@ -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);
|
|
@ -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 */
|
||||||
|
|
|
@ -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…
Reference in a new issue