Bluetooth: GATT: Make bt_gatt_write take a struct
This makes bt_gatt_write similar to bt_gatt_read where the parameters are stored in a struct which can be used to store intermediate values while the operation is in progress. Change-Id: I3c62af137b99985690cf88dcc37a977a0be891f5 Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
parent
c7982b65d2
commit
777033f710
|
@ -995,12 +995,11 @@ done:
|
||||||
bt_conn_unref(conn);
|
bt_conn_unref(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bt_gatt_write(struct bt_conn *conn, uint16_t handle, uint16_t offset,
|
int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params)
|
||||||
const void *data, uint16_t length, bt_gatt_rsp_func_t func)
|
|
||||||
{
|
{
|
||||||
struct nble_gattc_write_req req;
|
struct nble_gattc_write_req req;
|
||||||
|
|
||||||
if (!conn || !handle || !func) {
|
if (!conn || !params || !params->handle || !params->func) {
|
||||||
return -EINVAL;
|
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",
|
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));
|
memset(&req, 0, sizeof(req));
|
||||||
|
|
||||||
req.conn_handle = conn->handle;
|
req.conn_handle = conn->handle;
|
||||||
req.handle = handle;
|
req.handle = params->handle;
|
||||||
req.offset = offset;
|
req.offset = params->offset;
|
||||||
req.with_resp = 1;
|
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;
|
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 on_nble_gattc_write_rsp(const struct nble_gattc_write_rsp *rsp,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct bt_conn *conn;
|
struct bt_conn *conn;
|
||||||
|
struct bt_gatt_write_params *params;
|
||||||
bt_gatt_rsp_func_t func;
|
bt_gatt_rsp_func_t func;
|
||||||
|
|
||||||
conn = bt_conn_lookup_handle(rsp->conn_handle);
|
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);
|
BT_DBG("conn %p status %d user_data %p", conn, rsp->status, user_data);
|
||||||
|
|
||||||
func = conn->gatt_private;
|
if (conn->gatt_private == gatt_write_ccc_rsp) {
|
||||||
if (func) {
|
func = gatt_write_ccc_rsp;
|
||||||
func(conn, rsp->status);
|
} else {
|
||||||
conn->gatt_private = NULL;
|
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);
|
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,
|
static int gatt_write_ccc(struct bt_conn *conn,
|
||||||
struct bt_gatt_subscribe_params *params)
|
struct bt_gatt_subscribe_params *params)
|
||||||
{
|
{
|
||||||
uint16_t handle = params->ccc_handle;
|
struct nble_gattc_write_req req;
|
||||||
uint16_t value = params->value;
|
|
||||||
|
|
||||||
return bt_gatt_write(conn, handle, 0, &value, sizeof(value),
|
req.conn_handle = conn->handle;
|
||||||
gatt_write_ccc_rsp);
|
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,
|
int bt_gatt_subscribe(struct bt_conn *conn,
|
||||||
|
|
|
@ -217,12 +217,12 @@ struct nble_gattc_read_rsp {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* forward declaration */
|
/* 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,
|
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 */
|
/* Function invoked upon write response */
|
||||||
bt_att_func_t func;
|
bt_att_func_t func;
|
||||||
/* User specific data */
|
/* User specific data */
|
||||||
|
@ -235,7 +235,7 @@ struct nble_gattc_write_req {
|
||||||
uint16_t offset;
|
uint16_t offset;
|
||||||
/* different than 0 if response required */
|
/* different than 0 if response required */
|
||||||
uint8_t with_resp;
|
uint8_t with_resp;
|
||||||
struct bt_gatt_write_params wr_params;
|
struct nble_gatt_write_params wr_params;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nble_gattc_write_rsp {
|
struct nble_gattc_write_rsp {
|
||||||
|
@ -243,7 +243,7 @@ struct nble_gattc_write_rsp {
|
||||||
int status;
|
int status;
|
||||||
uint16_t handle;
|
uint16_t handle;
|
||||||
uint16_t len;
|
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 *);
|
void nble_gattc_read_req(const struct nble_gattc_read_req *);
|
||||||
|
|
|
@ -910,22 +910,34 @@ struct bt_gatt_read_params {
|
||||||
*/
|
*/
|
||||||
int bt_gatt_read(struct bt_conn *conn, struct bt_gatt_read_params *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
|
/** @brief Write Attribute Value by handle
|
||||||
*
|
*
|
||||||
* This procedure write the attribute value and return the result in the
|
* This procedure write the attribute value and return the result in the
|
||||||
* callback.
|
* callback.
|
||||||
*
|
*
|
||||||
|
* Note: This procedure is asynchronous therefore the parameters need to
|
||||||
|
* remains valid while it is active.
|
||||||
|
*
|
||||||
* @param conn Connection object.
|
* @param conn Connection object.
|
||||||
* @param handle Attribute handle.
|
* @param params Write parameters.
|
||||||
* @param offset Attribute data offset.
|
|
||||||
* @param data Data to be written.
|
|
||||||
* @param length Data length.
|
|
||||||
* @param func Callback function.
|
|
||||||
*
|
*
|
||||||
* @return 0 in case of success or negative value in case of error.
|
* @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,
|
int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params);
|
||||||
const void *data, uint16_t length, bt_gatt_rsp_func_t func);
|
|
||||||
|
|
||||||
/** @brief Write Attribute Value by handle without response
|
/** @brief Write Attribute Value by handle without response
|
||||||
*
|
*
|
||||||
|
|
|
@ -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);
|
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 net_buf *buf;
|
||||||
struct bt_att_exec_write_req *req;
|
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("");
|
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 {
|
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,
|
const void *pdu, uint16_t length,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct prepare_write_data *data = user_data;
|
struct bt_gatt_write_params *params = user_data;
|
||||||
bt_gatt_rsp_func_t func = data->func;
|
|
||||||
|
|
||||||
BT_DBG("err 0x%02x", err);
|
BT_DBG("err 0x%02x", err);
|
||||||
|
|
||||||
/* Reset func so next prepare don't fail */
|
|
||||||
data->func = NULL;
|
|
||||||
|
|
||||||
/* Don't continue in case of error */
|
/* Don't continue in case of error */
|
||||||
if (err) {
|
if (err) {
|
||||||
func(conn, err);
|
params->func(conn, err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If there is no more data execute */
|
/* If there is no more data execute */
|
||||||
if (!data->length) {
|
if (!params->length) {
|
||||||
gatt_exec_write(conn, func);
|
gatt_exec_write(conn, params);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write next chunk */
|
/* Write next chunk */
|
||||||
bt_gatt_write(conn, data->handle, data->offset, data->data,
|
bt_gatt_write(conn, params);
|
||||||
data->length, func);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gatt_prepare_write(struct bt_conn *conn, uint16_t handle,
|
static int gatt_prepare_write(struct bt_conn *conn,
|
||||||
uint16_t offset, const void *data,
|
struct bt_gatt_write_params *params)
|
||||||
uint16_t length, bt_gatt_rsp_func_t func)
|
|
||||||
{
|
{
|
||||||
struct net_buf *buf;
|
struct net_buf *buf;
|
||||||
struct bt_att_prepare_write_req *req;
|
struct bt_att_prepare_write_req *req;
|
||||||
static struct prepare_write_data prep_data;
|
|
||||||
uint16_t len;
|
uint16_t len;
|
||||||
|
|
||||||
if (prep_data.func) {
|
len = min(params->length, bt_att_get_mtu(conn) - sizeof(*req) - 1);
|
||||||
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;
|
|
||||||
|
|
||||||
buf = bt_att_create_pdu(conn, BT_ATT_OP_PREPARE_WRITE_REQ,
|
buf = bt_att_create_pdu(conn, BT_ATT_OP_PREPARE_WRITE_REQ,
|
||||||
sizeof(*req) + len);
|
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 = net_buf_add(buf, sizeof(*req));
|
||||||
req->handle = sys_cpu_to_le16(handle);
|
req->handle = sys_cpu_to_le16(params->handle);
|
||||||
req->offset = sys_cpu_to_le16(offset);
|
req->offset = sys_cpu_to_le16(params->offset);
|
||||||
memcpy(req->value, data, len);
|
memcpy(req->value, params->data, len);
|
||||||
net_buf_add(buf, 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,
|
int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params)
|
||||||
const void *data, uint16_t length, bt_gatt_rsp_func_t func)
|
|
||||||
{
|
{
|
||||||
struct net_buf *buf;
|
struct net_buf *buf;
|
||||||
struct bt_att_write_req *req;
|
struct bt_att_write_req *req;
|
||||||
|
|
||||||
if (!conn || !handle || !func) {
|
if (!conn || !params || !params->handle || !params->func) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Use Prepare Write if offset is set or Long Write is required */
|
/* Use Prepare Write if offset is set or Long Write is required */
|
||||||
if (offset || length > (bt_att_get_mtu(conn) - sizeof(*req) - 1)) {
|
if (params->offset ||
|
||||||
return gatt_prepare_write(conn, handle, offset, data, length,
|
params->length > (bt_att_get_mtu(conn) - sizeof(*req) - 1)) {
|
||||||
func);
|
return gatt_prepare_write(conn, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = bt_att_create_pdu(conn, BT_ATT_OP_WRITE_REQ,
|
buf = bt_att_create_pdu(conn, BT_ATT_OP_WRITE_REQ,
|
||||||
sizeof(*req) + length);
|
sizeof(*req) + params->length);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
req = net_buf_add(buf, sizeof(*req));
|
req = net_buf_add(buf, sizeof(*req));
|
||||||
req->handle = sys_cpu_to_le16(handle);
|
req->handle = sys_cpu_to_le16(params->handle);
|
||||||
memcpy(req->value, data, length);
|
memcpy(req->value, params->data, params->length);
|
||||||
net_buf_add(buf, 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,
|
static void gatt_subscription_add(struct bt_conn *conn,
|
||||||
|
|
|
@ -834,6 +834,8 @@ static void write_func(struct bt_conn *conn, uint8_t err)
|
||||||
printk("Write complete: err %u\n", 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[])
|
static void cmd_gatt_write(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
@ -868,8 +870,13 @@ static void cmd_gatt_write(int argc, char *argv[])
|
||||||
/* TODO: Add support for longer data */
|
/* TODO: Add support for longer data */
|
||||||
data = strtoul(argv[3], NULL, 16);
|
data = strtoul(argv[3], NULL, 16);
|
||||||
|
|
||||||
err = bt_gatt_write(default_conn, handle, offset, &data, sizeof(data),
|
write_params.handle = handle;
|
||||||
write_func);
|
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) {
|
if (err) {
|
||||||
printk("Write failed (err %d)\n", err);
|
printk("Write failed (err %d)\n", err);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1370,6 +1370,8 @@ static void write_rsp(struct bt_conn *conn, uint8_t err)
|
||||||
sizeof(err));
|
sizeof(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct bt_gatt_write_params write_params;
|
||||||
|
|
||||||
static void write(uint8_t *data, uint16_t len)
|
static void write(uint8_t *data, uint16_t len)
|
||||||
{
|
{
|
||||||
const struct gatt_write_cmd *cmd = (void *) data;
|
const struct gatt_write_cmd *cmd = (void *) data;
|
||||||
|
@ -1380,10 +1382,14 @@ static void write(uint8_t *data, uint16_t len)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bt_gatt_write(conn, sys_le16_to_cpu(cmd->handle), 0, cmd->data,
|
write_params.handle = sys_le16_to_cpu(cmd->handle);
|
||||||
sys_le16_to_cpu(cmd->data_length), write_rsp) < 0) {
|
write_params.func = write_rsp;
|
||||||
bt_conn_unref(conn);
|
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;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1411,12 +1417,14 @@ static void write_long(uint8_t *data, uint16_t len)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bt_gatt_write(conn, sys_le16_to_cpu(cmd->handle),
|
write_params.handle = sys_le16_to_cpu(cmd->handle);
|
||||||
sys_le16_to_cpu(cmd->offset), cmd->data,
|
write_params.func = write_long_rsp;
|
||||||
sys_le16_to_cpu(cmd->data_length),
|
write_params.offset = cmd->offset;
|
||||||
write_long_rsp) < 0) {
|
write_params.data = cmd->data;
|
||||||
bt_conn_unref(conn);
|
write_params.length = sys_le16_to_cpu(cmd->data_length);
|
||||||
|
|
||||||
|
if (bt_gatt_write(conn, &write_params) < 0) {
|
||||||
|
bt_conn_unref(conn);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue