Repository: incubator-mynewt-core Updated Branches: refs/heads/develop bd4a45687 -> 825f488b4
BLE Host - Chr updates for unconnected bonded peer We need to persist the fact that the characteristic was updated while the peer was unconnected or unbonded. When the peer restores bonding, we should send the notification or indication. Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/825f488b Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/825f488b Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/825f488b Branch: refs/heads/develop Commit: 825f488b4d57d30e530469f8705ae3f8da994fbf Parents: ddd76b6 Author: Christopher Collins <[email protected]> Authored: Fri May 20 19:29:45 2016 -0700 Committer: Christopher Collins <[email protected]> Committed: Sat May 21 08:57:12 2016 -0700 ---------------------------------------------------------------------- net/nimble/host/include/host/ble_store.h | 8 + net/nimble/host/src/ble_gatt_priv.h | 2 +- net/nimble/host/src/ble_gattc.c | 2 +- net/nimble/host/src/ble_gatts.c | 210 ++++++++++++-------------- net/nimble/host/src/ble_hs_conn.c | 46 ++++++ net/nimble/host/src/ble_hs_conn_priv.h | 3 + net/nimble/host/src/ble_store.c | 14 ++ 7 files changed, 168 insertions(+), 117 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/825f488b/net/nimble/host/include/host/ble_store.h ---------------------------------------------------------------------- diff --git a/net/nimble/host/include/host/ble_store.h b/net/nimble/host/include/host/ble_store.h index d25c238..0f56cbd 100644 --- a/net/nimble/host/include/host/ble_store.h +++ b/net/nimble/host/include/host/ble_store.h @@ -25,6 +25,7 @@ #define BLE_STORE_OBJ_TYPE_OUR_LTK 1 #define BLE_STORE_OBJ_TYPE_PEER_LTK 2 #define BLE_STORE_OBJ_TYPE_CCCD 3 +#define BLE_STORE_OBJ_TYPE_CCCD_IDX 4 struct ble_store_key_ltk { uint16_t ediv; @@ -43,6 +44,11 @@ struct ble_store_key_cccd { uint8_t peer_addr_type; }; +struct ble_store_key_cccd_idx { + uint16_t chr_def_handle; + uint8_t idx; +}; + struct ble_store_value_cccd { uint8_t peer_addr[6]; uint8_t peer_addr_type; @@ -72,6 +78,8 @@ int ble_store_read(int obj_type, union ble_store_key *key, int ble_store_write(int obj_type, union ble_store_value *val); int ble_store_delete(int obj_type, union ble_store_key *key); +int ble_store_read_cccd_idx(struct ble_store_key_cccd_idx *key, + struct ble_store_value_cccd *out_value); int ble_store_write_cccd(struct ble_store_value_cccd *value); int ble_store_delete_cccd(struct ble_store_key_cccd *key); http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/825f488b/net/nimble/host/src/ble_gatt_priv.h ---------------------------------------------------------------------- diff --git a/net/nimble/host/src/ble_gatt_priv.h b/net/nimble/host/src/ble_gatt_priv.h index 9a4c4fb..5653057 100644 --- a/net/nimble/host/src/ble_gatt_priv.h +++ b/net/nimble/host/src/ble_gatt_priv.h @@ -142,7 +142,7 @@ int ble_gattc_init(void); #define BLE_GATTS_INC_SVC_LEN_NO_UUID 4 #define BLE_GATTS_INC_SVC_LEN_UUID 6 -void ble_gatts_send_updates_for_conn(uint16_t conn_handle); +int ble_gatts_send_next_indicate(uint16_t conn_handle); /*** @misc. */ void ble_gatts_conn_deinit(struct ble_gatts_conn *gatts_conn); http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/825f488b/net/nimble/host/src/ble_gattc.c ---------------------------------------------------------------------- diff --git a/net/nimble/host/src/ble_gattc.c b/net/nimble/host/src/ble_gattc.c index 916da80..338010d 100644 --- a/net/nimble/host/src/ble_gattc.c +++ b/net/nimble/host/src/ble_gattc.c @@ -3664,7 +3664,7 @@ ble_gattc_indicate_rx_rsp(struct ble_gattc_proc *proc) /* Send the next indication if one is pending. */ if (conn != NULL) { - ble_gatts_send_updates_for_conn(proc->conn_handle); + ble_gatts_send_next_indicate(proc->conn_handle); } } http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/825f488b/net/nimble/host/src/ble_gatts.c ---------------------------------------------------------------------- diff --git a/net/nimble/host/src/ble_gatts.c b/net/nimble/host/src/ble_gatts.c index 62cfe80..3e51b85 100644 --- a/net/nimble/host/src/ble_gatts.c +++ b/net/nimble/host/src/ble_gatts.c @@ -6,7 +6,7 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, @@ -1017,170 +1017,150 @@ ble_gatts_conn_init(struct ble_gatts_conn *gatts_conn) return 0; } -static int -ble_gatts_send_one_update(uint16_t conn_handle) +int +ble_gatts_send_next_indicate(uint16_t conn_handle) { struct ble_gatts_clt_cfg *clt_cfg; struct ble_hs_conn *conn; uint16_t chr_val_handle; - uint8_t att_op; int rc; int i; - /* Silence spurious gcc warning. */ + /* Assume no pending indications. */ chr_val_handle = 0; - /* Assume no pending updates. */ - att_op = 0; - ble_hs_lock(); + conn = ble_hs_conn_find(conn_handle); if (conn != NULL) { for (i = 0; i < conn->bhc_gatt_svr.num_clt_cfgs; i++) { clt_cfg = conn->bhc_gatt_svr.clt_cfgs + i; if (clt_cfg->flags & BLE_GATTS_CLT_CFG_F_UPDATED) { - if (clt_cfg->flags & BLE_GATTS_CLT_CFG_F_NOTIFY) { - att_op = BLE_ATT_OP_NOTIFY_REQ; - } else if (clt_cfg->flags & BLE_GATTS_CLT_CFG_F_INDICATE && - !(conn->bhc_flags & BLE_HS_CONN_F_INDICATE_TXED)) { - att_op = BLE_ATT_OP_INDICATE_REQ; - } + BLE_HS_DBG_ASSERT(clt_cfg->flags & + BLE_GATTS_CLT_CFG_F_INDICATE); - if (att_op != 0) { - chr_val_handle = clt_cfg->chr_def_handle + 1; - clt_cfg->flags &= ~BLE_GATTS_CLT_CFG_F_UPDATED; - break; - } + /* Clear updated flag in anticipation of intication tx. */ + clt_cfg->flags &= ~BLE_GATTS_CLT_CFG_F_UPDATED; + + chr_val_handle = clt_cfg->chr_def_handle + 1; + break; } } } - ble_hs_unlock(); - - switch (att_op) { - case 0: - return BLE_HS_EDONE; - case BLE_ATT_OP_NOTIFY_REQ: - rc = ble_gattc_notify(conn_handle, chr_val_handle); - return rc; - - case BLE_ATT_OP_INDICATE_REQ: - rc = ble_gattc_indicate(conn_handle, chr_val_handle, NULL, NULL); - return rc; + ble_hs_unlock(); - default: - BLE_HS_DBG_ASSERT(0); - return BLE_HS_EUNKNOWN; + if (conn == NULL) { + return BLE_HS_ENOTCONN; } -} -static void -ble_gatts_send_updates(uint16_t *conn_handles, int num_conns) -{ - int more_sends; - int rc; - int i; - - more_sends = 1; - - while (more_sends) { - for (i = 0; i < num_conns; i++) { - more_sends = 0; - for (i = 0; i < num_conns; i++) { - if (conn_handles[i] != BLE_HS_CONN_HANDLE_NONE) { - rc = ble_gatts_send_one_update(conn_handles[i]); - if (rc == 0) { - more_sends = 1; - } else { - conn_handles[i] = BLE_HS_CONN_HANDLE_NONE; - } - } - } - } + if (chr_val_handle == 0) { + return BLE_HS_ENOENT; } -} - -void -ble_gatts_send_updates_for_conn(uint16_t conn_handle) -{ - ble_gatts_send_updates(&conn_handle, 1); -} -static int -ble_gatts_conns_with_pending_updates(uint16_t *conn_handles) -{ - struct ble_gatts_clt_cfg *clt_cfg; - struct ble_hs_conn *conn; - int num_conns; - int i; - - num_conns = 0; - - for (conn = ble_hs_conn_first(); - conn != NULL; - conn = SLIST_NEXT(conn, bhc_next)) { - - /* XXX: Consider caching this information as a connection flag. */ - for (i = 0; i < conn->bhc_gatt_svr.num_clt_cfgs; i++) { - clt_cfg = conn->bhc_gatt_svr.clt_cfgs + i; - - if (clt_cfg->flags & BLE_GATTS_CLT_CFG_F_UPDATED) { - conn_handles[num_conns++] = conn->bhc_handle; - break; - } - } + rc = ble_gattc_indicate(conn_handle, chr_val_handle, NULL, NULL); + if (rc != 0) { + return rc; } - return num_conns; + return 0; } void ble_gatts_chr_updated(uint16_t chr_def_handle) { + struct ble_store_key_cccd_idx cccd_idx; + struct ble_store_value_cccd cccd_value; struct ble_gatts_clt_cfg *clt_cfg; struct ble_hs_conn *conn; - uint16_t conn_handles[NIMBLE_OPT(MAX_CONNECTIONS)]; - int any_updates; - int num_conns; - int idx; + uint16_t chr_val_handle; + uint16_t clt_cfg_flags; + uint16_t conn_handle; + int clt_cfg_idx; + int rc; + int i; /* Determine if notifications / indications are enabled for this - * characteristic, and remember the client config offset. + * characteristic. */ - idx = ble_gatts_clt_cfg_find_idx(ble_gatts_clt_cfgs, chr_def_handle); - if (idx == -1) { + clt_cfg_idx = ble_gatts_clt_cfg_find_idx(ble_gatts_clt_cfgs, + chr_def_handle); + if (clt_cfg_idx == -1) { return; } - /* Assume no peers are subscribed to this characteristic. */ - any_updates = 0; + chr_val_handle = chr_def_handle + 1; + BLE_HS_DBG_ASSERT(chr_val_handle > chr_def_handle); - ble_hs_lock(); + /* Handle the connected devices. */ + for (i = 0; ; i++) { + ble_hs_lock(); - for (conn = ble_hs_conn_first(); - conn != NULL; - conn = SLIST_NEXT(conn, bhc_next)) { + conn = ble_hs_conn_find_by_idx(i); + if (conn != NULL) { + BLE_HS_DBG_ASSERT_EVAL(conn->bhc_gatt_svr.num_clt_cfgs > + clt_cfg_idx); + clt_cfg = conn->bhc_gatt_svr.clt_cfgs + clt_cfg_idx; + BLE_HS_DBG_ASSERT_EVAL(clt_cfg->chr_def_handle == chr_def_handle); - BLE_HS_DBG_ASSERT_EVAL(conn->bhc_gatt_svr.num_clt_cfgs > idx); - clt_cfg = conn->bhc_gatt_svr.clt_cfgs + idx; - BLE_HS_DBG_ASSERT_EVAL(clt_cfg->chr_def_handle == chr_def_handle); - if (clt_cfg->flags & - (BLE_GATTS_CLT_CFG_F_NOTIFY | BLE_GATTS_CLT_CFG_F_INDICATE)) { + if (clt_cfg->flags & BLE_GATTS_CLT_CFG_F_NOTIFY) { + clt_cfg_flags = clt_cfg->flags; + } else if (clt_cfg->flags & BLE_GATTS_CLT_CFG_F_INDICATE) { + if (conn->bhc_flags & BLE_HS_CONN_F_INDICATE_TXED) { + clt_cfg->flags |= BLE_GATTS_CLT_CFG_F_UPDATED; + clt_cfg_flags = 0; + } else { + clt_cfg_flags = clt_cfg->flags; + } + } else { + clt_cfg_flags = 0; + } + conn_handle = conn->bhc_handle; - clt_cfg->flags |= BLE_GATTS_CLT_CFG_F_UPDATED; - any_updates = 1; } - } + ble_hs_unlock(); + + if (conn == NULL) { + break; + } - if (any_updates) { - num_conns = ble_gatts_conns_with_pending_updates(conn_handles); + if (clt_cfg_flags & BLE_GATTS_CLT_CFG_F_INDICATE) { + ble_gattc_indicate(conn_handle, chr_val_handle, NULL, NULL); + } else if (clt_cfg_flags & BLE_GATTS_CLT_CFG_F_NOTIFY) { + ble_gattc_notify(conn_handle, chr_val_handle); + } } - ble_hs_unlock(); + /* Persist updated flag for devices for which an update was not sent or + * scheduled. + */ + cccd_idx.chr_def_handle = chr_def_handle; + for (cccd_idx.idx = 0; ; cccd_idx.idx++) { + rc = ble_store_read_cccd_idx(&cccd_idx, &cccd_value); + if (rc != 0) { + break; + } + + /* Assume no update was scheduled for this device .*/ + clt_cfg_flags = 0; - if (any_updates) { - ble_gatts_send_updates(conn_handles, num_conns); + ble_hs_lock(); + conn = ble_hs_conn_find_by_addr(cccd_value.peer_addr_type, + cccd_value.peer_addr); + if (conn != NULL) { + clt_cfg = conn->bhc_gatt_svr.clt_cfgs + clt_cfg_idx; + clt_cfg_flags = clt_cfg->flags; + } + ble_hs_unlock(); + + /* Only persist if the value changed flag wasn't already set (i.e., + * only if we are writing new information). + */ + if (clt_cfg_flags == 0 && !cccd_value.value_changed) { + cccd_value.value_changed = 1; + ble_store_write_cccd(&cccd_value); + } } } http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/825f488b/net/nimble/host/src/ble_hs_conn.c ---------------------------------------------------------------------- diff --git a/net/nimble/host/src/ble_hs_conn.c b/net/nimble/host/src/ble_hs_conn.c index 7afcce3..251a768 100644 --- a/net/nimble/host/src/ble_hs_conn.c +++ b/net/nimble/host/src/ble_hs_conn.c @@ -244,6 +244,52 @@ ble_hs_conn_find(uint16_t conn_handle) return NULL; } +struct ble_hs_conn * +ble_hs_conn_find_by_addr(uint8_t addr_type, uint8_t *addr) +{ +#if !NIMBLE_OPT(CONNECT) + return NULL; +#endif + + struct ble_hs_conn *conn; + + BLE_HS_DBG_ASSERT(ble_hs_thread_safe()); + + SLIST_FOREACH(conn, &ble_hs_conns, bhc_next) { + if (conn->bhc_addr_type == addr_type && + memcmp(conn->bhc_addr, addr, 6) == 0) { + + return conn; + } + } + + return NULL; +} + +struct ble_hs_conn * +ble_hs_conn_find_by_idx(int idx) +{ +#if !NIMBLE_OPT(CONNECT) + return NULL; +#endif + + struct ble_hs_conn *conn; + int i; + + BLE_HS_DBG_ASSERT(ble_hs_thread_safe()); + + i = 0; + SLIST_FOREACH(conn, &ble_hs_conns, bhc_next) { + if (i == idx) { + return conn; + } + + i++; + } + + return NULL; +} + int ble_hs_conn_exists(uint16_t conn_handle) { http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/825f488b/net/nimble/host/src/ble_hs_conn_priv.h ---------------------------------------------------------------------- diff --git a/net/nimble/host/src/ble_hs_conn_priv.h b/net/nimble/host/src/ble_hs_conn_priv.h index 4ccdbab..36f6747 100644 --- a/net/nimble/host/src/ble_hs_conn_priv.h +++ b/net/nimble/host/src/ble_hs_conn_priv.h @@ -20,6 +20,7 @@ #ifndef H_BLE_HS_CONN_ #define H_BLE_HS_CONN_ +#include <inttypes.h> #include "ble_l2cap_priv.h" #include "ble_gatt_priv.h" #include "ble_att_priv.h" @@ -64,6 +65,8 @@ void ble_hs_conn_free(struct ble_hs_conn *conn); void ble_hs_conn_insert(struct ble_hs_conn *conn); void ble_hs_conn_remove(struct ble_hs_conn *conn); struct ble_hs_conn *ble_hs_conn_find(uint16_t conn_handle); +struct ble_hs_conn *ble_hs_conn_find_by_addr(uint8_t addr_type, uint8_t *addr); +struct ble_hs_conn *ble_hs_conn_find_by_idx(int idx); int ble_hs_conn_exists(uint16_t conn_handle); struct ble_hs_conn *ble_hs_conn_first(void); struct ble_l2cap_chan *ble_hs_conn_chan_find(struct ble_hs_conn *conn, http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/825f488b/net/nimble/host/src/ble_store.c ---------------------------------------------------------------------- diff --git a/net/nimble/host/src/ble_store.c b/net/nimble/host/src/ble_store.c index de4cc7a..6ffbacc 100644 --- a/net/nimble/host/src/ble_store.c +++ b/net/nimble/host/src/ble_store.c @@ -64,6 +64,20 @@ ble_store_delete(int obj_type, union ble_store_key *key) } int +ble_store_read_cccd_idx(struct ble_store_key_cccd_idx *key, + struct ble_store_value_cccd *out_value) +{ + union ble_store_value *store_value; + union ble_store_key *store_key; + int rc; + + store_key = (void *)key; + store_value = (void *)out_value; + rc = ble_store_read(BLE_STORE_OBJ_TYPE_CCCD_IDX, store_key, store_value); + return rc; +} + +int ble_store_write_cccd(struct ble_store_value_cccd *value) { union ble_store_value *store_value;
