Skip to content

Commit

Permalink
feat(ble): add behavior to disconnect from BLE profile
Browse files Browse the repository at this point in the history
Adds new functionality and a behavior to disconnect an active BLE connection.
The motivation for this is that for some devices like phones, the presence of an
active BLE connection results in the onscreen keyboard being selected.
  • Loading branch information
chrisandreae authored Nov 20, 2023
1 parent d7d9eed commit 0a4b1a6
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 6 deletions.
2 changes: 2 additions & 0 deletions app/include/dt-bindings/zmk/bt.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#define BT_PRV_CMD 2
#define BT_SEL_CMD 3
// #define BT_FULL_RESET_CMD 4
#define BT_DISC_CMD 5

/*
Note: Some future commands will include additional parameters, so we
Expand All @@ -19,3 +20,4 @@ defines these aliases up front.
#define BT_NXT BT_NXT_CMD 0
#define BT_PRV BT_PRV_CMD 0
#define BT_SEL BT_SEL_CMD
#define BT_DISC BT_DISC_CMD
1 change: 1 addition & 0 deletions app/include/zmk/ble.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ int zmk_ble_clear_bonds();
int zmk_ble_prof_next();
int zmk_ble_prof_prev();
int zmk_ble_prof_select(uint8_t index);
int zmk_ble_prof_disconnect(uint8_t index);

int zmk_ble_active_profile_index();
bt_addr_le_t *zmk_ble_active_profile_addr();
Expand Down
2 changes: 2 additions & 0 deletions app/src/behaviors/behavior_bt.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
return zmk_ble_prof_prev();
case BT_SEL_CMD:
return zmk_ble_prof_select(binding->param2);
case BT_DISC_CMD:
return zmk_ble_prof_disconnect(binding->param2);
default:
LOG_ERR("Unknown BT command: %d", binding->param1);
}
Expand Down
21 changes: 21 additions & 0 deletions app/src/ble.c
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,27 @@ int zmk_ble_prof_prev() {
ZMK_BLE_PROFILE_COUNT);
};

int zmk_ble_prof_disconnect(uint8_t index) {
if (index >= ZMK_BLE_PROFILE_COUNT)
return -ERANGE;

bt_addr_le_t *addr = &profiles[index].peer;
struct bt_conn *conn;
int result;

if (!bt_addr_le_cmp(addr, BT_ADDR_LE_ANY)) {
return -ENODEV;
} else if ((conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr)) == NULL) {
return -ENODEV;
}

result = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
LOG_DBG("Disconnected from profile %d: %d", index, result);

bt_conn_unref(conn);
return result;
}

bt_addr_le_t *zmk_ble_active_profile_addr() { return &profiles[active_profile].peer; }

char *zmk_ble_active_profile_name() { return profiles[active_profile].name; }
Expand Down
21 changes: 15 additions & 6 deletions docs/docs/behaviors/bluetooth.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ computer/laptop/keyboard should receive the keyboard input; many of the commands
When pairing to a host device ZMK saves bond information to the selected profile. It will not replace this when you initiate pairing with another device. To pair with a new device select an unused profile with `BT_SEL`, `BT_NXT` or `BT_PRV` bindings, or by clearing an existing profile using `BT_CLR`.

A ZMK device may show as "connected" on multiple hosts at the same time. This is working as intended, and only the host associated with the active profile will receive keystrokes.

An _inactive_ connected profile can be explicitly disconnected using the `BT_DISC` behavior. This can be helpful in
cases when host devices behave differently when a bluetooth keyboard is connected, for example by hiding their on-screen
keyboard. Note that at present the active bluetooth profile will immediately reconnect if disconnected. This is true
even if OUT_USB is selected. To remain disconnected, another bluetooth profile must be first selected using (e.g.)
`BT_SEL`.

:::

## Bluetooth Command Defines
Expand All @@ -28,12 +35,14 @@ This will allow you to reference the actions defined in this header such as `BT_

Here is a table describing the command for each define:

| Define | Action |
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `BT_CLR` | Clear bond information between the keyboard and host for the selected profile. |
| `BT_NXT` | Switch to the next profile, cycling through to the first one when the end 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. Please note: this definition must include a number as an argument in the keymap to work correctly. eg. `BT_SEL 0` |
| Define | Action |
| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `BT_CLR` | Clear bond information between the keyboard and host for the selected profile. |
| `BT_NXT` | Switch to the next profile, cycling through to the first one when the end 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. Please note: this definition must include a number as an argument in the keymap to work correctly. eg. `BT_SEL 0` |
| `BT_DISC` | Disconnect from the 0-indexed profile by number, if it's currently connected and inactive. Please note: this definition must include a number as an |
| | argument in the keymap to work correctly. eg. `BT_DISC 0` |

:::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.
Expand Down

0 comments on commit 0a4b1a6

Please sign in to comment.