Bluetooth: Add bt_gatt_notify

bt_gatt_notify can be used to send ATT notifications:

< ACL Data TX: Handle 3585 flags 0x00 dlen 8
      ATT: Handle Value Notification (0x1b) len 3
        Handle: 0x0010
          Data: 64

Change-Id: I908f10f9e60dc7cef221e4b27c3b6e49e7b0cfc9
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
Luiz Augusto von Dentz 2015-05-26 14:29:30 +03:00 committed by Anas Nashif
commit e4e6f4dbe9
2 changed files with 91 additions and 0 deletions

View file

@ -378,4 +378,16 @@ int bt_gatt_attr_write_ccc(const bt_addr_le_t *peer,
.user_data = _value, \
}
/** @brief Notify attribute value change
*
* Send notification 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.
*
* @param handle attribute handle
* @param value attribute value
* @param len attribute value length
*/
void bt_gatt_notify(uint16_t handle, const void *data, size_t len);
#endif /* __BT_GATT_H */

View file

@ -44,6 +44,9 @@
#include <bluetooth/gatt.h>
#include "hci_core.h"
#include "conn.h"
#include "l2cap.h"
#include "att.h"
#if !defined(CONFIG_BLUETOOTH_DEBUG_GATT)
#undef BT_DBG
@ -265,3 +268,79 @@ int bt_gatt_attr_write_ccc(const bt_addr_le_t *peer,
return len;
}
struct notify_data {
uint8_t handle;
const void *data;
size_t len;
};
static uint8_t notify_cb(const struct bt_gatt_attr *attr, void *user_data)
{
struct notify_data *data = user_data;
struct bt_uuid uuid = { .type = BT_UUID_16, .u16 = BT_UUID_GATT_CCC };
struct bt_uuid chrc = { .type = BT_UUID_16, .u16 = BT_UUID_GATT_CHRC };
struct _bt_gatt_ccc *ccc;
size_t i;
if (bt_uuid_cmp(attr->uuid, &uuid)) {
/* Stop if we reach the next characteristic */
if (!bt_uuid_cmp(attr->uuid, &chrc))
return BT_GATT_ITER_STOP;
return BT_GATT_ITER_CONTINUE;
}
/* Check attribute user_data must be of type struct _bt_gatt_ccc */
if (attr->write != bt_gatt_attr_write_ccc) {
return BT_GATT_ITER_CONTINUE;
}
ccc = attr->user_data;
/* Notify all peers configured */
for (i = 0; i < ccc->cfg_len; i++) {
struct bt_conn *conn;
struct bt_buf *buf;
struct bt_att_notify *nfy;
conn = bt_conn_lookup_addr_le(&ccc->cfg[i].peer);
if (!conn) {
continue;
}
buf = bt_att_create_pdu(conn, BT_ATT_OP_NOTIFY,
sizeof(*nfy) + data->len);
if (!buf) {
BT_WARN("No buffer available to send notification");
return BT_GATT_ITER_STOP;
}
/* TODO: Handle indications */
if (ccc->value != BT_GATT_CCC_NOTIFY) {
continue;
}
BT_DBG("conn %p handle %u\n", conn, data->handle);
nfy = bt_buf_add(buf, sizeof(*nfy));
nfy->handle = sys_cpu_to_le16(data->handle);
bt_buf_add(buf, data->len);
memcpy(nfy->value, data->data, data->len);
bt_l2cap_send(conn, BT_L2CAP_CID_ATT, buf);
}
return BT_GATT_ITER_CONTINUE;
}
void bt_gatt_notify(uint16_t handle, const void *data, size_t len)
{
struct notify_data nfy;
nfy.handle = handle;
nfy.data = data;
nfy.len = len;
bt_gatt_foreach_attr(handle, 0xffff, notify_cb, &nfy);
}