Browse Source

Merge pull request #282 from petejohanson/ble/advertising-power-savings

BLE: Only advertise when needed.
xmkb
Pete Johanson 4 years ago committed by GitHub
parent
commit
3ecd7e42ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 146
      app/src/ble.c

146
app/src/ble.c

@ -45,10 +45,29 @@ static u8_t passkey_digit = 0;
#define PROFILE_COUNT CONFIG_BT_MAX_PAIRED #define PROFILE_COUNT CONFIG_BT_MAX_PAIRED
#endif #endif
enum advertising_type {
ZMK_ADV_NONE,
ZMK_ADV_DIR,
ZMK_ADV_CONN,
} advertising_status;
#define CURR_ADV(adv) (adv << 4)
#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)
static struct zmk_ble_profile profiles[PROFILE_COUNT]; static struct zmk_ble_profile profiles[PROFILE_COUNT];
static u8_t active_profile; static u8_t active_profile;
#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
static const struct bt_data zmk_ble_ad[] = { static const struct bt_data zmk_ble_ad[] = {
#if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL)
BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
BT_DATA_BYTES(BT_DATA_GAP_APPEARANCE, 0xC1, 0x03),
#endif
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
BT_DATA_BYTES(BT_DATA_UUID16_SOME, BT_DATA_BYTES(BT_DATA_UUID16_SOME,
#if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) #if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL)
@ -92,29 +111,101 @@ void set_profile_address(u8_t index, const bt_addr_le_t *addr) {
raise_profile_changed_event(); raise_profile_changed_event();
} }
int zmk_ble_adv_pause() { bool active_profile_is_connected() {
int err = bt_le_adv_stop(); struct bt_conn *conn;
if (err) { bt_addr_le_t *addr = zmk_ble_active_profile_addr();
LOG_ERR("Failed to stop advertising (err %d)", err); if (!bt_addr_le_cmp(addr, BT_ADDR_LE_ANY)) {
return err; return false;
} else if ((conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr)) == NULL) {
return false;
} }
return 0; bt_conn_unref(conn);
};
int zmk_ble_adv_resume() { return true;
LOG_DBG("active_profile %d, directed? %s", active_profile, }
active_profile_is_open() ? "no" : "yes");
int err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0); #define CHECKED_ADV_STOP() \
if (err) { err = bt_le_adv_stop(); \
LOG_ERR("Advertising failed to start (err %d)", err); advertising_status = ZMK_ADV_NONE; \
return err; if (err) { \
LOG_ERR("Failed to stop advertising (err %d)", err); \
return err; \
}
#define CHECKED_DIR_ADV() \
addr = zmk_ble_active_profile_addr(); \
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr); \
if (conn != NULL) { /* TODO: Check status of connection */ \
LOG_DBG("Skipping advertising, profile host is already connected"); \
bt_conn_unref(conn); \
return 0; \
} \
err = bt_le_adv_start(BT_LE_ADV_CONN_DIR_LOW_DUTY(addr), zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), \
NULL, 0); \
if (err) { \
LOG_ERR("Advertising failed to start (err %d)", err); \
return err; \
} \
advertising_status = ZMK_ADV_DIR;
#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) { \
LOG_ERR("Advertising failed to start (err %d)", err); \
return err; \
} \
advertising_status = ZMK_ADV_CONN;
int update_advertising() {
int err = 0;
bt_addr_le_t *addr;
struct bt_conn *conn;
enum advertising_type desired_adv = ZMK_ADV_NONE;
if (active_profile_is_open() || !active_profile_is_connected()) {
desired_adv = ZMK_ADV_CONN;
} else if (!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", log_strdup(addr_str));
// desired_adv = ZMK_ADV_DIR;
}
LOG_DBG("advertising from %d to %d", advertising_status, desired_adv);
switch (desired_adv + CURR_ADV(advertising_status)) {
case ZMK_ADV_NONE + CURR_ADV(ZMK_ADV_DIR):
case ZMK_ADV_NONE + CURR_ADV(ZMK_ADV_CONN):
CHECKED_ADV_STOP();
break;
case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_DIR):
case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_CONN):
CHECKED_ADV_STOP();
CHECKED_DIR_ADV();
break;
case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_NONE):
CHECKED_DIR_ADV();
break;
case ZMK_ADV_CONN + CURR_ADV(ZMK_ADV_DIR):
CHECKED_ADV_STOP();
CHECKED_OPEN_ADV();
break;
case ZMK_ADV_CONN + CURR_ADV(ZMK_ADV_NONE):
CHECKED_OPEN_ADV();
break;
} }
return 0; return 0;
}; };
static void update_advertising_callback(struct k_work *work) { update_advertising(); }
K_WORK_DEFINE(update_advertising_work, update_advertising_callback);
int zmk_ble_clear_bonds() { int zmk_ble_clear_bonds() {
LOG_DBG(""); LOG_DBG("");
@ -124,6 +215,8 @@ int zmk_ble_clear_bonds() {
set_profile_address(active_profile, BT_ADDR_LE_ANY); set_profile_address(active_profile, BT_ADDR_LE_ANY);
} }
update_advertising();
return 0; return 0;
}; };
@ -134,9 +227,13 @@ int zmk_ble_prof_select(u8_t index) {
} }
active_profile = index; active_profile = index;
return settings_save_one("ble/active_profile", &active_profile, sizeof(active_profile)); settings_save_one("ble/active_profile", &active_profile, sizeof(active_profile));
update_advertising();
raise_profile_changed_event(); raise_profile_changed_event();
return 0;
}; };
int zmk_ble_prof_next() { int zmk_ble_prof_next() {
@ -234,8 +331,11 @@ static void connected(struct bt_conn *conn, u8_t err) {
char addr[BT_ADDR_LE_STR_LEN]; char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
advertising_status = ZMK_ADV_NONE;
if (err) { if (err) {
LOG_WRN("Failed to connect to %s (%u)", log_strdup(addr), err); LOG_WRN("Failed to connect to %s (%u)", log_strdup(addr), err);
update_advertising();
return; return;
} }
@ -250,6 +350,8 @@ static void connected(struct bt_conn *conn, u8_t err) {
if (bt_conn_set_security(conn, BT_SECURITY_L2)) { if (bt_conn_set_security(conn, BT_SECURITY_L2)) {
LOG_ERR("Failed to set security"); LOG_ERR("Failed to set security");
} }
update_advertising();
} }
static void disconnected(struct bt_conn *conn, u8_t reason) { static void disconnected(struct bt_conn *conn, u8_t reason) {
@ -259,14 +361,9 @@ static void disconnected(struct bt_conn *conn, u8_t reason) {
LOG_DBG("Disconnected from %s (reason 0x%02x)", log_strdup(addr), reason); LOG_DBG("Disconnected from %s (reason 0x%02x)", log_strdup(addr), reason);
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) // We need to do this in a work callback, otherwise the advertising update will still see the
// if (bt_addr_le_cmp(&peripheral_addr, BT_ADDR_LE_ANY) && bt_addr_le_cmp(&peripheral_addr, // connection for a profile as active, and not start advertising yet.
// bt_conn_get_dst(conn))) { k_work_submit(&update_advertising_work);
// zmk_ble_adv_resume();
// }
#else
// zmk_ble_adv_resume();
#endif
} }
static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) { static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) {
@ -361,6 +458,7 @@ static void auth_pairing_complete(struct bt_conn *conn, bool bonded) {
#endif /* !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) */ #endif /* !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) */
set_profile_address(active_profile, dst); set_profile_address(active_profile, dst);
update_advertising();
}; };
static struct bt_conn_auth_cb zmk_ble_auth_cb_display = { static struct bt_conn_auth_cb zmk_ble_auth_cb_display = {
@ -383,7 +481,7 @@ static void zmk_ble_ready(int err) {
return; return;
} }
zmk_ble_adv_resume(); update_advertising();
} }
static int zmk_ble_init(struct device *_arg) { static int zmk_ble_init(struct device *_arg) {

Loading…
Cancel
Save