From 4e5989f121f156afa6c2d2bf0009af9153097f58 Mon Sep 17 00:00:00 2001 From: Arman Uguray Date: Fri, 19 Dec 2014 13:36:01 -0800 Subject: [PATCH] core/gatt: Implement GattDescriptor1.WriteValue This patch implements the WriteValue method of org.bluez.GattDescriptor1 --- src/gatt-client.c | 97 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 85 insertions(+), 12 deletions(-) diff --git a/src/gatt-client.c b/src/gatt-client.c index 9e4a8ef48..02ef57ef5 100644 --- a/src/gatt-client.c +++ b/src/gatt-client.c @@ -89,6 +89,7 @@ struct descriptor { char *path; bool in_read; + bool in_write; }; static gboolean descriptor_get_uuid(const GDBusPropertyTable *property, @@ -198,9 +199,12 @@ static bool parse_value_arg(DBusMessage *msg, uint8_t **value, return true; } +typedef bool (*async_dbus_op_complete_t)(void *data); + struct async_dbus_op { DBusMessage *msg; void *data; + async_dbus_op_complete_t complete; }; static void async_dbus_op_free(void *data) @@ -330,11 +334,9 @@ static void write_result_cb(bool success, bool reliable_error, struct async_dbus_op *op = user_data; DBusMessage *reply; - if (op->data) { - struct characteristic *chrc; - - chrc = op->data; - chrc->in_write = false; + if (op->complete && !op->complete(op->data)) { + reply = btd_error_failed(op->msg, "Operation failed"); + goto done; } if (!success) { @@ -363,11 +365,11 @@ static void write_cb(bool success, uint8_t att_ecode, void *user_data) write_result_cb(success, false, att_ecode, user_data); } - static bool start_long_write(DBusMessage *msg, uint16_t handle, struct bt_gatt_client *gatt, bool reliable, const uint8_t *value, - size_t value_len, void *data) + size_t value_len, void *data, + async_dbus_op_complete_t complete) { struct async_dbus_op *op; @@ -377,6 +379,7 @@ static bool start_long_write(DBusMessage *msg, uint16_t handle, op->msg = dbus_message_ref(msg); op->data = data; + op->complete = complete; if (bt_gatt_client_write_long_value(gatt, reliable, handle, 0, value, value_len, @@ -392,7 +395,8 @@ static bool start_long_write(DBusMessage *msg, uint16_t handle, static bool start_write_request(DBusMessage *msg, uint16_t handle, struct bt_gatt_client *gatt, const uint8_t *value, size_t value_len, - void *data) + void *data, + async_dbus_op_complete_t complete) { struct async_dbus_op *op; @@ -402,6 +406,7 @@ static bool start_write_request(DBusMessage *msg, uint16_t handle, op->msg = dbus_message_ref(msg); op->data = data; + op->complete = complete; if (bt_gatt_client_write_value(gatt, handle, value, value_len, write_cb, op, @@ -413,11 +418,63 @@ static bool start_write_request(DBusMessage *msg, uint16_t handle, return false; } +static bool desc_write_complete(void *data) +{ + struct descriptor *desc = data; + + desc->in_write = false; + + /* + * The descriptor might have been unregistered during the read. Return + * failure. + */ + return !!desc->chrc; +} + static DBusMessage *descriptor_write_value(DBusConnection *conn, DBusMessage *msg, void *user_data) { - /* TODO: Implement */ - return btd_error_failed(msg, "Not implemented"); + struct descriptor *desc = user_data; + struct bt_gatt_client *gatt = desc->chrc->service->client->gatt; + uint8_t *value = NULL; + size_t value_len = 0; + bool result; + bt_uuid_t uuid; + + if (desc->in_write) + return btd_error_in_progress(msg); + + if (!parse_value_arg(msg, &value, &value_len)) + return btd_error_invalid_args(msg); + + /* + * Don't allow writing to Client Characteristic Configuration + * descriptors. We achieve this through the StartNotify and StopNotify + * methods on GattCharacteristic1. + */ + bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID); + if (bt_uuid_cmp(&desc->uuid, &uuid)) + return btd_error_not_permitted(msg, "Write not permitted"); + + /* + * Based on the value length and the MTU, either use a write or a long + * write. + */ + if (value_len <= (unsigned) bt_gatt_client_get_mtu(gatt) - 3) + result = start_write_request(msg, desc->handle, gatt, value, + value_len, desc, + desc_write_complete); + else + result = start_long_write(msg, desc->handle, gatt, false, value, + value_len, desc, + desc_write_complete); + + if (!result) + return btd_error_failed(msg, "Failed to initiate write"); + + desc->in_write = true; + + return NULL; } static const GDBusPropertyTable descriptor_properties[] = { @@ -669,6 +726,19 @@ static DBusMessage *characteristic_read_value(DBusConnection *conn, return btd_error_failed(msg, "Failed to send read request"); } +static bool chrc_write_complete(void *data) +{ + struct characteristic *chrc = data; + + chrc->in_write = false; + + /* + * The characteristic might have been unregistered during the read. + * Return failure. + */ + return !!chrc->service; +} + static DBusMessage *characteristic_write_value(DBusConnection *conn, DBusMessage *msg, void *user_data) { @@ -709,10 +779,12 @@ static DBusMessage *characteristic_write_value(DBusConnection *conn, if (value_len <= (unsigned) mtu - 3) result = start_write_request(msg, chrc->value_handle, gatt, value, - value_len, chrc); + value_len, chrc, + chrc_write_complete); else result = start_long_write(msg, chrc->value_handle, gatt, - false, value, value_len, chrc); + false, value, value_len, chrc, + chrc_write_complete); if (result) goto done_async; @@ -729,6 +801,7 @@ static DBusMessage *characteristic_write_value(DBusConnection *conn, done_async: chrc->in_write = true; + return NULL; } -- 2.47.3