From ac43a1be315c0add6fe18a6beec21bf0b911eb66 Mon Sep 17 00:00:00 2001 From: ReFil <31960031+ReFil@users.noreply.github.com> Date: Thu, 10 Oct 2024 13:31:41 +0100 Subject: [PATCH] feat(ble): Add the ability to enable and disable advertising Currently advertising cannot be disabled, In some circumstances it may be desirable to disable advertising to the host e.g. seeking consistency between an endpoint switch and percieved board behaviour Update behavior_bt.c Revert "Update behavior_bt.c" This reverts commit d8225232f2d54bc2ec03d7d13a08028936c9bc1d. --- app/include/dt-bindings/zmk/bt.h | 6 ++++ app/include/zmk/ble.h | 9 ++++++ app/src/behaviors/behavior_bt.c | 24 ++++++++++++++++ app/src/ble.c | 36 +++++++++++++++++++----- docs/docs/keymaps/behaviors/bluetooth.md | 3 ++ 5 files changed, 71 insertions(+), 7 deletions(-) diff --git a/app/include/dt-bindings/zmk/bt.h b/app/include/dt-bindings/zmk/bt.h index aaad4dc5b8b..489c665f69c 100644 --- a/app/include/dt-bindings/zmk/bt.h +++ b/app/include/dt-bindings/zmk/bt.h @@ -10,6 +10,9 @@ #define BT_SEL_CMD 3 #define BT_CLR_ALL_CMD 4 #define BT_DISC_CMD 5 +#define BT_ADV_OFF_CMD 6 +#define BT_ADV_ON_CMD 7 +#define BT_ADV_TOG_CMD 8 /* Note: Some future commands will include additional parameters, so we @@ -22,3 +25,6 @@ defines these aliases up front. #define BT_SEL BT_SEL_CMD #define BT_CLR_ALL BT_CLR_ALL_CMD 0 #define BT_DISC BT_DISC_CMD +#define ADV_OFF BT_ADV_OFF_CMD 0 +#define ADV_ON BT_ADV_ON_CMD 0 +#define ADV_TOG BT_ADV_TOG_CMD 0 \ No newline at end of file diff --git a/app/include/zmk/ble.h b/app/include/zmk/ble.h index c44c5e16869..2c5cd6e1393 100644 --- a/app/include/zmk/ble.h +++ b/app/include/zmk/ble.h @@ -20,6 +20,12 @@ #define ZMK_BLE_PROFILE_COUNT CONFIG_BT_MAX_PAIRED #endif +enum advertising_type { + ZMK_ADV_NONE, + ZMK_ADV_DIR, + ZMK_ADV_CONN, +}; + void zmk_ble_clear_bonds(void); int zmk_ble_prof_next(void); int zmk_ble_prof_prev(void); @@ -41,6 +47,9 @@ int zmk_ble_unpair_all(void); int zmk_ble_set_device_name(char *name); +void zmk_ble_adv_mode_set(bool mode); +enum advertising_type zmk_ble_adv_mode_get(); + #if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) int zmk_ble_put_peripheral_addr(const bt_addr_le_t *addr); #endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */ diff --git a/app/src/behaviors/behavior_bt.c b/app/src/behaviors/behavior_bt.c index f439e49b1cf..966388647a2 100644 --- a/app/src/behaviors/behavior_bt.c +++ b/app/src/behaviors/behavior_bt.c @@ -43,6 +43,21 @@ static const struct behavior_parameter_value_metadata no_arg_values[] = { .type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE, .value = BT_CLR_CMD, }, + { + .display_name = "Disconnect All and Stop Advertising", + .type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE, + .value = BT_ADV_OFF_CMD, + }, + { + .display_name = "Start Advertising", + .type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE, + .value = BT_ADV_ON_CMD, + }, + { + .display_name = "Toggle Advertising", + .type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE, + .value = BT_ADV_TOG_CMD, + }, }; static const struct behavior_parameter_metadata_set no_args_set = { @@ -105,6 +120,15 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, return 0; case BT_DISC_CMD: return zmk_ble_prof_disconnect(binding->param2); + case BT_ADV_ON_CMD: + zmk_ble_adv_mode_set(true); + return 0; + case BT_ADV_OFF_CMD: + zmk_ble_adv_mode_set(false); + return 0; + case BT_ADV_TOG_CMD: + zmk_ble_adv_mode_set((zmk_ble_adv_mode_get() == ZMK_ADV_CONN) ? false : true); + return 0; default: LOG_ERR("Unknown BT command: %d", binding->param1); } diff --git a/app/src/ble.c b/app/src/ble.c index e63c63b0cca..5a82543b85d 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -47,11 +47,7 @@ RING_BUF_DECLARE(passkey_entries, PASSKEY_DIGITS); #endif /* IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) */ -enum advertising_type { - ZMK_ADV_NONE, - ZMK_ADV_DIR, - ZMK_ADV_CONN, -} advertising_status; +enum advertising_type advertising_status; #define CURR_ADV(adv) (adv << 4) @@ -63,6 +59,8 @@ enum advertising_type { static struct zmk_ble_profile profiles[ZMK_BLE_PROFILE_COUNT]; static uint8_t active_profile; +static bool permit_adv = true; + #define DEVICE_NAME CONFIG_BT_DEVICE_NAME #define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) @@ -167,9 +165,9 @@ int update_advertising(void) { struct bt_conn *conn; enum advertising_type desired_adv = ZMK_ADV_NONE; - if (zmk_ble_active_profile_is_open()) { + if (permit_adv && zmk_ble_active_profile_is_open()) { desired_adv = ZMK_ADV_CONN; - } else if (!zmk_ble_active_profile_is_connected()) { + } else if (permit_adv && !zmk_ble_active_profile_is_connected()) { desired_adv = ZMK_ADV_CONN; // Need to fix directed advertising for privacy centrals. See // https://github.com/zephyrproject-rtos/zephyr/pull/14984 char @@ -210,6 +208,30 @@ static void update_advertising_callback(struct k_work *work) { update_advertisin K_WORK_DEFINE(update_advertising_work, update_advertising_callback); +void zmk_ble_adv_mode_set(bool mode) { + if (mode) { + if (advertising_status != ZMK_ADV_CONN) { + permit_adv = true; + LOG_DBG("Enabling adv"); + } + update_advertising(); + } else { + if (advertising_status != ZMK_ADV_NONE) { + permit_adv = false; + LOG_DBG("Disabling adv and disconnecting"); + for (int i = 0; i < ZMK_BLE_PROFILE_COUNT; i++) { + int err = zmk_ble_prof_disconnect(i); + if (err) { + LOG_DBG("Failed to disconnect profile %d : %d", i, err); + } + } + update_advertising(); + } + } +} + +enum advertising_type zmk_ble_adv_mode_get() { return advertising_status; } + static void clear_profile_bond(uint8_t profile) { if (bt_addr_le_cmp(&profiles[profile].peer, BT_ADDR_LE_ANY)) { bt_unpair(BT_ID_DEFAULT, &profiles[profile].peer); diff --git a/docs/docs/keymaps/behaviors/bluetooth.md b/docs/docs/keymaps/behaviors/bluetooth.md index 93d0842814a..4a70951da52 100644 --- a/docs/docs/keymaps/behaviors/bluetooth.md +++ b/docs/docs/keymaps/behaviors/bluetooth.md @@ -46,6 +46,9 @@ Here is a table describing the command for each define: | `BT_PRV` | Switch to the previous profile, cycling through to the last one when the beginning is reached. | | `BT_SEL` | Select the 0-indexed profile by number; must include a number as an argument in the keymap to work correctly, e.g. `BT_SEL 0`. | | `BT_DISC` | Disconnect from the 0-indexed profile by number, if it's currently connected and inactive; must include a number as an argument in the keymap to work correctly, e.g. `BT_DISC 0`. | +| `ADV_OFF` | Disconnect from all profiles and disable advertising (The device will not show up as connectable on host devices) | +| `ADV_ON` | Enable Bluetooth advertising, the device will show up as connectable | +| `ADV_TOG` | Toggle advertising on and off | :::note[Selected profile persistence] The profile that is selected by the `BT_SEL`/`BT_PRV`/`BT_NXT` actions will be saved to flash storage and hence persist across restarts and firmware flashes.