Bluetooth: GATT: Add bt_gatt_indicate
This uses ATT Indicate Value command to indicate changes and wait for confirmation response. Change-Id: I123a00e374929d779f96a02440215c32c0e79423 Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
parent
29c8f95ec4
commit
68ee16d85c
4 changed files with 130 additions and 25 deletions
|
@ -376,6 +376,12 @@ int bt_gatt_notify(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bt_gatt_indicate(struct bt_conn *conn,
|
||||||
|
struct bt_gatt_indicate_params *params)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
int bt_gatt_exchange_mtu(struct bt_conn *conn, bt_gatt_rsp_func_t func)
|
int bt_gatt_exchange_mtu(struct bt_conn *conn, bt_gatt_rsp_func_t func)
|
||||||
{
|
{
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
|
|
|
@ -731,6 +731,45 @@ ssize_t bt_gatt_attr_read_cpf(struct bt_conn *conn,
|
||||||
int bt_gatt_notify(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
int bt_gatt_notify(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||||
const void *data, uint16_t len);
|
const void *data, uint16_t len);
|
||||||
|
|
||||||
|
/** @brief Indication complete result callback.
|
||||||
|
*
|
||||||
|
* @param conn Connection object.
|
||||||
|
* @param attr Attribute object.
|
||||||
|
* @param err: 0 success, error in the other case
|
||||||
|
*/
|
||||||
|
typedef void (*bt_gatt_indicate_func_t)(struct bt_conn *conn,
|
||||||
|
const struct bt_gatt_attr *attr,
|
||||||
|
int err);
|
||||||
|
|
||||||
|
/** @brief GATT Indicate Value parameters */
|
||||||
|
struct bt_gatt_indicate_params {
|
||||||
|
/** Indicate Attribute object*/
|
||||||
|
const struct bt_gatt_attr *attr;
|
||||||
|
/** Indicate Value callback */
|
||||||
|
bt_gatt_indicate_func_t func;
|
||||||
|
/** Indicate Value data*/
|
||||||
|
const void *data;
|
||||||
|
/** Indicate Value length*/
|
||||||
|
uint16_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Indicate attribute value change.
|
||||||
|
*
|
||||||
|
* Send an indication of attribute value change.
|
||||||
|
* Note: This function should only be called if CCC is declared with
|
||||||
|
* BT_GATT_CCC otherwise it cannot find a valid peer configuration.
|
||||||
|
*
|
||||||
|
* Note: This procedure is asynchronous therefore the parameters need to
|
||||||
|
* remains valid while it is active.
|
||||||
|
*
|
||||||
|
* @param conn Connection object.
|
||||||
|
* @param params Indicate parameters.
|
||||||
|
*
|
||||||
|
* @return 0 in case of success or negative value in case of error.
|
||||||
|
*/
|
||||||
|
int bt_gatt_indicate(struct bt_conn *conn,
|
||||||
|
struct bt_gatt_indicate_params *params);
|
||||||
|
|
||||||
#if defined(CONFIG_BLUETOOTH_GATT_CLIENT)
|
#if defined(CONFIG_BLUETOOTH_GATT_CLIENT)
|
||||||
/* Client API */
|
/* Client API */
|
||||||
|
|
||||||
|
|
|
@ -1735,7 +1735,6 @@ void bt_att_init(void)
|
||||||
bt_l2cap_fixed_chan_register(&chan);
|
bt_l2cap_fixed_chan_register(&chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_BLUETOOTH_GATT_CLIENT)
|
|
||||||
uint16_t bt_att_get_mtu(struct bt_conn *conn)
|
uint16_t bt_att_get_mtu(struct bt_conn *conn)
|
||||||
{
|
{
|
||||||
struct bt_att *att;
|
struct bt_att *att;
|
||||||
|
@ -1810,4 +1809,3 @@ void bt_att_cancel(struct bt_conn *conn)
|
||||||
|
|
||||||
att_req_destroy(&att->req);
|
att_req_destroy(&att->req);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BLUETOOTH_GATT_CLIENT */
|
|
||||||
|
|
|
@ -401,9 +401,11 @@ ssize_t bt_gatt_attr_read_cpf(struct bt_conn *conn,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct notify_data {
|
struct notify_data {
|
||||||
|
uint16_t type;
|
||||||
|
const struct bt_gatt_attr *attr;
|
||||||
const void *data;
|
const void *data;
|
||||||
size_t len;
|
uint16_t len;
|
||||||
uint16_t handle;
|
struct bt_gatt_indicate_params *params;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int att_notify(struct bt_conn *conn, uint16_t handle, const void *data,
|
static int att_notify(struct bt_conn *conn, uint16_t handle, const void *data,
|
||||||
|
@ -431,6 +433,53 @@ static int att_notify(struct bt_conn *conn, uint16_t handle, const void *data,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void gatt_indicate_rsp(struct bt_conn *conn, uint8_t err,
|
||||||
|
const void *pdu, uint16_t length, void *user_data)
|
||||||
|
{
|
||||||
|
struct bt_gatt_indicate_params *params = user_data;
|
||||||
|
|
||||||
|
params->func(conn, params->attr, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gatt_send(struct bt_conn *conn, struct net_buf *buf,
|
||||||
|
bt_att_func_t func, void *user_data,
|
||||||
|
bt_att_destroy_t destroy)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = bt_att_send(conn, buf, func, user_data, destroy);
|
||||||
|
if (err) {
|
||||||
|
BT_ERR("Error sending ATT PDU: %d", err);
|
||||||
|
net_buf_unref(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int att_indicate(struct bt_conn *conn,
|
||||||
|
struct bt_gatt_indicate_params *params)
|
||||||
|
{
|
||||||
|
struct net_buf *buf;
|
||||||
|
struct bt_att_indicate *ind;
|
||||||
|
|
||||||
|
buf = bt_att_create_pdu(conn, BT_ATT_OP_INDICATE,
|
||||||
|
sizeof(*ind) + params->len);
|
||||||
|
if (!buf) {
|
||||||
|
BT_WARN("No buffer available to send indication");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
BT_DBG("conn %p handle 0x%04x", conn, params->attr->handle);
|
||||||
|
|
||||||
|
ind = net_buf_add(buf, sizeof(*ind));
|
||||||
|
ind->handle = sys_cpu_to_le16(params->attr->handle);
|
||||||
|
|
||||||
|
net_buf_add(buf, params->len);
|
||||||
|
memcpy(ind->value, params->data, params->len);
|
||||||
|
|
||||||
|
return gatt_send(conn, buf, gatt_indicate_rsp, params, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t notify_cb(const struct bt_gatt_attr *attr, void *user_data)
|
static uint8_t notify_cb(const struct bt_gatt_attr *attr, void *user_data)
|
||||||
{
|
{
|
||||||
struct notify_data *data = user_data;
|
struct notify_data *data = user_data;
|
||||||
|
@ -455,9 +504,9 @@ static uint8_t notify_cb(const struct bt_gatt_attr *attr, void *user_data)
|
||||||
/* Notify all peers configured */
|
/* Notify all peers configured */
|
||||||
for (i = 0; i < ccc->cfg_len; i++) {
|
for (i = 0; i < ccc->cfg_len; i++) {
|
||||||
struct bt_conn *conn;
|
struct bt_conn *conn;
|
||||||
|
int err;
|
||||||
|
|
||||||
/* TODO: Handle indications */
|
if (ccc->value != data->type) {
|
||||||
if (ccc->value != BT_GATT_CCC_NOTIFY) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,12 +515,18 @@ static uint8_t notify_cb(const struct bt_gatt_attr *attr, void *user_data)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (att_notify(conn, data->handle, data->data, data->len) < 0) {
|
if (data->type == BT_GATT_CCC_INDICATE) {
|
||||||
bt_conn_unref(conn);
|
err = att_indicate(conn, data->params);
|
||||||
return BT_GATT_ITER_STOP;
|
} else {
|
||||||
|
err = att_notify(conn, data->attr->handle, data->data,
|
||||||
|
data->len);
|
||||||
}
|
}
|
||||||
|
|
||||||
bt_conn_unref(conn);
|
bt_conn_unref(conn);
|
||||||
|
|
||||||
|
if (err < 0) {
|
||||||
|
return BT_GATT_ITER_STOP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return BT_GATT_ITER_CONTINUE;
|
return BT_GATT_ITER_CONTINUE;
|
||||||
|
@ -490,7 +545,8 @@ int bt_gatt_notify(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||||
return att_notify(conn, attr->handle, data, len);
|
return att_notify(conn, attr->handle, data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
nfy.handle = attr->handle;
|
nfy.attr = attr;
|
||||||
|
nfy.type = BT_GATT_CCC_NOTIFY;
|
||||||
nfy.data = data;
|
nfy.data = data;
|
||||||
nfy.len = len;
|
nfy.len = len;
|
||||||
|
|
||||||
|
@ -499,6 +555,27 @@ int bt_gatt_notify(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bt_gatt_indicate(struct bt_conn *conn,
|
||||||
|
struct bt_gatt_indicate_params *params)
|
||||||
|
{
|
||||||
|
struct notify_data nfy;
|
||||||
|
|
||||||
|
if (!params || !params->attr || !params->attr->handle) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn) {
|
||||||
|
return att_indicate(conn, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
nfy.type = BT_GATT_CCC_INDICATE;
|
||||||
|
nfy.params = params;
|
||||||
|
|
||||||
|
bt_gatt_foreach_attr(params->attr->handle, 0xffff, notify_cb, &nfy);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t connected_cb(const struct bt_gatt_attr *attr, void *user_data)
|
static uint8_t connected_cb(const struct bt_gatt_attr *attr, void *user_data)
|
||||||
{
|
{
|
||||||
struct bt_conn *conn = user_data;
|
struct bt_conn *conn = user_data;
|
||||||
|
@ -645,21 +722,6 @@ static void gatt_mtu_rsp(struct bt_conn *conn, uint8_t err, const void *pdu,
|
||||||
func(conn, err);
|
func(conn, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gatt_send(struct bt_conn *conn, struct net_buf *buf,
|
|
||||||
bt_att_func_t func, void *user_data,
|
|
||||||
bt_att_destroy_t destroy)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = bt_att_send(conn, buf, func, user_data, destroy);
|
|
||||||
if (err) {
|
|
||||||
BT_ERR("Error sending ATT PDU: %d", err);
|
|
||||||
net_buf_unref(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
int bt_gatt_exchange_mtu(struct bt_conn *conn, bt_gatt_rsp_func_t func)
|
int bt_gatt_exchange_mtu(struct bt_conn *conn, bt_gatt_rsp_func_t func)
|
||||||
{
|
{
|
||||||
struct bt_att_exchange_mtu_req *req;
|
struct bt_att_exchange_mtu_req *req;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue