From bd5e07f842faf2b88bed6263793ff6f3ceca8a4d Mon Sep 17 00:00:00 2001 From: Nick Winans Date: Fri, 6 May 2022 00:19:08 -0500 Subject: [PATCH] feat(split): Increase split interval during idle --- app/src/split/bluetooth/CMakeLists.txt | 1 + app/src/split/bluetooth/Kconfig | 20 +++++ app/src/split/bluetooth/central.c | 1 - app/src/split/bluetooth/central_listener.c | 87 ++++++++++++++++++++++ 4 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 app/src/split/bluetooth/central_listener.c diff --git a/app/src/split/bluetooth/CMakeLists.txt b/app/src/split/bluetooth/CMakeLists.txt index 2980eb59..4258b209 100644 --- a/app/src/split/bluetooth/CMakeLists.txt +++ b/app/src/split/bluetooth/CMakeLists.txt @@ -9,6 +9,7 @@ if (NOT CONFIG_ZMK_SPLIT_ROLE_CENTRAL) endif() if (CONFIG_ZMK_SPLIT_ROLE_CENTRAL) target_sources(app PRIVATE central.c) + target_sources_ifdef(CONFIG_ZMK_SPLIT_BLE_PREF_IDLE app PRIVATE central_listener.c) endif() if (CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_PROXY) diff --git a/app/src/split/bluetooth/Kconfig b/app/src/split/bluetooth/Kconfig index 5f4a782f..c5f11945 100644 --- a/app/src/split/bluetooth/Kconfig +++ b/app/src/split/bluetooth/Kconfig @@ -74,6 +74,26 @@ config ZMK_SPLIT_BLE_PREF_TIMEOUT int "Supervision timeout to use for split central/peripheral connection" default 400 +config ZMK_SPLIT_BLE_PREF_IDLE + bool "Set slower split peripheral BLE params on idle to save power" + default y + +if ZMK_SPLIT_BLE_PREF_IDLE + +config ZMK_SPLIT_BLE_PREF_IDLE_INT + int "Peripheral idle connection interval in 1.25ms units" + default 18 + +config ZMK_SPLIT_BLE_PREF_IDLE_LATENCY + int "Peripheral idle latency in Connection Intervals" + default 10 + +config ZMK_SPLIT_BLE_PREF_IDLE_TIMEOUT + int "Peripheral idle supervision timeout in 10ms units" + default 400 + +endif # ZMK_SPLIT_BLE_PREF_IDLE + endif # ZMK_SPLIT_ROLE_CENTRAL if !ZMK_SPLIT_ROLE_CENTRAL diff --git a/app/src/split/bluetooth/central.c b/app/src/split/bluetooth/central.c index 6fdbcbd2..382c7bad 100644 --- a/app/src/split/bluetooth/central.c +++ b/app/src/split/bluetooth/central.c @@ -1178,7 +1178,6 @@ static void split_central_update_layers_callback(struct k_work *work) { LOG_DBG("Sent Layers over to peripheral"); raise_zmk_split_peripheral_layer_changed( (struct zmk_split_peripheral_layer_changed){.layers = layers}); - } } } diff --git a/app/src/split/bluetooth/central_listener.c b/app/src/split/bluetooth/central_listener.c new file mode 100644 index 00000000..87e471cb --- /dev/null +++ b/app/src/split/bluetooth/central_listener.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include + +#include +#include + +static void set_sleep_params(struct bt_conn *conn, void *data) { + struct bt_conn_info info; + + bt_conn_get_info(conn, &info); + + if (info.role == BT_CONN_ROLE_CENTRAL) { + int err = + bt_conn_le_param_update(conn, BT_LE_CONN_PARAM(CONFIG_ZMK_SPLIT_BLE_PREF_IDLE_INT, + CONFIG_ZMK_SPLIT_BLE_PREF_IDLE_INT, + CONFIG_ZMK_SPLIT_BLE_PREF_IDLE_LATENCY, + CONFIG_ZMK_SPLIT_BLE_PREF_IDLE_TIMEOUT)); + + if (err) { + LOG_DBG("Failed to sleep split connection: %d", err); + } + } +} + +static void set_wake_params(struct bt_conn *conn, void *data) { + struct bt_conn_info info; + + bt_conn_get_info(conn, &info); + + if (info.role == BT_CONN_ROLE_CENTRAL) { + int err = bt_conn_le_param_update( + conn, + BT_LE_CONN_PARAM(CONFIG_ZMK_SPLIT_BLE_PREF_INT, CONFIG_ZMK_SPLIT_BLE_PREF_INT, + CONFIG_ZMK_SPLIT_BLE_PREF_LATENCY, CONFIG_ZMK_SPLIT_BLE_PREF_TIMEOUT)); + + if (err) { + LOG_DBG("Failed to wake up split connection: %d", err); + } + } +} + +static void sleep_all() { + LOG_DBG("Setting idle connection parameters on peripherals"); + + bt_conn_foreach(BT_CONN_TYPE_LE, set_sleep_params, NULL); +} + +static void wake_all() { + LOG_DBG("Waking up from idle connection parameters on peripherals"); + + bt_conn_foreach(BT_CONN_TYPE_LE, set_wake_params, NULL); +} + +int central_event_handler(const zmk_event_t *eh) { + struct zmk_activity_state_changed *ev = as_zmk_activity_state_changed(eh); + if (ev == NULL) { + return -ENOTSUP; + } + + switch (ev->state) { + case ZMK_ACTIVITY_ACTIVE: + wake_all(); + break; + case ZMK_ACTIVITY_IDLE: + sleep_all(); + break; + case ZMK_ACTIVITY_SLEEP: + break; + default: + LOG_WRN("Unhandled activity state: %d", ev->state); + return -EINVAL; + } + return 0; +} + +ZMK_LISTENER(central, central_event_handler); +ZMK_SUBSCRIPTION(central, zmk_activity_state_changed);