[PATCHv5 09/14] shared/gatt: Discover secondary services

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

 



Add searching of secondary services in gatt-client.
---
 src/shared/gatt-client.c | 117 +++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 104 insertions(+), 13 deletions(-)

diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index 724fde2..e04724c 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -200,23 +200,36 @@ static void mark_notify_data_invalid_if_in_range(void *data, void *user_data)
 		notify_data->invalid = true;
 }
 
-static bool service_list_add_service(struct service_list **head,
-						struct service_list **tail,
-						bool primary, uint16_t start,
-						uint16_t end,
+static struct service_list *new_service_list(uint16_t start, uint16_t end,
+						bool primary,
 						uint8_t uuid[BT_GATT_UUID_SIZE])
 {
 	struct service_list *list;
 
 	list = new0(struct service_list, 1);
 	if (!list)
-		return false;
+		return NULL;
 
 	list->service.primary = primary;
 	list->service.start_handle = start;
 	list->service.end_handle = end;
 	memcpy(list->service.uuid, uuid, UUID_BYTES);
 
+	return list;
+}
+
+static bool service_list_add_service(struct service_list **head,
+						struct service_list **tail,
+						bool primary, uint16_t start,
+						uint16_t end,
+						uint8_t uuid[BT_GATT_UUID_SIZE])
+{
+	struct service_list *list;
+
+	list = new_service_list(start, end, primary, uuid);
+	if (!list)
+		return false;
+
 	if (!(*head))
 		*head = *tail = list;
 	else {
@@ -364,6 +377,8 @@ struct discovery_op {
 	struct bt_gatt_client *client;
 	struct service_list *result_head, *result_tail, *cur_service;
 	struct chrc_data *cur_chrc;
+	uint16_t start;
+	uint16_t end;
 	int cur_chrc_index;
 	int ref_count;
 	void (*complete_func)(struct discovery_op *op, bool success,
@@ -634,6 +649,79 @@ done:
 	op->complete_func(op, success, att_ecode);
 }
 
+static void discover_secondary_cb(bool success, uint8_t att_ecode,
+						struct bt_gatt_result *result,
+						void *user_data)
+{
+	struct discovery_op *op = user_data;
+	struct bt_gatt_client *client = op->client;
+	struct bt_gatt_iter iter;
+	uint16_t start, end;
+	uint8_t uuid[BT_GATT_UUID_SIZE];
+	char uuid_str[MAX_LEN_UUID_STR];
+	struct service_list *service;
+
+	if (!success) {
+		util_debug(client->debug_callback, client->debug_data,
+					"Secondary service discovery failed."
+					" ATT ECODE: 0x%02x", att_ecode);
+		switch (att_ecode) {
+		case BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND:
+		case BT_ATT_ERROR_UNSUPPORTED_GROUP_TYPE:
+			goto next;
+		default:
+			goto done;
+		}
+	}
+
+	if (!result || !bt_gatt_iter_init(&iter, result)) {
+		success = false;
+		goto done;
+	}
+
+	util_debug(client->debug_callback, client->debug_data,
+					"Secondary services found: %u",
+					bt_gatt_result_service_count(result));
+
+	while (bt_gatt_iter_next_service(&iter, &start, &end, uuid)) {
+		uuid_to_string(uuid, uuid_str);
+		util_debug(client->debug_callback, client->debug_data,
+				"start: 0x%04x, end: 0x%04x, uuid: %s",
+				start, end, uuid_str);
+
+		/* Store the service */
+		service = new_service_list(start, end, false, uuid);
+		if (!service) {
+			util_debug(client->debug_callback, client->debug_data,
+						"Failed to create service");
+			success = false;
+			goto done;
+		}
+
+		service_list_insert_services(&op->result_head, &op->result_tail,
+							service, service);
+	}
+
+next:
+	/* Sequentially discover the characteristics of all services */
+	op->cur_service = op->result_head;
+	if (bt_gatt_discover_characteristics(client->att,
+					op->cur_service->service.start_handle,
+					op->cur_service->service.end_handle,
+					discover_chrcs_cb,
+					discovery_op_ref(op),
+					discovery_op_unref))
+		return;
+
+	util_debug(client->debug_callback, client->debug_data,
+				"Failed to start characteristic discovery");
+	discovery_op_unref(op);
+	success = false;
+
+done:
+	op->complete_func(op, success, att_ecode);
+}
+
 static void discover_primary_cb(bool success, uint8_t att_ecode,
 						struct bt_gatt_result *result,
 						void *user_data)
@@ -686,18 +774,17 @@ static void discover_primary_cb(bool success, uint8_t att_ecode,
 	if (!op->result_head)
 		goto done;
 
-	/* Sequentially discover the characteristics of all services */
+	/* Discover secondary services */
 	op->cur_service = op->result_head;
-	if (bt_gatt_discover_characteristics(client->att,
-					op->cur_service->service.start_handle,
-					op->cur_service->service.end_handle,
-					discover_chrcs_cb,
-					discovery_op_ref(op),
-					discovery_op_unref))
+	if (bt_gatt_discover_secondary_services(client->att, NULL,
+							op->start, op->end,
+							discover_secondary_cb,
+							discovery_op_ref(op),
+							discovery_op_unref))
 		return;
 
 	util_debug(client->debug_callback, client->debug_data,
-				"Failed to start characteristic discovery");
+				"Failed to start secondary service discovery");
 	discovery_op_unref(op);
 	success = false;
 
@@ -870,6 +957,8 @@ static void process_service_changed(struct bt_gatt_client *client,
 
 	op->client = client;
 	op->complete_func = service_changed_complete;
+	op->start = start_handle;
+	op->end = end_handle;
 
 	if (!bt_gatt_discover_primary_services(client->att, NULL,
 						start_handle, end_handle,
@@ -1002,6 +1091,8 @@ static bool gatt_client_init(struct bt_gatt_client *client, uint16_t mtu)
 
 	op->client = client;
 	op->complete_func = init_complete;
+	op->start = 0x0001;
+	op->end = 0xffff;
 
 	/* Configure the MTU */
 	if (!bt_gatt_exchange_mtu(client->att, MAX(BT_ATT_DEFAULT_LE_MTU, mtu),
-- 
1.9.3

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