[PATCHv2 3/5] android/gatt: Add descriptors sending and caching for client

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

 



This adds descriptors caching at first get descriptor call. After that
descriptors are send from the cache.
---
 android/gatt.c | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 152 insertions(+), 8 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index b496d8a..2039920 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -287,6 +287,16 @@ static bool match_char_by_higher_inst_id(const void *data,
 	return inst_id < ch->id.instance;
 }
 
+static bool match_descr_by_higher_inst_id(const void *data,
+							const void *user_data)
+{
+	const struct descriptor *descr = data;
+	uint8_t instance = PTR_TO_INT(user_data);
+
+	/* For now we match instance as it is unique */
+	return instance < descr->id.instance;
+}
+
 static bool match_char_by_instance(const void *data, const void *user_data)
 {
 	const struct characteristic *ch = data;
@@ -1420,6 +1430,15 @@ done:
 				HAL_OP_GATT_CLIENT_GET_CHARACTERISTIC, status);
 }
 
+struct discover_desc_data {
+	int32_t conn_id;
+	const struct element_id *srvc_id;
+	const struct element_id *char_id;
+	uint8_t primary;
+
+	struct queue *descriptors;
+};
+
 static void send_client_descr_notify(int32_t status, int32_t conn_id,
 					bool primary,
 					const struct element_id *srvc,
@@ -1443,6 +1462,126 @@ static void send_client_descr_notify(int32_t status, int32_t conn_id,
 			HAL_EV_GATT_CLIENT_GET_DESCRIPTOR, sizeof(ev), &ev);
 }
 
+
+static void cache_all_descr(const uint8_t *pdu, guint16 len,
+							struct queue *queue)
+{
+	struct att_data_list *list;
+	guint8 format;
+	int i;
+
+	list = dec_find_info_resp(pdu, len, &format);
+	if (!list || !queue)
+		return;
+
+	for (i = 0; i < list->num; i++) {
+		char uuidstr[MAX_LEN_UUID_STR];
+		struct descriptor *descr;
+		bt_uuid_t uuid128;
+		uint16_t handle;
+		uint8_t *value;
+		bt_uuid_t uuid;
+
+		value = list->data[i];
+		handle = get_le16(value);
+
+		if (format == ATT_FIND_INFO_RESP_FMT_16BIT) {
+			bt_uuid16_create(&uuid, get_le16(&value[2]));
+			bt_uuid_to_uuid128(&uuid, &uuid128);
+		} else {
+			uint128_t u128;
+
+			bswap_128(&value[2], &u128);
+			bt_uuid128_create(&uuid128, u128);
+		}
+
+		bt_uuid_to_string(&uuid128, uuidstr, MAX_LEN_UUID_STR);
+		DBG("gatt: Cached descriptor handle = 0x%04x, uuid = %s\n",
+							handle, uuidstr);
+
+		descr = new0(struct descriptor, 1);
+		if (!descr)
+			break;
+
+		descr->id.instance = i;
+		descr->handle = handle;
+		descr->id.uuid = uuid128;
+
+		if (!queue_push_tail(queue, descr))
+			free(descr);
+	}
+
+	att_data_list_free(list);
+}
+
+static void gatt_discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
+							gpointer user_data)
+{
+	struct discover_desc_data *data = user_data;
+	struct descriptor *descr;
+
+	if (!data) {
+		error("No user data");
+		return;
+	}
+
+	if (status != 0)
+		error("gatt: Discover all char descriptors failed: %s\n",
+							att_ecode2str(status));
+	else
+		cache_all_descr(pdu, len, data->descriptors);
+
+	descr = queue_peek_head(data->descriptors);
+	send_client_descr_notify(status, data->conn_id, data->primary,
+						data->srvc_id, data->char_id,
+						&descr->id);
+
+	free(data);
+}
+
+static bool build_descr_cache(int32_t conn_id, struct gatt_device *dev,
+					struct service *srvc, uint8_t primary,
+					struct characteristic *ch)
+{
+	struct discover_desc_data *cb_data;
+	struct characteristic *next_ch;
+	uint16_t start, end;
+
+	/* Clip range to given characteristic */
+	start = ch->ch.value_handle + 1;
+	end = srvc->primary.range.end;
+
+	/* Use next characteristic start as end. If there is none -
+	 * service end is valid end.
+	 * TODO: we should cache char end handle to avoid this search */
+	next_ch = queue_find(srvc->chars, match_char_by_higher_inst_id,
+					INT_TO_PTR(ch->id.instance));
+	if (next_ch)
+		end = next_ch->ch.handle - 1;
+
+	/* If there are no descriptors, notify with fail status. */
+	if (start > end)
+		return false;
+
+	cb_data = new0(struct discover_desc_data, 1);
+	if (!cb_data)
+		return false;
+
+	cb_data->conn_id = conn_id;
+	cb_data->srvc_id = &srvc->id;
+	cb_data->char_id = &ch->id;
+	cb_data->primary = primary;
+	cb_data->descriptors = ch->descriptors;
+
+	if (!gatt_discover_char_desc(dev->attrib, start, end,
+					gatt_discover_desc_cb,	cb_data)) {
+		free(cb_data);
+		return false;
+	}
+
+	return true;
+}
+
 static void handle_client_get_descriptor(const void *buf, uint16_t len)
 {
 	const struct hal_cmd_gatt_client_get_descriptor *cmd = buf;
@@ -1488,19 +1627,24 @@ static void handle_client_get_descriptor(const void *buf, uint16_t len)
 		goto failed;
 	}
 
-
 	if (queue_isempty(ch->descriptors)) {
-		/* TODO: Build the cache */
-
-		ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
+		if (build_descr_cache(conn_id, dev, srvc, primary, ch)) {
+			ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
 					HAL_OP_GATT_CLIENT_GET_DESCRIPTOR,
-					HAL_STATUS_FAILED);
-		return;
+					HAL_STATUS_SUCCESS);
+			return;
+		}
 	}
 
-	status = HAL_STATUS_FAILED;
+	status = HAL_STATUS_SUCCESS;
 
-	/* TODO: Send from cache */
+	/* Send from cache */
+	if (cmd->number > 1)
+		descr = queue_find(ch->descriptors,
+					match_descr_by_higher_inst_id,
+					INT_TO_PTR(cmd->gatt_id[1].inst_id));
+	else
+		descr = queue_peek_head(ch->descriptors);
 
 failed:
 	send_client_descr_notify(descr ? GATT_SUCCESS : GATT_FAILURE, conn_id,
-- 
1.9.0

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