linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] android/gatt: Keep client notify functions names consistent
@ 2014-03-24 14:27 Grzegorz Kolodziejczyk
  2014-03-24 14:27 ` [PATCH 2/2] android/gatt: Handle get characteristic client command Grzegorz Kolodziejczyk
  2014-03-25 10:36 ` [PATCH 1/2] android/gatt: Keep client notify functions names consistent Szymon Janc
  0 siblings, 2 replies; 3+ messages in thread
From: Grzegorz Kolodziejczyk @ 2014-03-24 14:27 UTC (permalink / raw)
  To: linux-bluetooth

We should use consistent names for client notify functions.
---
 android/gatt.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index 2189e8e..302a9b9 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -292,7 +292,7 @@ static void connection_cleanup(struct gatt_device *device)
 	}
 }
 
-static void send_disconnect_notify(int32_t id, struct gatt_device *dev,
+static void send_client_disconnect_notify(int32_t id, struct gatt_device *dev,
 								uint8_t status)
 {
 	struct hal_ev_gatt_client_disconnect ev;
@@ -306,12 +306,12 @@ static void send_disconnect_notify(int32_t id, struct gatt_device *dev,
 			HAL_EV_GATT_CLIENT_DISCONNECT, sizeof(ev), &ev);
 }
 
-static void disconnect_notify(void *data, void *user_data)
+static void client_disconnect_notify(void *data, void *user_data)
 {
 	struct gatt_device *dev = user_data;
 	int32_t id = PTR_TO_INT(data);
 
-	send_disconnect_notify(id, dev, HAL_STATUS_SUCCESS);
+	send_client_disconnect_notify(id, dev, HAL_STATUS_SUCCESS);
 }
 
 static bool is_device_wating_for_connect(const bdaddr_t *addr,
@@ -402,7 +402,7 @@ static gboolean disconnected_cb(GIOChannel *io, GIOCondition cond,
 done:
 	connection_cleanup(dev);
 
-	queue_foreach(dev->clients, disconnect_notify, dev);
+	queue_foreach(dev->clients, client_disconnect_notify, dev);
 	destroy_device(dev);
 
 	return FALSE;
@@ -802,7 +802,7 @@ reply:
 	 * If this is last client, this is still OK to do because on connect
 	 * request we do le scan and wait until remote device start
 	 * advertisement */
-	send_disconnect_notify(cmd->client_if, dev, HAL_STATUS_SUCCESS);
+	send_client_disconnect_notify(cmd->client_if, dev, HAL_STATUS_SUCCESS);
 
 	/* If there is more clients just return */
 	if (!queue_isempty(dev->clients))
-- 
1.8.5.2


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

* [PATCH 2/2] android/gatt: Handle get characteristic client command
  2014-03-24 14:27 [PATCH 1/2] android/gatt: Keep client notify functions names consistent Grzegorz Kolodziejczyk
@ 2014-03-24 14:27 ` Grzegorz Kolodziejczyk
  2014-03-25 10:36 ` [PATCH 1/2] android/gatt: Keep client notify functions names consistent Szymon Janc
  1 sibling, 0 replies; 3+ messages in thread
From: Grzegorz Kolodziejczyk @ 2014-03-24 14:27 UTC (permalink / raw)
  To: linux-bluetooth

This adds get characteristic client command handling.
---
 android/gatt.c | 247 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 242 insertions(+), 5 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index 302a9b9..fbc3b61 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -53,6 +53,28 @@ struct gatt_client {
 	uint8_t uuid[16];
 };
 
+struct gatt_id {
+	bt_uuid_t uuid;
+	uint8_t inst_id;
+};
+
+struct gatt_srvc_char {
+	struct gatt_id id;
+	struct gatt_char ch;
+};
+
+struct gatt_srvc {
+	struct gatt_id id;
+	struct gatt_primary service;
+
+	struct queue *chars;
+};
+
+struct generic_call_data {
+	struct gatt_device *dev;
+	struct gatt_srvc *gatt_srvc;
+};
+
 struct gatt_device {
 	bdaddr_t bdaddr;
 	uint8_t bdaddr_type;
@@ -66,6 +88,7 @@ struct gatt_device {
 	GIOChannel *att_io;
 	struct queue *services;
 
+	uint8_t char_inst_id;
 	guint watch_id;
 };
 
@@ -79,6 +102,14 @@ static struct queue *conn_wait_queue = NULL;	/* Devs waiting to connect */
 
 static void bt_le_discovery_stop_cb(void);
 
+static void free_gatt_service(void *data)
+{
+	struct gatt_srvc *srvc = data;
+
+	queue_destroy(srvc->chars, free);
+	free(srvc);
+}
+
 static bool match_client_by_uuid(const void *data, const void *user_data)
 {
 	const uint8_t *exp_uuid = user_data;
@@ -123,12 +154,43 @@ static bool match_dev_by_conn_id(const void *data, const void *user_data)
 	return dev->conn_id == conn_id;
 }
 
+static bool match_srvc_by_gatt_id(const void *data, const void *user_data)
+{
+	const struct gatt_id *exp_id = user_data;
+	const struct gatt_srvc *service = data;
+	bt_uuid_t uuid;
+
+	bt_string_to_uuid(&uuid, service->service.uuid);
+	if (service->id.inst_id == exp_id->inst_id)
+		return !bt_uuid_cmp(&uuid, &exp_id->uuid);
+
+	return false;
+}
+
+static bool match_char_by_higher_inst_id(const void *data,
+							const void *user_data)
+{
+	const struct gatt_srvc_char *chars = data;
+	uint8_t inst_id = PTR_TO_INT(user_data);
+
+	/* For now we match inst_id as it is unique, we'll match uuids later */
+	return inst_id < chars->id.inst_id;
+}
+
+static bool match_char_by_inst_id(const void *data, const void *user_data)
+{
+	const struct gatt_srvc_char *chars = data;
+	uint8_t inst_id = PTR_TO_INT(user_data);
+
+	return inst_id == chars->id.inst_id;
+}
+
 static void destroy_device(void *data)
 {
 	struct gatt_device *dev = data;
 
 	queue_destroy(dev->clients, NULL);
-	queue_destroy(dev->services, free);
+	queue_destroy(dev->services, free_gatt_service);
 	free(dev);
 }
 
@@ -224,19 +286,26 @@ static void primary_cb(uint8_t status, GSList *services, void *user_data)
 	for (l = services; l; l = l->next) {
 		struct hal_ev_gatt_client_search_result ev_res;
 		struct gatt_primary *prim = l->data;
-		struct gatt_primary *p;
+		struct gatt_srvc *p;
 		bt_uuid_t uuid;
 
-		p = new0(struct gatt_primary, 1);
+		p = new0(struct gatt_srvc, 1);
 		if (!p) {
 			error("gatt: Cannot allocate memory for gatt_primary");
 			continue;
 		}
 
+		p->chars = queue_new();
+		if (!p->chars) {
+			error("gatt: Cannot allocate memory for char cache");
+			free(p);
+			continue;
+		}
+
 		memset(&ev_res, 0, sizeof(ev_res));
 
 		/* Put primary service to our local list */
-		memcpy(p, prim, sizeof(*p));
+		memcpy(&p->service, prim, sizeof(p->service));
 		if (!queue_push_tail(dev->services, p)) {
 			error("gatt: Cannot push primary service to the list");
 			free(p);
@@ -869,13 +938,181 @@ static void handle_client_get_included_service(const void *buf, uint16_t len)
 					HAL_STATUS_FAILED);
 }
 
+static void send_client_char_notify(const struct gatt_srvc_char *chars,
+				uint8_t status, struct generic_call_data *data)
+{
+	struct hal_ev_gatt_client_get_characteristic ev;
+	bt_uuid_t uuid;
+
+	ev.conn_id = data->dev->conn_id;
+	ev.status = status;
+	ev.char_prop = chars->ch.properties;
+
+	/* TODO need to be handled for included services too */
+	ev.srvc_id.is_primary = 1;
+	ev.srvc_id.inst_id = data->gatt_srvc->id.inst_id;
+	bt_string_to_uuid(&uuid, data->gatt_srvc->service.uuid);
+	memcpy(&ev.srvc_id.uuid, &uuid.value.u128.data,
+						sizeof(ev.srvc_id.uuid));
+
+	ev.char_id.inst_id = chars->id.inst_id;
+	bt_string_to_uuid(&uuid, chars->ch.uuid);
+	memcpy(&ev.char_id.uuid, &uuid.value.u128.data,
+						sizeof(ev.char_id.uuid));
+
+	ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+					HAL_EV_GATT_CLIENT_GET_CHARACTERISTIC,
+					sizeof(ev), &ev);
+}
+
+static void cache_all_srvc_chars(GSList *characteristics, struct queue *q)
+{
+	uint16_t inst_id = 0;
+	bt_uuid_t uuid;
+	GSList *l;
+
+	/* Refresh chararcter cache if already exist */
+	if (!queue_isempty(q))
+		queue_remove_all(q, NULL, NULL, free);
+
+	for (l = characteristics; l; l = l->next) {
+		struct gatt_srvc_char *chars;
+
+		chars = new0(struct gatt_srvc_char, 1);
+		if (!chars) {
+			error("gatt: Could not allocate characteristic");
+			continue;
+		}
+
+		memcpy(&chars->ch, l->data, sizeof(chars->ch));
+
+		bt_string_to_uuid(&uuid, chars->ch.uuid);
+		bt_uuid_to_uuid128(&chars->id.uuid, &uuid);
+
+		/* For now we increment inst_id and use it as characteristic
+		 * handle
+		 */
+		chars->id.inst_id = ++inst_id;
+
+		if (!queue_push_tail(q, chars))
+			info("gatt: Error while caching characteristic");
+	}
+}
+
+static void gatt_discover_char_cb(uint8_t status, GSList *characteristics,
+								void *user_data)
+{
+	struct generic_call_data *call_data = user_data;
+
+	cache_all_srvc_chars(characteristics, call_data->gatt_srvc->chars);
+
+	if (call_data && !queue_isempty(call_data->gatt_srvc->chars))
+		send_client_char_notify(queue_peek_head(
+					call_data->gatt_srvc->chars),
+					HAL_STATUS_SUCCESS, call_data);
+
+	free(call_data);
+}
+
+static void hal_srvc_id_to_gatt_id(const struct hal_gatt_srvc_id *from,
+							struct gatt_id *to)
+{
+	uint128_t uuid128;
+
+	to->inst_id = from->inst_id;
+
+	memcpy(&uuid128.data, &from->uuid, sizeof(uuid128));
+	bt_uuid128_create(&to->uuid, uuid128);
+}
+
 static void handle_client_get_characteristic(const void *buf, uint16_t len)
 {
+	const struct hal_cmd_gatt_client_get_characteristic *cmd = buf;
+	struct generic_call_data *call_data = NULL;
+	struct gatt_srvc_char *chars = NULL;
+	struct gatt_id match_id;
+	struct gatt_device *dev;
+	struct gatt_srvc *srvc;
+	uint8_t status;
+	uint8_t char_status;
+
 	DBG("");
 
+	if (!cmd) {
+		status = HAL_STATUS_FAILED;
+		goto done;
+	}
+
+	/* search on list by connection id */
+	dev = queue_find(conn_list, match_dev_by_conn_id,
+						INT_TO_PTR(cmd->conn_id));
+	if (!dev) {
+		error("gatt: conn_id=%d not found", cmd->conn_id);
+		status = HAL_STATUS_FAILED;
+		goto done;
+	}
+
+	hal_srvc_id_to_gatt_id(&cmd->srvc_id, &match_id);
+	srvc = queue_find(dev->services, match_srvc_by_gatt_id, &match_id);
+	if (!srvc) {
+		error("gatt: Service with inst_id: %d not found",
+							match_id.inst_id);
+		status = HAL_STATUS_FAILED;
+		goto done;
+	}
+
+	call_data = new0(struct generic_call_data, 1);
+	if (!call_data) {
+		error("gatt: Cannot allocate call data");
+		status = HAL_STATUS_FAILED;
+		goto done;
+	}
+
+	call_data->gatt_srvc = srvc;
+	call_data->dev = dev;
+
+	/* Discover all characteristics for services */
+	if (queue_isempty(srvc->chars)) {
+		gatt_discover_char(dev->attrib, srvc->service.range.start,
+					srvc->service.range.end, NULL,
+					gatt_discover_char_cb, call_data);
+	} else {
+		if (cmd->number)
+			chars = queue_find(srvc->chars,
+						match_char_by_higher_inst_id,
+					INT_TO_PTR(cmd->gatt_id[0].inst_id));
+		else
+			chars = queue_peek_head(srvc->chars);
+
+		char_status = HAL_STATUS_SUCCESS;
+
+		if (!chars) {
+			error("gatt: Can't get next char");
+			/* Return last known/given char with failed status if
+			 * no char left.
+			 */
+			chars = queue_find(srvc->chars, match_char_by_inst_id,
+					INT_TO_PTR(cmd->gatt_id[0].inst_id));
+
+			char_status = HAL_STATUS_FAILED;
+
+			/* free generic data if no given char is found */
+			if (!chars)
+				free(call_data);
+		}
+	}
+
+	status = HAL_STATUS_SUCCESS;
+
+done:
 	ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
 					HAL_OP_GATT_CLIENT_GET_CHARACTERISTIC,
-					HAL_STATUS_FAILED);
+					status);
+
+	if (chars) {
+		send_client_char_notify(chars, char_status, call_data);
+		free(call_data);
+	}
 }
 
 static void handle_client_get_descriptor(const void *buf, uint16_t len)
-- 
1.8.5.2


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

* Re: [PATCH 1/2] android/gatt: Keep client notify functions names consistent
  2014-03-24 14:27 [PATCH 1/2] android/gatt: Keep client notify functions names consistent Grzegorz Kolodziejczyk
  2014-03-24 14:27 ` [PATCH 2/2] android/gatt: Handle get characteristic client command Grzegorz Kolodziejczyk
@ 2014-03-25 10:36 ` Szymon Janc
  1 sibling, 0 replies; 3+ messages in thread
From: Szymon Janc @ 2014-03-25 10:36 UTC (permalink / raw)
  To: Grzegorz Kolodziejczyk; +Cc: linux-bluetooth

Hi Grzegorz,

On Monday 24 of March 2014 15:27:23 Grzegorz Kolodziejczyk wrote:
> We should use consistent names for client notify functions.
> ---
>  android/gatt.c | 10 +++++-----
>  1 file changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/android/gatt.c b/android/gatt.c
> index 2189e8e..302a9b9 100644
> --- a/android/gatt.c
> +++ b/android/gatt.c
> @@ -292,7 +292,7 @@ static void connection_cleanup(struct gatt_device
> *device) }
>  }
> 
> -static void send_disconnect_notify(int32_t id, struct gatt_device *dev,
> +static void send_client_disconnect_notify(int32_t id, struct gatt_device
> *dev, uint8_t status)
>  {
>  	struct hal_ev_gatt_client_disconnect ev;
> @@ -306,12 +306,12 @@ static void send_disconnect_notify(int32_t id, struct
> gatt_device *dev, HAL_EV_GATT_CLIENT_DISCONNECT, sizeof(ev), &ev);
>  }
> 
> -static void disconnect_notify(void *data, void *user_data)
> +static void client_disconnect_notify(void *data, void *user_data)
>  {
>  	struct gatt_device *dev = user_data;
>  	int32_t id = PTR_TO_INT(data);
> 
> -	send_disconnect_notify(id, dev, HAL_STATUS_SUCCESS);
> +	send_client_disconnect_notify(id, dev, HAL_STATUS_SUCCESS);
>  }
> 
>  static bool is_device_wating_for_connect(const bdaddr_t *addr,
> @@ -402,7 +402,7 @@ static gboolean disconnected_cb(GIOChannel *io,
> GIOCondition cond, done:
>  	connection_cleanup(dev);
> 
> -	queue_foreach(dev->clients, disconnect_notify, dev);
> +	queue_foreach(dev->clients, client_disconnect_notify, dev);
>  	destroy_device(dev);
> 
>  	return FALSE;
> @@ -802,7 +802,7 @@ reply:
>  	 * If this is last client, this is still OK to do because on connect
>  	 * request we do le scan and wait until remote device start
>  	 * advertisement */
> -	send_disconnect_notify(cmd->client_if, dev, HAL_STATUS_SUCCESS);
> +	send_client_disconnect_notify(cmd->client_if, dev, HAL_STATUS_SUCCESS);
> 
>  	/* If there is more clients just return */
>  	if (!queue_isempty(dev->clients))

Patch 1 is now applied, thanks.

Patch 2 needs fixing as discussed offline.

-- 
BR
Szymon Janc

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

end of thread, other threads:[~2014-03-25 10:36 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-03-24 14:27 [PATCH 1/2] android/gatt: Keep client notify functions names consistent Grzegorz Kolodziejczyk
2014-03-24 14:27 ` [PATCH 2/2] android/gatt: Handle get characteristic client command Grzegorz Kolodziejczyk
2014-03-25 10:36 ` [PATCH 1/2] android/gatt: Keep client notify functions names consistent Szymon Janc

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).