Skip to content
Permalink
Browse files

Bluetooth: GATT: Add support to notify by UUID

This reworks bt_gatt_notify_cb to allow passing an UUID, in addition to
that it can now accept multiple notification at once as there could be
multiple instance of the same UUID the user can set multiple set of
parameters.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  • Loading branch information...
Vudentz authored and jhedberg committed May 28, 2019
1 parent 9bf61da commit 648a53d50ffa01583a52cfdbfdc06d4d175ba534
Showing with 115 additions and 53 deletions.
  1. +39 −15 include/bluetooth/gatt.h
  2. +76 −38 subsys/bluetooth/host/gatt.c
@@ -769,35 +769,51 @@ ssize_t bt_gatt_attr_read_cpf(struct bt_conn *conn,
*/
typedef void (*bt_gatt_complete_func_t) (struct bt_conn *conn, void *user_data);

/** @brief Notify attribute value change with callback.
struct bt_gatt_notify_params {
/** Notification Attribute UUID type */
const struct bt_uuid *uuid;
/** Notification Attribute object*/
const struct bt_gatt_attr *attr;
/** Notification Value data */
const void *data;
/** Notification Value length */
u16_t len;
/** Notification Value callback */
bt_gatt_complete_func_t func;
/** Notification Value callback user data */
void *user_data;
};

/** @brief Notify attribute value change.
*
* This function works in the same way as @ref bt_gatt_notify.
* With the addition that after sending the notification the
* callback function will be called.
* callback function will be called and can dispatch multiple
* notifications at once.
* Alternatively it is possible to notify by UUID by setting it on the
* parameters, when using this method the attribute given when be used as the
* start range when looking up for possible matches.
*
* @param conn Connection object.
* @param attr Characteristic or Characteristic Value attribute.
* @param data Pointer to Attribute data.
* @param len Attribute value length.
* @param func Notification value callback.
* @param user_data User data to be passed back to the callback.
* @param num_params Number of Notification parameters.
* @param params Notification parameters.
*
* @return 0 in case of success or negative value in case of error.
*/
int bt_gatt_notify_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr,
const void *data, u16_t len,
bt_gatt_complete_func_t func, void *user_data);
int bt_gatt_notify_cb(struct bt_conn *conn, u16_t num_params,
struct bt_gatt_notify_params *params);

/** @brief Notify attribute value change.
*
* Send notification of attribute value change, if connection is NULL notify
* all peer that have notification enabled via CCC otherwise do a direct
* notification only the given connection.
*
* 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
* The attribute object on the parameters 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.
*
* @param conn Connection object.
@@ -811,7 +827,15 @@ static inline int bt_gatt_notify(struct bt_conn *conn,
const struct bt_gatt_attr *attr,
const void *data, u16_t len)
{
return bt_gatt_notify_cb(conn, attr, data, len, NULL, NULL);
struct bt_gatt_notify_params params;

memset(&params, 0, sizeof(params));

params.attr = attr;
params.data = data;
params.len = len;

return bt_gatt_notify_cb(conn, 1, &params);
}

/** @typedef bt_gatt_indicate_func_t
@@ -1295,16 +1295,14 @@ static u16_t find_static_attr(const struct bt_gatt_attr *attr)
struct notify_data {
int err;
u16_t type;
const struct bt_gatt_attr *attr;
bt_gatt_complete_func_t func;
void *user_data;
const void *data;
u16_t len;
struct bt_gatt_indicate_params *params;
union {
struct bt_gatt_notify_params *nfy_params;
struct bt_gatt_indicate_params *ind_params;
};
};

static int gatt_notify(struct bt_conn *conn, u16_t handle, const void *data,
size_t len, bt_gatt_complete_func_t cb, void *user_data)
static int gatt_notify(struct bt_conn *conn, u16_t handle,
struct bt_gatt_notify_params *params)
{
struct net_buf *buf;
struct bt_att_notify *nfy;
@@ -1320,7 +1318,8 @@ static int gatt_notify(struct bt_conn *conn, u16_t handle, const void *data,
}
#endif

buf = bt_att_create_pdu(conn, BT_ATT_OP_NOTIFY, sizeof(*nfy) + len);
buf = bt_att_create_pdu(conn, BT_ATT_OP_NOTIFY,
sizeof(*nfy) + params->len);
if (!buf) {
BT_WARN("No buffer available to send notification");
return -ENOMEM;
@@ -1331,10 +1330,10 @@ static int gatt_notify(struct bt_conn *conn, u16_t handle, const void *data,
nfy = net_buf_add(buf, sizeof(*nfy));
nfy->handle = sys_cpu_to_le16(handle);

net_buf_add(buf, len);
memcpy(nfy->value, data, len);
net_buf_add(buf, params->len);
memcpy(nfy->value, params->data, params->len);

return bt_att_send(conn, buf, cb, user_data);
return bt_att_send(conn, buf, params->func, params->user_data);
}

static void gatt_indicate_rsp(struct bt_conn *conn, u8_t err,
@@ -1483,7 +1482,7 @@ static u8_t notify_cb(const struct bt_gatt_attr *attr, void *user_data)
if (!conn) {
#if defined(CONFIG_BT_GATT_DYNAMIC_DB)
if (ccc->cfg == sc_ccc_cfg) {
sc_save(cfg, data->params);
sc_save(cfg, data->ind_params);
}
#endif /* CONFIG_BT_GATT_DYNAMIC_DB */
continue;
@@ -1501,11 +1500,10 @@ static u8_t notify_cb(const struct bt_gatt_attr *attr, void *user_data)

if (data->type == BT_GATT_CCC_INDICATE) {
err = gatt_indicate(conn, attr->handle - 1,
data->params);
data->ind_params);
} else {
err = gatt_notify(conn, attr->handle - 1, data->data,
data->len, data->func,
data->user_data);
err = gatt_notify(conn, attr->handle - 1,
data->nfy_params);
}

bt_conn_unref(conn);
@@ -1520,20 +1518,45 @@ static u8_t notify_cb(const struct bt_gatt_attr *attr, void *user_data)
return BT_GATT_ITER_CONTINUE;
}

int bt_gatt_notify_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr,
const void *data, u16_t len,
bt_gatt_complete_func_t func, void *user_data)
static u8_t match_uuid(const struct bt_gatt_attr *attr, void *user_data)
{
struct notify_data nfy;
const struct bt_gatt_attr **found = user_data;

*found = attr;

return BT_GATT_ITER_STOP;
}

static int gatt_notify_params(struct bt_conn *conn,
struct bt_gatt_notify_params *params)
{
struct notify_data data;
const struct bt_gatt_attr *attr;
u16_t handle;

__ASSERT(attr, "invalid parameters\n");
attr = params->attr;

handle = attr->handle ? : find_static_attr(attr);
if (!handle) {
return -ENOENT;
}

/* Lookup UUID if it was given */
if (params->uuid) {
attr = NULL;

bt_gatt_foreach_attr_type(handle, 0xffff, params->uuid,
NULL, 1, match_uuid, &attr);
if (!attr) {
return -ENOENT;
}

handle = attr->handle ? : find_static_attr(attr);
if (!handle) {
return -ENOENT;
}
}

/* Check if attribute is a characteristic then adjust the handle */
if (!bt_uuid_cmp(attr->uuid, BT_UUID_GATT_CHRC)) {
struct bt_gatt_chrc *chrc = attr->user_data;
@@ -1546,27 +1569,42 @@ int bt_gatt_notify_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr,
}

if (conn) {
return gatt_notify(conn, handle, data, len, func, user_data);
return gatt_notify(conn, handle, params);
}

nfy.err = -ENOTCONN;
nfy.attr = attr;
nfy.func = func;
nfy.user_data = user_data;
nfy.type = BT_GATT_CCC_NOTIFY;
nfy.data = data;
nfy.len = len;
data.err = -ENOTCONN;
data.type = BT_GATT_CCC_NOTIFY;
data.nfy_params = params;

bt_gatt_foreach_attr_type(handle, 0xffff, BT_UUID_GATT_CCC, NULL, 1,
notify_cb, &nfy);
notify_cb, &data);

return data.err;
}

int bt_gatt_notify_cb(struct bt_conn *conn, u16_t num_params,
struct bt_gatt_notify_params *params)
{
int i, ret;

__ASSERT(params, "invalid parameters\n");
__ASSERT(num_params, "invalid parameters\n");
__ASSERT(params->attr, "invalid parameters\n");

return nfy.err;
for (i = 0; i < num_params; i++) {
ret = gatt_notify_params(conn, &params[i]);
if (ret < 0) {
return ret;
}
}

return 0;
}

int bt_gatt_indicate(struct bt_conn *conn,
struct bt_gatt_indicate_params *params)
{
struct notify_data nfy;
struct notify_data data;
u16_t handle;

__ASSERT(params, "invalid parameters\n");
@@ -1581,14 +1619,14 @@ int bt_gatt_indicate(struct bt_conn *conn,
return gatt_indicate(conn, handle, params);
}

nfy.err = -ENOTCONN;
nfy.type = BT_GATT_CCC_INDICATE;
nfy.params = params;
data.err = -ENOTCONN;
data.type = BT_GATT_CCC_INDICATE;
data.ind_params = params;

bt_gatt_foreach_attr_type(handle, 0xffff, BT_UUID_GATT_CCC, NULL, 1,
notify_cb, &nfy);
notify_cb, &data);

return nfy.err;
return data.err;
}

u16_t bt_gatt_get_mtu(struct bt_conn *conn)

0 comments on commit 648a53d

Please sign in to comment.
You can’t perform that action at this time.