feat(bluetooth): Add back profiles, split fixes.

* Add back in profiles, not using Zephyr
  BT identity infrastructure.
* Restore additional `&bt` commands for profile
  operations.
* Fix for split pairing and subscriptions, since
  Zephyr persists subscriptions across connects.
* Remove keymap from peripheral builds, reduces
  firmware size, and avoids unneeded attempts
  to send HID data.
This commit is contained in:
Pete Johanson 2020-09-08 23:26:00 -04:00
parent e88d0833c5
commit 39f980a06d
14 changed files with 376 additions and 128 deletions

View File

@ -29,23 +29,26 @@ target_sources(app PRIVATE src/hid.c)
target_sources(app PRIVATE src/sensors.c)
target_sources_ifdef(CONFIG_ZMK_DISPLAY app PRIVATE src/display.c)
target_sources(app PRIVATE src/event_manager.c)
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/ble_unpair_combo.c)
target_sources(app PRIVATE src/events/position_state_changed.c)
target_sources(app PRIVATE src/events/keycode_state_changed.c)
target_sources(app PRIVATE src/events/modifiers_state_changed.c)
target_sources(app PRIVATE src/events/sensor_event.c)
target_sources(app PRIVATE src/behaviors/behavior_key_press.c)
target_sources(app PRIVATE src/behaviors/behavior_reset.c)
target_sources(app PRIVATE src/behaviors/behavior_hold_tap.c)
target_sources(app PRIVATE src/behaviors/behavior_momentary_layer.c)
target_sources(app PRIVATE src/behaviors/behavior_toggle_layer.c)
target_sources(app PRIVATE src/behaviors/behavior_transparent.c)
target_sources(app PRIVATE src/behaviors/behavior_none.c)
target_sources(app PRIVATE src/behaviors/behavior_sensor_rotate_key_press.c)
target_sources(app PRIVATE src/keymap.c)
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/events/ble_active_profile_changed.c)
if (NOT CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL)
target_sources(app PRIVATE src/behaviors/behavior_key_press.c)
target_sources(app PRIVATE src/behaviors/behavior_reset.c)
target_sources(app PRIVATE src/behaviors/behavior_hold_tap.c)
target_sources(app PRIVATE src/behaviors/behavior_momentary_layer.c)
target_sources(app PRIVATE src/behaviors/behavior_toggle_layer.c)
target_sources(app PRIVATE src/behaviors/behavior_transparent.c)
target_sources(app PRIVATE src/behaviors/behavior_none.c)
target_sources(app PRIVATE src/behaviors/behavior_sensor_rotate_key_press.c)
target_sources(app PRIVATE src/keymap.c)
endif()
target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/behaviors/behavior_rgb_underglow.c)
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/behaviors/behavior_bt.c)
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/ble.c)
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/ble_unpair_combo.c)
target_sources_ifdef(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL app PRIVATE src/split_listener.c)
target_sources_ifdef(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL app PRIVATE src/split/bluetooth/service.c)
target_sources_ifdef(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL app PRIVATE src/split/bluetooth/central.c)

View File

@ -37,6 +37,7 @@ menuconfig ZMK_BLE
select BT
select BT_SMP
select BT_SMP_SC_PAIR_ONLY
select BT_SMP_APP_PAIRING_ACCEPT
select BT_PERIPHERAL
select BT_GATT_DIS
select BT_GATT_BAS
@ -105,19 +106,9 @@ config ZMK_SPLIT_BLE_ROLE_CENTRAL
select BT_CENTRAL
select BT_GATT_CLIENT
if ZMK_SPLIT_BLE_ROLE_CENTRAL
config BT_MAX_CONN
default 2
config BT_MAX_PAIRED
# Bump this everywhere once we support switching active connections!
default 2
endif
config ZMK_SPLIT_BLE_ROLE_PERIPHERAL
bool "Peripheral"
select BT_KEYS_OVERWRITE_OLDEST
if ZMK_SPLIT_BLE_ROLE_PERIPHERAL
@ -128,16 +119,25 @@ config BT_MAX_PAIRED
default 1
config BT_MAX_CONN
default 2
default 1
config BT_GAP_AUTO_UPDATE_CONN_PARAMS
default n
endif
endchoice
if ZMK_BLE && (!ZMK_SPLIT_BLE || ZMK_SPLIT_BLE_ROLE_CENTRAL)
config BT_MAX_CONN
default 6
config BT_MAX_PAIRED
default 5
endif
endif
endif

View File

@ -4,11 +4,18 @@
* SPDX-License-Identifier: MIT
*/
#define BT_CLEAR_BONDS_CMD 0
#define BT_CLEAR_BONDS_CMD 0
#define BT_PROF_NEXT_CMD 1
#define BT_PROF_PREV_CMD 2
#define BT_PROF_SEL_CMD 3
// #define BT_FULL_RESET_CMD 4
/*
Note: Some future commands will include additional parameters, so we
defines these aliases up front.
*/
#define BT_CLEAR_BONDS BT_CLEAR_BONDS_CMD 0
#define BT_CLEAR_BONDS BT_CLEAR_BONDS_CMD 0
#define BT_PROF_NEXT BT_PROF_NEXT_CMD 0
#define BT_PROF_PREV BT_PROF_PREV_CMD 0
#define BT_PROF_SEL BT_PROF_SEL_CMD

View File

@ -6,11 +6,16 @@
#pragma once
#include <bluetooth/addr.h>
#include <zmk/keys.h>
#include <zmk/ble/profile.h>
int zmk_ble_clear_bonds();
int zmk_ble_prof_next();
int zmk_ble_prof_prev();
int zmk_ble_prof_select(u8_t index);
bt_addr_le_t *zmk_ble_active_profile_addr();
char *zmk_ble_active_profile_name();
int zmk_ble_unpair_all();
bool zmk_ble_handle_key_user(struct zmk_key_event *key_event);

View File

@ -0,0 +1,16 @@
/*
* Copyright (c) 2020 Peter Johanson <peter@peterjohanson.com>
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <bluetooth/addr.h>
#define ZMK_BLE_PROFILE_NAME_MAX 15
struct zmk_ble_profile {
char name[ZMK_BLE_PROFILE_NAME_MAX];
bt_addr_le_t peer;
};

View File

@ -0,0 +1,22 @@
/*
* Copyright (c) 2020 Peter Johanson <peter@peterjohanson.com>
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <zephyr.h>
#include <zmk/event-manager.h>
#include <device.h>
#include <zmk/ble/profile.h>
struct ble_active_profile_changed {
struct zmk_event_header header;
u8_t index;
struct zmk_ble_profile *profile;
};
ZMK_EVENT_DECLARE(ble_active_profile_changed);

View File

@ -24,6 +24,12 @@ static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t c
{
case BT_CLEAR_BONDS_CMD:
return zmk_ble_clear_bonds();
case BT_PROF_NEXT_CMD:
return zmk_ble_prof_next();
case BT_PROF_PREV_CMD:
return zmk_ble_prof_prev();
case BT_PROF_SEL_CMD:
return zmk_ble_prof_select(arg);
default:
LOG_ERR("Unknown BT command: %d", command);
}

View File

@ -25,49 +25,30 @@
#endif
#include <logging/log.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <zmk/ble.h>
#include <zmk/keys.h>
#include <zmk/split/bluetooth/uuid.h>
#include <zmk/event-manager.h>
#include <zmk/events/ble-active-profile-changed.h>
static struct bt_conn *auth_passkey_entry_conn;
static u8_t passkey_entries[6] = {0, 0, 0, 0, 0, 0};
static u8_t passkey_digit = 0;
#define ZMK_BT_LE_ADV_PARAM_INIT(_id, _options, _int_min, _int_max, _peer) \
{ \
.id = _id, \
.sid = 0, \
.secondary_max_skip = 0, \
.options = (_options), \
.interval_min = (_int_min), \
.interval_max = (_int_max), \
.peer = (_peer), \
}
#define ZMK_BT_LE_ADV_PARAM(_id, _options, _int_min, _int_max, _peer) \
((struct bt_le_adv_param[]) { \
ZMK_BT_LE_ADV_PARAM_INIT(_id, _options, _int_min, _int_max, _peer) \
})
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
#define ZMK_ADV_PARAMS(_id) ZMK_BT_LE_ADV_PARAM(_id, \
BT_LE_ADV_OPT_CONNECTABLE | \
BT_LE_ADV_OPT_ONE_TIME | \
BT_LE_ADV_OPT_USE_NAME, \
BT_GAP_ADV_FAST_INT_MIN_2, \
BT_GAP_ADV_FAST_INT_MAX_2, NULL)
#define PROFILE_COUNT (CONFIG_BT_MAX_PAIRED - 1)
#else
#define ZMK_ADV_PARAMS(_id) ZMK_BT_LE_ADV_PARAM(_id, \
BT_LE_ADV_OPT_CONNECTABLE | \
BT_LE_ADV_OPT_USE_NAME, \
BT_GAP_ADV_FAST_INT_MIN_2, \
BT_GAP_ADV_FAST_INT_MAX_2, NULL)
#define PROFILE_COUNT CONFIG_BT_MAX_PAIRED
#endif
static struct zmk_ble_profile profiles[PROFILE_COUNT];
static u8_t active_profile;
static const struct bt_data zmk_ble_ad[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
BT_DATA_BYTES(BT_DATA_UUID16_SOME,
@ -88,6 +69,33 @@ static bt_addr_le_t peripheral_addr;
#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */
static void raise_profile_changed_event()
{
struct ble_active_profile_changed *ev = new_ble_active_profile_changed();
ev->index = active_profile;
ev->profile = &profiles[active_profile];
ZMK_EVENT_RAISE(ev);
}
static bool active_profile_is_open()
{
return !bt_addr_le_cmp(&profiles[active_profile].peer, BT_ADDR_LE_ANY);
}
void set_profile_address(u8_t index, const bt_addr_le_t *addr)
{
char setting_name[15];
char addr_str[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
memcpy(&profiles[index].peer, addr, sizeof(bt_addr_le_t));
sprintf(setting_name, "ble/profiles/%d", index);
LOG_DBG("Setting profile addr for %s to %s", log_strdup(setting_name), log_strdup(addr_str));
settings_save_one(setting_name, &profiles[index], sizeof(struct zmk_ble_profile));
raise_profile_changed_event();
}
int zmk_ble_adv_pause()
{
@ -102,10 +110,12 @@ int zmk_ble_adv_pause()
int zmk_ble_adv_resume()
{
struct bt_le_adv_param *adv_params = ZMK_ADV_PARAMS(BT_ID_DEFAULT);
LOG_DBG("active_profile %d, directed? %s", active_profile, active_profile_is_open() ? "no" : "yes");
LOG_DBG("");
int err = bt_le_adv_start(adv_params, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0);
int err = bt_le_adv_start(
BT_LE_ADV_CONN_NAME,
zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad),
NULL, 0);
if (err)
{
LOG_ERR("Advertising failed to start (err %d)", err);
@ -115,44 +125,54 @@ int zmk_ble_adv_resume()
return 0;
};
static void disconnect_host_connection(struct bt_conn *conn, void *arg)
{
struct bt_conn_info info;
bt_conn_get_info(conn, &info);
if (info.role != BT_CONN_ROLE_SLAVE) {
return;
}
bt_conn_disconnect(conn, BT_HCI_ERR_LOCALHOST_TERM_CONN);
};
static void unpair_non_peripheral_bonds(const struct bt_bond_info *info, void *user_data) {
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(&info->addr, addr, sizeof(addr));
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
if (!bt_addr_le_cmp(&info->addr, &peripheral_addr)) {
LOG_DBG("Skipping unpairing peripheral %s", log_strdup(addr));
return;
}
#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */
LOG_DBG("Unpairing %s", log_strdup(addr));
bt_unpair(BT_ID_DEFAULT, &info->addr);
}
int zmk_ble_clear_bonds()
{
LOG_DBG("");
bt_conn_foreach(BT_ID_DEFAULT, disconnect_host_connection, NULL);
bt_foreach_bond(BT_ID_DEFAULT, unpair_non_peripheral_bonds, NULL);
if (bt_addr_le_cmp(&profiles[active_profile].peer, BT_ADDR_LE_ANY)) {
LOG_DBG("Unpairing!");
bt_unpair(BT_ID_DEFAULT, &profiles[active_profile].peer);
set_profile_address(active_profile, BT_ADDR_LE_ANY);
}
return 0;
};
int zmk_ble_prof_select(u8_t index)
{
LOG_DBG("profile %d", index);
if (active_profile == index) {
return 0;
}
active_profile = index;
return settings_save_one("ble/active_profile", &active_profile, sizeof(active_profile));
raise_profile_changed_event();
};
int zmk_ble_prof_next()
{
LOG_DBG("");
return zmk_ble_prof_select((active_profile + 1) % PROFILE_COUNT);
};
int zmk_ble_prof_prev()
{
LOG_DBG("");
return zmk_ble_prof_select((active_profile + PROFILE_COUNT - 1) % PROFILE_COUNT);
};
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;
}
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
void zmk_ble_set_peripheral_addr(bt_addr_le_t *addr)
@ -171,8 +191,47 @@ static int ble_profiles_handle_set(const char *name, size_t len, settings_read_c
LOG_DBG("Setting BLE value %s", log_strdup(name));
if (settings_name_steq(name, "profiles", &next) && next) {
char *endptr;
u8_t idx = strtoul(next, &endptr, 10);
if (*endptr != '\0') {
LOG_WRN("Invalid profile index: %s", log_strdup(next));
return -EINVAL;
}
if (len != sizeof(struct zmk_ble_profile)) {
LOG_ERR("Invalid profile size (got %d expected %d)", len, sizeof(struct zmk_ble_profile));
return -EINVAL;
}
if (idx >= PROFILE_COUNT) {
LOG_WRN("Profile address for index %d is larger than max of %d", idx, PROFILE_COUNT);
return -EINVAL;
}
int err = read_cb(cb_arg, &profiles[idx], sizeof(struct zmk_ble_profile));
if (err <= 0) {
LOG_ERR("Failed to handle profile address from settings (err %d)", err);
return err;
}
char addr_str[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(&profiles[idx].peer, addr_str, sizeof(addr_str));
LOG_DBG("Loaded %s address for profile %d", log_strdup(addr_str), idx);
} else if (settings_name_steq(name, "active_profile", &next) && !next) {
if (len != sizeof(active_profile)) {
return -EINVAL;
}
int err = read_cb(cb_arg, &active_profile, sizeof(active_profile));
if (err <= 0) {
LOG_ERR("Failed to handle active profile from settings (err %d)", err);
return err;
}
}
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
if (settings_name_steq(name, "peripheral_address", &next) && !next) {
else if (settings_name_steq(name, "peripheral_address", &next) && !next) {
if (len != sizeof(bt_addr_le_t)) {
return -EINVAL;
}
@ -197,7 +256,6 @@ struct settings_handler profiles_handler = {
static void connected(struct bt_conn *conn, u8_t err)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
if (err)
@ -229,11 +287,11 @@ static void disconnected(struct bt_conn *conn, u8_t reason)
LOG_DBG("Disconnected from %s (reason 0x%02x)", log_strdup(addr), reason);
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
if (bt_addr_le_cmp(&peripheral_addr, BT_ADDR_LE_ANY) && bt_addr_le_cmp(&peripheral_addr, bt_conn_get_dst(conn))) {
zmk_ble_adv_resume();
}
// if (bt_addr_le_cmp(&peripheral_addr, BT_ADDR_LE_ANY) && bt_addr_le_cmp(&peripheral_addr, bt_conn_get_dst(conn))) {
// zmk_ble_adv_resume();
// }
#else
zmk_ble_adv_resume();
// zmk_ble_adv_resume();
#endif
}
@ -301,7 +359,52 @@ static void auth_cancel(struct bt_conn *conn)
LOG_DBG("Pairing cancelled: %s", log_strdup(addr));
}
#if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL)
static enum bt_security_err auth_pairing_accept(struct bt_conn *conn, const struct bt_conn_pairing_feat *const feat)
{
struct bt_conn_info info;
bt_conn_get_info(conn, &info);
LOG_DBG("role %d, open? %s", info.role, active_profile_is_open() ? "yes" : "no");
if (info.role != BT_CONN_ROLE_SLAVE && !active_profile_is_open()) {
LOG_WRN("Rejecting pairing request to taken profile %d", active_profile);
return BT_SECURITY_ERR_PAIR_NOT_ALLOWED;
}
return BT_SECURITY_ERR_SUCCESS;
};
#endif /* !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) */
static void auth_pairing_complete(struct bt_conn *conn, bool bonded)
{
struct bt_conn_info info;
char addr[BT_ADDR_LE_STR_LEN];
const bt_addr_le_t *dst = bt_conn_get_dst(conn);
bt_addr_le_to_str(dst, addr, sizeof(addr));
bt_conn_get_info(conn, &info);
if (info.role != BT_CONN_ROLE_SLAVE) {
LOG_DBG("SKIPPING FOR ROLE %d", info.role);
return;
}
#if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL)
if (!active_profile_is_open()) {
LOG_ERR("Pairing completed but current profile is not open: %s", log_strdup(addr));
bt_unpair(BT_ID_DEFAULT, dst);
return;
}
#endif /* !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) */
set_profile_address(active_profile, dst);
};
static struct bt_conn_auth_cb zmk_ble_auth_cb_display = {
#if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL)
.pairing_accept = auth_pairing_accept,
#endif /* !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) */
.pairing_complete = auth_pairing_complete,
// .passkey_display = auth_passkey_display,
#ifdef CONFIG_ZMK_BLE_PASSKEY_ENTRY
@ -348,11 +451,20 @@ static int zmk_ble_init(struct device *_arg)
#if IS_ENABLED(CONFIG_ZMK_BLE_CLEAR_BONDS_ON_START)
LOG_WRN("Clearing all existing BLE bond information from the keyboard");
settings_delete("bt/name");
for (int i = 0; i < 10; i++) {
bt_unpair(i, NULL);
}
for (int i = 0; i < PROFILE_COUNT; i++) {
char setting_name[15];
sprintf(setting_name, "ble/profiles/%d", i);
err = settings_delete(setting_name);
if (err) {
LOG_ERR("Failed to delete setting: %d", err);
}
}
#endif
bt_conn_cb_register(&conn_callbacks);

View File

@ -0,0 +1,10 @@
/*
* Copyright (c) 2020 Peter Johanson <peter@peterjohanson.com>
*
* SPDX-License-Identifier: MIT
*/
#include <kernel.h>
#include <zmk/events/ble-active-profile-changed.h>
ZMK_EVENT_IMPL(ble_active_profile_changed);

View File

@ -6,6 +6,10 @@
#include <settings/settings.h>
#include <logging/log.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <bluetooth/bluetooth.h>
#include <bluetooth/gatt.h>
@ -148,12 +152,40 @@ BT_GATT_SERVICE_DEFINE(hog_svc,
BT_GATT_PERM_WRITE,
NULL, write_ctrl_point, &ctrl_point));
struct bt_conn *destination_connection() {
struct bt_conn *conn;
bt_addr_le_t *addr = zmk_ble_active_profile_addr();
LOG_DBG("Address pointer %p", addr);
if (!bt_addr_le_cmp(addr, BT_ADDR_LE_ANY)) {
LOG_WRN("Not sending, no active address for current profile");
return NULL;
} else if ((conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr)) == NULL) {
LOG_WRN("Not sending, not connected to active profile");
return NULL;
}
return conn;
}
int zmk_hog_send_keypad_report(struct zmk_hid_keypad_report_body *report)
{
return bt_gatt_notify(NULL, &hog_svc.attrs[5], report, sizeof(struct zmk_hid_keypad_report_body));
struct bt_conn *conn = destination_connection();
if (conn == NULL) {
return -ENOTCONN;
}
LOG_DBG("Sending to NULL? %s", conn == NULL ? "yes" : "no");
return bt_gatt_notify(conn, &hog_svc.attrs[5], report, sizeof(struct zmk_hid_keypad_report_body));
};
int zmk_hog_send_consumer_report(struct zmk_hid_consumer_report_body *report)
{
return bt_gatt_notify(NULL, &hog_svc.attrs[10], report, sizeof(struct zmk_hid_consumer_report_body));
struct bt_conn *conn = destination_connection();
if (conn == NULL) {
return -ENOTCONN;
}
return bt_gatt_notify(conn, &hog_svc.attrs[10], report, sizeof(struct zmk_hid_consumer_report_body));
};

View File

@ -76,10 +76,19 @@ static u8_t split_central_notify_func(struct bt_conn *conn,
static int split_central_subscribe(struct bt_conn *conn)
{
int err = bt_gatt_subscribe(conn, &subscribe_params);
if (err && err != -EALREADY) {
LOG_ERR("Subscribe failed (err %d)", err);
} else {
switch (err) {
case -EALREADY:
LOG_DBG("[ALREADY SUBSCRIBED]");
break;
// break;
// bt_gatt_unsubscribe(conn, &subscribe_params);
// return split_central_subscribe(conn);
case 0:
LOG_DBG("[SUBSCRIBED]");
break;
default:
LOG_ERR("Subscribe failed (err %d)", err);
break;
}
return 0;
@ -145,21 +154,17 @@ static void split_central_process_connection(struct bt_conn *conn) {
return;
}
if (conn == default_conn) {
if (subscribe_params.value) {
split_central_subscribe(conn);
} else {
discover_params.uuid = &uuid.uuid;
discover_params.func = split_central_discovery_func;
discover_params.start_handle = 0x0001;
discover_params.end_handle = 0xffff;
discover_params.type = BT_GATT_DISCOVER_PRIMARY;
if (conn == default_conn && !subscribe_params.value) {
discover_params.uuid = &uuid.uuid;
discover_params.func = split_central_discovery_func;
discover_params.start_handle = 0x0001;
discover_params.end_handle = 0xffff;
discover_params.type = BT_GATT_DISCOVER_PRIMARY;
err = bt_gatt_discover(default_conn, &discover_params);
if (err) {
LOG_ERR("Discover failed(err %d)", err);
return;
}
err = bt_gatt_discover(default_conn, &discover_params);
if (err) {
LOG_ERR("Discover failed(err %d)", err);
return;
}
}
@ -281,7 +286,7 @@ static void split_central_connected(struct bt_conn *conn, u8_t conn_err)
if (conn_err) {
LOG_ERR("Failed to connect to %s (%u)", addr, conn_err);
LOG_ERR("Failed to connect to %s (%u)", log_strdup(addr), conn_err);
bt_conn_unref(default_conn);
default_conn = NULL;

View File

@ -6,6 +6,11 @@
#include <zephyr/types.h>
#include <sys/util.h>
#include <logging/log.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <bluetooth/gatt.h>
#include <bluetooth/uuid.h>
@ -28,6 +33,7 @@ static ssize_t split_svc_num_of_positions(struct bt_conn *conn, const struct bt_
static void split_svc_pos_state_ccc(const struct bt_gatt_attr *attr, u16_t value)
{
LOG_DBG("value %d", value);
}

View File

@ -25,9 +25,9 @@ int split_listener(const struct zmk_event_header *eh)
if (is_position_state_changed(eh)) {
const struct position_state_changed *ev = cast_position_state_changed(eh);
if (ev->state) {
zmk_split_bt_position_pressed(ev->position);
return zmk_split_bt_position_pressed(ev->position);
} else {
zmk_split_bt_position_released(ev->position);
return zmk_split_bt_position_released(ev->position);
}
}
return 0;

View File

@ -6,8 +6,8 @@ sidebar_label: Bluetooth
## Summary
The bluetooth behavior allows management of various settings and states related to the bluetooth connection(s)
between the keyboard and the host. As of right now, there is only one such action support, but in the future
more will be added.
between the keyboard and the host. By default, ZMK supports five "profiles" for selecting which bonded host
computer/laptop/keyboard should receive the keyboard input; many of the commands here operation on those profiles.
## Bluetooth Command Defines
@ -22,16 +22,22 @@ 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_CLEAR_BONDS_CMD` | Clear bond information between the keyboard and host [^1] |
| Define | Action |
| -------------------- | ---------------------------------------------------------------------------------------------- |
| `BT_CLEAR_BONDS_CMD` | Clear bond information between the keyboard and host for the selected profile [^1] |
| `BT_PROF_NEXT_CMD` | Switch to the next profile, cycling through to the first one when the end is reached. |
| `BT_PROF_PREV_CMD` | Switch to the previous profile, cycling through to the last one when the beginning is reached. |
| `BT_PROF_SEL_CMD` | Select the 0-indexed profile by number. |
Because future bluetooth commands will take an additional parameter, it is recommended to use
the following alias in your keymap to avoid having to change it later.
Because at least one bluetooth commands takes an additional parameter, it is recommended to use
the following aliases in your keymap to avoid having to specify an ignored second parameter:
| Define | Action |
| ---------------- | ---------------------------------------------------------------------- |
| `BT_CLEAR_BONDS` | Alias for `BT_CLEAR_BONDS_CMD 0` to clear the bond to the current host |
| Define | Action |
| ---------------- | ---------------------------------------------------------------------------------------- |
| `BT_CLEAR_BONDS` | Alias for `BT_CLEAR_BONDS_CMD 0` to clear the current profile's bond to the current host |
| `BT_PROF_NEXT` | Alias for `BT_PROF_NEXT_CMD 0` to select the next profile |
| `BT_PROF_PREV` | Alias for `BT_PROF_PREV_CMD 0` to select the previous profile |
| `BT_PROF_SEL` | Alias for `BT_PROF_SEL_CMD` to select the given profile, e.g. `&bt BT_PROF_SEL 1` |
## Bluetooth Behavior
@ -45,8 +51,26 @@ The bluetooth behavior completes an bluetooth action given on press.
### Examples
1. Behavior to clear the paired host:
1. Behavior binding to clear the paired host for the selected profile:
```
&bt BT_CLEAR_BONDS
```
1. Behavior binding to select the next profile:
```
&bt BT_PROF_NEXT
```
1. Behavior binding to select the previous profile:
```
&bt BT_PROF_NEXT
```
1. Behavior binding to select the 2nd profile (passed parameters are [zero based](https://en.wikipedia.org/wiki/Zero-based_numbering)):
```
&bt BT_PROF_SEL 1
```