[PATCHv2 09/27] android/hog: Use gatt_db to search for services and characteristics in db

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

 



With this patch services and characteristics are searched in previously
cached database. This required changes in declarations of callbacks.
char_discovered_cb has been rebuilt to be called everytime when some
characteristic is found. Method of discovering report and external
report has been also simplified.

Moreover this patch:

1. Separates callbacks for services discovery:
services_cb: Services which already use database cached by bt_gatt_client
primary_cb: for attrib

2. Instead of using gatt_primary to create new instance of service
service handle will be used. On attach, having service handle we can call
gatt_db_get_attribute.
---
 android/hidhost.c |   2 +-
 android/hog.c     | 300 ++++++++++++++++++++++--------------------------------
 android/hog.h     |   4 +-
 unit/test-hog.c   |   2 +-
 4 files changed, 126 insertions(+), 182 deletions(-)

diff --git a/android/hidhost.c b/android/hidhost.c
index 00b6efa..0f28120 100644
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -862,7 +862,7 @@ static void hog_conn_cb(const bdaddr_t *addr, int err, void *attrib)
 	if (!dev->hog) {
 		/* TODO: Get device details */
 		dev->hog = bt_hog_new_default("bluez-input-device", dev->vendor,
-					dev->product, dev->version, NULL, 0);
+					dev->product, dev->version, 0);
 		if (!dev->hog) {
 			error("HoG: unable to create session");
 			goto fail;
diff --git a/android/hog.c b/android/hog.c
index 5aceecd..8570cab 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -86,7 +86,6 @@ struct bt_hog {
 	uint16_t		vendor;
 	uint16_t		product;
 	uint16_t		version;
-	struct gatt_primary	*primary;
 	GAttrib			*attrib;
 	GSList			*reports;
 	struct bt_uhid		*uhid;
@@ -106,6 +105,7 @@ struct bt_hog {
 	struct queue		*bas;
 	GSList			*instances;
 	struct bt_gatt_client	*client;
+	struct gatt_db		*db;
 };
 
 struct report {
@@ -196,71 +196,35 @@ static void external_report_reference_cb(bool success, uint8_t status,
 					const uint8_t *value, uint16_t length,
 					void *user_data);
 
-static void discover_external_cb(uint8_t status, GSList *descs, void *user_data)
+static void discover_external_cb(struct gatt_db_attribute *attrib,
+								void *user_data)
 {
 	struct bt_hog *hog = user_data;
+	bt_uuid_t ext_rep_uuid;
+	const bt_uuid_t *uuid = gatt_db_attribute_get_type(attrib);
+	uint16_t handle = gatt_db_attribute_get_handle(attrib);
 
-	if (status != 0) {
-		error("Discover external descriptors failed: %s",
-							att_ecode2str(status));
-		return;
-	}
-
-	for ( ; descs; descs = descs->next) {
-		struct gatt_desc *desc = descs->data;
+	bt_uuid16_create(&ext_rep_uuid, GATT_EXTERNAL_REPORT_REFERENCE);
 
-		bt_gatt_client_read_value(hog->client, desc->handle,
+	if (!bt_uuid_cmp(&ext_rep_uuid, uuid))
+		bt_gatt_client_read_value(hog->client, handle,
 				external_report_reference_cb, hog, NULL);
-	}
-}
-
-static void discover_external(struct bt_hog *hog, GAttrib *attrib,
-						uint16_t start, uint16_t end,
-						gpointer user_data)
-{
-	bt_uuid_t uuid;
-
-	if (start > end)
-		return;
-
-	bt_uuid16_create(&uuid, GATT_EXTERNAL_REPORT_REFERENCE);
-
-	gatt_discover_desc(attrib, start, end, NULL, discover_external_cb,
-								user_data);
 }
 
-static void discover_report_cb(uint8_t status, GSList *descs, void *user_data)
+static void discover_report_cb(struct gatt_db_attribute *attrib,
+								void *user_data)
 {
 	struct report *report = user_data;
 	struct bt_hog *hog = report->hog;
+	bt_uuid_t rep_ref_uuid;
+	const bt_uuid_t *uuid = gatt_db_attribute_get_type(attrib);
+	uint16_t handle = gatt_db_attribute_get_handle(attrib);
 
-	if (status != 0) {
-		error("Discover report descriptors failed: %s",
-							att_ecode2str(status));
-		return;
-	}
+	bt_uuid16_create(&rep_ref_uuid, GATT_REPORT_REFERENCE);
 
-	for ( ; descs; descs = descs->next) {
-		struct gatt_desc *desc = descs->data;
-
-		switch (desc->uuid16) {
-		case GATT_REPORT_REFERENCE:
-			bt_gatt_client_read_value(hog->client, desc->handle,
+	if (!bt_uuid_cmp(&rep_ref_uuid, uuid))
+		bt_gatt_client_read_value(hog->client, handle,
 					report_reference_cb, report, NULL);
-			break;
-		}
-	}
-}
-
-static void discover_report(struct bt_hog *hog, GAttrib *attrib,
-						uint16_t start, uint16_t end,
-							gpointer user_data)
-{
-	if (start > end)
-		return;
-
-	gatt_discover_desc(attrib, start, end, NULL, discover_report_cb,
-								user_data);
 }
 
 static void report_read_cb(bool success, uint8_t att_ecode,
@@ -282,50 +246,37 @@ static void report_read_cb(bool success, uint8_t att_ecode,
 	report->len = len;
 }
 
-static struct report *report_new(struct bt_hog *hog, struct gatt_char *chr)
+static struct report *report_new(struct bt_hog *hog, uint16_t value_handle,
+							uint8_t properties)
 {
 	struct report *report;
 
 	report = g_new0(struct report, 1);
 	report->hog = hog;
-	report->decl = g_memdup(chr, sizeof(*chr));
+	report->decl = new0(struct gatt_char, 1);
+	report->decl->value_handle = value_handle;
+	report->decl->properties = properties;
 	hog->reports = g_slist_append(hog->reports, report);
 
-	bt_gatt_client_read_value(hog->client, chr->value_handle,
+	bt_gatt_client_read_value(hog->client, value_handle,
 						report_read_cb, report, NULL);
 
 	return report;
 }
 
-static void external_service_char_cb(uint8_t status, GSList *chars,
-								void *user_data)
+static void external_service_char_cb(void *data, void *user_data)
 {
 	struct bt_hog *hog = user_data;
-	struct gatt_primary *primary = hog->primary;
+	struct gatt_db_attribute *attrib = data;
 	struct report *report;
-	GSList *l;
+	uint16_t value_handle;
+	uint8_t properties;
 
-	if (status != 0) {
-		const char *str = att_ecode2str(status);
-		DBG("Discover external service characteristic failed: %s", str);
-		return;
-	}
-
-	for (l = chars; l; l = g_slist_next(l)) {
-		struct gatt_char *chr, *next;
-		uint16_t start, end;
-
-		chr = l->data;
-		next = l->next ? l->next->data : NULL;
-
-		DBG("0x%04x UUID: %s properties: %02x",
-				chr->handle, chr->uuid, chr->properties);
+	gatt_db_attribute_get_char_data(attrib, NULL, &value_handle,
+							&properties, NULL);
 
-		report = report_new(hog, chr);
-		start = chr->value_handle + 1;
-		end = (next ? next->handle - 1 : primary->range.end);
-		discover_report(hog, hog->attrib, start, end, report);
-	}
+	report = report_new(hog, value_handle, properties);
+	gatt_db_service_foreach_desc(attrib, discover_report_cb, report);
 }
 
 static void external_report_reference_cb(bool success, uint8_t status,
@@ -335,6 +286,7 @@ static void external_report_reference_cb(bool success, uint8_t status,
 	struct bt_hog *hog = user_data;
 	uint16_t uuid16;
 	bt_uuid_t uuid;
+	struct queue *chrs;
 
 	if (!success) {
 		error("Read External Report Reference descriptor failed: %s",
@@ -355,9 +307,20 @@ static void external_report_reference_cb(bool success, uint8_t status,
 	if (uuid16 != HOG_REPORT_UUID)
 		return;
 
+	chrs = queue_new();
+	if (!chrs) {
+		error("Insufficient resources");
+		return;
+	}
+
 	bt_uuid16_create(&uuid, uuid16);
-	gatt_discover_char(hog->attrib, 0x0001, 0xffff, &uuid,
-					external_service_char_cb, hog);
+	gatt_db_read_by_type(hog->db, 0x0001, 0xffff, uuid, chrs);
+
+	if (queue_isempty(chrs))
+		return;
+
+	queue_foreach(chrs, external_service_char_cb, hog);
+	queue_destroy(chrs, NULL);
 }
 
 static int report_cmp(gconstpointer a, gconstpointer b)
@@ -824,21 +787,15 @@ static void proto_mode_read_cb(bool success, uint8_t att_ecode,
 		DBG("HoG is operating in Report Protocol Mode");
 }
 
-static void char_discovered_cb(uint8_t status, GSList *chars, void *user_data)
+static void char_discovered_cb(struct gatt_db_attribute *attrib,
+								void *user_data)
 {
 	struct bt_hog *hog = user_data;
-	struct gatt_primary *primary = hog->primary;
-	bt_uuid_t report_uuid, report_map_uuid, info_uuid;
-	bt_uuid_t proto_mode_uuid, ctrlpt_uuid;
+	bt_uuid_t report_uuid, report_map_uuid, proto_mode_uuid, ctrlpt_uuid;
+	bt_uuid_t info_uuid, uuid;
 	struct report *report;
-	GSList *l;
-	uint16_t info_handle = 0, proto_mode_handle = 0;
-
-	if (status != 0) {
-		const char *str = att_ecode2str(status);
-		DBG("Discover all characteristics failed: %s", str);
-		return;
-	}
+	uint16_t value_handle;
+	uint8_t properties;
 
 	bt_uuid16_create(&report_uuid, HOG_REPORT_UUID);
 	bt_uuid16_create(&report_map_uuid, HOG_REPORT_MAP_UUID);
@@ -846,47 +803,27 @@ static void char_discovered_cb(uint8_t status, GSList *chars, void *user_data)
 	bt_uuid16_create(&proto_mode_uuid, HOG_PROTO_MODE_UUID);
 	bt_uuid16_create(&ctrlpt_uuid, HOG_CONTROL_POINT_UUID);
 
-	for (l = chars; l; l = g_slist_next(l)) {
-		struct gatt_char *chr, *next;
-		bt_uuid_t uuid;
-		uint16_t start, end;
-
-		chr = l->data;
-		next = l->next ? l->next->data : NULL;
-
-		DBG("0x%04x UUID: %s properties: %02x",
-				chr->handle, chr->uuid, chr->properties);
-
-		bt_string_to_uuid(&uuid, chr->uuid);
-
-		start = chr->value_handle + 1;
-		end = (next ? next->handle - 1 : primary->range.end);
-
-		if (bt_uuid_cmp(&uuid, &report_uuid) == 0) {
-			report = report_new(hog, chr);
-			discover_report(hog, hog->attrib, start, end, report);
-		} else if (bt_uuid_cmp(&uuid, &report_map_uuid) == 0) {
-			bt_gatt_client_read_long_value(hog->client,
-				chr->value_handle, 0, report_map_read_cb,
-				hog, NULL);
-			discover_external(hog, hog->attrib, start, end, hog);
-		} else if (bt_uuid_cmp(&uuid, &info_uuid) == 0)
-			info_handle = chr->value_handle;
-		else if (bt_uuid_cmp(&uuid, &proto_mode_uuid) == 0)
-			proto_mode_handle = chr->value_handle;
-		else if (bt_uuid_cmp(&uuid, &ctrlpt_uuid) == 0)
-			hog->ctrlpt_handle = chr->value_handle;
-	}
-
-	if (proto_mode_handle) {
-		hog->proto_mode_handle = proto_mode_handle;
-		bt_gatt_client_read_value(hog->client, proto_mode_handle,
+	gatt_db_attribute_get_char_data(attrib, NULL, &value_handle,
+							&properties, &uuid);
+
+	if (!bt_uuid_cmp(&uuid, &report_uuid)) {
+		report = report_new(hog, value_handle, properties);
+		gatt_db_service_foreach_desc(attrib, discover_report_cb,
+									report);
+	} else if (!bt_uuid_cmp(&uuid, &report_map_uuid)) {
+		bt_gatt_client_read_long_value(hog->client, value_handle, 0,
+						report_map_read_cb, hog, NULL);
+		gatt_db_service_foreach_desc(attrib, discover_external_cb, hog);
+	} else if (!bt_uuid_cmp(&uuid, &info_uuid)) {
+		bt_gatt_client_read_value(hog->client, value_handle,
+						info_read_cb, hog, NULL);
+	} else if (!bt_uuid_cmp(&uuid, &proto_mode_uuid)) {
+		hog->proto_mode_handle = value_handle;
+		bt_gatt_client_read_value(hog->client, value_handle,
 						proto_mode_read_cb, hog, NULL);
+	} else if (!bt_uuid_cmp(&uuid, &ctrlpt_uuid)) {
+		hog->ctrlpt_handle = value_handle;
 	}
-
-	if (info_handle)
-		bt_gatt_client_read_value(hog->client, info_handle,
-						info_read_cb, hog, NULL);
 }
 
 static void report_free(void *data)
@@ -894,7 +831,7 @@ static void report_free(void *data)
 	struct report *report = data;
 
 	g_free(report->value);
-	g_free(report->decl);
+	free(report->decl);
 	g_free(report);
 }
 
@@ -912,21 +849,19 @@ static void hog_free(void *data)
 	bt_uhid_unref(hog->uhid);
 	g_slist_free_full(hog->reports, report_free);
 	g_free(hog->name);
-	g_free(hog->primary);
 	g_free(hog);
 }
 
 struct bt_hog *bt_hog_new_default(const char *name, uint16_t vendor,
 					uint16_t product, uint16_t version,
-					void *primary, uint16_t service_handle)
+					uint16_t service_handle)
 {
-	return bt_hog_new(-1, name, vendor, product, version, primary,
-								service_handle);
+	return bt_hog_new(-1, name, vendor, product, version, service_handle);
 }
 
 struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
 					uint16_t product, uint16_t version,
-					void *primary, uint16_t service_handle)
+					uint16_t service_handle)
 {
 	struct bt_hog *hog;
 
@@ -953,9 +888,6 @@ struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
 	hog->product = product;
 	hog->version = version;
 
-	if (primary)
-		hog->primary = g_memdup(primary, sizeof(*hog->primary));
-
 	if (service_handle)
 		hog->service_handle = service_handle;
 
@@ -983,24 +915,13 @@ void bt_hog_unref(struct bt_hog *hog)
 	hog_free(hog);
 }
 
-static void find_included_cb(uint8_t status, GSList *services, void *user_data)
+static void find_included_cb(struct gatt_db_attribute *attrib, void *user_data)
 {
-	GSList *l;
-
-	DBG("");
-
-	if (status) {
-		const char *str = att_ecode2str(status);
-		DBG("Find included failed: %s", str);
-		return;
-	}
+	uint16_t start_handle;
 
-	for (l = services; l; l = l->next) {
-		struct gatt_included *include = l->data;
+	gatt_db_attribute_get_incl_data(attrib, NULL, &start_handle, NULL);
 
-		DBG("included: handle %x, uuid %s",
-			include->handle, include->uuid);
-	}
+	DBG("included: handle %x", start_handle);
 }
 
 static void hog_attach_scpp(struct bt_hog *hog, struct gatt_primary *primary)
@@ -1051,28 +972,25 @@ static void hog_attach_bas(struct bt_hog *hog, struct gatt_primary *primary)
 	queue_push_head(hog->bas, instance);
 }
 
-static void hog_attach_hog(struct bt_hog *hog, struct gatt_primary *primary)
+static void hog_attach_hog(struct bt_hog *hog, uint16_t service_handle)
 {
 	struct bt_hog *instance;
+	struct gatt_db_attribute *attrib;
+
+	attrib = gatt_db_get_attribute(hog->db, service_handle);
 
-	if (!hog->primary) {
-		hog->primary = g_memdup(primary, sizeof(*primary));
-		gatt_discover_char(hog->attrib, primary->range.start,
-						primary->range.end, NULL,
-						char_discovered_cb, hog);
-		gatt_find_included(hog->attrib, primary->range.start,
-				primary->range.end, find_included_cb, hog);
+	if (!hog->service_handle) {
+		hog->service_handle = service_handle;
+		gatt_db_service_foreach_char(attrib, char_discovered_cb, hog);
+		gatt_db_service_foreach_incl(attrib, find_included_cb, hog);
 		return;
 	}
 
 	instance = bt_hog_new(hog->uhid_fd, hog->name, hog->vendor,
-					hog->product, hog->version, primary, 0);
+				hog->product, hog->version, service_handle);
 	if (!instance)
 		return;
 
-	gatt_find_included(hog->attrib, primary->range.start,
-			primary->range.end, find_included_cb, instance);
-
 	bt_hog_attach(instance, hog->attrib, hog->client);
 	hog->instances = g_slist_append(hog->instances, instance);
 }
@@ -1111,17 +1029,38 @@ static void primary_cb(uint8_t status, GSList *services, void *user_data)
 
 		if (strcmp(primary->uuid, BATTERY_UUID) == 0) {
 			hog_attach_bas(hog, primary);
-			continue;
 		}
-
-		if (strcmp(primary->uuid, HOG_UUID) == 0)
-			hog_attach_hog(hog, primary);
 	}
 }
 
+static void service_cb(struct gatt_db_attribute *attrib, void *user_data)
+{
+	struct bt_hog *hog = user_data;
+	bt_uuid_t service_uuid;
+	char uuid[MAX_LEN_UUID_STR + 1];
+	uint16_t service_handle;
+
+	if (!gatt_db_attribute_get_service_data(attrib, &service_handle,
+						NULL, NULL, &service_uuid))
+		return;
+
+	bt_uuid_to_string(&service_uuid, uuid, sizeof(uuid));
+
+	if (!bt_uuid_strcmp(uuid, HOG_UUID))
+		hog_attach_hog(hog, service_handle);
+	else if (!bt_uuid_strcmp(uuid, SCAN_PARAMETERS_UUID))
+		/* TODO */
+		return;
+	else if (!bt_uuid_strcmp(uuid, DEVICE_INFORMATION_UUID))
+		/* TODO */
+		return;
+	else if (!bt_uuid_strcmp(uuid, BATTERY_UUID))
+		/* TODO */
+		return;
+}
+
 bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)
 {
-	struct gatt_primary *primary = hog->primary;
 	GSList *l;
 
 	if (hog->attrib || hog->client)
@@ -1129,8 +1068,10 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)
 
 	hog->attrib = g_attrib_ref(gatt);
 	hog->client = bt_gatt_client_ref(client);
+	hog->db = gatt_db_ref(bt_gatt_client_get_db(hog->client));
 
-	if (!primary) {
+	if (!hog->service_handle) {
+		gatt_db_foreach_service(hog->db, NULL, service_cb, hog);
 		gatt_discover_primary(hog->attrib, NULL, primary_cb, hog);
 		return true;
 	}
@@ -1150,9 +1091,11 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)
 	}
 
 	if (hog->reports == NULL) {
-		gatt_discover_char(hog->attrib, primary->range.start,
-						primary->range.end, NULL,
-						char_discovered_cb, hog);
+		struct gatt_db_attribute *service;
+
+		service = gatt_db_get_attribute(hog->db, hog->service_handle);
+		gatt_db_service_foreach_char(service, char_discovered_cb, hog);
+		gatt_db_service_foreach_incl(service, find_included_cb, hog);
 		return true;
 	}
 
@@ -1199,6 +1142,7 @@ void bt_hog_detach(struct bt_hog *hog)
 	if (hog->dis)
 		bt_dis_detach(hog->dis);
 
+	gatt_db_unref(hog->db);
 	bt_gatt_client_unref(hog->client);
 	hog->client = NULL;
 	g_attrib_unref(hog->attrib);
diff --git a/android/hog.h b/android/hog.h
index 61d756c..cfe6873 100644
--- a/android/hog.h
+++ b/android/hog.h
@@ -25,11 +25,11 @@ struct bt_hog;
 
 struct bt_hog *bt_hog_new_default(const char *name, uint16_t vendor,
 					uint16_t product, uint16_t version,
-					void *primary, uint16_t service_handle);
+					uint16_t service_handle);
 
 struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
 					uint16_t product, uint16_t version,
-					void *primary, uint16_t service_handle);
+					uint16_t service_handle);
 
 struct bt_hog *bt_hog_ref(struct bt_hog *hog);
 void bt_hog_unref(struct bt_hog *hog);
diff --git a/unit/test-hog.c b/unit/test-hog.c
index c7c64e4..5794c5e 100644
--- a/unit/test-hog.c
+++ b/unit/test-hog.c
@@ -196,7 +196,7 @@ static struct context *create_context(gconstpointer data)
 	fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
 	g_assert(fd > 0);
 
-	context->hog = bt_hog_new(fd, name, vendor, product, version, NULL, 0);
+	context->hog = bt_hog_new(fd, name, vendor, product, version, 0);
 	g_assert(context->hog);
 
 	channel = g_io_channel_unix_new(sv[1]);
-- 
1.9.1

--
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