diff --git a/include/bluetooth/gatt.h b/include/bluetooth/gatt.h index 1cdf9b77061..1c6fbe25bc6 100644 --- a/include/bluetooth/gatt.h +++ b/include/bluetooth/gatt.h @@ -917,6 +917,27 @@ struct bt_gatt_indicate_params { int bt_gatt_indicate(struct bt_conn *conn, struct bt_gatt_indicate_params *params); + +/** @brief Check if connection have subscribed to attribute + * + * Check if connection has subscribed to attribute value change. + * + * The attribute object can be the so called Characteristic Declaration, + * which is usually declared with BT_GATT_CHARACTERISTIC followed + * by BT_GATT_CCC, or the Characteristic Value Declaration which is + * automatically created after the Characteristic Declaration when using + * BT_GATT_CHARACTERISTIC, or the Client Characteristic Configuration + * Descriptor (CCCD) which is created by BT_GATT_CCC. + * + * @param conn Connection object. + * @param attr Attribute object. + * @param ccc_value The subscription type, either notifications or indications. + * + * @return true if the attribute object has been subscribed. + */ +bool bt_gatt_is_subscribed(struct bt_conn *conn, + const struct bt_gatt_attr *attr, u16_t ccc_value); + /** @brief Get ATT MTU for a connection * * Get negotiated ATT connection MTU, note that this does not equal the largest diff --git a/subsys/bluetooth/host/gatt.c b/subsys/bluetooth/host/gatt.c index 9801d040701..58277f67c43 100644 --- a/subsys/bluetooth/host/gatt.c +++ b/subsys/bluetooth/host/gatt.c @@ -2082,6 +2082,55 @@ static u8_t disconnected_cb(const struct bt_gatt_attr *attr, void *user_data) return BT_GATT_ITER_CONTINUE; } +bool bt_gatt_is_subscribed(struct bt_conn *conn, + const struct bt_gatt_attr *attr, u16_t ccc_value) +{ + const struct _bt_gatt_ccc *ccc; + + __ASSERT(conn, "invalid parameter\n"); + __ASSERT(attr, "invalid parameter\n"); + + if (conn->state != BT_CONN_CONNECTED) { + return false; + } + + /* Check if attribute is a characteristic declaration */ + if (!bt_uuid_cmp(attr->uuid, BT_UUID_GATT_CHRC)) { + struct bt_gatt_chrc *chrc = attr->user_data; + + if (!(chrc->properties & + (BT_GATT_CHRC_NOTIFY | BT_GATT_CHRC_INDICATE))) { + /* Characteristic doesn't support subscription */ + return false; + } + + attr = bt_gatt_attr_next(attr); + } + + /* Check if attribute is a characteristic value */ + if (bt_uuid_cmp(attr->uuid, BT_UUID_GATT_CCC) != 0) { + attr = bt_gatt_attr_next(attr); + } + + /* Check if the attribute is the CCC Descriptor */ + if (bt_uuid_cmp(attr->uuid, BT_UUID_GATT_CCC) != 0) { + return false; + } + + ccc = attr->user_data; + + /* Check if the connection is subscribed */ + for (size_t i = 0; i < BT_GATT_CCC_MAX; i++) { + if (conn->id == ccc->cfg[i].id && + !bt_conn_addr_le_cmp(conn, &ccc->cfg[i].peer) && + (ccc_value & ccc->cfg[i].value)) { + return true; + } + } + + return false; +} + #if defined(CONFIG_BT_GATT_CLIENT) void bt_gatt_notification(struct bt_conn *conn, u16_t handle, const void *data, u16_t length)