Bluetooth: Gatt: Automatic discover of CCC when subscribing

Added a feature that allows an application to request
automatic discovery of the CCCD handle when subscriping
to a characteristic. In order to preserver RAM, the application
is expected to provide the discovery parameters, and it's up
to the application whether or not it wants to reuse the
discovery parameters or use one for each characteristic.

Signed-off-by: Emil Gydesen <emil_gydesen@bose.com>
This commit is contained in:
Emil Gydesen 2020-06-23 22:59:25 +02:00 committed by Carles Cufí
commit 5b59c002f6
5 changed files with 98 additions and 0 deletions

View file

@ -1145,6 +1145,10 @@ struct bt_gatt_discover_params {
uint16_t end_handle;
/** Discover type */
uint8_t type;
#if defined(CONFIG_BT_GATT_AUTO_DISCOVER_CCC)
/** Only for stack-internal use, used for automatic discovery. */
struct bt_gatt_subscribe_params *sub_params;
#endif /* defined(CONFIG_BT_GATT_AUTO_DISCOVER_CCC) */
};
/** @brief GATT Discover function
@ -1400,6 +1404,12 @@ struct bt_gatt_subscribe_params {
uint16_t value_handle;
/** Subscribe CCC handle */
uint16_t ccc_handle;
#if defined(CONFIG_BT_GATT_AUTO_DISCOVER_CCC)
/** Subscribe End handle (for automatic discovery) */
uint16_t end_handle;
/** Discover parameters used when ccc_handle = 0 */
struct bt_gatt_discover_params *disc_params;
#endif /* CONFIG_BT_GATT_AUTO_DISCOVER_CCC */
/** Subscribe value */
uint16_t value;
/** Subscription flags */

View file

@ -137,6 +137,13 @@ config BT_GATT_READ_MULTIPLE
This option enables support for the GATT Read Multiple Characteristic
Values procedure.
config BT_GATT_AUTO_DISCOVER_CCC
bool "Support to automatic discover the CCC handles of characteristics"
depends on BT_GATT_CLIENT
help
This option enables support for GATT to initiate discovery for CCC
handles if the CCC handle is unknown by the application.
config BT_GAP_AUTO_UPDATE_CONN_PARAMS
bool "Automatic Update of Connection Parameters"
default y

View file

@ -3893,6 +3893,62 @@ static int gatt_write_ccc(struct bt_conn *conn, uint16_t handle, uint16_t value,
return gatt_send(conn, buf, func, params, NULL);
}
#if defined(CONFIG_BT_GATT_AUTO_DISCOVER_CCC)
static uint8_t gatt_ccc_discover_cb(struct bt_conn *conn,
const struct bt_gatt_attr *attr,
struct bt_gatt_discover_params *params)
{
struct bt_gatt_subscribe_params *sub_params = params->sub_params;
if (!attr) {
memset(params, 0, sizeof(*params));
sub_params->notify(conn, sub_params, NULL, 0);
return BT_GATT_ITER_STOP;
}
if (params->type == BT_GATT_DISCOVER_DESCRIPTOR) {
memset(params, 0, sizeof(*params));
sub_params->ccc_handle = attr->handle;
if (bt_gatt_subscribe(conn, sub_params)) {
sub_params->notify(conn, sub_params, NULL, 0);
}
/* else if no error occurred, then `bt_gatt_subscribe` will
* call the notify function once subscribed.
*/
return BT_GATT_ITER_STOP;
}
return BT_GATT_ITER_CONTINUE;
}
static int gatt_ccc_discover(struct bt_conn *conn,
struct bt_gatt_subscribe_params *params)
{
int err;
static struct bt_uuid_16 ccc_uuid = BT_UUID_INIT_16(0);
memcpy(&ccc_uuid, BT_UUID_GATT_CCC, sizeof(ccc_uuid));
memset(params->disc_params, 0, sizeof(*params->disc_params));
params->disc_params->sub_params = params;
params->disc_params->uuid = &ccc_uuid.uuid;
params->disc_params->type = BT_GATT_DISCOVER_DESCRIPTOR;
params->disc_params->start_handle = params->value_handle;
params->disc_params->end_handle = params->end_handle;
params->disc_params->func = gatt_ccc_discover_cb;
err = bt_gatt_discover(conn, params->disc_params);
if (err) {
BT_DBG("CCC Discovery failed (err %d)", err);
return err;
}
return 0;
}
#endif /* CONFIG_BT_GATT_AUTO_DISCOVER_CCC */
int bt_gatt_subscribe(struct bt_conn *conn,
struct bt_gatt_subscribe_params *params)
{
@ -3903,7 +3959,13 @@ int bt_gatt_subscribe(struct bt_conn *conn,
__ASSERT(conn, "invalid parameters\n");
__ASSERT(params && params->notify, "invalid parameters\n");
__ASSERT(params->value, "invalid parameters\n");
#if defined(CONFIG_BT_GATT_AUTO_DISCOVER_CCC)
__ASSERT(params->ccc_handle ||
(params->end_handle && params->disc_params),
"invalid parameters\n");
#else
__ASSERT(params->ccc_handle, "invalid parameters\n");
#endif
if (conn->state != BT_CONN_CONNECTED) {
return -ENOTCONN;
@ -3933,6 +3995,14 @@ int bt_gatt_subscribe(struct bt_conn *conn,
if (!has_subscription) {
int err;
#if defined(CONFIG_BT_GATT_AUTO_DISCOVER_CCC)
if (!params->ccc_handle) {
err = gatt_ccc_discover(conn, params);
if (err) {
return err;
}
}
#endif
err = gatt_write_ccc(conn, params->ccc_handle, params->value,
gatt_write_ccc_rsp, params);
if (err) {

View file

@ -561,6 +561,16 @@ static int cmd_subscribe(const struct shell *shell, size_t argc, char *argv[])
subscribe_params.value = BT_GATT_CCC_NOTIFY;
subscribe_params.notify = notify_func;
#if defined(CONFIG_BT_GATT_AUTO_DISCOVER_CCC)
if (subscribe_params.ccc_handle == 0) {
static struct bt_gatt_discover_params disc_params;
subscribe_params.disc_params = &disc_params;
subscribe_params.end_handle = 0xFFFF;
}
#endif /* CONFIG_BT_GATT_AUTO_DISCOVER_CCC */
if (argc > 3 && !strcmp(argv[3], "ind")) {
subscribe_params.value = BT_GATT_CCC_INDICATE;
}

View file

@ -26,6 +26,7 @@ CONFIG_BT_GATT_HRS=y
CONFIG_BT_WHITELIST=y
CONFIG_BT_REMOTE_INFO=y
CONFIG_BT_REMOTE_VERSION=y
CONFIG_BT_GATT_AUTO_DISCOVER_CCC=y
CONFIG_BT_SETTINGS=y
CONFIG_FLASH=y