[PATCH 01/11] attrib: Add simpler call for descriptors discovery

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds gatt_discover_desc() function which performs descriptor
discovery in a manner similar to gatt_discover_char(), i.e. it does
complete discovery procedure and returns list of descriptors found when
finished. For 16-bit UUIDs in addition to string UUID, short UUID is
provided.

It's also possible to specify single descriptor UUID to look for and
discovery procedure is interrupted as soon as UUID is found. This way
no more than one descriptor is returned which is useful when searching
for common descriptors like CCC.
---
 attrib/gatt.c | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 attrib/gatt.h |  10 ++++
 2 files changed, 156 insertions(+)

diff --git a/attrib/gatt.c b/attrib/gatt.c
index f5917db..f766617 100644
--- a/attrib/gatt.c
+++ b/attrib/gatt.c
@@ -73,6 +73,16 @@ struct discover_char {
 	void *user_data;
 };
 
+struct discover_desc {
+	int ref;
+	GAttrib *attrib;
+	bt_uuid_t *uuid;
+	uint16_t end;
+	GSList *descriptors;
+	gatt_cb_t cb;
+	void *user_data;
+};
+
 static void discover_primary_unref(void *data)
 {
 	struct discover_primary *dp = data;
@@ -139,6 +149,28 @@ static struct discover_char *discover_char_ref(struct discover_char *dc)
 	return dc;
 }
 
+static void discover_desc_unref(void *data)
+{
+	struct discover_desc *dd = data;
+
+	dd->ref--;
+
+	if (dd->ref > 0)
+		return;
+
+	g_slist_free_full(dd->descriptors, g_free);
+	g_attrib_unref(dd->attrib);
+	g_free(dd->uuid);
+	g_free(dd);
+}
+
+static struct discover_desc *discover_desc_ref(struct discover_desc *dd)
+{
+	dd->ref++;
+
+	return dd;
+}
+
 static void put_uuid_le(const bt_uuid_t *uuid, void *dst)
 {
 	if (uuid->type == BT_UUID16)
@@ -907,6 +939,120 @@ guint gatt_exchange_mtu(GAttrib *attrib, uint16_t mtu, GAttribResultFunc func,
 	return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
 }
 
+
+static void desc_discovered_cb(guint8 status, const guint8 *ipdu,
+					guint16 iplen, gpointer user_data)
+{
+	struct discover_desc *dd = user_data;
+	struct att_data_list *list;
+	unsigned int i, err = ATT_ECODE_ATTR_NOT_FOUND;
+	guint8 format;
+	uint16_t last = 0xffff;
+	uint8_t type;
+	gboolean uuid_found = FALSE;
+
+	if (status) {
+		err = status;
+		goto done;
+	}
+
+	list = dec_find_info_resp(ipdu, iplen, &format);
+	if (!list) {
+		err = ATT_ECODE_IO;
+		goto done;
+	}
+
+	if (format == ATT_FIND_INFO_RESP_FMT_16BIT)
+		type = BT_UUID16;
+	else
+		type = BT_UUID128;
+
+	for (i = 0; i < list->num; i++) {
+		uint8_t *value = list->data[i];
+		struct gatt_desc *desc;
+		bt_uuid_t uuid128;
+
+		last = get_le16(value);
+
+		get_uuid128(type, &value[2], &uuid128);
+
+		if (dd->uuid) {
+			if (bt_uuid_cmp(dd->uuid, &uuid128))
+				continue;
+			else
+				uuid_found = TRUE;
+		}
+
+		desc = g_try_new0(struct gatt_desc, 1);
+		if (!desc) {
+			att_data_list_free(list);
+			err = ATT_ECODE_INSUFF_RESOURCES;
+			goto done;
+		}
+
+		bt_uuid_to_string(&uuid128, desc->uuid, sizeof(desc->uuid));
+		desc->handle = last;
+
+		if (type == BT_UUID16)
+			desc->uuid16 = get_le16(&value[2]);
+
+		dd->descriptors = g_slist_append(dd->descriptors, desc);
+
+		if (uuid_found)
+			break;
+	}
+
+	att_data_list_free(list);
+
+	if (last + 1 < dd->end && !uuid_found) {
+		guint16 oplen;
+		size_t buflen;
+		uint8_t *buf;
+
+		buf = g_attrib_get_buffer(dd->attrib, &buflen);
+
+		oplen = enc_find_info_req(last + 1, dd->end, buf, buflen);
+		if (oplen == 0)
+			return;
+
+		g_attrib_send(dd->attrib, 0, buf, oplen, desc_discovered_cb,
+				discover_desc_ref(dd), discover_desc_unref);
+
+		return;
+	}
+
+done:
+	err = (dd->descriptors ? 0 : err);
+	dd->cb(err, dd->descriptors, dd->user_data);
+}
+
+guint gatt_discover_desc(GAttrib *attrib, uint16_t start, uint16_t end,
+						bt_uuid_t *uuid, gatt_cb_t func,
+						gpointer user_data)
+{
+	size_t buflen;
+	uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
+	struct discover_desc *dd;
+	guint16 plen;
+
+	plen = enc_find_info_req(start, end, buf, buflen);
+	if (plen == 0)
+		return 0;
+
+	dd = g_try_new0(struct discover_desc, 1);
+	if (dd == NULL)
+		return 0;
+
+	dd->attrib = g_attrib_ref(attrib);
+	dd->cb = func;
+	dd->user_data = user_data;
+	dd->end = end;
+	dd->uuid = g_memdup(uuid, sizeof(bt_uuid_t));
+
+	return g_attrib_send(attrib, 0, buf, plen, desc_discovered_cb,
+				discover_desc_ref(dd), discover_desc_unref);
+}
+
 guint gatt_discover_char_desc(GAttrib *attrib, uint16_t start, uint16_t end,
 				GAttribResultFunc func, gpointer user_data)
 {
diff --git a/attrib/gatt.h b/attrib/gatt.h
index 3fe6041..533bfd7 100644
--- a/attrib/gatt.h
+++ b/attrib/gatt.h
@@ -67,6 +67,12 @@ struct gatt_char {
 	uint16_t value_handle;
 };
 
+struct gatt_desc {
+	char uuid[MAX_LEN_UUID_STR + 1];
+	uint16_t handle;
+	uint16_t uuid16;
+};
+
 guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func,
 							gpointer user_data);
 
@@ -84,6 +90,10 @@ guint gatt_write_char(GAttrib *attrib, uint16_t handle, const uint8_t *value,
 					size_t vlen, GAttribResultFunc func,
 					gpointer user_data);
 
+guint gatt_discover_desc(GAttrib *attrib, uint16_t start, uint16_t end,
+						bt_uuid_t *uuid, gatt_cb_t func,
+						gpointer user_data);
+
 guint gatt_reliable_write_char(GAttrib *attrib, uint16_t handle,
 					const uint8_t *value, size_t vlen,
 					GAttribResultFunc func,
-- 
1.9.2

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux