Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCHv2 0/5] Client descriptor operations
@ 2014-04-01 15:19 Jakub Tyszkowski
  2014-04-01 15:19 ` [PATCHv2 1/5] android/gatt: Add queue for characteristic descriptors caching Jakub Tyszkowski
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Jakub Tyszkowski @ 2014-04-01 15:19 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jakub Tyszkowski

v2 changes:
	* Rebased on top of latest changes and cleanups.
	* Function flow was redesigned to minimize label jumps.

Jakub Tyszkowski (5):
  android/gatt: Add queue for characteristic descriptors caching
  android/gatt: Handle get descriptor client command
  android/gatt: Add descriptors sending and caching for client
  android/gatt: Add client read descriptor handler
  android/gatt: Add client write descriptor handler

 android/gatt.c | 529 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 525 insertions(+), 4 deletions(-)

--
1.9.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCHv2 1/5] android/gatt: Add queue for characteristic descriptors caching
  2014-04-01 15:19 [PATCHv2 0/5] Client descriptor operations Jakub Tyszkowski
@ 2014-04-01 15:19 ` Jakub Tyszkowski
  2014-04-01 15:19 ` [PATCHv2 2/5] android/gatt: Handle get descriptor client command Jakub Tyszkowski
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Jakub Tyszkowski @ 2014-04-01 15:19 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jakub Tyszkowski

This is where descriptors will be cached.
---
 android/gatt.c | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/android/gatt.c b/android/gatt.c
index 8bd7028..0e63df5 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -67,9 +67,16 @@ struct element_id {
 	uint8_t instance;
 };
 
+struct descriptor {
+	struct element_id id;
+	uint16_t handle;
+};
+
 struct characteristic {
 	struct element_id id;
 	struct gatt_char ch;
+
+	struct queue *descriptors;
 };
 
 struct service {
@@ -171,6 +178,17 @@ static void element_id_to_hal_gatt_id(const struct element_id *from,
 	uuid2android(&from->uuid, to->uuid);
 }
 
+static void destroy_characteristic(void *data)
+{
+	struct characteristic *chars = data;
+
+	if (!chars)
+		return;
+
+	queue_destroy(chars->descriptors, free);
+	free(chars);
+}
+
 static void destroy_service(void *data)
 {
 	struct service *srvc = data;
@@ -178,7 +196,7 @@ static void destroy_service(void *data)
 	if (!srvc)
 		return;
 
-	queue_destroy(srvc->chars, free);
+	queue_destroy(srvc->chars, destroy_characteristic);
 	free(srvc);
 }
 
@@ -1268,6 +1286,12 @@ static void cache_all_srvc_chars(GSList *characteristics, struct queue *q)
 			continue;
 		}
 
+		ch->descriptors = queue_new();
+		if (!ch->descriptors) {
+			free(ch);
+			continue;
+		}
+
 		memcpy(&ch->ch, characteristics->data, sizeof(ch->ch));
 
 		bt_string_to_uuid(&uuid, ch->ch.uuid);
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCHv2 2/5] android/gatt: Handle get descriptor client command
  2014-04-01 15:19 [PATCHv2 0/5] Client descriptor operations Jakub Tyszkowski
  2014-04-01 15:19 ` [PATCHv2 1/5] android/gatt: Add queue for characteristic descriptors caching Jakub Tyszkowski
@ 2014-04-01 15:19 ` Jakub Tyszkowski
  2014-04-01 15:19 ` [PATCHv2 3/5] android/gatt: Add descriptors sending and caching for client Jakub Tyszkowski
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Jakub Tyszkowski @ 2014-04-01 15:19 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jakub Tyszkowski

This adds basic get characteristic descriptor command handling. In case
of no descriptor, proper notification with bad status is being sent.
---
 android/gatt.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 85 insertions(+), 1 deletion(-)

diff --git a/android/gatt.c b/android/gatt.c
index 0e63df5..b496d8a 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -31,6 +31,7 @@
 #include <glib.h>
 #include <errno.h>
 #include <sys/socket.h>
+#include <assert.h>
 
 #include "ipc.h"
 #include "ipc-common.h"
@@ -1419,12 +1420,95 @@ done:
 				HAL_OP_GATT_CLIENT_GET_CHARACTERISTIC, status);
 }
 
+static void send_client_descr_notify(int32_t status, int32_t conn_id,
+					bool primary,
+					const struct element_id *srvc,
+					const struct element_id *ch,
+					const struct element_id *opt_descr)
+{
+	struct hal_ev_gatt_client_get_descriptor ev;
+
+	memset(&ev, 0, sizeof(ev));
+
+	ev.status = status;
+	ev.conn_id = conn_id;
+
+	element_id_to_hal_srvc_id(srvc, primary, &ev.srvc_id);
+	element_id_to_hal_gatt_id(ch, &ev.char_id);
+
+	if (opt_descr)
+		element_id_to_hal_gatt_id(opt_descr, &ev.descr_id);
+
+	ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+			HAL_EV_GATT_CLIENT_GET_DESCRIPTOR, sizeof(ev), &ev);
+}
+
 static void handle_client_get_descriptor(const void *buf, uint16_t len)
 {
+	const struct hal_cmd_gatt_client_get_descriptor *cmd = buf;
+	struct descriptor *descr = NULL;
+	struct characteristic *ch;
+	struct service *srvc;
+	struct element_id srvc_id;
+	struct element_id char_id;
+	struct gatt_device *dev;
+	int32_t conn_id;
+	uint8_t primary;
+	uint8_t status;
+
 	DBG("");
 
+	if (len != sizeof(*cmd) + cmd->number * sizeof(cmd->gatt_id[0])) {
+		error("gatt: Get descr. bad cmd size (%u b), terminating", len);
+
+		raise(SIGTERM);
+		return;
+	}
+
+	assert(cmd->number);
+
+	conn_id = cmd->conn_id;
+	primary = cmd->srvc_id.is_primary;
+
+	hal_srvc_id_to_element_id(&cmd->srvc_id, &srvc_id);
+	hal_gatt_id_to_element_id(&cmd->gatt_id[0], &char_id);
+
+	if (!find_service(conn_id, &srvc_id, &dev, &srvc)) {
+		error("gatt: Get descr. could not find service.");
+
+		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
+
+	ch = queue_find(srvc->chars, match_char_by_element_id, &char_id);
+	if (!ch) {
+		error("gatt: Get descr. could not find characteristic.");
+
+		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
+
+
+	if (queue_isempty(ch->descriptors)) {
+		/* TODO: Build the cache */
+
+		ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
+					HAL_OP_GATT_CLIENT_GET_DESCRIPTOR,
+					HAL_STATUS_FAILED);
+		return;
+	}
+
+	status = HAL_STATUS_FAILED;
+
+	/* TODO: Send from cache */
+
+failed:
+	send_client_descr_notify(descr ? GATT_SUCCESS : GATT_FAILURE, conn_id,
+						primary, &srvc_id, &char_id,
+						&descr->id);
+
 	ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
-			HAL_OP_GATT_CLIENT_GET_DESCRIPTOR, HAL_STATUS_FAILED);
+				HAL_OP_GATT_CLIENT_GET_DESCRIPTOR, status);
 }
 
 struct read_char_data {
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCHv2 3/5] android/gatt: Add descriptors sending and caching for client
  2014-04-01 15:19 [PATCHv2 0/5] Client descriptor operations Jakub Tyszkowski
  2014-04-01 15:19 ` [PATCHv2 1/5] android/gatt: Add queue for characteristic descriptors caching Jakub Tyszkowski
  2014-04-01 15:19 ` [PATCHv2 2/5] android/gatt: Handle get descriptor client command Jakub Tyszkowski
@ 2014-04-01 15:19 ` Jakub Tyszkowski
  2014-04-01 15:19 ` [PATCHv2 4/5] android/gatt: Add client read descriptor handler Jakub Tyszkowski
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Jakub Tyszkowski @ 2014-04-01 15:19 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jakub Tyszkowski

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


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCHv2 4/5] android/gatt: Add client read descriptor handler
  2014-04-01 15:19 [PATCHv2 0/5] Client descriptor operations Jakub Tyszkowski
                   ` (2 preceding siblings ...)
  2014-04-01 15:19 ` [PATCHv2 3/5] android/gatt: Add descriptors sending and caching for client Jakub Tyszkowski
@ 2014-04-01 15:19 ` Jakub Tyszkowski
  2014-04-01 15:19 ` [PATCHv2 5/5] android/gatt: Add client write " Jakub Tyszkowski
  2014-04-03 14:27 ` [PATCHv2 0/5] Client descriptor operations Szymon Janc
  5 siblings, 0 replies; 7+ messages in thread
From: Jakub Tyszkowski @ 2014-04-01 15:19 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jakub Tyszkowski

This patch adds descriptor reading. In case of providing wrong
descriptor, error status is being sent with notification.
---
 android/gatt.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 141 insertions(+), 1 deletion(-)

diff --git a/android/gatt.c b/android/gatt.c
index 2039920..6c3ecf0 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -49,6 +49,9 @@
 #include "attrib/gatt.h"
 #include "btio/btio.h"
 
+/* set according to android's bt_gatt_client.h */
+#define GATT_MAX_ATTR_LEN 600
+
 #define GATT_SUCCESS	0x00000000
 #define GATT_FAILURE	0x00000101
 
@@ -287,6 +290,17 @@ static bool match_char_by_higher_inst_id(const void *data,
 	return inst_id < ch->id.instance;
 }
 
+static bool match_descr_by_element_id(const void *data, const void *user_data)
+{
+	const struct element_id *exp_id = user_data;
+	const struct descriptor *descr = data;
+
+	if (exp_id->instance == descr->id.instance)
+		return !bt_uuid_cmp(&descr->id.uuid, &exp_id->uuid);
+
+	return false;
+}
+
 static bool match_descr_by_higher_inst_id(const void *data,
 							const void *user_data)
 {
@@ -1885,12 +1899,138 @@ failed:
 						cmd->srvc_id.is_primary);
 }
 
+static void send_client_descr_read_notify(int32_t status, const uint8_t *pdu,
+						guint16 len, int32_t conn_id,
+						const struct element_id *srvc,
+						const struct element_id *ch,
+						const struct element_id *descr,
+						uint8_t primary)
+{
+	uint8_t buf[IPC_MTU];
+	struct hal_ev_gatt_client_read_descriptor *ev = (void *) buf;
+
+	memset(buf, 0, sizeof(buf));
+
+	ev->status = status;
+	ev->conn_id = conn_id;
+
+	element_id_to_hal_srvc_id(srvc, primary, &ev->data.srvc_id);
+	element_id_to_hal_gatt_id(ch, &ev->data.char_id);
+	element_id_to_hal_gatt_id(descr, &ev->data.descr_id);
+
+	if (len && pdu)
+		ev->data.len = dec_read_resp(pdu, len, ev->data.value,
+							GATT_MAX_ATTR_LEN);
+
+	ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+					HAL_EV_GATT_CLIENT_READ_DESCRIPTOR,
+					sizeof(*ev) + ev->data.len, ev);
+}
+
+struct read_desc_data {
+	int32_t conn_id;
+	const struct element_id *srvc_id;
+	const struct element_id *char_id;
+	const struct element_id *descr_id;
+	uint8_t primary;
+};
+
+static void read_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
+							gpointer user_data)
+{
+	struct read_desc_data *cb_data = user_data;
+
+	if (status != 0)
+		error("gatt: Discover all char descriptors failed: %s\n",
+							att_ecode2str(status));
+
+	send_client_descr_read_notify(status, pdu, len, cb_data->conn_id,
+					cb_data->srvc_id, cb_data->char_id,
+					cb_data->descr_id, cb_data->primary);
+
+	free(cb_data);
+}
+
 static void handle_client_read_descriptor(const void *buf, uint16_t len)
 {
+	const struct hal_cmd_gatt_client_read_descriptor *cmd = buf;
+	struct read_desc_data *cb_data;
+	struct characteristic *ch;
+	struct descriptor *descr;
+	struct service *srvc;
+	struct element_id char_id;
+	struct element_id descr_id;
+	struct element_id srvc_id;
+	struct gatt_device *dev;
+	int32_t conn_id = 0;
+	uint8_t primary;
+	uint8_t status;
+
 	DBG("");
 
+	conn_id = cmd->conn_id;
+	primary = cmd->srvc_id.is_primary;
+
+	hal_srvc_id_to_element_id(&cmd->srvc_id, &srvc_id);
+	hal_gatt_id_to_element_id(&cmd->char_id, &char_id);
+	hal_gatt_id_to_element_id(&cmd->descr_id, &descr_id);
+
+	if (!find_service(conn_id, &srvc_id, &dev, &srvc)) {
+		error("gatt: Read descr. could not find service");
+
+		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
+
+	ch = queue_find(srvc->chars, match_char_by_element_id, &char_id);
+	if (!ch) {
+		error("gatt: Read descr. could not find characteristic");
+
+		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
+
+	descr = queue_find(ch->descriptors, match_descr_by_element_id,
+								&descr_id);
+	if (!descr) {
+		error("gatt: Read descr. could not find descriptor");
+
+		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
+
+	cb_data = new0(struct read_desc_data, 1);
+	if (!cb_data) {
+		error("gatt: Read descr. could not allocate callback data");
+
+		status = HAL_STATUS_NOMEM;
+		goto failed;
+	}
+
+	cb_data->conn_id = conn_id;
+	cb_data->srvc_id = &srvc->id;
+	cb_data->char_id = &ch->id;
+	cb_data->descr_id = &descr->id;
+	cb_data->primary = primary;
+
+	if (!gatt_read_char(dev->attrib, descr->handle, read_desc_cb,
+								cb_data)) {
+		free(cb_data);
+
+		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
+
+	status = HAL_STATUS_SUCCESS;
+
+failed:
+	if (status != HAL_STATUS_SUCCESS)
+		send_client_descr_read_notify(GATT_FAILURE, NULL, 0, conn_id,
+						&srvc_id, &char_id, &descr_id,
+						primary);
+
 	ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
-			HAL_OP_GATT_CLIENT_READ_DESCRIPTOR, HAL_STATUS_FAILED);
+			HAL_OP_GATT_CLIENT_READ_DESCRIPTOR, status);
 }
 
 static void handle_client_write_descriptor(const void *buf, uint16_t len)
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCHv2 5/5]  android/gatt: Add client write descriptor handler
  2014-04-01 15:19 [PATCHv2 0/5] Client descriptor operations Jakub Tyszkowski
                   ` (3 preceding siblings ...)
  2014-04-01 15:19 ` [PATCHv2 4/5] android/gatt: Add client read descriptor handler Jakub Tyszkowski
@ 2014-04-01 15:19 ` Jakub Tyszkowski
  2014-04-03 14:27 ` [PATCHv2 0/5] Client descriptor operations Szymon Janc
  5 siblings, 0 replies; 7+ messages in thread
From: Jakub Tyszkowski @ 2014-04-01 15:19 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jakub Tyszkowski

This adds writing descriptors. In case of providing invalid descriptor
error status is send with notification.
---
 android/gatt.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 130 insertions(+), 1 deletion(-)

diff --git a/android/gatt.c b/android/gatt.c
index 6c3ecf0..cee65ef 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -2033,12 +2033,141 @@ failed:
 			HAL_OP_GATT_CLIENT_READ_DESCRIPTOR, status);
 }
 
+struct write_descr_data {
+	int32_t conn_id;
+	const struct element_id *srvc_id;
+	const struct element_id *char_id;
+	const struct element_id *descr_id;
+	uint8_t primary;
+};
+
+static void send_client_descr_write_notify(int32_t status, int32_t conn_id,
+						const struct element_id *srvc,
+						const struct element_id *ch,
+						const struct element_id *descr,
+						uint8_t primary) {
+	uint8_t buf[IPC_MTU];
+	struct hal_ev_gatt_client_write_descriptor *ev = (void *) buf;
+
+	memset(buf, 0, sizeof(buf));
+
+	ev->status = status;
+	ev->conn_id = conn_id;
+
+	element_id_to_hal_srvc_id(srvc, primary, &ev->data.srvc_id);
+	element_id_to_hal_gatt_id(ch, &ev->data.char_id);
+	element_id_to_hal_gatt_id(descr, &ev->data.descr_id);
+
+	ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+					HAL_EV_GATT_CLIENT_WRITE_DESCRIPTOR,
+					sizeof(*ev), ev);
+}
+
+
+static void write_descr_cb(guint8 status, const guint8 *pdu, guint16 len,
+							gpointer user_data)
+{
+	struct read_desc_data *cb_data = user_data;
+
+	if (status != 0)
+		error("gatt: Write descriptors failed: %s\n",
+							att_ecode2str(status));
+
+	send_client_descr_write_notify(status, cb_data->conn_id,
+					cb_data->srvc_id, cb_data->char_id,
+					cb_data->descr_id, cb_data->primary);
+
+	free(cb_data);
+
+}
+
 static void handle_client_write_descriptor(const void *buf, uint16_t len)
 {
+	const struct hal_cmd_gatt_client_write_descriptor *cmd = buf;
+	struct write_descr_data *cb_data;
+	struct characteristic *ch;
+	struct descriptor *descr;
+	struct service *srvc;
+	struct element_id srvc_id;
+	struct element_id char_id;
+	struct element_id descr_id;
+	struct gatt_device *dev;
+	int32_t conn_id = 0;
+	uint8_t primary;
+	uint8_t status;
+
 	DBG("");
 
+	primary = cmd->srvc_id.is_primary;
+	conn_id = cmd->conn_id;
+
+	if (len != sizeof(*cmd) + cmd->len * sizeof(cmd->value[0])) {
+		error("gatt: Write descr. msg size invalid (%d bytes)", len);
+
+		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
+
+	hal_srvc_id_to_element_id(&cmd->srvc_id, &srvc_id);
+	hal_gatt_id_to_element_id(&cmd->char_id, &char_id);
+	hal_gatt_id_to_element_id(&cmd->descr_id, &descr_id);
+
+	if (!find_service(cmd->conn_id, &srvc_id, &dev, &srvc)) {
+		error("gatt: Read descr. could not find service");
+
+		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
+
+	ch = queue_find(srvc->chars, match_char_by_element_id, &char_id);
+	if (!ch) {
+		error("gatt: Read descr. could not find characteristic");
+
+		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
+
+	descr = queue_find(ch->descriptors, match_descr_by_element_id,
+								&descr_id);
+	if (!descr) {
+		error("gatt: Read descr. could not find descriptor");
+
+		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
+
+	cb_data = new0(struct write_descr_data, 1);
+	if (!cb_data) {
+		error("gatt: Read descr. could not allocate callback data");
+
+		status = HAL_STATUS_NOMEM;
+		goto failed;
+	}
+
+	cb_data->conn_id = conn_id;
+	cb_data->srvc_id = &srvc->id;
+	cb_data->char_id = &ch->id;
+	cb_data->descr_id = &descr->id;
+	cb_data->primary = primary;
+
+	if (!gatt_write_char(dev->attrib, descr->handle, cmd->value,
+					cmd->len * sizeof(cmd->value[0]),
+					write_descr_cb, cb_data)) {
+		free(cb_data);
+
+		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
+
+	status = HAL_STATUS_SUCCESS;
+
+failed:
+	if (status != HAL_STATUS_SUCCESS)
+		send_client_descr_write_notify(GATT_FAILURE, conn_id, &srvc_id,
+						&char_id, &descr_id, primary);
+
 	ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
-			HAL_OP_GATT_CLIENT_WRITE_DESCRIPTOR, HAL_STATUS_FAILED);
+				HAL_OP_GATT_CLIENT_WRITE_DESCRIPTOR, status);
 }
 
 static void handle_client_execute_write(const void *buf, uint16_t len)
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCHv2 0/5] Client descriptor operations
  2014-04-01 15:19 [PATCHv2 0/5] Client descriptor operations Jakub Tyszkowski
                   ` (4 preceding siblings ...)
  2014-04-01 15:19 ` [PATCHv2 5/5] android/gatt: Add client write " Jakub Tyszkowski
@ 2014-04-03 14:27 ` Szymon Janc
  5 siblings, 0 replies; 7+ messages in thread
From: Szymon Janc @ 2014-04-03 14:27 UTC (permalink / raw)
  To: Jakub Tyszkowski; +Cc: linux-bluetooth

Hi Jakub,

On Tuesday 01 of April 2014 17:19:22 Jakub Tyszkowski wrote:
> v2 changes:
> 	* Rebased on top of latest changes and cleanups.
> 	* Function flow was redesigned to minimize label jumps.
> 
> Jakub Tyszkowski (5):
>   android/gatt: Add queue for characteristic descriptors caching
>   android/gatt: Handle get descriptor client command
>   android/gatt: Add descriptors sending and caching for client
>   android/gatt: Add client read descriptor handler
>   android/gatt: Add client write descriptor handler
> 

I've pushed all patches (with quite a few fixes and cleanups though), thanks.

-- 
Best regards, 
Szymon Janc

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2014-04-03 14:27 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-04-01 15:19 [PATCHv2 0/5] Client descriptor operations Jakub Tyszkowski
2014-04-01 15:19 ` [PATCHv2 1/5] android/gatt: Add queue for characteristic descriptors caching Jakub Tyszkowski
2014-04-01 15:19 ` [PATCHv2 2/5] android/gatt: Handle get descriptor client command Jakub Tyszkowski
2014-04-01 15:19 ` [PATCHv2 3/5] android/gatt: Add descriptors sending and caching for client Jakub Tyszkowski
2014-04-01 15:19 ` [PATCHv2 4/5] android/gatt: Add client read descriptor handler Jakub Tyszkowski
2014-04-01 15:19 ` [PATCHv2 5/5] android/gatt: Add client write " Jakub Tyszkowski
2014-04-03 14:27 ` [PATCHv2 0/5] Client descriptor operations Szymon Janc

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox