diff --git a/README.md b/README.md index 2d843b1..ffeba9b 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,10 @@ Examples ./examples/notification/notification +* [Demonstrate GATT Write Without Response](/examples/nordic_uart/nordic_uart.c): + + ./examples/nordic_uart/nordic_uart + **Note:** `examples/gatttool` has been partially ported to gattlib. There are two reasons: the laziness (some of the GATT functions could be replaced by their gattlib equivalent) and the completeness (there are still some missing functions in gattlib). diff --git a/bluez/gattlib_read_write.c b/bluez/gattlib_read_write.c index a1a123e..f670529 100644 --- a/bluez/gattlib_read_write.c +++ b/bluez/gattlib_read_write.c @@ -200,6 +200,18 @@ int gattlib_write_char_by_uuid(gatt_connection_t* connection, uuid_t* uuid, cons return gattlib_write_char_by_handle(connection, handle, buffer, buffer_len); } +int gattlib_write_without_response_char_by_uuid(gatt_connection_t* connection, uuid_t* uuid, const void* buffer, size_t buffer_len) +{ + // Only supported in the DBUS API (ie: Bluez > v5.40) at the moment + return GATTLIB_NOT_SUPPORTED; +} + +int gattlib_write_without_response_char_by_handle(gatt_connection_t* connection, uint16_t handle, const void* buffer, size_t buffer_len) +{ + // Only supported in the DBUS API (ie: Bluez > v5.40) at the moment + return GATTLIB_NOT_SUPPORTED; +} + int gattlib_notification_start(gatt_connection_t* connection, const uuid_t* uuid) { uint16_t handle; uint16_t enable_notification = 0x0001; diff --git a/dbus/gattlib.c b/dbus/gattlib.c index 9a176cd..e5cb162 100644 --- a/dbus/gattlib.c +++ b/dbus/gattlib.c @@ -31,6 +31,11 @@ #define CONNECT_TIMEOUT 4 +#define BLUEZ_GATT_WRITE_VALUE_TYPE_MASK (0x7) +#define BLUEZ_GATT_WRITE_VALUE_TYPE_WRITE_WITH_RESPONSE (1 << 0) +#define BLUEZ_GATT_WRITE_VALUE_TYPE_WRITE_WITHOUT_RESPONSE (1 << 1) +#define BLUEZ_GATT_WRITE_VALUE_TYPE_RELIABLE_WRITE (1 << 2) + static const uuid_t m_battery_level_uuid = CREATE_UUID16(0x2A19); static const uuid_t m_ccc_uuid = CREATE_UUID16(0x2902); @@ -1322,7 +1327,7 @@ int gattlib_read_char_by_uuid_async(gatt_connection_t* connection, uuid_t* uuid, return GATTLIB_SUCCESS; } -static int write_char(struct dbus_characteristic *dbus_characteristic, const void* buffer, size_t buffer_len) +static int write_char(struct dbus_characteristic *dbus_characteristic, const void* buffer, size_t buffer_len, uint32_t options) { GVariant *value = g_variant_new_from_data(G_VARIANT_TYPE ("ay"), buffer, buffer_len, TRUE, NULL, NULL); GError *error = NULL; @@ -1330,9 +1335,14 @@ static int write_char(struct dbus_characteristic *dbus_characteristic, const voi #if BLUEZ_VERSION < BLUEZ_VERSIONS(5, 40) org_bluez_gatt_characteristic1_call_write_value_sync(dbus_characteristic->gatt, value, NULL, &error); #else - GVariantBuilder *options = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); - org_bluez_gatt_characteristic1_call_write_value_sync(dbus_characteristic->gatt, value, g_variant_builder_end(options), NULL, &error); - g_variant_builder_unref(options); + GVariantBuilder *variant_options = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); + + if ((options & BLUEZ_GATT_WRITE_VALUE_TYPE_MASK) == BLUEZ_GATT_WRITE_VALUE_TYPE_WRITE_WITHOUT_RESPONSE) { + g_variant_builder_add(variant_options, "{sv}", "type", g_variant_new("s", "request")); + } + + org_bluez_gatt_characteristic1_call_write_value_sync(dbus_characteristic->gatt, value, g_variant_builder_end(variant_options), NULL, &error); + g_variant_builder_unref(variant_options); #endif if (error != NULL) { @@ -1358,7 +1368,7 @@ int gattlib_write_char_by_uuid(gatt_connection_t* connection, uuid_t* uuid, cons assert(dbus_characteristic.type == TYPE_GATT); } - return write_char(&dbus_characteristic, buffer, buffer_len); + return write_char(&dbus_characteristic, buffer, buffer_len, BLUEZ_GATT_WRITE_VALUE_TYPE_WRITE_WITH_RESPONSE); } int gattlib_write_char_by_handle(gatt_connection_t* connection, uint16_t handle, const void* buffer, size_t buffer_len) { @@ -1367,9 +1377,34 @@ int gattlib_write_char_by_handle(gatt_connection_t* connection, uint16_t handle, return GATTLIB_NOT_FOUND; } - return write_char(&dbus_characteristic, buffer, buffer_len); + return write_char(&dbus_characteristic, buffer, buffer_len, BLUEZ_GATT_WRITE_VALUE_TYPE_WRITE_WITH_RESPONSE); } +int gattlib_write_without_response_char_by_uuid(gatt_connection_t* connection, uuid_t* uuid, const void* buffer, size_t buffer_len) +{ + struct dbus_characteristic dbus_characteristic = get_characteristic_from_uuid(connection, uuid); + if (dbus_characteristic.type == TYPE_NONE) { + return GATTLIB_NOT_FOUND; + } else if (dbus_characteristic.type == TYPE_BATTERY_LEVEL) { + return GATTLIB_NOT_SUPPORTED; // Battery level does not support write + } else { + assert(dbus_characteristic.type == TYPE_GATT); + } + + return write_char(&dbus_characteristic, buffer, buffer_len, BLUEZ_GATT_WRITE_VALUE_TYPE_WRITE_WITHOUT_RESPONSE); +} + +int gattlib_write_without_response_char_by_handle(gatt_connection_t* connection, uint16_t handle, const void* buffer, size_t buffer_len) +{ + struct dbus_characteristic dbus_characteristic = get_characteristic_from_handle(connection, handle); + if (dbus_characteristic.type == TYPE_NONE) { + return GATTLIB_NOT_FOUND; + } + + return write_char(&dbus_characteristic, buffer, buffer_len, BLUEZ_GATT_WRITE_VALUE_TYPE_WRITE_WITHOUT_RESPONSE); +} + + #if BLUEZ_VERSION > BLUEZ_VERSIONS(5, 40) gboolean on_handle_battery_level_property_change( OrgBluezBattery1 *object, diff --git a/examples/nordic_uart/nordic_uart.c b/examples/nordic_uart/nordic_uart.c index 2fc4a00..82fc76d 100644 --- a/examples/nordic_uart/nordic_uart.c +++ b/examples/nordic_uart/nordic_uart.c @@ -2,7 +2,7 @@ * * GattLib - GATT Library * - * Copyright (C) 2016-2017 Olivier Martin + * Copyright (C) 2016-2019 Olivier Martin * * * This program is free software; you can redistribute it and/or modify @@ -125,8 +125,8 @@ int main(int argc, char *argv[]) { // NUS TX can only receive 20 bytes at a time input_ptr = input; for (total_length = strlen(input) + 1; total_length > 0; total_length -= length) { - length = MIN(total_length, 20); - ret = gattlib_write_char_by_handle(m_connection, tx_handle, input_ptr, length); + length = MIN(total_length, 20); + ret = gattlib_write_without_response_char_by_handle(m_connection, tx_handle, input_ptr, length); if (ret) { fprintf(stderr, "Fail to send data to NUS TX characteristic.\n"); return 1; diff --git a/include/gattlib.h b/include/gattlib.h index e63d223..fc8cb22 100644 --- a/include/gattlib.h +++ b/include/gattlib.h @@ -224,9 +224,54 @@ int gattlib_read_char_by_uuid(gatt_connection_t* connection, uuid_t* uuid, void* */ int gattlib_read_char_by_uuid_async(gatt_connection_t* connection, uuid_t* uuid, gatt_read_cb_t gatt_read_cb); +/** + * @brief Function to write to the GATT characteristic UUID + * + * @param connection Active GATT connection + * @param uuid UUID of the GATT characteristic to read + * @param buffer contains the values to write to the GATT characteristic + * @param buffer_len is the length of the buffer to write + * + * @return GATTLIB_SUCCESS on success or GATTLIB_* error code + */ int gattlib_write_char_by_uuid(gatt_connection_t* connection, uuid_t* uuid, const void* buffer, size_t buffer_len); + +/** + * @brief Function to write to the GATT characteristic handle + * + * @param connection Active GATT connection + * @param handle is the handle of the GATT characteristic + * @param buffer contains the values to write to the GATT characteristic + * @param buffer_len is the length of the buffer to write + * + * @return GATTLIB_SUCCESS on success or GATTLIB_* error code + */ int gattlib_write_char_by_handle(gatt_connection_t* connection, uint16_t handle, const void* buffer, size_t buffer_len); +/** + * @brief Function to write without response to the GATT characteristic UUID + * + * @param connection Active GATT connection + * @param uuid UUID of the GATT characteristic to read + * @param buffer contains the values to write to the GATT characteristic + * @param buffer_len is the length of the buffer to write + * + * @return GATTLIB_SUCCESS on success or GATTLIB_* error code + */ +int gattlib_write_without_response_char_by_uuid(gatt_connection_t* connection, uuid_t* uuid, const void* buffer, size_t buffer_len); + +/** + * @brief Function to write without response to the GATT characteristic handle + * + * @param connection Active GATT connection + * @param handle is the handle of the GATT characteristic + * @param buffer contains the values to write to the GATT characteristic + * @param buffer_len is the length of the buffer to write + * + * @return GATTLIB_SUCCESS on success or GATTLIB_* error code + */ +int gattlib_write_without_response_char_by_handle(gatt_connection_t* connection, uint16_t handle, const void* buffer, size_t buffer_len); + /* * @param uuid UUID of the characteristic that will trigger the notification */