Skip to content

Commit a6a0e2f

Browse files
committed
feat(core): Optionally disable endpoint fallback
Adds and documents a new Kconfig option to disable automatically falling back to a working endpoint if the preferred endpoint is unavailable
1 parent edf5c08 commit a6a0e2f

6 files changed

Lines changed: 90 additions & 26 deletions

File tree

app/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@ config USB_HID_POLL_INTERVAL_MS
141141

142142
endif # ZMK_USB
143143

144+
config ZMK_ENDPOINT_DISABLE_FALLBACK
145+
bool "Disable automatic endpoint fallback when preferred endpoint is unavailable"
146+
144147
menuconfig ZMK_BLE
145148
bool "BLE (HID over GATT)"
146149
select BT

app/include/zmk/endpoints.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
*/
1515
#define ZMK_ENDPOINT_STR_LEN 10
1616

17+
#define ZMK_ENDPOINT_NONE_COUNT 1
18+
1719
#ifdef CONFIG_ZMK_USB
1820
#define ZMK_ENDPOINT_USB_COUNT 1
1921
#else
@@ -33,7 +35,8 @@
3335
* Note that this value may change between firmware versions, so it should not
3436
* be used in any persistent storage.
3537
*/
36-
#define ZMK_ENDPOINT_COUNT (ZMK_ENDPOINT_USB_COUNT + ZMK_ENDPOINT_BLE_COUNT)
38+
#define ZMK_ENDPOINT_COUNT \
39+
(ZMK_ENDPOINT_NONE_COUNT + ZMK_ENDPOINT_USB_COUNT + ZMK_ENDPOINT_BLE_COUNT)
3740

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

@@ -64,10 +67,15 @@ int zmk_endpoints_select_transport(enum zmk_transport transport);
6467
int zmk_endpoints_toggle_transport(void);
6568

6669
/**
67-
* Gets the currently-selected endpoint.
70+
* Gets the currently in use endpoint.
6871
*/
6972
struct zmk_endpoint_instance zmk_endpoints_selected(void);
7073

74+
/**
75+
* Gets the preferred endpoint.
76+
*/
77+
struct zmk_endpoint_instance zmk_endpoints_preferred(void);
78+
7179
int zmk_endpoints_send_report(uint16_t usage_page);
7280

7381
#if IS_ENABLED(CONFIG_ZMK_POINTING)

app/include/zmk/endpoints_types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* The method by which data is sent.
1111
*/
1212
enum zmk_transport {
13+
ZMK_TRANSPORT_NONE,
1314
ZMK_TRANSPORT_USB,
1415
ZMK_TRANSPORT_BLE,
1516
};

app/src/endpoints.c

Lines changed: 66 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@
2323
#include <zephyr/logging/log.h>
2424
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
2525

26+
#if !IS_ENABLED(CONFIG_ZMK_ENDPOINT_DISABLE_FALLBACK)
2627
#define DEFAULT_TRANSPORT \
2728
COND_CODE_1(IS_ENABLED(CONFIG_ZMK_BLE), (ZMK_TRANSPORT_BLE), (ZMK_TRANSPORT_USB))
29+
#endif
2830

2931
static struct zmk_endpoint_instance current_instance = {};
3032
static enum zmk_transport preferred_transport =
@@ -54,6 +56,9 @@ bool zmk_endpoint_instance_eq(struct zmk_endpoint_instance a, struct zmk_endpoin
5456
}
5557

5658
switch (a.transport) {
59+
case ZMK_TRANSPORT_NONE:
60+
return true;
61+
5762
case ZMK_TRANSPORT_USB:
5863
return true;
5964

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

6873
int zmk_endpoint_instance_to_str(struct zmk_endpoint_instance endpoint, char *str, size_t len) {
6974
switch (endpoint.transport) {
75+
case ZMK_TRANSPORT_NONE:
76+
return snprintf(str, len, "None");
77+
7078
case ZMK_TRANSPORT_USB:
7179
return snprintf(str, len, "USB");
7280

@@ -78,11 +86,15 @@ int zmk_endpoint_instance_to_str(struct zmk_endpoint_instance endpoint, char *st
7886
}
7987
}
8088

81-
#define INSTANCE_INDEX_OFFSET_USB 0
82-
#define INSTANCE_INDEX_OFFSET_BLE ZMK_ENDPOINT_USB_COUNT
89+
#define INSTANCE_INDEX_OFFSET_NONE 0
90+
#define INSTANCE_INDEX_OFFSET_USB (INSTANCE_INDEX_OFFSET_NONE + ZMK_ENDPOINT_NONE_COUNT)
91+
#define INSTANCE_INDEX_OFFSET_BLE (INSTANCE_INDEX_OFFSET_USB + ZMK_ENDPOINT_USB_COUNT)
8392

8493
int zmk_endpoint_instance_to_index(struct zmk_endpoint_instance endpoint) {
8594
switch (endpoint.transport) {
95+
case ZMK_TRANSPORT_NONE:
96+
return INSTANCE_INDEX_OFFSET_NONE;
97+
8698
case ZMK_TRANSPORT_USB:
8799
return INSTANCE_INDEX_OFFSET_USB;
88100

@@ -118,6 +130,27 @@ int zmk_endpoints_toggle_transport(void) {
118130

119131
struct zmk_endpoint_instance zmk_endpoints_selected(void) { return current_instance; }
120132

133+
static struct zmk_endpoint_instance get_instance_from_transport(enum zmk_transport transport) {
134+
struct zmk_endpoint_instance instance = {.transport = transport};
135+
switch (instance.transport) {
136+
#if IS_ENABLED(CONFIG_ZMK_BLE)
137+
case ZMK_TRANSPORT_BLE:
138+
instance.ble.profile_index = zmk_ble_active_profile_index();
139+
break;
140+
#endif // IS_ENABLED(CONFIG_ZMK_BLE)
141+
142+
default:
143+
// No extra data for this transport.
144+
break;
145+
}
146+
147+
return instance;
148+
}
149+
150+
struct zmk_endpoint_instance zmk_endpoints_preferred(void) {
151+
return get_instance_from_transport(preferred_transport);
152+
}
153+
121154
static int send_keyboard_report(void) {
122155
switch (current_instance.transport) {
123156
case ZMK_TRANSPORT_USB: {
@@ -146,6 +179,8 @@ static int send_keyboard_report(void) {
146179
return -ENOTSUP;
147180
#endif /* IS_ENABLED(CONFIG_ZMK_BLE) */
148181
}
182+
case ZMK_TRANSPORT_NONE:
183+
return 0;
149184
}
150185

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

155190
static int send_consumer_report(void) {
156191
switch (current_instance.transport) {
192+
case ZMK_TRANSPORT_NONE:
193+
return 0;
194+
157195
case ZMK_TRANSPORT_USB: {
158196
#if IS_ENABLED(CONFIG_ZMK_USB)
159197
int err = zmk_usb_hid_send_consumer_report();
@@ -204,6 +242,9 @@ int zmk_endpoints_send_report(uint16_t usage_page) {
204242
#if IS_ENABLED(CONFIG_ZMK_POINTING)
205243
int zmk_endpoints_send_mouse_report() {
206244
switch (current_instance.transport) {
245+
case ZMK_TRANSPORT_NONE:
246+
return 0;
247+
207248
case ZMK_TRANSPORT_USB: {
208249
#if IS_ENABLED(CONFIG_ZMK_USB)
209250
int err = zmk_usb_hid_send_mouse_report();
@@ -281,7 +322,28 @@ static bool is_ble_ready(void) {
281322
#endif
282323
}
283324

325+
#if IS_ENABLED(CONFIG_ZMK_ENDPOINT_DISABLE_FALLBACK)
326+
284327
static enum zmk_transport get_selected_transport(void) {
328+
switch (preferred_transport) {
329+
case ZMK_TRANSPORT_NONE:
330+
return ZMK_TRANSPORT_NONE;
331+
332+
case ZMK_TRANSPORT_BLE:
333+
return is_ble_ready() ? ZMK_TRANSPORT_BLE : ZMK_TRANSPORT_NONE;
334+
335+
case ZMK_TRANSPORT_USB:
336+
return is_usb_ready() ? ZMK_TRANSPORT_USB : ZMK_TRANSPORT_NONE;
337+
}
338+
339+
LOG_ERR("Unknown transport %d", preferred_transport);
340+
return ZMK_TRANSPORT_NONE;
341+
}
342+
343+
#else
344+
345+
static enum zmk_transport get_selected_transport(void) {
346+
285347
if (is_ble_ready()) {
286348
if (is_usb_ready()) {
287349
LOG_DBG("Both endpoint transports are ready. Using %d", preferred_transport);
@@ -300,23 +362,10 @@ static enum zmk_transport get_selected_transport(void) {
300362
LOG_DBG("No endpoint transports are ready.");
301363
return DEFAULT_TRANSPORT;
302364
}
365+
#endif
303366

304367
static struct zmk_endpoint_instance get_selected_instance(void) {
305-
struct zmk_endpoint_instance instance = {.transport = get_selected_transport()};
306-
307-
switch (instance.transport) {
308-
#if IS_ENABLED(CONFIG_ZMK_BLE)
309-
case ZMK_TRANSPORT_BLE:
310-
instance.ble.profile_index = zmk_ble_active_profile_index();
311-
break;
312-
#endif // IS_ENABLED(CONFIG_ZMK_BLE)
313-
314-
default:
315-
// No extra data for this transport.
316-
break;
317-
}
318-
319-
return instance;
368+
return get_instance_from_transport(get_selected_transport());
320369
}
321370

322371
static int zmk_endpoints_init(void) {

docs/docs/config/system.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@ Definition file: [zmk/app/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/
1313

1414
### General
1515

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

2425
### HID
2526

docs/docs/keymaps/behaviors/outputs.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ keyboard to USB for power but outputting to a different device over bluetooth.
1212
By default, output is sent to USB when both USB and BLE are connected.
1313
Once you select a different output, it will be remembered until you change it again.
1414

15+
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)
16+
1517
:::note[Powering the keyboard via USB]
1618
ZMK is not always able to detect if the other end of a USB connection accepts keyboard input or not.
1719
So if you are using USB only to power your keyboard (for example with a charger or a portable power bank), you will want

0 commit comments

Comments
 (0)