diff --git a/drivers/bluetooth/nble/gatt.c b/drivers/bluetooth/nble/gatt.c index 2248c294ff..29fe39d282 100644 --- a/drivers/bluetooth/nble/gatt.c +++ b/drivers/bluetooth/nble/gatt.c @@ -995,12 +995,11 @@ done: bt_conn_unref(conn); } -int bt_gatt_write(struct bt_conn *conn, uint16_t handle, uint16_t offset, - const void *data, uint16_t length, bt_gatt_rsp_func_t func) +int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params) { struct nble_gattc_write_req req; - if (!conn || !handle || !func) { + if (!conn || !params || !params->handle || !params->func) { return -EINVAL; } @@ -1013,26 +1012,35 @@ int bt_gatt_write(struct bt_conn *conn, uint16_t handle, uint16_t offset, } BT_DBG("conn %p handle 0x%04x offset 0x%04x len %u data %p", - conn, handle, offset, length, data); + conn, params->handle, params->offset, params->length, + params->data); memset(&req, 0, sizeof(req)); req.conn_handle = conn->handle; - req.handle = handle; - req.offset = offset; + req.handle = params->handle; + req.offset = params->offset; req.with_resp = 1; - conn->gatt_private = func; + conn->gatt_private = params; - nble_gattc_write_req(&req, data, length); + nble_gattc_write_req(&req, params->data, params->length); return 0; } +static void gatt_write_ccc_rsp(struct bt_conn *conn, uint8_t err) +{ + BT_DBG("conn %p err %u", conn, err); + + /* TODO: Remove failed subscription */ +} + void on_nble_gattc_write_rsp(const struct nble_gattc_write_rsp *rsp, void *user_data) { struct bt_conn *conn; + struct bt_gatt_write_params *params; bt_gatt_rsp_func_t func; conn = bt_conn_lookup_handle(rsp->conn_handle); @@ -1043,12 +1051,17 @@ void on_nble_gattc_write_rsp(const struct nble_gattc_write_rsp *rsp, BT_DBG("conn %p status %d user_data %p", conn, rsp->status, user_data); - func = conn->gatt_private; - if (func) { - func(conn, rsp->status); - conn->gatt_private = NULL; + if (conn->gatt_private == gatt_write_ccc_rsp) { + func = gatt_write_ccc_rsp; + } else { + params = conn->gatt_private; + func = params->func; } + /* Reset private data so the callback start new procedures */ + conn->gatt_private = NULL; + func(conn, rsp->status); + bt_conn_unref(conn); } @@ -1127,21 +1140,22 @@ static void remove_subscriptions(struct bt_conn *conn) } } -static void gatt_write_ccc_rsp(struct bt_conn *conn, uint8_t err) -{ - BT_DBG("conn %p err %u", conn, err); - - /* TODO: Remove failed subscription */ -} - static int gatt_write_ccc(struct bt_conn *conn, struct bt_gatt_subscribe_params *params) { - uint16_t handle = params->ccc_handle; - uint16_t value = params->value; + struct nble_gattc_write_req req; - return bt_gatt_write(conn, handle, 0, &value, sizeof(value), - gatt_write_ccc_rsp); + req.conn_handle = conn->handle; + req.handle = params->ccc_handle; + req.offset = 0; + req.with_resp = 1; + + conn->gatt_private = gatt_write_ccc_rsp; + + nble_gattc_write_req(&req, (void *)¶ms->value, + sizeof(params->value)); + + return 0; } int bt_gatt_subscribe(struct bt_conn *conn, diff --git a/drivers/bluetooth/nble/gatt_internal.h b/drivers/bluetooth/nble/gatt_internal.h index e0717adf5f..e691222b22 100644 --- a/drivers/bluetooth/nble/gatt_internal.h +++ b/drivers/bluetooth/nble/gatt_internal.h @@ -217,12 +217,12 @@ struct nble_gattc_read_rsp { }; /* forward declaration */ -struct bt_gatt_write_params; +struct nble_gatt_write_params; typedef void (*bt_att_func_t)(struct bt_conn *conn, uint8_t err, - const struct bt_gatt_write_params *wr_params); + const struct nble_gatt_write_params *wr_params); -struct bt_gatt_write_params { +struct nble_gatt_write_params { /* Function invoked upon write response */ bt_att_func_t func; /* User specific data */ @@ -235,7 +235,7 @@ struct nble_gattc_write_req { uint16_t offset; /* different than 0 if response required */ uint8_t with_resp; - struct bt_gatt_write_params wr_params; + struct nble_gatt_write_params wr_params; }; struct nble_gattc_write_rsp { @@ -243,7 +243,7 @@ struct nble_gattc_write_rsp { int status; uint16_t handle; uint16_t len; - struct bt_gatt_write_params wr_params; + struct nble_gatt_write_params wr_params; }; void nble_gattc_read_req(const struct nble_gattc_read_req *); diff --git a/include/bluetooth/gatt.h b/include/bluetooth/gatt.h index d0ee596e9a..73207ceb89 100644 --- a/include/bluetooth/gatt.h +++ b/include/bluetooth/gatt.h @@ -910,22 +910,34 @@ struct bt_gatt_read_params { */ int bt_gatt_read(struct bt_conn *conn, struct bt_gatt_read_params *params); +/** @brief GATT Write parameters */ +struct bt_gatt_write_params { + /** Response callback */ + bt_gatt_rsp_func_t func; + /** Attribute handle */ + uint16_t handle; + /** Attribute data offset */ + uint16_t offset; + /** Data to be written */ + const void *data; + /** Length of the data */ + uint16_t length; +}; + /** @brief Write Attribute Value by handle * * This procedure write the attribute value and return the result in the * callback. * + * Note: This procedure is asynchronous therefore the parameters need to + * remains valid while it is active. + * * @param conn Connection object. - * @param handle Attribute handle. - * @param offset Attribute data offset. - * @param data Data to be written. - * @param length Data length. - * @param func Callback function. + * @param params Write parameters. * * @return 0 in case of success or negative value in case of error. */ -int bt_gatt_write(struct bt_conn *conn, uint16_t handle, uint16_t offset, - const void *data, uint16_t length, bt_gatt_rsp_func_t func); +int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params); /** @brief Write Attribute Value by handle without response * diff --git a/net/bluetooth/gatt.c b/net/bluetooth/gatt.c index 48c9d85dbb..d97e5ef389 100644 --- a/net/bluetooth/gatt.c +++ b/net/bluetooth/gatt.c @@ -1414,7 +1414,8 @@ int bt_gatt_write_without_response(struct bt_conn *conn, uint16_t handle, return gatt_send(conn, buf, NULL, NULL, NULL); } -static int gatt_exec_write(struct bt_conn *conn, bt_gatt_rsp_func_t func) +static int gatt_exec_write(struct bt_conn *conn, + struct bt_gatt_write_params *params) { struct net_buf *buf; struct bt_att_exec_write_req *req; @@ -1429,7 +1430,7 @@ static int gatt_exec_write(struct bt_conn *conn, bt_gatt_rsp_func_t func) BT_DBG(""); - return gatt_send(conn, buf, att_write_rsp, func, NULL); + return gatt_send(conn, buf, att_write_rsp, params->func, NULL); } struct prepare_write_data { @@ -1444,51 +1445,35 @@ static void att_prepare_write_rsp(struct bt_conn *conn, uint8_t err, const void *pdu, uint16_t length, void *user_data) { - struct prepare_write_data *data = user_data; - bt_gatt_rsp_func_t func = data->func; + struct bt_gatt_write_params *params = user_data; BT_DBG("err 0x%02x", err); - /* Reset func so next prepare don't fail */ - data->func = NULL; /* Don't continue in case of error */ if (err) { - func(conn, err); + params->func(conn, err); return; } /* If there is no more data execute */ - if (!data->length) { - gatt_exec_write(conn, func); + if (!params->length) { + gatt_exec_write(conn, params); return; } /* Write next chunk */ - bt_gatt_write(conn, data->handle, data->offset, data->data, - data->length, func); + bt_gatt_write(conn, params); } -static int gatt_prepare_write(struct bt_conn *conn, uint16_t handle, - uint16_t offset, const void *data, - uint16_t length, bt_gatt_rsp_func_t func) +static int gatt_prepare_write(struct bt_conn *conn, + struct bt_gatt_write_params *params) { struct net_buf *buf; struct bt_att_prepare_write_req *req; - static struct prepare_write_data prep_data; uint16_t len; - if (prep_data.func) { - return -EBUSY; - } - - len = min(length, bt_att_get_mtu(conn) - sizeof(*req) - 1); - - prep_data.func = func; - prep_data.handle = handle; - prep_data.offset = offset + len; - prep_data.data = data + len; - prep_data.length = length - len; + len = min(params->length, bt_att_get_mtu(conn) - sizeof(*req) - 1); buf = bt_att_create_pdu(conn, BT_ATT_OP_PREPARE_WRITE_REQ, sizeof(*req) + len); @@ -1497,46 +1482,51 @@ static int gatt_prepare_write(struct bt_conn *conn, uint16_t handle, } req = net_buf_add(buf, sizeof(*req)); - req->handle = sys_cpu_to_le16(handle); - req->offset = sys_cpu_to_le16(offset); - memcpy(req->value, data, len); + req->handle = sys_cpu_to_le16(params->handle); + req->offset = sys_cpu_to_le16(params->offset); + memcpy(req->value, params->data, len); net_buf_add(buf, len); - BT_DBG("handle 0x%04x offset %u len %u", handle, offset, len); + /* Update params */ + params->offset += len; + params->data += len; + params->length -= len; - return gatt_send(conn, buf, att_prepare_write_rsp, &prep_data, NULL); + BT_DBG("handle 0x%04x offset %u len %u", params->handle, params->offset, + params->length); + + return gatt_send(conn, buf, att_prepare_write_rsp, params, NULL); } -int bt_gatt_write(struct bt_conn *conn, uint16_t handle, uint16_t offset, - const void *data, uint16_t length, bt_gatt_rsp_func_t func) +int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params) { struct net_buf *buf; struct bt_att_write_req *req; - if (!conn || !handle || !func) { + if (!conn || !params || !params->handle || !params->func) { return -EINVAL; } /* Use Prepare Write if offset is set or Long Write is required */ - if (offset || length > (bt_att_get_mtu(conn) - sizeof(*req) - 1)) { - return gatt_prepare_write(conn, handle, offset, data, length, - func); + if (params->offset || + params->length > (bt_att_get_mtu(conn) - sizeof(*req) - 1)) { + return gatt_prepare_write(conn, params); } buf = bt_att_create_pdu(conn, BT_ATT_OP_WRITE_REQ, - sizeof(*req) + length); + sizeof(*req) + params->length); if (!buf) { return -ENOMEM; } req = net_buf_add(buf, sizeof(*req)); - req->handle = sys_cpu_to_le16(handle); - memcpy(req->value, data, length); - net_buf_add(buf, length); + req->handle = sys_cpu_to_le16(params->handle); + memcpy(req->value, params->data, params->length); + net_buf_add(buf, params->length); - BT_DBG("handle 0x%04x length %u", handle, length); + BT_DBG("handle 0x%04x length %u", params->handle, params->length); - return gatt_send(conn, buf, att_write_rsp, func, NULL); + return gatt_send(conn, buf, att_write_rsp, params->func, NULL); } static void gatt_subscription_add(struct bt_conn *conn, diff --git a/tests/bluetooth/shell/src/main.c b/tests/bluetooth/shell/src/main.c index 48de8a768d..d775cbdcc3 100644 --- a/tests/bluetooth/shell/src/main.c +++ b/tests/bluetooth/shell/src/main.c @@ -834,6 +834,8 @@ static void write_func(struct bt_conn *conn, uint8_t err) printk("Write complete: err %u\n", err); } +static struct bt_gatt_write_params write_params; + static void cmd_gatt_write(int argc, char *argv[]) { int err; @@ -868,8 +870,13 @@ static void cmd_gatt_write(int argc, char *argv[]) /* TODO: Add support for longer data */ data = strtoul(argv[3], NULL, 16); - err = bt_gatt_write(default_conn, handle, offset, &data, sizeof(data), - write_func); + write_params.handle = handle; + write_params.offset = offset; + write_params.func = write_func; + write_params.data = &data; + write_params.length = sizeof(data); + + err = bt_gatt_write(default_conn, &write_params); if (err) { printk("Write failed (err %d)\n", err); } else { diff --git a/tests/bluetooth/tester/src/gatt.c b/tests/bluetooth/tester/src/gatt.c index 2238830696..132108711b 100644 --- a/tests/bluetooth/tester/src/gatt.c +++ b/tests/bluetooth/tester/src/gatt.c @@ -1370,6 +1370,8 @@ static void write_rsp(struct bt_conn *conn, uint8_t err) sizeof(err)); } +static struct bt_gatt_write_params write_params; + static void write(uint8_t *data, uint16_t len) { const struct gatt_write_cmd *cmd = (void *) data; @@ -1380,10 +1382,14 @@ static void write(uint8_t *data, uint16_t len) goto fail; } - if (bt_gatt_write(conn, sys_le16_to_cpu(cmd->handle), 0, cmd->data, - sys_le16_to_cpu(cmd->data_length), write_rsp) < 0) { - bt_conn_unref(conn); + write_params.handle = sys_le16_to_cpu(cmd->handle); + write_params.func = write_rsp; + write_params.offset = 0; + write_params.data = cmd->data; + write_params.length = sys_le16_to_cpu(cmd->data_length); + if (bt_gatt_write(conn, &write_params) < 0) { + bt_conn_unref(conn); goto fail; } @@ -1411,12 +1417,14 @@ static void write_long(uint8_t *data, uint16_t len) goto fail; } - if (bt_gatt_write(conn, sys_le16_to_cpu(cmd->handle), - sys_le16_to_cpu(cmd->offset), cmd->data, - sys_le16_to_cpu(cmd->data_length), - write_long_rsp) < 0) { - bt_conn_unref(conn); + write_params.handle = sys_le16_to_cpu(cmd->handle); + write_params.func = write_long_rsp; + write_params.offset = cmd->offset; + write_params.data = cmd->data; + write_params.length = sys_le16_to_cpu(cmd->data_length); + if (bt_gatt_write(conn, &write_params) < 0) { + bt_conn_unref(conn); goto fail; }