[PATCH BlueZ 09/11] shared/gatt-client: Add service iterator functions.

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

 



This patch introduces high-level structures and functions for iterating through,
and storing, data about the discovered services.
---
 src/shared/TODO          |   1 -
 src/shared/gatt-client.c | 153 +++++++++++++++++++++++++++++++++++++++++++++--
 src/shared/gatt-client.h |  42 +++++++++++++
 3 files changed, 191 insertions(+), 5 deletions(-)

diff --git a/src/shared/TODO b/src/shared/TODO
index 6f51890..8ffaacf 100644
--- a/src/shared/TODO
+++ b/src/shared/TODO
@@ -1,6 +1,5 @@
 TODOs for shared/gatt-client
 
-* Add high-level abstraction for services, characteristics, and descriptors.
 * Implement characteristic discovery.
 * Implement descriptor discovery.
 * Handle request timeouts.
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index a46ff4e..f25b5b7 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -31,6 +31,13 @@
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
 #endif
 
+#define UUID_BYTES BT_GATT_UUID_SIZE * sizeof(uint8_t)
+
+struct service_list {
+	bt_gatt_service_t service;
+	struct service_list *next;
+};
+
 struct bt_gatt_client {
 	struct bt_att *att;
 	bool persist;
@@ -39,9 +46,66 @@ struct bt_gatt_client {
 	bt_gatt_client_destroy_func_t debug_destroy;
 	void *debug_data;
 
+	struct service_list *svc_head, *svc_tail;
 	bool in_init;
+	bool initialized;
+
+	/* GATT service handles */
+	uint16_t gatt_sv_handle;
+	uint16_t svcc_handle;
+	uint16_t svc_ccc_handle;
 };
 
+static bool gatt_client_add_service(struct bt_gatt_client *client,
+						uint16_t start, uint16_t end,
+						uint8_t uuid[BT_GATT_UUID_SIZE])
+{
+	struct service_list *list;
+
+	list = new0(struct service_list, 1);
+	if (!list)
+		return false;
+
+	list->service.start_handle = start;
+	list->service.end_handle = end;
+	memcpy(list->service.uuid, uuid, UUID_BYTES);
+
+	if (!client->svc_head)
+		client->svc_head = client->svc_tail = list;
+	else {
+		client->svc_tail->next = list;
+		client->svc_tail = list;
+	}
+
+	return true;
+}
+
+static void service_destroy_characteristics(bt_gatt_service_t *service)
+{
+	unsigned int i;
+
+	for (i = 0; i < service->num_chrcs; i++)
+		free((bt_gatt_descriptor_t *) service->chrcs[i].descs);
+
+	free((bt_gatt_characteristic_t *) service->chrcs);
+}
+
+static void gatt_client_clear_services(struct bt_gatt_client *client)
+{
+	struct service_list *l, *tmp;
+
+	l = client->svc_head;
+
+	while (l) {
+		service_destroy_characteristics(&l->service);
+		tmp = l;
+		l = tmp->next;
+		free(tmp);
+	}
+
+	client->svc_head = client->svc_tail = NULL;
+}
+
 struct bt_gatt_client *bt_gatt_client_new(struct bt_att *att)
 {
 	struct bt_gatt_client *client;
@@ -142,7 +206,7 @@ static void discover_primary_cb(bool success, uint8_t att_ecode,
 	struct bt_gatt_client *client = op->client;
 	struct bt_gatt_iter iter;
 	uint16_t start, end;
-	uint8_t uuid[16];
+	uint8_t uuid[BT_GATT_UUID_SIZE];
 	char uuid_str[MAX_LEN_UUID_STR];
 	bt_uuid_t tmp;
 
@@ -164,8 +228,6 @@ static void discover_primary_cb(bool success, uint8_t att_ecode,
 					bt_gatt_result_service_count(result));
 
 	while (bt_gatt_iter_next_service(&iter, &start, &end, uuid)) {
-		/* TODO: discover characteristics and store the service. */
-
 		/* Log debug message. */
 		tmp.type = BT_UUID128;
 		memcpy(tmp.value.u128.data, uuid, sizeof(uuid));
@@ -173,11 +235,25 @@ static void discover_primary_cb(bool success, uint8_t att_ecode,
 		util_debug(client->debug_callback, client->debug_data,
 				"start: 0x%04x, end: 0x%04x, uuid: %s",
 				start, end, uuid_str);
+
+		/* Store the service */
+		if (!gatt_client_add_service(client, start, end, uuid)) {
+			util_debug(client->debug_callback, client->debug_data,
+						"Failed to store service");
+
+			gatt_client_clear_services(client);
+
+			success = false;
+			goto done;
+		}
 	}
 
 done:
 	client->in_init = false;
 
+	if (success)
+		client->initialized = true;
+
 	if (op->callback)
 		op->callback(success, att_ecode, op->user_data);
 }
@@ -228,7 +304,7 @@ bool bt_gatt_client_init(struct bt_gatt_client *client, uint16_t mtu,
 {
 	struct async_op *op;
 
-	if (!client || client->in_init)
+	if (!client || client->in_init || client->initialized)
 		return false;
 
 	op = new0(struct async_op, 1);
@@ -254,6 +330,11 @@ bool bt_gatt_client_init(struct bt_gatt_client *client, uint16_t mtu,
 	return true;
 }
 
+bool bt_gatt_client_is_initialized(struct bt_gatt_client *client)
+{
+	return (client && client->initialized);
+}
+
 unsigned int bt_gatt_client_register_service_changed(
 				struct bt_gatt_client *client,
 				uint16_t handle,
@@ -271,3 +352,67 @@ bool bt_gatt_client_unregister_service_changed(struct bt_gatt_client *client,
 	// TODO
 	return false;
 }
+
+bool bt_gatt_service_iter_init(struct bt_gatt_service_iter *iter,
+						struct bt_gatt_client *client)
+{
+	if (!iter || !client)
+		return false;
+
+	if (client->in_init)
+		return false;
+
+	memset(iter, 0, sizeof(*iter));
+	iter->client = client;
+	iter->ptr = NULL;
+
+	return true;
+}
+
+bool bt_gatt_service_iter_next(struct bt_gatt_service_iter *iter,
+						bt_gatt_service_t *service)
+{
+	struct service_list *l;
+
+	if (!iter || !service)
+		return false;
+
+	l = iter->ptr;
+
+	if (!l)
+		l = iter->client->svc_head;
+	else
+		l = l->next;
+
+	if (!l)
+		return false;
+
+	*service = l->service;
+	iter->ptr = l;
+
+	return true;
+}
+
+bool bt_gatt_service_iter_next_by_handle(struct bt_gatt_service_iter *iter,
+						uint16_t start_handle,
+						bt_gatt_service_t *service)
+{
+	while (bt_gatt_service_iter_next(iter, service)) {
+		if (service->start_handle == start_handle)
+			return true;
+	}
+
+	return false;
+}
+
+bool bt_gatt_service_iter_next_by_uuid(struct bt_gatt_service_iter *iter,
+					const uint8_t uuid[BT_GATT_UUID_SIZE],
+					bt_gatt_service_t *service)
+{
+	while (bt_gatt_service_iter_next(iter, service)) {
+		if (memcmp(service->uuid, uuid, UUID_BYTES) == 0)
+			return true;
+	}
+
+	return false;
+}
diff --git a/src/shared/gatt-client.h b/src/shared/gatt-client.h
index 7a46cca..97033f8 100644
--- a/src/shared/gatt-client.h
+++ b/src/shared/gatt-client.h
@@ -23,6 +23,9 @@
 
 #include <stdbool.h>
 #include <stdint.h>
+#include <stddef.h>
+
+#define BT_GATT_UUID_SIZE 16
 
 struct bt_gatt_client;
 
@@ -50,6 +53,7 @@ bool bt_gatt_client_init(struct bt_gatt_client *client, uint16_t mtu,
 					bt_gatt_client_callback_t callback,
 					void *user_data,
 					bt_gatt_client_destroy_func_t destroy);
+bool bt_gatt_client_is_initialized(struct bt_gatt_client *client);
 
 unsigned int bt_gatt_client_register_service_changed(
 				struct bt_gatt_client *client,
@@ -59,3 +63,41 @@ unsigned int bt_gatt_client_register_service_changed(
 				bt_gatt_client_destroy_func_t destroy);
 bool bt_gatt_client_unregister_service_changed(struct bt_gatt_client *client,
 							unsigned int id);
+
+typedef struct {
+	uint16_t handle;
+	uint8_t uuid[BT_GATT_UUID_SIZE];
+} bt_gatt_descriptor_t;
+
+typedef struct {
+	uint16_t handle;
+	uint16_t value_handle;
+	uint8_t properties;
+	uint8_t uuid[BT_GATT_UUID_SIZE];
+	const bt_gatt_descriptor_t *descs;
+	size_t num_descs;
+} bt_gatt_characteristic_t;
+
+typedef struct {
+	uint16_t start_handle;
+	uint16_t end_handle;
+	uint8_t uuid[BT_GATT_UUID_SIZE];
+	const bt_gatt_characteristic_t *chrcs;
+	size_t num_chrcs;
+} bt_gatt_service_t;
+
+struct bt_gatt_service_iter {
+	struct bt_gatt_client *client;
+	void *ptr;
+};
+
+bool bt_gatt_service_iter_init(struct bt_gatt_service_iter *iter,
+						struct bt_gatt_client *client);
+bool bt_gatt_service_iter_next(struct bt_gatt_service_iter *iter,
+						bt_gatt_service_t *service);
+bool bt_gatt_service_iter_next_by_handle(struct bt_gatt_service_iter *iter,
+						uint16_t start_handle,
+						bt_gatt_service_t *service);
+bool bt_gatt_service_iter_next_by_uuid(struct bt_gatt_service_iter *iter,
+					const uint8_t uuid[BT_GATT_UUID_SIZE],
+					bt_gatt_service_t *service);
-- 
2.1.0.rc2.206.gedb03e5

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