Skip to content

Commit

Permalink
feat(core): Optionally disable endpoint fallback
Browse files Browse the repository at this point in the history
Adds and documents a new Kconfig option to disable automatically falling back to a working endpoint if the preferred endpoint is unavailable
  • Loading branch information
ReFil committed Nov 25, 2024
1 parent fb359f5 commit e29af2d
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 26 deletions.
3 changes: 3 additions & 0 deletions app/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ config USB_HID_POLL_INTERVAL_MS
#ZMK_USB
endif

config ZMK_ENDPOINT_DISABLE_FALLBACK
bool "Disable automatic endpoint fallback when preferred endpoint is unavailable"

menuconfig ZMK_BLE
bool "BLE (HID over GATT)"
select BT
Expand Down
12 changes: 10 additions & 2 deletions app/include/zmk/endpoints.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
*/
#define ZMK_ENDPOINT_STR_LEN 10

#define ZMK_ENDPOINT_NONE_COUNT 1

#ifdef CONFIG_ZMK_USB
#define ZMK_ENDPOINT_USB_COUNT 1
#else
Expand All @@ -33,7 +35,8 @@
* 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)
#define ZMK_ENDPOINT_COUNT \
(ZMK_ENDPOINT_NONE_COUNT + ZMK_ENDPOINT_USB_COUNT + ZMK_ENDPOINT_BLE_COUNT)

bool zmk_endpoint_instance_eq(struct zmk_endpoint_instance a, struct zmk_endpoint_instance b);

Expand Down Expand Up @@ -64,10 +67,15 @@ int zmk_endpoints_select_transport(enum zmk_transport transport);
int zmk_endpoints_toggle_transport(void);

/**
* Gets the currently-selected endpoint.
* Gets the currently in use endpoint.
*/
struct zmk_endpoint_instance zmk_endpoints_selected(void);

/**
* Gets the preferred endpoint.
*/
struct zmk_endpoint_instance zmk_endpoints_preferred(void);

int zmk_endpoints_send_report(uint16_t usage_page);

#if IS_ENABLED(CONFIG_ZMK_MOUSE)
Expand Down
1 change: 1 addition & 0 deletions app/include/zmk/endpoints_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* The method by which data is sent.
*/
enum zmk_transport {
ZMK_TRANSPORT_NONE,
ZMK_TRANSPORT_USB,
ZMK_TRANSPORT_BLE,
};
Expand Down
83 changes: 66 additions & 17 deletions app/src/endpoints.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);

#if !IS_ENABLED(CONFIG_ZMK_ENDPOINT_DISABLE_FALLBACK)
#define DEFAULT_TRANSPORT \
COND_CODE_1(IS_ENABLED(CONFIG_ZMK_BLE), (ZMK_TRANSPORT_BLE), (ZMK_TRANSPORT_USB))
#endif

static struct zmk_endpoint_instance current_instance = {};
static enum zmk_transport preferred_transport =
Expand Down Expand Up @@ -54,6 +56,9 @@ bool zmk_endpoint_instance_eq(struct zmk_endpoint_instance a, struct zmk_endpoin
}

switch (a.transport) {
case ZMK_TRANSPORT_NONE:
return true;

case ZMK_TRANSPORT_USB:
return true;

Expand All @@ -67,6 +72,9 @@ bool zmk_endpoint_instance_eq(struct zmk_endpoint_instance a, struct zmk_endpoin

int zmk_endpoint_instance_to_str(struct zmk_endpoint_instance endpoint, char *str, size_t len) {
switch (endpoint.transport) {
case ZMK_TRANSPORT_NONE:
return snprintf(str, len, "None");

case ZMK_TRANSPORT_USB:
return snprintf(str, len, "USB");

Expand All @@ -78,11 +86,15 @@ int zmk_endpoint_instance_to_str(struct zmk_endpoint_instance endpoint, char *st
}
}

#define INSTANCE_INDEX_OFFSET_USB 0
#define INSTANCE_INDEX_OFFSET_BLE ZMK_ENDPOINT_USB_COUNT
#define INSTANCE_INDEX_OFFSET_NONE 0
#define INSTANCE_INDEX_OFFSET_USB (INSTANCE_INDEX_OFFSET_NONE + ZMK_ENDPOINT_NONE_COUNT)
#define INSTANCE_INDEX_OFFSET_BLE (INSTANCE_INDEX_OFFSET_USB + ZMK_ENDPOINT_USB_COUNT)

int zmk_endpoint_instance_to_index(struct zmk_endpoint_instance endpoint) {
switch (endpoint.transport) {
case ZMK_TRANSPORT_NONE:
return INSTANCE_INDEX_OFFSET_NONE;

case ZMK_TRANSPORT_USB:
return INSTANCE_INDEX_OFFSET_USB;

Expand Down Expand Up @@ -118,6 +130,27 @@ int zmk_endpoints_toggle_transport(void) {

struct zmk_endpoint_instance zmk_endpoints_selected(void) { return current_instance; }

static struct zmk_endpoint_instance get_instance_from_transport(enum zmk_transport transport) {
struct zmk_endpoint_instance instance = {.transport = 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;
}

struct zmk_endpoint_instance zmk_endpoints_preferred(void) {
return get_instance_from_transport(preferred_transport);
}

static int send_keyboard_report(void) {
switch (current_instance.transport) {
case ZMK_TRANSPORT_USB: {
Expand Down Expand Up @@ -146,6 +179,8 @@ static int send_keyboard_report(void) {
return -ENOTSUP;
#endif /* IS_ENABLED(CONFIG_ZMK_BLE) */
}
case ZMK_TRANSPORT_NONE:
return 0;
}

LOG_ERR("Unhandled endpoint transport %d", current_instance.transport);
Expand All @@ -154,6 +189,9 @@ static int send_keyboard_report(void) {

static int send_consumer_report(void) {
switch (current_instance.transport) {
case ZMK_TRANSPORT_NONE:
return 0;

case ZMK_TRANSPORT_USB: {
#if IS_ENABLED(CONFIG_ZMK_USB)
int err = zmk_usb_hid_send_consumer_report();
Expand Down Expand Up @@ -204,6 +242,9 @@ int zmk_endpoints_send_report(uint16_t usage_page) {
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
int zmk_endpoints_send_mouse_report() {
switch (current_instance.transport) {
case ZMK_TRANSPORT_NONE:
return 0;

case ZMK_TRANSPORT_USB: {
#if IS_ENABLED(CONFIG_ZMK_USB)
int err = zmk_usb_hid_send_mouse_report();
Expand Down Expand Up @@ -281,7 +322,28 @@ static bool is_ble_ready(void) {
#endif
}

#if IS_ENABLED(CONFIG_ZMK_ENDPOINT_DISABLE_FALLBACK)

static enum zmk_transport get_selected_transport(void) {
switch (preferred_transport) {
case ZMK_TRANSPORT_NONE:
return ZMK_TRANSPORT_NONE;

case ZMK_TRANSPORT_BLE:
return is_ble_ready() ? ZMK_TRANSPORT_BLE : ZMK_TRANSPORT_NONE;

case ZMK_TRANSPORT_USB:
return is_usb_ready() ? ZMK_TRANSPORT_USB : ZMK_TRANSPORT_NONE;
}

LOG_ERR("Unknown transport %d", preferred_transport);
return ZMK_TRANSPORT_NONE;
}

#else

static enum zmk_transport get_selected_transport(void) {

if (is_ble_ready()) {
if (is_usb_ready()) {
LOG_DBG("Both endpoint transports are ready. Using %d", preferred_transport);
Expand All @@ -300,23 +362,10 @@ static enum zmk_transport get_selected_transport(void) {
LOG_DBG("No endpoint transports are ready.");
return DEFAULT_TRANSPORT;
}
#endif

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;
return get_instance_from_transport(get_selected_transport());
}

static int zmk_endpoints_init(void) {
Expand Down
15 changes: 8 additions & 7 deletions docs/docs/config/system.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ Definition file: [zmk/app/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/

### General

| Config | Type | Description | Default |
| ------------------------------------ | ------ | ----------------------------------------------------------------------------- | ------- |
| `CONFIG_ZMK_KEYBOARD_NAME` | string | The name of the keyboard (max 16 characters) | |
| `CONFIG_ZMK_SETTINGS_RESET_ON_START` | bool | Clears all persistent settings from the keyboard at startup | n |
| `CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE` | int | Milliseconds to wait after a setting change before writing it to flash memory | 60000 |
| `CONFIG_ZMK_WPM` | bool | Enable calculating words per minute | n |
| `CONFIG_HEAP_MEM_POOL_SIZE` | int | Size of the heap memory pool | 8192 |
| Config | Type | Description | Default |
| -------------------------------------- | ------ | --------------------------------------------------------------------------------------------- | ------- |
| `CONFIG_ZMK_KEYBOARD_NAME` | string | The name of the keyboard (max 16 characters) | |
| `CONFIG_ZMK_SETTINGS_RESET_ON_START` | bool | Clears all persistent settings from the keyboard at startup | n |
| `CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE` | int | Milliseconds to wait after a setting change before writing it to flash memory | 60000 |
| `CONFIG_ZMK_WPM` | bool | Enable calculating words per minute | n |
| `CONFIG_HEAP_MEM_POOL_SIZE` | int | Size of the heap memory pool | 8192 |
| `CONFIG_ZMK_ENDPOINT_DISABLE_FALLBACK` | bool | Disable automatically falling back to the other endpoint if preferred endpoint is unavailable | n |

### HID

Expand Down
2 changes: 2 additions & 0 deletions docs/docs/keymaps/behaviors/outputs.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ keyboard to USB for power but outputting to a different device over bluetooth.
By default, output is sent to USB when both USB and BLE are connected.
Once you select a different output, it will be remembered until you change it again.

By default, if USB is selected but only BLE is available or vice versa the keyboard will output to the connected output. If this behavior is not desired you can change it so the keyboard will insist on using the selected output even if it not available using [`CONFIG_ZMK_ENDPOINT_DISABLE_FALLBACK`](../../config/system.md#general)

:::note[Powering the keyboard via USB]
ZMK is not always able to detect if the other end of a USB connection accepts keyboard input or not.
So if you are using USB only to power your keyboard (for example with a charger or a portable power bank), you will want
Expand Down

0 comments on commit e29af2d

Please sign in to comment.