Skip to content

Commit a140045

Browse files
committed
feat(split): allow central to connect to multiple peripherals
1 parent efcc49f commit a140045

File tree

4 files changed

+266
-134
lines changed

4 files changed

+266
-134
lines changed

app/Kconfig

+4
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ config ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE
121121
int "Max number of key position state events to queue when received from peripherals"
122122
default 5
123123

124+
config ZMK_SPLIT_BLE_CENTRAL_PERIPHERALS
125+
int "The number of peripherals the central should connect to"
126+
default 1
127+
124128
endif
125129

126130
if !ZMK_SPLIT_BLE_ROLE_CENTRAL

app/include/zmk/ble.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,5 @@ int zmk_ble_unpair_all();
2424
bool zmk_ble_handle_key_user(struct zmk_key_event *key_event);
2525

2626
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
27-
void zmk_ble_set_peripheral_addr(bt_addr_le_t *addr);
28-
#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */
27+
int zmk_ble_put_peripheral_addr(bt_addr_le_t *addr);
28+
#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */

app/src/ble.c

+66-18
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ static uint8_t passkey_entries[6] = {0, 0, 0, 0, 0, 0};
4040
static uint8_t passkey_digit = 0;
4141

4242
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
43-
#define PROFILE_COUNT (CONFIG_BT_MAX_PAIRED - 1)
43+
#define PROFILE_COUNT (CONFIG_BT_MAX_PAIRED - CONFIG_ZMK_SPLIT_BLE_CENTRAL_PERIPHERALS)
4444
#else
4545
#define PROFILE_COUNT CONFIG_BT_MAX_PAIRED
4646
#endif
@@ -89,7 +89,7 @@ static const struct bt_data zmk_ble_ad[] = {
8989

9090
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
9191

92-
static bt_addr_le_t peripheral_addr;
92+
static bt_addr_le_t peripheral_addrs[CONFIG_ZMK_SPLIT_BLE_CENTRAL_PERIPHERALS];
9393

9494
#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */
9595

@@ -281,9 +281,34 @@ char *zmk_ble_active_profile_name() { return profiles[active_profile].name; }
281281

282282
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
283283

284-
void zmk_ble_set_peripheral_addr(bt_addr_le_t *addr) {
285-
memcpy(&peripheral_addr, addr, sizeof(bt_addr_le_t));
286-
settings_save_one("ble/peripheral_address", addr, sizeof(bt_addr_le_t));
284+
int zmk_ble_put_peripheral_addr(bt_addr_le_t *addr) {
285+
for (int i = 0; i < CONFIG_ZMK_SPLIT_BLE_CENTRAL_PERIPHERALS; i++) {
286+
// If the address is recognized and already stored in settings, return
287+
// index and no additional action is necessary.
288+
if (!bt_addr_le_cmp(&peripheral_addrs[i], addr)) {
289+
return i;
290+
}
291+
292+
// If the peripheral address slot is open, store new peripheral in the
293+
// slot and return index. This compares against BT_ADDR_LE_ANY as that
294+
// is the zero value.
295+
if (!bt_addr_le_cmp(&peripheral_addrs[i], BT_ADDR_LE_ANY)) {
296+
char addr_str[BT_ADDR_LE_STR_LEN];
297+
bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
298+
LOG_DBG("Storing peripheral %s in slot %d", log_strdup(addr_str), i);
299+
300+
bt_addr_le_copy(&peripheral_addrs[i], addr);
301+
302+
char setting_name[32];
303+
sprintf(setting_name, "ble/peripheral_addresses/%d", i);
304+
settings_save_one(setting_name, addr, sizeof(bt_addr_le_t));
305+
306+
return i;
307+
}
308+
}
309+
310+
// The peripheral in question does not match any of the known peripherals.
311+
return -1;
287312
}
288313

289314
#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */
@@ -337,15 +362,20 @@ static int ble_profiles_handle_set(const char *name, size_t len, settings_read_c
337362
}
338363
}
339364
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
340-
else if (settings_name_steq(name, "peripheral_address", &next) && !next) {
365+
else if (settings_name_steq(name, "peripheral_addresses", &next) && next) {
341366
if (len != sizeof(bt_addr_le_t)) {
342367
return -EINVAL;
343368
}
344369

345-
int err = read_cb(cb_arg, &peripheral_addr, sizeof(bt_addr_le_t));
346-
if (err <= 0) {
347-
LOG_ERR("Failed to handle peripheral address from settings (err %d)", err);
348-
return err;
370+
int i = atoi(next);
371+
if (i >= CONFIG_ZMK_SPLIT_BLE_CENTRAL_PERIPHERALS) {
372+
LOG_ERR("Failed to store peripheral address");
373+
} else {
374+
int err = read_cb(cb_arg, &peripheral_addrs[i], sizeof(bt_addr_le_t));
375+
if (err <= 0) {
376+
LOG_ERR("Failed to handle peripheral address from settings (err %d)", err);
377+
return err;
378+
}
349379
}
350380
}
351381
#endif
@@ -361,19 +391,29 @@ static bool is_conn_active_profile(const struct bt_conn *conn) {
361391
}
362392

363393
static void connected(struct bt_conn *conn, uint8_t err) {
364-
char addr[BT_ADDR_LE_STR_LEN];
365-
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
394+
// Skip if MAC address if it matches a peripheral.
395+
char addr_str[BT_ADDR_LE_STR_LEN];
396+
const bt_addr_le_t *addr = bt_conn_get_dst(conn);
397+
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
398+
for (int i = 0; i < CONFIG_ZMK_SPLIT_BLE_CENTRAL_PERIPHERALS; i++) {
399+
if (!bt_addr_le_cmp(&peripheral_addrs[i], addr)) {
400+
return;
401+
}
402+
}
403+
#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */
404+
bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
405+
366406
LOG_DBG("Connected thread: %p", k_current_get());
367407

368408
advertising_status = ZMK_ADV_NONE;
369409

370410
if (err) {
371-
LOG_WRN("Failed to connect to %s (%u)", log_strdup(addr), err);
411+
LOG_WRN("Failed to connect to %s (%u)", log_strdup(addr_str), err);
372412
update_advertising();
373413
return;
374414
}
375415

376-
LOG_DBG("Connected %s", log_strdup(addr));
416+
LOG_DBG("Connected %s", log_strdup(addr_str));
377417

378418
err = bt_conn_le_param_update(conn, BT_LE_CONN_PARAM(0x0006, 0x000c, 30, 400));
379419
if (err) {
@@ -397,11 +437,19 @@ static void connected(struct bt_conn *conn, uint8_t err) {
397437
}
398438

399439
static void disconnected(struct bt_conn *conn, uint8_t reason) {
400-
char addr[BT_ADDR_LE_STR_LEN];
401-
402-
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
440+
// Skip if MAC address if it matches a peripheral.
441+
char addr_str[BT_ADDR_LE_STR_LEN];
442+
const bt_addr_le_t *addr = bt_conn_get_dst(conn);
443+
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
444+
for (int i = 0; i < CONFIG_ZMK_SPLIT_BLE_CENTRAL_PERIPHERALS; i++) {
445+
if (!bt_addr_le_cmp(&peripheral_addrs[i], addr)) {
446+
return;
447+
}
448+
}
449+
#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */
450+
bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
403451

404-
LOG_DBG("Disconnected from %s (reason 0x%02x)", log_strdup(addr), reason);
452+
LOG_DBG("Disconnected from %s (reason 0x%02x)", log_strdup(addr_str), reason);
405453

406454
// We need to do this in a work callback, otherwise the advertising update will still see the
407455
// connection for a profile as active, and not start advertising yet.

0 commit comments

Comments
 (0)