From bf6aa89e7222092c26fa5bd031aba9d9fdd6568f Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Wed, 20 Dec 2023 22:21:53 -0500 Subject: [PATCH 1/9] Disconnect old BLE profile when selecting new one --- app/src/ble.c | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/ble.c b/app/src/ble.c index a5f973a4..3efedcf4 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -261,6 +261,7 @@ int zmk_ble_prof_select(uint8_t index) { return 0; } + zmk_ble_prof_disconnect(active_profile); active_profile = index; ble_save_profile(); From 5cf41b75965371525a6420534065055431c99ce6 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 21 Dec 2023 02:14:31 -0500 Subject: [PATCH 2/9] Add fast switching config --- app/Kconfig | 4 ++++ app/src/ble.c | 20 ++++++++++++++++++-- docs/docs/config/bluetooth.md | 1 + 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/app/Kconfig b/app/Kconfig index a5fa54f6..9f593701 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -185,6 +185,10 @@ config BT_CTLR_PHY_2M config BT_TINYCRYPT_ECC default y if BT_HCI && !BT_CTLR +config ZMK_BLE_FAST_SWITCHING + bool "Fast switching between bluetooth profiles by maintaining connection" + default y + config SYSTEM_WORKQUEUE_STACK_SIZE default 4096 if SOC_RP2040 default 2048 diff --git a/app/src/ble.c b/app/src/ble.c index 3efedcf4..de3190ba 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -261,7 +261,10 @@ int zmk_ble_prof_select(uint8_t index) { return 0; } +#if !IS_ENABLED(CONFIG_ZMK_BLE_FAST_SWITCHING) zmk_ble_prof_disconnect(active_profile); +#endif + active_profile = index; ble_save_profile(); @@ -454,12 +457,25 @@ static void connected(struct bt_conn *conn, uint8_t err) { } #endif // !IS_ENABLED(CONFIG_BT_GATT_AUTO_SEC_REQ) - update_advertising(); - if (is_conn_active_profile(conn)) { LOG_DBG("Active profile connected"); k_work_submit(&raise_profile_changed_event_work); + +#if !IS_ENABLED(CONFIG_ZMK_BLE_FAST_SWITCHING) + // Due to a bug with directed advertising, we had to use open + // advertising and probably connected to multiple profiles. + // Now that we have the desired active connection, we disconnect + // everything else. + for (int i = 0; i < ZMK_BLE_PROFILE_COUNT; i++) { + if (i != active_profile && !bt_addr_le_cmp(&profiles[i].peer, BT_ADDR_LE_ANY)) { + zmk_ble_prof_disconnect(i); + } + } +#endif } + + update_advertising(); + } static void disconnected(struct bt_conn *conn, uint8_t reason) { diff --git a/docs/docs/config/bluetooth.md b/docs/docs/config/bluetooth.md index 9149b36b..1e666010 100644 --- a/docs/docs/config/bluetooth.md +++ b/docs/docs/config/bluetooth.md @@ -16,3 +16,4 @@ See [Configuration Overview](index.md) for instructions on how to change these s | `CONFIG_ZMK_BLE_EXPERIMENTAL_FEATURES` | bool | Aggregate config that enables both `CONFIG_ZMK_BLE_EXPERIMENTAL_CONN` and `CONFIG_ZMK_BLE_EXPERIMENTAL_SEC`. | n | | `CONFIG_ZMK_BLE_PASSKEY_ENTRY` | bool | Enable passkey entry during pairing for enhanced security. (Note: After enabling this, you will need to re-pair all previously paired hosts.) | n | | `CONFIG_BT_GATT_ENFORCE_SUBSCRIPTION` | bool | Low level setting for GATT subscriptions. Set to `n` to work around an annoying Windows bug with battery notifications. | y | +| `CONFIG_ZMK_BLE_FAST_SWITCHING` | bool | Enables faster switching between profiles by maintaining the bluetooth connection even after switching to a different profile. Disabling this will disconnect (but remain paired) from the old profile when selecting a new one. | y | From a171ff1f614d503bc93eb75957c70d510bad86e2 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 21 Dec 2023 02:28:55 -0500 Subject: [PATCH 3/9] Fix addr compare --- app/src/ble.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/ble.c b/app/src/ble.c index de3190ba..594fea11 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -467,7 +467,7 @@ static void connected(struct bt_conn *conn, uint8_t err) { // Now that we have the desired active connection, we disconnect // everything else. for (int i = 0; i < ZMK_BLE_PROFILE_COUNT; i++) { - if (i != active_profile && !bt_addr_le_cmp(&profiles[i].peer, BT_ADDR_LE_ANY)) { + if (i != active_profile && bt_addr_le_cmp(&profiles[i].peer, BT_ADDR_LE_ANY)) { zmk_ble_prof_disconnect(i); } } From 1a24da25aa606ecbd70d2bff781bb837993c8889 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 21 Dec 2023 02:48:13 -0500 Subject: [PATCH 4/9] Fix lint --- app/src/ble.c | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/ble.c b/app/src/ble.c index 594fea11..c788cdf1 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -475,7 +475,6 @@ static void connected(struct bt_conn *conn, uint8_t err) { } update_advertising(); - } static void disconnected(struct bt_conn *conn, uint8_t reason) { From aaf973efa2c7d9f7199e0b15cf81dc31730d2b31 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 21 Dec 2023 03:16:05 -0500 Subject: [PATCH 5/9] Update config/bluetooth.md wording Co-Authored-By: Cem Aksoylar --- docs/docs/config/bluetooth.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/config/bluetooth.md b/docs/docs/config/bluetooth.md index 1e666010..5d18e21e 100644 --- a/docs/docs/config/bluetooth.md +++ b/docs/docs/config/bluetooth.md @@ -16,4 +16,4 @@ See [Configuration Overview](index.md) for instructions on how to change these s | `CONFIG_ZMK_BLE_EXPERIMENTAL_FEATURES` | bool | Aggregate config that enables both `CONFIG_ZMK_BLE_EXPERIMENTAL_CONN` and `CONFIG_ZMK_BLE_EXPERIMENTAL_SEC`. | n | | `CONFIG_ZMK_BLE_PASSKEY_ENTRY` | bool | Enable passkey entry during pairing for enhanced security. (Note: After enabling this, you will need to re-pair all previously paired hosts.) | n | | `CONFIG_BT_GATT_ENFORCE_SUBSCRIPTION` | bool | Low level setting for GATT subscriptions. Set to `n` to work around an annoying Windows bug with battery notifications. | y | -| `CONFIG_ZMK_BLE_FAST_SWITCHING` | bool | Enables faster switching between profiles by maintaining the bluetooth connection even after switching to a different profile. Disabling this will disconnect (but remain paired) from the old profile when selecting a new one. | y | +| `CONFIG_ZMK_BLE_FAST_SWITCHING` | bool | Enable faster switching between profiles by maintaining the bluetooth connection even after switching to a different profile. Disabling this will disconnect from (but remain paired to) the previous profile after selecting a different one. | y | From 8d0474267bcb26e79d399797debfefd514c6cc90 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 21 Dec 2023 12:45:40 -0500 Subject: [PATCH 6/9] Disconnect on any connection --- app/src/ble.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/app/src/ble.c b/app/src/ble.c index c788cdf1..3efe6156 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -424,13 +424,15 @@ static int ble_profiles_handle_set(const char *name, size_t len, settings_read_c struct settings_handler profiles_handler = {.name = "ble", .h_set = ble_profiles_handle_set}; #endif /* IS_ENABLED(CONFIG_SETTINGS) */ -static bool is_conn_active_profile(const struct bt_conn *conn) { - return bt_addr_le_cmp(bt_conn_get_dst(conn), &profiles[active_profile].peer) == 0; +static bool is_addr_active_profile(const bt_addr_le_t *addr) { + return bt_addr_le_cmp(addr, &profiles[active_profile].peer) == 0; } static void connected(struct bt_conn *conn, uint8_t err) { char addr[BT_ADDR_LE_STR_LEN]; struct bt_conn_info info; + const bt_addr_le_t *dst = bt_conn_get_dst(conn); + LOG_DBG("Connected thread: %p", k_current_get()); bt_conn_get_info(conn, &info); @@ -440,7 +442,7 @@ static void connected(struct bt_conn *conn, uint8_t err) { return; } - bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + bt_addr_le_to_str(dst, addr, sizeof(addr)); advertising_status = ZMK_ADV_NONE; if (err) { @@ -457,19 +459,14 @@ static void connected(struct bt_conn *conn, uint8_t err) { } #endif // !IS_ENABLED(CONFIG_BT_GATT_AUTO_SEC_REQ) - if (is_conn_active_profile(conn)) { + if (is_addr_active_profile(dst)) { LOG_DBG("Active profile connected"); k_work_submit(&raise_profile_changed_event_work); - + } else { #if !IS_ENABLED(CONFIG_ZMK_BLE_FAST_SWITCHING) - // Due to a bug with directed advertising, we had to use open - // advertising and probably connected to multiple profiles. - // Now that we have the desired active connection, we disconnect - // everything else. - for (int i = 0; i < ZMK_BLE_PROFILE_COUNT; i++) { - if (i != active_profile && bt_addr_le_cmp(&profiles[i].peer, BT_ADDR_LE_ANY)) { - zmk_ble_prof_disconnect(i); - } + int index = zmk_ble_profile_index(dst); + if (index >= 0) { + zmk_ble_prof_disconnect(index); } #endif } @@ -480,8 +477,9 @@ static void connected(struct bt_conn *conn, uint8_t err) { static void disconnected(struct bt_conn *conn, uint8_t reason) { char addr[BT_ADDR_LE_STR_LEN]; struct bt_conn_info info; + const bt_addr_le_t *dst = bt_conn_get_dst(conn); - bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + bt_addr_le_to_str(dst, addr, sizeof(addr)); LOG_DBG("Disconnected from %s (reason 0x%02x)", addr, reason); @@ -496,7 +494,7 @@ static void disconnected(struct bt_conn *conn, uint8_t reason) { // connection for a profile as active, and not start advertising yet. k_work_submit(&update_advertising_work); - if (is_conn_active_profile(conn)) { + if (is_addr_active_profile(dst)) { LOG_DBG("Active profile disconnected"); k_work_submit(&raise_profile_changed_event_work); } From 95c911e13aa9a502becf2d1419692f3c9b4020e2 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 21 Dec 2023 16:18:27 -0500 Subject: [PATCH 7/9] Disconnect from hosts after pairing --- app/src/ble.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/app/src/ble.c b/app/src/ble.c index 3efe6156..a49a87eb 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -168,6 +168,8 @@ int update_advertising() { enum advertising_type desired_adv = ZMK_ADV_NONE; if (zmk_ble_active_profile_is_open()) { + // We don't have an address for the active profile, so we need to open + // advertise so any interested hosts can connect. desired_adv = ZMK_ADV_CONN; } else if (!zmk_ble_active_profile_is_connected()) { desired_adv = ZMK_ADV_CONN; @@ -251,6 +253,16 @@ static int ble_save_profile() { #endif } +#if !IS_ENABLED(CONFIG_ZMK_BLE_FAST_SWITCHING) +static void zmk_ble_disconnect_other_profiles(int keep_index) { + for (int i = 0; i < ZMK_BLE_PROFILE_COUNT; i++) { + if (i != keep_index && bt_addr_le_cmp(&profiles[i].peer, BT_ADDR_LE_ANY)) { + zmk_ble_prof_disconnect(i); + } + } +} +#endif + int zmk_ble_prof_select(uint8_t index) { if (index >= ZMK_BLE_PROFILE_COUNT) { return -ERANGE; @@ -262,7 +274,10 @@ int zmk_ble_prof_select(uint8_t index) { } #if !IS_ENABLED(CONFIG_ZMK_BLE_FAST_SWITCHING) - zmk_ble_prof_disconnect(active_profile); + if (zmk_ble_active_profile_is_open()) { + // We may have connected to multiple hosts while the active profile was open. + zmk_ble_disconnect_other_profiles(index); + } #endif active_profile = index; @@ -464,9 +479,14 @@ static void connected(struct bt_conn *conn, uint8_t err) { k_work_submit(&raise_profile_changed_event_work); } else { #if !IS_ENABLED(CONFIG_ZMK_BLE_FAST_SWITCHING) - int index = zmk_ble_profile_index(dst); - if (index >= 0) { - zmk_ble_prof_disconnect(index); + // If the active profile is open, then we don't know what host we want + // to connect to. We need to wait for the profile to pair before we can + // start disconnecting. + if (!zmk_ble_active_profile_is_open()) { + // A different host connected to us for some reason. Maybe we're in the + // middle of an open advertisement? + int result = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + LOG_DBG("Disconnected from %s: %d", addr, result); } #endif } @@ -609,6 +629,12 @@ static void auth_pairing_complete(struct bt_conn *conn, bool bonded) { } set_profile_address(active_profile, dst); + +#if !IS_ENABLED(CONFIG_ZMK_BLE_FAST_SWITCHING) + // We may have connected to multiple hosts while the active profile was open. + zmk_ble_disconnect_other_profiles(active_profile); +#endif + update_advertising(); }; From 9a8ca231a9f291201d921e5cda25caeafa3f6ea9 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 21 Dec 2023 17:44:36 -0500 Subject: [PATCH 8/9] Update active_profile before disconnecting inactive ones --- app/src/ble.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/app/src/ble.c b/app/src/ble.c index a49a87eb..9d9ff637 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -254,9 +254,9 @@ static int ble_save_profile() { } #if !IS_ENABLED(CONFIG_ZMK_BLE_FAST_SWITCHING) -static void zmk_ble_disconnect_other_profiles(int keep_index) { +static void zmk_ble_disconnect_inactive_profiles() { for (int i = 0; i < ZMK_BLE_PROFILE_COUNT; i++) { - if (i != keep_index && bt_addr_le_cmp(&profiles[i].peer, BT_ADDR_LE_ANY)) { + if (i != active_profile && bt_addr_le_cmp(&profiles[i].peer, BT_ADDR_LE_ANY)) { zmk_ble_prof_disconnect(i); } } @@ -273,14 +273,17 @@ int zmk_ble_prof_select(uint8_t index) { return 0; } -#if !IS_ENABLED(CONFIG_ZMK_BLE_FAST_SWITCHING) - if (zmk_ble_active_profile_is_open()) { +#if IS_ENABLED(CONFIG_ZMK_BLE_FAST_SWITCHING) + active_profile = index; +#else + bool was_active_profile_open = zmk_ble_active_profile_is_open(); + active_profile = index; + if (was_active_profile_open) { // We may have connected to multiple hosts while the active profile was open. - zmk_ble_disconnect_other_profiles(index); + zmk_ble_disconnect_inactive_profiles(); } #endif - active_profile = index; ble_save_profile(); update_advertising(); @@ -632,7 +635,7 @@ static void auth_pairing_complete(struct bt_conn *conn, bool bonded) { #if !IS_ENABLED(CONFIG_ZMK_BLE_FAST_SWITCHING) // We may have connected to multiple hosts while the active profile was open. - zmk_ble_disconnect_other_profiles(active_profile); + zmk_ble_disconnect_inactive_profiles(); #endif update_advertising(); From 65afd080510f9c71e81e42aa381b28203e7c2fbb Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sat, 23 Dec 2023 02:07:04 -0500 Subject: [PATCH 9/9] Always run disconnect inactive profiles after switching --- app/src/ble.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/app/src/ble.c b/app/src/ble.c index 9d9ff637..1e2ed6b2 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -273,15 +273,13 @@ int zmk_ble_prof_select(uint8_t index) { return 0; } -#if IS_ENABLED(CONFIG_ZMK_BLE_FAST_SWITCHING) active_profile = index; -#else - bool was_active_profile_open = zmk_ble_active_profile_is_open(); - active_profile = index; - if (was_active_profile_open) { - // We may have connected to multiple hosts while the active profile was open. - zmk_ble_disconnect_inactive_profiles(); - } + +#if !IS_ENABLED(CONFIG_ZMK_BLE_FAST_SWITCHING) + // If the previous profile wasn't paired, then we may be connected to + // multiple hosts during the open advertisement. And if it was, we still + // want to disconnect the previous profile. + zmk_ble_disconnect_inactive_profiles(); #endif ble_save_profile();