Hi Luiz, > -----Original Message----- > From: Luiz Augusto von Dentz <luiz.dentz@xxxxxxxxx> > Sent: Friday, June 5, 2020 10:32 PM > To: Singh, AmitX K <amitx.k.singh@xxxxxxxxx> > Cc: linux-bluetooth@xxxxxxxxxxxxxxx > Subject: Re: [PATCH] bluetoothctl:Add support for read characteristics value > > Hi Amit, > > On Fri, Jun 5, 2020 at 7:30 AM Amitsi5x <amitx.k.singh@xxxxxxxxx> wrote: > > > > From: amit <amitx.k.singh@xxxxxxxxx> > > > > Changes made to add support for read charateristic value by uuid in > > bluetoothctl. > > > > Signed-off-by: amit <amitx.k.singh@xxxxxxxxx> > > --- > > client/gatt.c | 70 ++++++++++++++++++++++++++++++++ > > client/gatt.h | 1 + > > client/main.c | 18 +++++++++ > > src/gatt-client.c | 70 ++++++++++++++++++++++++++++++++ > > src/shared/gatt-client.c | 86 > > +++++++++++++++++++++++++++++++++++++++- > > src/shared/gatt-client.h | 5 +++ > > 6 files changed, 249 insertions(+), 1 deletion(-) > > > > diff --git a/client/gatt.c b/client/gatt.c index 53f875050..8c2844ed6 > > 100644 > > --- a/client/gatt.c > > +++ b/client/gatt.c > > @@ -681,6 +681,76 @@ void gatt_read_attribute(GDBusProxy *proxy, int > argc, char *argv[]) > > return bt_shell_noninteractive_quit(EXIT_FAILURE); > > } > > > > +static void charreadbyuuid_reply(DBusMessage *message, void > > +*user_data) { > > + DBusError error; > > + DBusMessageIter iter, array; > > + uint8_t *value; > > + int len; > > + > > + dbus_error_init(&error); > > + > > + if (dbus_set_error_from_message(&error, message) == TRUE) { > > + bt_shell_printf("Failed to read: %s\n", error.name); > > + dbus_error_free(&error); > > + return bt_shell_noninteractive_quit(EXIT_FAILURE); > > + } > > + > > + dbus_message_iter_init(message, &iter); > > + > > + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { > > + bt_shell_printf("Invalid response to read\n"); > > + return bt_shell_noninteractive_quit(EXIT_FAILURE); > > + } > > + > > + dbus_message_iter_recurse(&iter, &array); > > + dbus_message_iter_get_fixed_array(&array, &value, &len); > > + > > + if (len < 0) { > > + bt_shell_printf("Unable to parse value\n"); > > + return bt_shell_noninteractive_quit(EXIT_FAILURE); > > + } > > + > > + bt_shell_hexdump(value, len); > > + > > + return bt_shell_noninteractive_quit(EXIT_SUCCESS); > > +} > > + > > +static void charreadbyuuid_setup(DBusMessageIter *iter, void > > +*user_data) { > > + char *uuid = user_data; > > + > > + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid); > > +} > > + > > +static void charreadbyuuid_attribute(GDBusProxy *proxy, char *uuid) { > > + if (g_dbus_proxy_method_call(proxy, "CharReadByUUID", > charreadbyuuid_setup, charreadbyuuid_reply, > > + uuid, NULL) == FALSE) { > > + bt_shell_printf("Failed to set uuid\n"); > > + return bt_shell_noninteractive_quit(EXIT_FAILURE); > > + } > > + > > + bt_shell_printf("Attempting to read service handle %s\n", > > +g_dbus_proxy_get_path(proxy)); } > > + > > +void gatt_charreadbyuuid_attribute(GDBusProxy *proxy, int argc, char > > +*argv[]) { > > + const char *iface; > > + > > + iface = g_dbus_proxy_get_interface(proxy); > > + > > + if (!strcmp(iface, "org.bluez.GattCharacteristic1")) { > > + charreadbyuuid_attribute(proxy, argv[1]); > > + return; > > + } > > + > > + bt_shell_printf("Unable to read attribute %s\n", > > + > > + g_dbus_proxy_get_path(proxy)); > > + > > + return bt_shell_noninteractive_quit(EXIT_FAILURE); > > +} > > + > > static void charbyuuid_reply(DBusMessage *message, void *user_data) > > { > > DBusError error; > > diff --git a/client/gatt.h b/client/gatt.h index 692fb5758..8f96d8665 > > 100644 > > --- a/client/gatt.h > > +++ b/client/gatt.h > > @@ -35,6 +35,7 @@ GDBusProxy *gatt_select_attribute(GDBusProxy > > *parent, const char *path); char *gatt_attribute_generator(const char > > *text, int state); void gatt_servbyuuid_attribute(GDBusProxy *proxy, > > int argc, char *argv[]); void gatt_charbyuuid_attribute(GDBusProxy > > *proxy, int argc, char *argv[]); > > +void gatt_charreadbyuuid_attribute(GDBusProxy *proxy, int argc, char > > +*argv[]); > > void gatt_read_attribute(GDBusProxy *proxy, int argc, char *argv[]); > > void gatt_write_attribute(GDBusProxy *proxy, int argc, char *argv[]); > > void gatt_notify_attribute(GDBusProxy *proxy, bool enable); diff --git > > a/client/main.c b/client/main.c index 10e64e17b..4dd1e593a 100644 > > --- a/client/main.c > > +++ b/client/main.c > > @@ -2071,6 +2071,22 @@ static void cmd_attribute_info(int argc, char > *argv[]) > > return bt_shell_noninteractive_quit(EXIT_SUCCESS); > > } > > > > +static void cmd_char_read_by_uuid(int argc, char *argv[]) { > > + GDBusProxy *proxy; > > + > > + proxy = find_attribute(argc, argv); > > + > > + set_default_attribute(proxy); > > + > > + if (!default_attr) { > > + bt_shell_printf("No attribute selected\n"); > > + return bt_shell_noninteractive_quit(EXIT_FAILURE); > > + } > > + > > + gatt_charreadbyuuid_attribute(default_attr, argc, argv); } > > + > > static void cmd_char_by_uuid(int argc, char *argv[]) { > > GDBusProxy *proxy; > > @@ -2718,6 +2734,8 @@ static const struct bt_shell_menu gatt_menu = { > > "Discover Primary Services by UUID" }, > > { "char-by-uuid", "[UUID]", cmd_char_by_uuid, > > "Discover Characteristic Services by > > UUID" }, > > + { "char-read-by-uuid", "[UUID]", cmd_char_read_by_uuid, > > + "Read Characteristic by UUID" }, > > { "select-attribute", "<attribute/UUID>", cmd_select_attribute, > > "Select attribute", attribute_generator }, > > { "attribute-info", "[attribute/UUID]", cmd_attribute_info, > > diff --git a/src/gatt-client.c b/src/gatt-client.c index > > da811ea4f..cd6d6dfde 100644 > > --- a/src/gatt-client.c > > +++ b/src/gatt-client.c > > @@ -444,6 +444,27 @@ static struct async_dbus_op > *async_dbus_op_new(DBusMessage *msg, void *data) > > return op; > > } > > > > +static struct async_dbus_op *fetch_char_read_by_uuid(struct > bt_gatt_client *gatt, > > + DBusMessage *msg, > > + char *uuid, > > + bt_gatt_client_char_by_uuid_callback_t callback, > > + void *data) { > > + struct async_dbus_op *op; > > + > > + op = async_dbus_op_new(msg, data); > > + op->id = bt_gatt_client_char_read_by_uuid(gatt, uuid, callback, > > + async_dbus_op_ref(op), > > + async_dbus_op_unref); > > + > > + if (op->id) > > + return op; > > + > > + async_dbus_op_free(op); > > + > > + return NULL; > > +} > > + > > static struct async_dbus_op *fetch_char_by_uuid(struct bt_gatt_client > *gatt, > > DBusMessage *msg, > > char *uuid, @@ -972,6 +993,52 > > @@ fail: > > chrc->read_op = NULL; > > } > > > > +static void char_read_by_uuid_cb(bool success, uint8_t att_ecode, const > uint8_t *value, > > + uint16_t length, void > > +*user_data) { > > + struct async_dbus_op *op = user_data; > > + struct characteristic *opchar = op->data; > > + > > + if (!success) > > + goto fail; > > + > > + async_dbus_op_reply(op, att_ecode, value, length); > > + > > + return; > > + > > +fail: > > + async_dbus_op_reply(op, att_ecode, NULL, 0); > > + > > + opchar->type_op = NULL; > > +} > > + > > +static DBusMessage *char_read_by_uuid(DBusConnection *conn, > > + DBusMessage *msg, void > > +*user_data) { > > + struct characteristic *chardata = user_data; > > + struct bt_gatt_client *gatt = chardata->service->client->gatt; > > + DBusMessageIter iter; > > + > > + char *uuid = 0; > > + > > + if (!gatt) > > + return btd_error_failed(msg, "Not connected"); > > + > > + dbus_message_iter_init(msg, &iter); > > + > > + if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) > > + dbus_message_iter_get_basic(&iter,&uuid); > > + else > > + return NULL; > > + > > + chardata->type_op = fetch_char_read_by_uuid(gatt, msg,uuid, > > + char_read_by_uuid_cb, chardata); > > + > > + if (!chardata->type_op) > > + return btd_error_failed(msg, "Failed to send read > > + request"); > > + > > + return NULL; > > +} > > + > > static void characteristic_by_uuid_cb(bool success, uint8_t att_ecode, > const uint8_t *value, > > uint16_t length, void > > *user_data) { @@ -1786,6 +1853,9 @@ static const GDBusMethodTable > > characteristic_methods[] = { > > { GDBUS_ASYNC_METHOD("CharByUUID", GDBUS_ARGS({ "options", > "s" }), > > GDBUS_ARGS({ "value", "ay" }), > > chardiscover_by_uuid) }, > > + { GDBUS_ASYNC_METHOD("CharReadByUUID", GDBUS_ARGS({ > "options", "s" }), > > + GDBUS_ARGS({ "value", "ay" }), > > + char_read_by_uuid) }, > > It would have helped if you had communicated that you would be looking > into add support for this type of operation, these procedures obviously > cannot be part of Characteristic interface since that is only available after the > discovery procedure then you can just lookup internally in the cache. So this > type of procedure will probably need to be under a Device object and lets > please agree on the documentation first before we move forward. > When we verify the PTS test case GATT/CL/GAR/BV-03-C "Read using characterisitic UUID", the Test case expect read request from device . Added a code for sending read request for reading characteristic value using UUID over characteristic interface > > { GDBUS_ASYNC_METHOD("ReadValue", GDBUS_ARGS({ "options", > "a{sv}" }), > > GDBUS_ARGS({ "value", "ay" }), > > characteristic_read_value) }, > > diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c index > > 8a696c77f..7c9d25ec3 100644 > > --- a/src/shared/gatt-client.c > > +++ b/src/shared/gatt-client.c > > @@ -2725,6 +2725,90 @@ done: > > op->callback(success, att_ecode, value, length, > > op->user_data); } > > > > +unsigned int bt_gatt_client_char_read_by_uuid(struct bt_gatt_client > *client, > > + char *uuid, > > + bt_gatt_client_char_by_uuid_callback_t callback, > > + void *user_data, > > + > > +bt_gatt_client_destroy_func_t destroy) { > > + struct request *req; > > + struct char_by_uuid_op *op; > > + unsigned char *pdu; > > + uint16_t len ; > > + uint16_t start_handle = 0x0001; > > + uint16_t end_handle = 0xffff; > > + bt_uuid_t btuuid; > > + uint8_t uuid128[16]; > > + > > + /* Length of pdu will be vary according to uuid type > > + for 2 byte uuid total length is 8 (start handle(2) + end handle(2) + > uuid(2)) > > + for 16 byte uuid total length is 22 (start handle(2) + end handle(2) + > uuid(16)) > > + */ > > + uint16_t pdu_len_16bit_uuid = 6; > > + uint16_t pdu_len_128bit_uuid = 20; > > + > > + if (bt_string_to_uuid(&btuuid, uuid) < 0) { > > + return 0; > > + } > > + > > + if (btuuid.type == BT_UUID16){ > > + pdu = (unsigned char *) malloc(pdu_len_16bit_uuid); > > + len = pdu_len_16bit_uuid; > > + } else { > > + pdu = (unsigned char *) malloc(pdu_len_128bit_uuid); > > + len = pdu_len_128bit_uuid; > > + } > > + > > + if (!client) > > + return 0; > > + > > + op = new0(struct char_by_uuid_op, 1); > > + req = request_create(client); > > + if (!req) { > > + free(op); > > + return 0; > > + } > > + if (!client) > > + return 0; > > + > > + op = new0(struct char_by_uuid_op, 1); > > + req = request_create(client); > > + > > + if (!req) { > > + free(op); > > + return 0; > > + } > > + > > + op->callback = callback; > > + op->user_data = user_data; > > + op->destroy = destroy; > > + req->data = op; > > + req->destroy = destroy_char_by_uuid_op; > > + > > + put_le16(start_handle, pdu); > > + put_le16(end_handle, pdu+2); > > + > > + if (btuuid.type == BT_UUID16) > > + put_le16(btuuid.value.u16, pdu+4); > > + else { > > + bswap_128(&btuuid.value.u128.data[0], &uuid128[0]); > > + memcpy(pdu + 4, uuid128, 16); > > + } > > + > > + req->att_id = bt_att_send(client->att, > BT_ATT_OP_READ_BY_TYPE_REQ, > > + pdu, len, > > + char_by_uuid_cb, req, > > + > > + request_unref); > > + > > + if (!req->att_id) { > > + op->destroy = NULL; > > + request_unref(req); > > + return 0; > > + } > > + > > + return req->id; > > +} > > + > > unsigned int bt_gatt_client_char_by_uuid(struct bt_gatt_client *client, > > char *uuid, > > > > bt_gatt_client_char_by_uuid_callback_t callback, @@ -2754,7 +2838,7 @@ > unsigned int bt_gatt_client_char_by_uuid(struct bt_gatt_client *client, > > if (btuuid.type == BT_UUID16){ > > pdu = (unsigned char *) malloc(pdu_len_16bit_uuid); > > len = pdu_len_16bit_uuid; > > - } else { > > + }else { > > pdu = (unsigned char *) malloc(pdu_len_128bit_uuid); > > len = pdu_len_128bit_uuid; > > } > > diff --git a/src/shared/gatt-client.h b/src/shared/gatt-client.h index > > f5d5169ce..50859ce52 100644 > > --- a/src/shared/gatt-client.h > > +++ b/src/shared/gatt-client.h > > @@ -97,6 +97,11 @@ unsigned int bt_gatt_client_char_by_uuid(struct > bt_gatt_client *client, > > bt_gatt_client_read_callback_t callback, > > void *user_data, > > bt_gatt_client_destroy_func_t > > destroy); > > +unsigned int bt_gatt_client_char_read_by_uuid(struct bt_gatt_client > *client, > > + char *uuid, > > + bt_gatt_client_read_callback_t callback, > > + void *user_data, > > + bt_gatt_client_destroy_func_t > > +destroy); > > unsigned int bt_gatt_client_read_value(struct bt_gatt_client *client, > > uint16_t value_handle, > > bt_gatt_client_read_callback_t > > callback, > > -- > > 2.17.1 > > > > > -- > Luiz Augusto von Dentz