Added zmk_ble_active_profile_is_connected() to allow code outside ble.c to check the status of the active profile, and changed the ble_active_profile_changed event to also notify when the active profile connects or disconnects. Changed endpoint selection to to also update when the active profile changes, connects, or disconnects.
167 lines
No EOL
4.2 KiB
C
167 lines
No EOL
4.2 KiB
C
/*
|
|
* Copyright (c) 2020 The ZMK Contributors
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
#include <zmk/ble.h>
|
|
#include <zmk/endpoints.h>
|
|
#include <zmk/hid.h>
|
|
#include <zmk/usb.h>
|
|
#include <zmk/hog.h>
|
|
#include <zmk/event-manager.h>
|
|
#include <zmk/events/ble-active-profile-changed.h>
|
|
#include <zmk/events/usb-conn-state-changed.h>
|
|
|
|
#include <logging/log.h>
|
|
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|
|
|
enum endpoint {
|
|
ENDPOINT_USB,
|
|
ENDPOINT_BLE,
|
|
};
|
|
|
|
#define DEFAULT_ENDPOINT COND_CODE_1(IS_ENABLED(CONFIG_ZMK_BLE), (ENDPOINT_BLE), (ENDPOINT_USB))
|
|
|
|
static enum endpoint current_endpoint = DEFAULT_ENDPOINT;
|
|
|
|
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) {
|
|
|
|
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:
|
|
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 are ready.");
|
|
// TODO: add user setting to control this
|
|
return ENDPOINT_USB;
|
|
}
|
|
|
|
LOG_DBG("Only BLE is ready.");
|
|
return ENDPOINT_BLE;
|
|
}
|
|
|
|
if (is_usb_ready()) {
|
|
LOG_DBG("Only USB is ready.");
|
|
return ENDPOINT_USB;
|
|
}
|
|
|
|
LOG_DBG("No endpoints are ready.");
|
|
return DEFAULT_ENDPOINT;
|
|
}
|
|
|
|
static void disconnect_current_endpoint() {
|
|
zmk_hid_keypad_clear();
|
|
zmk_hid_consumer_clear();
|
|
|
|
zmk_endpoints_send_report(USAGE_KEYPAD);
|
|
zmk_endpoints_send_report(USAGE_CONSUMER);
|
|
}
|
|
|
|
static int endpoint_listener(const struct zmk_event_header *eh) {
|
|
enum endpoint new_endpoint = get_selected_endpoint();
|
|
|
|
if (new_endpoint != current_endpoint) {
|
|
/* 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);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
ZMK_LISTENER(endpoint_listener, endpoint_listener);
|
|
#if IS_ENABLED(CONFIG_ZMK_USB)
|
|
ZMK_SUBSCRIPTION(endpoint_listener, usb_conn_state_changed);
|
|
#endif
|
|
#if IS_ENABLED(CONFIG_ZMK_BLE)
|
|
ZMK_SUBSCRIPTION(endpoint_listener, ble_active_profile_changed);
|
|
#endif |