diff --git a/app/Kconfig b/app/Kconfig index 3502c652..76035147 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -175,6 +175,14 @@ config ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE int "Max number of key position state events to queue when received from peripherals" default 5 +config ZMK_BLE_SPLIT_CENTRAL_SPLIT_RUN_STACK_SIZE + int "BLE split central write thread stack size" + default 512 + +config ZMK_BLE_SPLIT_CENTRAL_SPLIT_RUN_QUEUE_SIZE + int "Max number of behavior run events to queue to send to the peripheral(s)" + default 5 + endif if !ZMK_SPLIT_BLE_ROLE_CENTRAL diff --git a/app/src/split/bluetooth/central.c b/app/src/split/bluetooth/central.c index d123f4ec..c28941f1 100644 --- a/app/src/split/bluetooth/central.c +++ b/app/src/split/bluetooth/central.c @@ -352,6 +352,51 @@ static struct bt_conn_cb conn_callbacks = { .disconnected = split_central_disconnected, }; +K_THREAD_STACK_DEFINE(split_central_split_run_q_stack, + CONFIG_ZMK_BLE_SPLIT_CENTRAL_SPLIT_RUN_STACK_SIZE); + +struct k_work_q split_central_split_run_q; + +K_MSGQ_DEFINE(zmk_split_central_split_run_msgq, sizeof(struct zmk_split_run_behavior_payload), + CONFIG_ZMK_BLE_SPLIT_CENTRAL_SPLIT_RUN_QUEUE_SIZE, 4); + +void split_central_split_run_callback(struct k_work *work) { + struct zmk_split_run_behavior_payload payload; + + while (k_msgq_get(&zmk_split_central_split_run_msgq, &payload, K_NO_WAIT) == 0) { + int err = + bt_gatt_write_without_response(default_conn, run_behavior_handle, &payload, + sizeof(struct zmk_split_run_behavior_payload), true); + + if (err) { + LOG_ERR("Failed to write the behavior characteristic (err %d)", err); + } + } +} + +K_WORK_DEFINE(split_central_split_run_work, split_central_split_run_callback); + +static int split_bt_invoke_behavior_payload(struct zmk_split_run_behavior_payload payload) { + int err = k_msgq_put(&zmk_split_central_split_run_msgq, &payload, K_MSEC(100)); + if (err) { + switch (err) { + case -EAGAIN: { + LOG_WRN("Consumer message queue full, popping first message and queueing again"); + struct zmk_split_run_behavior_payload discarded_report; + k_msgq_get(&zmk_split_central_split_run_msgq, &discarded_report, K_NO_WAIT); + return split_bt_invoke_behavior_payload(payload); + } + default: + LOG_WRN("Failed to queue behavior to send (%d)", err); + return err; + } + } + + k_work_submit_to_queue(&split_central_split_run_q, &split_central_split_run_work); + + return 0; +}; + int zmk_split_bt_invoke_behavior(const bt_addr_le_t *source, struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, bool state) { struct zmk_split_run_behavior_payload payload = {.data = { @@ -363,17 +408,13 @@ int zmk_split_bt_invoke_behavior(const bt_addr_le_t *source, struct zmk_behavior strncpy(payload.behavior_dev, binding->behavior_dev, ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN - 1); payload.behavior_dev[ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN - 1] = '\0'; - int err = bt_gatt_write_without_response(default_conn, run_behavior_handle, &payload, - sizeof(struct zmk_split_run_behavior_payload), true); - - if (err) { - LOG_ERR("Failed to write the behavior characteristic (err %d)", err); - } - - return err; -}; + return split_bt_invoke_behavior_payload(payload); +} int zmk_split_bt_central_init(const struct device *_arg) { + k_work_q_start(&split_central_split_run_q, split_central_split_run_q_stack, + K_THREAD_STACK_SIZEOF(split_central_split_run_q_stack), + CONFIG_ZMK_BLE_THREAD_PRIORITY); bt_conn_cb_register(&conn_callbacks); return start_scan();