diff --git a/drivers/nble/gatt.c b/drivers/nble/gatt.c index f458ffa38d3..5adcd555099 100644 --- a/drivers/nble/gatt.c +++ b/drivers/nble/gatt.c @@ -376,6 +376,12 @@ int bt_gatt_notify(struct bt_conn *conn, const struct bt_gatt_attr *attr, 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) { return -ENOSYS; diff --git a/include/bluetooth/gatt.h b/include/bluetooth/gatt.h index 542f3d3f784..4a005bf7b82 100644 --- a/include/bluetooth/gatt.h +++ b/include/bluetooth/gatt.h @@ -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, 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) /* Client API */ diff --git a/net/bluetooth/att.c b/net/bluetooth/att.c index b19278cb34a..a5b50e4a73d 100644 --- a/net/bluetooth/att.c +++ b/net/bluetooth/att.c @@ -1735,7 +1735,6 @@ void bt_att_init(void) bt_l2cap_fixed_chan_register(&chan); } -#if defined(CONFIG_BLUETOOTH_GATT_CLIENT) uint16_t bt_att_get_mtu(struct bt_conn *conn) { struct bt_att *att; @@ -1810,4 +1809,3 @@ void bt_att_cancel(struct bt_conn *conn) att_req_destroy(&att->req); } -#endif /* CONFIG_BLUETOOTH_GATT_CLIENT */ diff --git a/net/bluetooth/gatt.c b/net/bluetooth/gatt.c index e770d607839..ed05446faf8 100644 --- a/net/bluetooth/gatt.c +++ b/net/bluetooth/gatt.c @@ -401,9 +401,11 @@ ssize_t bt_gatt_attr_read_cpf(struct bt_conn *conn, } struct notify_data { + uint16_t type; + const struct bt_gatt_attr *attr; const void *data; - size_t len; - uint16_t handle; + uint16_t len; + struct bt_gatt_indicate_params *params; }; 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; } +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) { 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 */ for (i = 0; i < ccc->cfg_len; i++) { struct bt_conn *conn; + int err; - /* TODO: Handle indications */ - if (ccc->value != BT_GATT_CCC_NOTIFY) { + if (ccc->value != data->type) { continue; } @@ -466,12 +515,18 @@ static uint8_t notify_cb(const struct bt_gatt_attr *attr, void *user_data) continue; } - if (att_notify(conn, data->handle, data->data, data->len) < 0) { - bt_conn_unref(conn); - return BT_GATT_ITER_STOP; + if (data->type == BT_GATT_CCC_INDICATE) { + err = att_indicate(conn, data->params); + } else { + err = att_notify(conn, data->attr->handle, data->data, + data->len); } bt_conn_unref(conn); + + if (err < 0) { + return BT_GATT_ITER_STOP; + } } 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); } - nfy.handle = attr->handle; + nfy.attr = attr; + nfy.type = BT_GATT_CCC_NOTIFY; nfy.data = data; nfy.len = len; @@ -499,6 +555,27 @@ int bt_gatt_notify(struct bt_conn *conn, const struct bt_gatt_attr *attr, 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) { 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); } -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) { struct bt_att_exchange_mtu_req *req;