Compare commits

...

2 Commits

Author SHA1 Message Date
Willow Herring 9d66bc448e
Merge fb35ed4d14 into e34793e8c7 2025-11-17 22:44:06 +01:00
ReFil fb35ed4d14 feat(ble): Add the ability to enable and disable advertising
Added functionality to enable and disable BLE advertising using new &bt behavior bindings, adds documentation for the new parameters and a note that default behavior is unchanged

Co-Authored-By: Nicolas Munnich <98408764+Nick-Munnich@users.noreply.github.com>
Co-Authored-By: Cem Aksoylar <caksoylar@users.noreply.github.com>
2025-08-02 20:21:52 +01:00
5 changed files with 73 additions and 7 deletions

View File

@ -10,6 +10,9 @@
#define BT_SEL_CMD 3 #define BT_SEL_CMD 3
#define BT_CLR_ALL_CMD 4 #define BT_CLR_ALL_CMD 4
#define BT_DISC_CMD 5 #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 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_SEL BT_SEL_CMD
#define BT_CLR_ALL BT_CLR_ALL_CMD 0 #define BT_CLR_ALL BT_CLR_ALL_CMD 0
#define BT_DISC BT_DISC_CMD #define BT_DISC BT_DISC_CMD
#define BT_ADV_OFF BT_ADV_OFF_CMD 0
#define BT_ADV_ON BT_ADV_ON_CMD 0
#define BT_ADV_TOG BT_ADV_TOG_CMD 0

View File

@ -19,6 +19,12 @@
#define ZMK_BLE_PROFILE_COUNT CONFIG_BT_MAX_PAIRED #define ZMK_BLE_PROFILE_COUNT CONFIG_BT_MAX_PAIRED
#endif #endif
enum advertising_type {
ZMK_ADV_NONE,
ZMK_ADV_DIR,
ZMK_ADV_CONN,
};
void zmk_ble_clear_bonds(void); void zmk_ble_clear_bonds(void);
int zmk_ble_prof_next(void); int zmk_ble_prof_next(void);
int zmk_ble_prof_prev(void); int zmk_ble_prof_prev(void);
@ -44,6 +50,9 @@ int zmk_ble_unpair_all(void);
int zmk_ble_set_device_name(char *name); int zmk_ble_set_device_name(char *name);
void zmk_ble_adv_enabled_set(bool adv_enabled);
bool zmk_ble_adv_enabled_get(void);
#if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) #if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
int zmk_ble_put_peripheral_addr(const bt_addr_le_t *addr); int zmk_ble_put_peripheral_addr(const bt_addr_le_t *addr);
#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */ #endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */

View File

@ -43,6 +43,21 @@ static const struct behavior_parameter_value_metadata no_arg_values[] = {
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE, .type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
.value = BT_CLR_CMD, .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 = { 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; return 0;
case BT_DISC_CMD: case BT_DISC_CMD:
return zmk_ble_prof_disconnect(binding->param2); return zmk_ble_prof_disconnect(binding->param2);
case BT_ADV_ON_CMD:
zmk_ble_adv_enabled_set(true);
return 0;
case BT_ADV_OFF_CMD:
zmk_ble_adv_enabled_set(false);
return 0;
case BT_ADV_TOG_CMD:
zmk_ble_adv_enabled_set(zmk_ble_adv_enabled_get() ? false : true);
return 0;
default: default:
LOG_ERR("Unknown BT command: %d", binding->param1); LOG_ERR("Unknown BT command: %d", binding->param1);
} }

View File

@ -47,11 +47,7 @@ RING_BUF_DECLARE(passkey_entries, PASSKEY_DIGITS);
#endif /* IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) */ #endif /* IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) */
enum advertising_type { enum advertising_type advertising_status;
ZMK_ADV_NONE,
ZMK_ADV_DIR,
ZMK_ADV_CONN,
} advertising_status;
#define CURR_ADV(adv) (adv << 4) #define CURR_ADV(adv) (adv << 4)
@ -63,6 +59,8 @@ enum advertising_type {
static struct zmk_ble_profile profiles[ZMK_BLE_PROFILE_COUNT]; static struct zmk_ble_profile profiles[ZMK_BLE_PROFILE_COUNT];
static uint8_t active_profile; static uint8_t active_profile;
static bool permit_adv = true;
#define DEVICE_NAME CONFIG_BT_DEVICE_NAME #define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) #define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
@ -181,9 +179,9 @@ int update_advertising(void) {
struct bt_conn *conn; struct bt_conn *conn;
enum advertising_type desired_adv = ZMK_ADV_NONE; 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; 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; desired_adv = ZMK_ADV_CONN;
// Need to fix directed advertising for privacy centrals. See // Need to fix directed advertising for privacy centrals. See
// https://github.com/zephyrproject-rtos/zephyr/pull/14984 char // https://github.com/zephyrproject-rtos/zephyr/pull/14984 char
@ -224,6 +222,28 @@ static void update_advertising_callback(struct k_work *work) { update_advertisin
K_WORK_DEFINE(update_advertising_work, update_advertising_callback); K_WORK_DEFINE(update_advertising_work, update_advertising_callback);
void zmk_ble_adv_enabled_set(bool adv_enabled) {
if (adv_enabled) {
if (advertising_status != ZMK_ADV_CONN) {
permit_adv = true;
LOG_DBG("Enabling adv");
}
update_advertising();
} else {
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();
}
}
bool zmk_ble_adv_enabled_get(void) { return permit_adv; }
static void clear_profile_bond(uint8_t profile) { static void clear_profile_bond(uint8_t profile) {
if (bt_addr_le_cmp(&profiles[profile].peer, BT_ADDR_LE_ANY)) { if (bt_addr_le_cmp(&profiles[profile].peer, BT_ADDR_LE_ANY)) {
bt_unpair(BT_ID_DEFAULT, &profiles[profile].peer); bt_unpair(BT_ID_DEFAULT, &profiles[profile].peer);

View File

@ -46,12 +46,19 @@ 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_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_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`. | | `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`. |
| `BT_ADV_OFF` | Disable advertising and disconnect from all profiles |
| `BT_ADV_ON` | Enable advertising and attempt to reconnect to profiles |
| `BT_ADV_TOG` | Toggle advertising on and off |
:::note[Selected profile persistence] :::note[Selected profile persistence]
The profile that is selected by the `BT_SEL`/`BT_PRV`/`BT_NXT` actions will be [saved to flash storage](../../config/settings.md) and hence persist across restarts and firmware flashes. The profile that is selected by the `BT_SEL`/`BT_PRV`/`BT_NXT` actions will be [saved to flash storage](../../config/settings.md) and hence persist across restarts and firmware flashes.
However it will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory. However it will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory.
::: :::
:::note[Advertising]
Bluetooth advertising is enabled in all situations by default, and doesn't have to be explicitly enabled via the bindings above.
:::
## Bluetooth Behavior ## Bluetooth Behavior
The bluetooth behavior completes an bluetooth action given on press. The bluetooth behavior completes an bluetooth action given on press.