diff mbox series

bluetoothctl:Add support for read characteristics value

Message ID 20200605142541.28412-3-amitx.k.singh@intel.com
State New
Headers show
Series bluetoothctl:Add support for read characteristics value | expand

Commit Message

Singh, AmitX K June 5, 2020, 2:25 p.m. UTC
From: amit <amitx.k.singh@intel.com>

Changes made to add support for read charateristic value
by uuid in bluetoothctl.

Signed-off-by: amit <amitx.k.singh@intel.com>
---
 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(-)

Comments

Singh, AmitX K July 16, 2020, 8:40 a.m. UTC | #1
Hi Luiz,

> -----Original Message-----

> From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>

> Sent: Friday, June 5, 2020 10:32 PM

> To: Singh, AmitX K <amitx.k.singh@intel.com>

> Cc: linux-bluetooth@vger.kernel.org

> 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@intel.com> wrote:

> >

> > From: amit <amitx.k.singh@intel.com>

> >

> > Changes made to add support for read charateristic value by uuid in

> > bluetoothctl.

> >

> > Signed-off-by: amit <amitx.k.singh@intel.com>

> > ---

> >  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
diff mbox series

Patch

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) },
 	{ 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,