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>
This commit is contained in:
Luiz Augusto von Dentz 2019-05-28 12:12:16 +03:00 committed by Johan Hedberg
commit 648a53d50f
2 changed files with 115 additions and 53 deletions

View file

@ -769,24 +769,40 @@ 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.
*
@ -794,10 +810,10 @@ int bt_gatt_notify_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr,
* 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

View file

@ -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 nfy.err;
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");
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)