feat(split): Runtime selection of split transport (#2886)

feat(split): Runtime selection of split transport

Allow building multiple split transports, and select an active
one based on the transport availability. Wired split availability
depends on additional `detect-gpios` which must be a GPIO pin
that goes active when a wired connection is present.

feat(split): Suspend/resume wired UART devices.

To better support runtime split support, suspend/resume the UART
as necessary to save power when not using the UART.

docs(split): Document adjusting nRF52 UART interrupt priorities

For wired split on nRF52, you may need to adjust the priority for UART
interrupts lower, to ensure the interrupts used for timing sensitive
BT operations can run when needed, so document this in our pinctrl docs.

refactor(split): Restore use of aync UART on nRF52.

With fixes for Zephyr UART driver, re-enable using async API on nRF52.

fix(split): Minor wired split fixes.

Various minor fixes for wired split to avoid spurious TX in half duplex,
etc.

fix: Unconditionally define HID payloads to avoid error.

Don't conditionally define HID indicator payload, to avoid compilation
errors.

docs(split): Expand on details of split transports.

Expand the split keyboard documentation with a more fleshed out section
on the available split trasnports, and what is and isn't supported by
each, including the runtime selection functionality.

---------

Co-authored-by: Nicolas Munnich <98408764+nmunnich@users.noreply.github.com>
This commit is contained in:
Pete Johanson
2025-06-16 01:45:25 -06:00
committed by GitHub
parent 462d48b78e
commit 6b44d33db2
22 changed files with 830 additions and 93 deletions

View File

@@ -289,8 +289,6 @@ struct zmk_hid_keyboard_report {
struct zmk_hid_keyboard_report_body body;
} __packed;
#if IS_ENABLED(CONFIG_ZMK_HID_INDICATORS)
struct zmk_hid_led_report_body {
uint8_t leds;
} __packed;
@@ -300,8 +298,6 @@ struct zmk_hid_led_report {
struct zmk_hid_led_report_body body;
} __packed;
#endif // IS_ENABLED(CONFIG_ZMK_HID_INDICATORS)
struct zmk_hid_consumer_report_body {
#if IS_ENABLED(CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_BASIC)
uint8_t keys[CONFIG_ZMK_HID_CONSUMER_REPORT_SIZE];

View File

@@ -10,13 +10,23 @@
#include <zmk/split/transport/types.h>
struct zmk_split_transport_central;
typedef int (*zmk_split_transport_central_status_changed_cb_t)(
const struct zmk_split_transport_central *transport, struct zmk_split_transport_status status);
typedef int (*zmk_split_transport_central_send_command_t)(
uint8_t source, struct zmk_split_transport_central_command cmd);
typedef int (*zmk_split_transport_central_get_available_source_ids_t)(uint8_t *sources);
typedef int (*zmk_split_transport_central_set_status_callback_t)(
zmk_split_transport_central_status_changed_cb_t cb);
struct zmk_split_transport_central_api {
zmk_split_transport_central_send_command_t send_command;
zmk_split_transport_central_get_available_source_ids_t get_available_source_ids;
zmk_split_transport_set_enabled_t set_enabled;
zmk_split_transport_get_status_t get_status;
zmk_split_transport_central_set_status_callback_t set_status_callback;
};
struct zmk_split_transport_central {
@@ -27,7 +37,8 @@ int zmk_split_transport_central_peripheral_event_handler(
const struct zmk_split_transport_central *transport, uint8_t source,
struct zmk_split_transport_peripheral_event ev);
#define ZMK_SPLIT_TRANSPORT_CENTRAL_REGISTER(name, _api) \
STRUCT_SECTION_ITERABLE(zmk_split_transport_central, name) = { \
#define ZMK_SPLIT_TRANSPORT_CENTRAL_REGISTER(name, _api, priority) \
STRUCT_SECTION_ITERABLE_NAMED(zmk_split_transport_central, _CONCAT(priority, _##name), \
name) = { \
.api = _api, \
};

View File

@@ -10,11 +10,22 @@
#include <zmk/split/transport/types.h>
typedef int (*zmk_split_central_report_event_callback_t)(
struct zmk_split_transport_peripheral;
typedef int (*zmk_split_transport_peripheral_status_changed_cb_t)(
const struct zmk_split_transport_peripheral *transport,
struct zmk_split_transport_status status);
typedef int (*zmk_split_transport_peripheral_report_event_callback_t)(
const struct zmk_split_transport_peripheral_event *event);
typedef int (*zmk_split_transport_peripheral_set_status_callback_t)(
zmk_split_transport_peripheral_status_changed_cb_t cb);
struct zmk_split_transport_peripheral_api {
zmk_split_central_report_event_callback_t report_event;
zmk_split_transport_peripheral_report_event_callback_t report_event;
zmk_split_transport_set_enabled_t set_enabled;
zmk_split_transport_get_status_t get_status;
zmk_split_transport_peripheral_set_status_callback_t set_status_callback;
};
struct zmk_split_transport_peripheral {
@@ -25,7 +36,8 @@ int zmk_split_transport_peripheral_command_handler(
const struct zmk_split_transport_peripheral *transport,
struct zmk_split_transport_central_command cmd);
#define ZMK_SPLIT_TRANSPORT_PERIPHERAL_REGISTER(name, _api) \
STRUCT_SECTION_ITERABLE(zmk_split_transport_peripheral, name) = { \
#define ZMK_SPLIT_TRANSPORT_PERIPHERAL_REGISTER(name, _api, priority) \
STRUCT_SECTION_ITERABLE_NAMED(zmk_split_transport_peripheral, _CONCAT(priority, _##name), \
name) = { \
.api = _api, \
};

View File

@@ -10,6 +10,21 @@
#include <zmk/sensors.h>
#include <zephyr/sys/util.h>
enum zmk_split_transport_connections_status {
ZMK_SPLIT_TRANSPORT_CONNECTIONS_STATUS_DISCONNECTED = 0,
ZMK_SPLIT_TRANSPORT_CONNECTIONS_STATUS_SOME_CONNECTED,
ZMK_SPLIT_TRANSPORT_CONNECTIONS_STATUS_ALL_CONNECTED,
};
struct zmk_split_transport_status {
bool available;
bool enabled;
enum zmk_split_transport_connections_status connections;
};
typedef struct zmk_split_transport_status (*zmk_split_transport_get_status_t)(void);
typedef int (*zmk_split_transport_set_enabled_t)(bool enabled);
enum zmk_split_transport_peripheral_event_type {
ZMK_SPLIT_TRANSPORT_PERIPHERAL_EVENT_TYPE_KEY_POSITION_EVENT,
ZMK_SPLIT_TRANSPORT_PERIPHERAL_EVENT_TYPE_SENSOR_EVENT,