Skip to content

Commit

Permalink
feat(ble): handle user disconnection request
Browse files Browse the repository at this point in the history
  • Loading branch information
cvcore committed Jul 25, 2023
1 parent 4b5ecbc commit 7066739
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 14 deletions.
72 changes: 58 additions & 14 deletions app/src/ble.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <zmk/event_manager.h>
#include <zmk/events/ble_active_profile_changed.h>

#if IS_ENABLED(CONFIG_ZMK_HANDLE_BLE_DISCONNECTION)
#include <zmk/activity.h>
#include <zmk/events/keycode_state_changed.h>
#endif /* IS_ENABLED(CONFIG_ZMK_HANDLE_BLE_DISCONNECTION) */

#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY)
#include <zmk/events/keycode_state_changed.h>

Expand Down Expand Up @@ -63,11 +68,15 @@ enum advertising_type {

#define ZMK_ADV_CONN_NAME \
BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME, BT_GAP_ADV_FAST_INT_MIN_2, \
BT_GAP_ADV_FAST_INT_MAX_2, NULL)
BT_GAP_ADV_FAST_INT_MAX_2, NULL) // 100 - 150 ms advertising interval

static struct zmk_ble_profile profiles[ZMK_BLE_PROFILE_COUNT];
static uint8_t active_profile;

#if IS_ENABLED(CONFIG_ZMK_HANDLE_BLE_DISCONNECTION)
bool active_profile_seeking_connection = true;
#endif

#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)

Expand Down Expand Up @@ -133,6 +142,7 @@ bool zmk_ble_active_profile_is_connected() {
return info.state == BT_CONN_STATE_CONNECTED;
}

/* Stop advertising */
#define CHECKED_ADV_STOP() \
err = bt_le_adv_stop(); \
advertising_status = ZMK_ADV_NONE; \
Expand All @@ -141,6 +151,7 @@ bool zmk_ble_active_profile_is_connected() {
return err; \
}

/* Start direct advertising to peer if no connection exists for active profile */
#define CHECKED_DIR_ADV() \
addr = zmk_ble_active_profile_addr(); \
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr); \
Expand All @@ -157,6 +168,7 @@ bool zmk_ble_active_profile_is_connected() {
} \
advertising_status = ZMK_ADV_DIR;

/* Start open advertising with parameters specified in ZMK_ADV_CONN_NAME */
#define CHECKED_OPEN_ADV() \
err = bt_le_adv_start(ZMK_ADV_CONN_NAME, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0); \
if (err) { \
Expand All @@ -165,23 +177,32 @@ bool zmk_ble_active_profile_is_connected() {
} \
advertising_status = ZMK_ADV_CONN;

/* Update advertising mode according to the status of current profile */
int update_advertising() {
int err = 0;
bt_addr_le_t *addr;
struct bt_conn *conn;
enum advertising_type desired_adv = ZMK_ADV_NONE;

if (zmk_ble_active_profile_is_open()) {
if (zmk_ble_active_profile_is_open()) { // not paired
desired_adv = ZMK_ADV_CONN;
} else if (!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
// addr_str[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(zmk_ble_active_profile_addr(), addr_str,
// sizeof(addr_str));

// LOG_DBG("Directed advertising to %s", addr_str);
// desired_adv = ZMK_ADV_DIR;
} else { // paired
#if IS_ENABLED(CONFIG_ZMK_HANDLE_BLE_DISCONNECTION)
if (!zmk_ble_active_profile_is_connected() && active_profile_seeking_connection) {
desired_adv = ZMK_ADV_CONN;
}
#else
if (!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
// addr_str[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(zmk_ble_active_profile_addr(),
// addr_str, sizeof(addr_str));

// LOG_DBG("Directed advertising to %s", addr_str);
// desired_adv = ZMK_ADV_DIR;
}
#endif /* IS_ENABLED(CONFIG_ZMK_HANDLE_BLE_DISCONNECTION) */
}
LOG_DBG("advertising from %d to %d", advertising_status, desired_adv);

Expand Down Expand Up @@ -212,6 +233,7 @@ int update_advertising() {

static void update_advertising_callback(struct k_work *work) { update_advertising(); }

/* Define `update_advertising_work` work item. */
K_WORK_DEFINE(update_advertising_work, update_advertising_callback);

int zmk_ble_clear_bonds() {
Expand Down Expand Up @@ -255,6 +277,7 @@ static int ble_save_profile() {
#endif
}

/* Select bluetooth profile with `index` */
int zmk_ble_prof_select(uint8_t index) {
if (index >= ZMK_BLE_PROFILE_COUNT) {
return -ERANGE;
Expand All @@ -268,6 +291,9 @@ int zmk_ble_prof_select(uint8_t index) {
active_profile = index;
ble_save_profile();

#if IS_ENABLED(CONFIG_ZMK_HANDLE_BLE_DISCONNECTION)
active_profile_seeking_connection = true;
#endif
update_advertising();

raise_profile_changed_event();
Expand Down Expand Up @@ -297,7 +323,8 @@ void zmk_ble_set_peripheral_addr(bt_addr_le_t *addr) {
settings_save_one("ble/peripheral_address", addr, sizeof(bt_addr_le_t));
}

// This can be expanded to take peripheral index as an input when multiple peripherals are an option
// This can be expanded to take peripheral index as an input when multiple peripherals are an
// option

bt_addr_le_t *zmk_ble_get_peripheral_addr() { return &peripheral_addr; }

Expand Down Expand Up @@ -406,6 +433,9 @@ static void connected(struct bt_conn *conn, uint8_t err) {
update_advertising();

if (is_conn_active_profile(conn)) {
#if IS_ENABLED(CONFIG_ZMK_HANDLE_BLE_DISCONNECTION)
active_profile_seeking_connection = false;
#endif
LOG_DBG("Active profile connected");
k_work_submit(&raise_profile_changed_event_work);
}
Expand All @@ -426,8 +456,8 @@ static void disconnected(struct bt_conn *conn, uint8_t reason) {
return;
}

// We need to do this in a work callback, otherwise the advertising update will still see the
// connection for a profile as active, and not start advertising yet.
// We need to do this in a work callback, otherwise the advertising update will still see
// the connection for a profile as active, and not start advertising yet.
k_work_submit(&update_advertising_work);

if (is_conn_active_profile(conn)) {
Expand Down Expand Up @@ -694,4 +724,18 @@ ZMK_LISTENER(zmk_ble, zmk_ble_listener);
ZMK_SUBSCRIPTION(zmk_ble, zmk_keycode_state_changed);
#endif /* IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) */

#if IS_ENABLED(CONFIG_ZMK_HANDLE_BLE_DISCONNECTION)
/* Try to estabilish again BLE connection upon user key press */
static int ble_keypress_listener(const zmk_event_t *eh) {
if (as_zmk_keycode_state_changed(eh) != NULL && !active_profile_seeking_connection &&
!zmk_ble_active_profile_is_connected()) {
active_profile_seeking_connection = true;
k_work_submit(&update_advertising_work);
}
return 0;
}
ZMK_LISTENER(ble_keypress, ble_keypress_listener);
ZMK_SUBSCRIPTION(ble_keypress, zmk_keycode_state_changed);
#endif /* IS_ENABLED(CONFIG_ZMK_HANDLE_BLE_DISCONNECTION) */

SYS_INIT(zmk_ble_init, APPLICATION, CONFIG_ZMK_BLE_INIT_PRIORITY);
1 change: 1 addition & 0 deletions docs/docs/config/system.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ for more information on configuring Bluetooth.
| `CONFIG_ZMK_BLE_THREAD_PRIORITY` | int | Priority of the BLE notify thread | 5 |
| `CONFIG_ZMK_BLE_THREAD_STACK_SIZE` | int | Stack size of the BLE notify thread | 512 |
| `CONFIG_ZMK_BLE_PASSKEY_ENTRY` | bool | Experimental: require typing passkey from host to pair BLE connection | n |
| `CONFIG_ZMK_HANDLE_BLE_DISCONNECTION` | bool | Experimental: respect user disconnection request from computer | n |

Note that `CONFIG_BT_MAX_CONN` and `CONFIG_BT_MAX_PAIRED` should be set to the same value. On a split keyboard they should only be set for the central and must be set to one greater than the desired number of bluetooth profiles.

Expand Down

0 comments on commit 7066739

Please sign in to comment.