diff --git a/src/gatt-client.c b/src/gatt-client.c
index 9e4a8ef..02ef57e 100644
--- a/src/gatt-client.c
+++ b/src/gatt-client.c
char *path;
bool in_read;
+ bool in_write;
};
static gboolean descriptor_get_uuid(const GDBusPropertyTable *property,
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)
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) {
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;
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,
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;
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,
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[] = {
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)
{
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;
done_async:
chrc->in_write = true;
+
return NULL;
}