Linux bluetooth development
 help / color / mirror / Atom feed
* Re: [PATCH] android/client: Don't alignt name property while printing
From: Johan Hedberg @ 2013-10-31 13:48 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth
In-Reply-To: <1383225721-7579-1-git-send-email-szymon.janc@tieto.com>

Hi Szymon,

On Thu, Oct 31, 2013, Szymon Janc wrote:
> Received name property is guaranteed to be NULL terminated so there is
> no need to use length specifier. This also fix really long space while
> printing due to text alignment to the right.
> ---
>  android/client/if-bt.c | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)

Applied (after the obvious typo fix for the subject). Thanks.

Johan

^ permalink raw reply

* Re: [PATCH v2 1/2] android: Always enable SSP if supported by controller
From: Johan Hedberg @ 2013-10-31 13:47 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth
In-Reply-To: <1383225309-7260-1-git-send-email-szymon.janc@tieto.com>

Hi Szymon,

On Thu, Oct 31, 2013, Szymon Janc wrote:
> There is no HAL function to enable/disable SSP so always enable it if
> supported by controller.
> ---
> 
> v2:
>   use missing_settings mask for checking if setting is enabled
> 
>  android/adapter.c | 8 ++++++++
>  1 file changed, 8 insertions(+)

Both patches have been applied. Thanks.

Johan

^ permalink raw reply

* Re: [RFC] android/daemon: Fix not reporting scan mode to Java
From: Johan Hedberg @ 2013-10-31 13:46 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <1383223355-4628-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

Hi Andrei,

On Thu, Oct 31, 2013, Andrei Emeltchenko wrote:
> After set_adapter_property() higher layer expects callback to be returned
> even if property is not changes. Otherwise Java timeouts and reset Bluetooth
> enetring to the loop.
> ...
> BluetoothAdapterState( 2850): Timeout will setting scan mode..
>   Continuing with disable...
> ...
> ---
>  android/adapter.c |   12 +++++++++---
>  1 file changed, 9 insertions(+), 3 deletions(-)

Applied. Thanks.

Johan

^ permalink raw reply

* Re: [PATCH] android/daemon: Fix error setting property
From: Johan Hedberg @ 2013-10-31 13:45 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <1383220358-5436-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

Hi Andrei,

On Thu, Oct 31, 2013, Andrei Emeltchenko wrote:
> Do not return error setting property which is already set. This fixes
> bug with set_scan_mode which might return HAL_STATUS_DONE.
> ---
>  android/adapter.c |    2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)

Applied. Thanks.

Johan

^ permalink raw reply

* RE: l2cap sockets not properly multiplexed on ARM
From: Tim Tisdall @ 2013-10-31 13:31 UTC (permalink / raw)
  To: Alexander Holler, Marcel Holtmann; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <527190DA.6000805@ahsoftware.de>

> As Anderson Lizardo already mentioned, maybe first verify that the x86=0A=
> kernel 3.4 doesn't have the same problem and that it's really a problem=
=0A=
> of the ARM kernel. Up to now he didn't say what kernel version he uses=0A=
> on x86.=0A=
=0A=
here's my desktop version:=0A=
$ uname -a=0A=
Linux tzing 3.8.0-32-generic #47-Ubuntu SMP Tue Oct 1 22:35:23 UTC 2013 x86=
_64 x86_64 x86_64 GNU/Linux=0A=
=0A=
I'm trying to get an older version of the kernel running on another machine=
 and then I'll report back=0A=

^ permalink raw reply

* [PATCH] android/client: Don't alignt name property while printing
From: Szymon Janc @ 2013-10-31 13:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

Received name property is guaranteed to be NULL terminated so there is
no need to use length specifier. This also fix really long space while
printing due to text alignment to the right.
---
 android/client/if-bt.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/android/client/if-bt.c b/android/client/if-bt.c
index 16bd882..c9681fc 100644
--- a/android/client/if-bt.c
+++ b/android/client/if-bt.c
@@ -88,8 +88,7 @@ static char *btproperty2str(bt_property_t property)
 	switch (property.type) {
 	case BT_PROPERTY_BDNAME:
 	case BT_PROPERTY_REMOTE_FRIENDLY_NAME:
-		sprintf(p, "%*s", property.len,
-					((bt_bdname_t *) property.val)->name);
+		sprintf(p, "%s", ((bt_bdname_t *) property.val)->name);
 		break;
 
 	case BT_PROPERTY_BDADDR:
-- 
1.8.4.1


^ permalink raw reply related

* [PATCH] android: Add supported uuids when adapter initialized
From: Marcin Kraglak @ 2013-10-31 13:17 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Marcin Kraglak

It will set class of device with proper service hints.
We set it statically because we don't want to change
class of device while adding/removing sdp services.
---
 android/adapter.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/android/adapter.c b/android/adapter.c
index a3f9aa6..5a1cc9b 100644
--- a/android/adapter.c
+++ b/android/adapter.c
@@ -39,6 +39,29 @@
 
 static GIOChannel *notification_io = NULL;
 
+/*
+ * This is an array of supported uuids and service hints. We add them via mgmt
+ * interface when adapter is initialized. Uuids are in reverse orded.
+ */
+static const struct mgmt_cp_add_uuid sup_uuids[] = {
+	/* OBEX_OPP_UUID */
+	{ .uuid = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
+			0x00, 0x10, 0x00, 0x00, 0x05, 0x11, 0x00, 0x00 },
+	.svc_hint = 0x10 },
+	/* HFP_AG_UUID */
+	{ .uuid = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
+			0x00, 0x10, 0x00, 0x00, 0x1f, 0x11, 0x00, 0x00 },
+	.svc_hint = 0x40 },
+	/* ADVANCED_AUDIO_UUID */
+	{ .uuid = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
+			0x00, 0x10, 0x00, 0x00, 0x0d, 0x11, 0x00, 0x00 },
+	.svc_hint = 0x08 },
+	/* PANU_UUID */
+	{ .uuid = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
+			0x00, 0x10, 0x00, 0x00, 0x15, 0x11, 0x00, 0x00 },
+	.svc_hint = 0x02 }
+};
+
 struct bt_adapter {
 	uint16_t index;
 	struct mgmt *mgmt;
@@ -438,6 +461,38 @@ static void load_link_keys(GSList *keys)
 	}
 }
 
+static void add_uuid_complete(uint8_t status, uint16_t length,
+					const void *param, void *user_data)
+{
+	if (status != MGMT_STATUS_SUCCESS) {
+		error("Failed to add UUID: %s (0x%02x)",
+						mgmt_errstr(status), status);
+		return;
+	}
+
+	mgmt_dev_class_changed_event(adapter->index, length, param, NULL);
+}
+
+static void add_uuids(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < sizeof(sup_uuids) / sizeof(sup_uuids[0]); i++)
+		mgmt_send(adapter->mgmt, MGMT_OP_ADD_UUID, adapter->index,
+				sizeof(sup_uuids[i]), &sup_uuids[i],
+				add_uuid_complete, NULL, NULL);
+}
+
+static void clear_uuids(void)
+{
+	struct mgmt_cp_remove_uuid cp;
+
+	memset(&cp, 0, sizeof(cp));
+
+	mgmt_send(adapter->mgmt, MGMT_OP_REMOVE_UUID, adapter->index,
+			sizeof(cp), &cp, NULL, NULL, NULL);
+}
+
 static void set_mode_complete(uint8_t status, uint16_t length,
 					const void *param, void *user_data)
 {
@@ -530,6 +585,9 @@ static void read_info_complete(uint8_t status, uint16_t length, const void *para
 	set_io_capability();
 	set_mode(MGMT_OP_SET_PAIRABLE, 0x01);
 
+	clear_uuids();
+	add_uuids();
+
 	return;
 
 failed:
-- 
1.8.4.1


^ permalink raw reply related

* [PATCH v2 2/2] android: Set pairable mode only if it is not set
From: Szymon Janc @ 2013-10-31 13:15 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1383225309-7260-1-git-send-email-szymon.janc@tieto.com>

There is no need to set already set setting.
---
 android/adapter.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/android/adapter.c b/android/adapter.c
index c6fcf96..f1a4258 100644
--- a/android/adapter.c
+++ b/android/adapter.c
@@ -536,7 +536,8 @@ static void read_info_complete(uint8_t status, uint16_t length, const void *para
 	if (missing_settings & MGMT_SETTING_SSP)
 		set_mode(MGMT_OP_SET_SSP, 0x01);
 
-	set_mode(MGMT_OP_SET_PAIRABLE, 0x01);
+	if (missing_settings & MGMT_SETTING_PAIRABLE)
+		set_mode(MGMT_OP_SET_PAIRABLE, 0x01);
 
 	return;
 
-- 
1.8.4.1


^ permalink raw reply related

* [PATCH v2 1/2] android: Always enable SSP if supported by controller
From: Szymon Janc @ 2013-10-31 13:15 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

There is no HAL function to enable/disable SSP so always enable it if
supported by controller.
---

v2:
  use missing_settings mask for checking if setting is enabled

 android/adapter.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/android/adapter.c b/android/adapter.c
index a3f9aa6..c6fcf96 100644
--- a/android/adapter.c
+++ b/android/adapter.c
@@ -490,6 +490,7 @@ static void read_info_complete(uint8_t status, uint16_t length, const void *para
 							void *user_data)
 {
 	const struct mgmt_rp_read_info *rp = param;
+	uint32_t missing_settings;
 	int err;
 
 	DBG("");
@@ -528,6 +529,13 @@ static void read_info_complete(uint8_t status, uint16_t length, const void *para
 	load_link_keys(NULL);
 
 	set_io_capability();
+
+	missing_settings = adapter->current_settings ^
+						adapter->supported_settings;
+
+	if (missing_settings & MGMT_SETTING_SSP)
+		set_mode(MGMT_OP_SET_SSP, 0x01);
+
 	set_mode(MGMT_OP_SET_PAIRABLE, 0x01);
 
 	return;
-- 
1.8.4.1


^ permalink raw reply related

* Re: [PATCH BlueZ 1/3] android/hid: Add handling of incoming connections
From: Johan Hedberg @ 2013-10-31 13:00 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <1383221988-1601-1-git-send-email-luiz.dentz@gmail.com>

Hi Luiz,

On Thu, Oct 31, 2013, Luiz Augusto von Dentz wrote:
> ---
>  android/hid.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 90 insertions(+)

All three patches have been applied (with one minor coding style fix to
2/3). Thanks.

Johan

^ permalink raw reply

* [RFC] android/daemon: Fix not reporting scan mode to Java
From: Andrei Emeltchenko @ 2013-10-31 12:42 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

After set_adapter_property() higher layer expects callback to be returned
even if property is not changes. Otherwise Java timeouts and reset Bluetooth
enetring to the loop.
...
BluetoothAdapterState( 2850): Timeout will setting scan mode..
  Continuing with disable...
...
---
 android/adapter.c |   12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/android/adapter.c b/android/adapter.c
index 892e6bb..3622a72 100644
--- a/android/adapter.c
+++ b/android/adapter.c
@@ -631,21 +631,21 @@ static uint8_t set_scan_mode(void *buf, uint16_t len)
 	switch (*mode) {
 	case HAL_ADAPTER_SCAN_MODE_NONE:
 		if (!cur_conn && !cur_disc)
-			return HAL_STATUS_DONE;
+			goto done;
 
 		conn = false;
 		disc = false;
 		break;
 	case HAL_ADAPTER_SCAN_MODE_CONN:
 		if (cur_conn && !cur_disc)
-			return HAL_STATUS_DONE;
+			goto done;
 
 		conn = true;
 		disc = false;
 		break;
 	case HAL_ADAPTER_SCAN_MODE_CONN_DISC:
 		if (cur_conn && cur_disc)
-			return HAL_STATUS_DONE;
+			goto done;
 
 		conn = true;
 		disc = true;
@@ -665,6 +665,12 @@ static uint8_t set_scan_mode(void *buf, uint16_t len)
 	}
 
 	return HAL_STATUS_SUCCESS;
+
+done:
+	/* Android expects property changed callback */
+	scan_mode_changed();
+
+	return HAL_STATUS_DONE;
 }
 
 static uint8_t set_property(void *buf, uint16_t len)
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH BlueZ 3/3] android/hid: Add handling of HAL_EV_HID_CONN_STATE
From: Luiz Augusto von Dentz @ 2013-10-31 12:19 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1383221988-1601-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This patches generate proper events when the connection state changes:

>hidhost connect
BlueZ D: android/hal-hidhost.c:hh_connect()
connection_state_cb: bd_addr= connection_state=BTHH_CONN_STATE_CONNECTING
if_hh->connect: BT_STATUS_SUCCESS
connection_state_cb: bd_addr= connection_state=BTHH_CONN_STATE_CONNECTED
>hidhost disconnect
BlueZ D: android/hal-hidhost.c:hh_disconnect()
connection_state_cb: bd_addr= connection_state=BTHH_CONN_STATE_DISCONNECTING
if_hh->disconnect: BT_STATUS_SUCCESS
connection_state_cb: bd_addr= connection_state=BTHH_CONN_STATE_DISCONNECTED
---
 android/hid.c | 46 +++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 39 insertions(+), 7 deletions(-)

diff --git a/android/hid.c b/android/hid.c
index 92efd72..5caa25b 100644
--- a/android/hid.c
+++ b/android/hid.c
@@ -51,6 +51,7 @@ static GSList *devices = NULL;
 
 struct hid_device {
 	bdaddr_t	dst;
+	uint8_t		state;
 	GIOChannel	*ctrl_io;
 	GIOChannel	*intr_io;
 	guint		ctrl_watch;
@@ -104,18 +105,34 @@ static gboolean intr_io_watch_cb(GIOChannel *chan, gpointer data)
 	return TRUE;
 }
 
+static void bt_hid_set_state(struct hid_device *hdev, uint8_t state)
+{
+	struct hal_ev_hid_conn_state ev;
+	char address[18];
+
+	if (hdev->state == state)
+		return;
+
+	hdev->state = state;
+
+	ba2str(&hdev->dst, address);
+	DBG("device %s state %u", address, state);
+
+	bdaddr2android(&hdev->dst, ev.bdaddr);
+	ev.state = state;
+
+	ipc_send(notification_io, HAL_SERVICE_ID_HIDHOST,
+				HAL_EV_HID_CONN_STATE, sizeof(ev), &ev, -1);
+}
+
 static gboolean intr_watch_cb(GIOChannel *chan, GIOCondition cond,
 								gpointer data)
 {
 	struct hid_device *hdev = data;
-	char address[18];
 
 	if (cond & G_IO_IN)
 		return intr_io_watch_cb(chan, data);
 
-	ba2str(&hdev->dst, address);
-	DBG("Device %s disconnected", address);
-
 	/* Checking for ctrl_watch avoids a double g_io_channel_shutdown since
 	 * it's likely that ctrl_watch_cb has been queued for dispatching in
 	 * this mainloop iteration */
@@ -143,7 +160,7 @@ static gboolean ctrl_watch_cb(GIOChannel *chan, GIOCondition cond,
 	char address[18];
 
 	ba2str(&hdev->dst, address);
-	DBG("Device %s disconnected", address);
+	bt_hid_set_state(hdev, HAL_HID_STATE_DISCONNECTED);
 
 	/* Checking for intr_watch avoids a double g_io_channel_shutdown since
 	 * it's likely that intr_watch_cb has been queued for dispatching in
@@ -175,6 +192,8 @@ static void interrupt_connect_cb(GIOChannel *chan, GError *conn_err,
 				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
 				intr_watch_cb, hdev);
 
+	bt_hid_set_state(hdev, HAL_HID_STATE_CONNECTED);
+
 	return;
 
 failed:
@@ -203,6 +222,7 @@ static void control_connect_cb(GIOChannel *chan, GError *conn_err,
 	DBG("");
 
 	if (conn_err) {
+		bt_hid_set_state(hdev, HAL_HID_STATE_DISCONNECTED);
 		error("%s", conn_err->message);
 		goto failed;
 	}
@@ -270,6 +290,7 @@ static uint8_t bt_hid_connect(struct hal_cmd_hid_connect *cmd, uint16_t len)
 	}
 
 	devices = g_slist_append(devices, hdev);
+	bt_hid_set_state(hdev, HAL_HID_STATE_CONNECTING);
 
 	return HAL_STATUS_SUCCESS;
 }
@@ -277,6 +298,7 @@ static uint8_t bt_hid_connect(struct hal_cmd_hid_connect *cmd, uint16_t len)
 static uint8_t bt_hid_disconnect(struct hal_cmd_hid_disconnect *cmd,
 								uint16_t len)
 {
+	struct hid_device *hdev;
 	GSList *l;
 	bdaddr_t dst;
 
@@ -291,7 +313,16 @@ static uint8_t bt_hid_disconnect(struct hal_cmd_hid_disconnect *cmd,
 	if (!l)
 		return HAL_STATUS_FAILED;
 
-	hid_device_free(l->data);
+	hdev = l->data;
+
+	/* Wait either channels to HUP */
+	if (hdev->intr_io)
+		g_io_channel_shutdown(hdev->intr_io, TRUE, NULL);
+
+	if (hdev->ctrl_io)
+		g_io_channel_shutdown(hdev->ctrl_io, TRUE, NULL);
+
+	bt_hid_set_state(hdev, HAL_HID_STATE_DISCONNECTING);
 
 	return HAL_STATUS_SUCCESS;
 }
@@ -357,7 +388,7 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 		hdev->ctrl_watch = g_io_add_watch(hdev->ctrl_io,
 					G_IO_HUP | G_IO_ERR | G_IO_NVAL,
 					ctrl_watch_cb, hdev);
-
+		bt_hid_set_state(hdev, HAL_HID_STATE_CONNECTING);
 		break;
 
 	case L2CAP_PSM_HIDP_INTR:
@@ -370,6 +401,7 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 		hdev->intr_watch = g_io_add_watch(hdev->intr_io,
 				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
 				intr_watch_cb, hdev);
+		bt_hid_set_state(hdev, HAL_HID_STATE_CONNECTED);
 		break;
 	}
 }
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ 2/3] android/hal-hidhost: Add implementation of .connection_state_cb
From: Luiz Augusto von Dentz @ 2013-10-31 12:19 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1383221988-1601-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 android/hal-hidhost.c   | 25 +++++++++++++++++++++++++
 android/hal-ipc-api.txt |  1 +
 android/hal-ipc.c       |  3 +++
 android/hal-msg.h       | 14 ++++++++++++++
 android/hal.h           |  1 +
 5 files changed, 44 insertions(+)

diff --git a/android/hal-hidhost.c b/android/hal-hidhost.c
index 032e961..9354b95 100644
--- a/android/hal-hidhost.c
+++ b/android/hal-hidhost.c
@@ -31,6 +31,31 @@ static bool interface_ready(void)
 	return bt_hh_cbacks != NULL;
 }
 
+static void handle_conn_state(void *buf)
+{
+	struct hal_ev_hid_conn_state *ev = buf;
+
+	if (bt_hh_cbacks->connection_state_cb)
+		bt_hh_cbacks->connection_state_cb((bt_bdaddr_t *) (ev->bdaddr),
+								ev->state);
+}
+
+/* will be called from notification thread context */
+void bt_notify_hh(uint16_t opcode, void *buf, uint16_t len)
+{
+	if (!interface_ready())
+		return;
+
+	switch (opcode) {
+	case HAL_EV_HID_CONN_STATE:
+		handle_conn_state(buf);
+		break;
+	default:
+		DBG("Unhandled callback opcode=0x%x", opcode);
+		break;
+	}
+}
+
 static bt_status_t hh_connect(bt_bdaddr_t *bd_addr)
 {
 	struct hal_cmd_hid_connect cmd;
diff --git a/android/hal-ipc-api.txt b/android/hal-ipc-api.txt
index a5d1980..6b11684 100644
--- a/android/hal-ipc-api.txt
+++ b/android/hal-ipc-api.txt
@@ -574,6 +574,7 @@ Notifications:
 	Opcode 0x81 - Connection State notification
 
 		Notification parameters: Remote address (6 octets)
+		                         Connection State (1 octets)
 
 		Valid connection states: 0x00 = Connected
 		                         0x01 = Connecting
diff --git a/android/hal-ipc.c b/android/hal-ipc.c
index f68e789..14be69b 100644
--- a/android/hal-ipc.c
+++ b/android/hal-ipc.c
@@ -49,6 +49,9 @@ static void notification_dispatch(struct hal_hdr *msg, int fd)
 	case HAL_SERVICE_ID_BLUETOOTH:
 		bt_notify_adapter(msg->opcode, msg->payload, msg->len);
 		break;
+	case HAL_SERVICE_ID_HIDHOST:
+		bt_notify_hh(msg->opcode, msg->payload, msg->len);
+		break;
 	case HAL_SERVICE_ID_A2DP:
 		bt_notify_av(msg->opcode, msg->payload, msg->len);
 		break;
diff --git a/android/hal-msg.h b/android/hal-msg.h
index dfe73cc..b792411 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -423,6 +423,20 @@ struct hal_ev_le_test_mode {
 	uint16_t num_packets;
 } __attribute__((packed));
 
+#define HAL_HID_STATE_CONNECTED		0x00
+#define HAL_HID_STATE_CONNECTING	0x01
+#define HAL_HID_STATE_DISCONNECTED	0x02
+#define HAL_HID_STATE_DISCONNECTING	0x03
+#define HAL_HID_STATE_NO_HID		0x07
+#define HAL_HID_STATE_FAILED		0x08
+#define HAL_HID_STATE_UNKNOWN		0x09
+
+#define HAL_EV_HID_CONN_STATE		0x81
+struct hal_ev_hid_conn_state {
+	uint8_t bdaddr[6];
+	uint8_t state;
+} __attribute__((packed));
+
 #define HAL_EV_AV_CONNECTION_STATE	0x81
 struct hal_ev_av_connection_state {
 	uint8_t state;
diff --git a/android/hal.h b/android/hal.h
index a377649..5d6a93e 100644
--- a/android/hal.h
+++ b/android/hal.h
@@ -29,4 +29,5 @@ btav_interface_t *bt_get_av_interface(void);
 void bt_notify_adapter(uint16_t opcode, void *buf, uint16_t len);
 void bt_thread_associate(void);
 void bt_thread_disassociate(void);
+void bt_notify_hh(uint16_t opcode, void *buf, uint16_t len);
 void bt_notify_av(uint16_t opcode, void *buf, uint16_t len);
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ 1/3] android/hid: Add handling of incoming connections
From: Luiz Augusto von Dentz @ 2013-10-31 12:19 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 android/hid.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)

diff --git a/android/hid.c b/android/hid.c
index 49e9c52..92efd72 100644
--- a/android/hid.c
+++ b/android/hid.c
@@ -45,6 +45,8 @@
 #define MAX_READ_BUFFER		4096
 
 static GIOChannel *notification_io = NULL;
+static GIOChannel *ctrl_io = NULL;
+static GIOChannel *intr_io = NULL;
 static GSList *devices = NULL;
 
 struct hid_device {
@@ -313,12 +315,94 @@ void bt_hid_handle_cmd(GIOChannel *io, uint8_t opcode, void *buf, uint16_t len)
 	ipc_send_rsp(io, HAL_SERVICE_ID_HIDHOST, status);
 }
 
+static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
+{
+	struct hid_device *hdev;
+	bdaddr_t dst;
+	char address[18];
+	uint16_t psm;
+	GError *gerr = NULL;
+	GSList *l;
+
+	if (err) {
+		error("%s", err->message);
+		return;
+	}
+
+	bt_io_get(chan, &err,
+			BT_IO_OPT_DEST_BDADDR, &dst,
+			BT_IO_OPT_PSM, &psm,
+			BT_IO_OPT_INVALID);
+	if (err) {
+		error("%s", gerr->message);
+		g_io_channel_shutdown(chan, TRUE, NULL);
+		return;
+	}
+
+	ba2str(&dst, address);
+	DBG("Incoming connection from %s on PSM %d", address, psm);
+
+	switch (psm) {
+	case L2CAP_PSM_HIDP_CTRL:
+		l = g_slist_find_custom(devices, &dst, device_cmp);
+		if (l)
+			return;
+
+		hdev = g_new0(struct hid_device, 1);
+		bacpy(&hdev->dst, &dst);
+		hdev->ctrl_io = g_io_channel_ref(chan);
+
+		devices = g_slist_append(devices, hdev);
+
+		hdev->ctrl_watch = g_io_add_watch(hdev->ctrl_io,
+					G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+					ctrl_watch_cb, hdev);
+
+		break;
+
+	case L2CAP_PSM_HIDP_INTR:
+		l = g_slist_find_custom(devices, &dst, device_cmp);
+		if (!l)
+			return;
+
+		hdev = l->data;
+		hdev->intr_io = g_io_channel_ref(chan);
+		hdev->intr_watch = g_io_add_watch(hdev->intr_io,
+				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+				intr_watch_cb, hdev);
+		break;
+	}
+}
+
 bool bt_hid_register(GIOChannel *io, const bdaddr_t *addr)
 {
+	GError *err = NULL;
+
 	DBG("");
 
 	notification_io = g_io_channel_ref(io);
 
+	ctrl_io = bt_io_listen(connect_cb, NULL, NULL, NULL, &err,
+				BT_IO_OPT_PSM, L2CAP_PSM_HIDP_CTRL,
+				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+				BT_IO_OPT_INVALID);
+	if (!ctrl_io) {
+		error("Failed to listen on control channel");
+		g_error_free(err);
+		return false;
+	}
+
+	intr_io = bt_io_listen(connect_cb, NULL, NULL, NULL, &err,
+				BT_IO_OPT_PSM, L2CAP_PSM_HIDP_INTR,
+				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+				BT_IO_OPT_INVALID);
+	if (!intr_io) {
+		error("Failed to listen on interrupt channel");
+		g_io_channel_unref(ctrl_io);
+		g_error_free(err);
+		return false;
+	}
+
 	return true;
 }
 
@@ -328,4 +412,10 @@ void bt_hid_unregister(void)
 
 	g_io_channel_unref(notification_io);
 	notification_io = NULL;
+
+	g_io_channel_unref(ctrl_io);
+	ctrl_io = NULL;
+
+	g_io_channel_unref(intr_io);
+	intr_io = NULL;
 }
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH 2/2] Bluetooth: Store supported commands only during setup procedure
From: Marcel Holtmann @ 2013-10-31 11:54 UTC (permalink / raw)
  To: linux-bluetooth

The list of supported commands of a controller can not change during
its lifetime. So store the list just once during the setup procedure
and not every time the HCI command is executed.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 net/bluetooth/hci_event.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index d75d51ff4fdd..4d0f4018df18 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -486,7 +486,10 @@ static void hci_cc_read_local_commands(struct hci_dev *hdev,
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
-	if (!rp->status)
+	if (rp->status)
+		return;
+
+	if (test_bit(HCI_SETUP, &hdev->dev_flags))
 		memcpy(hdev->commands, rp->commands, sizeof(hdev->commands));
 }
 
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH 1/2] Bluetooth: Remove debug statement for features complete event
From: Marcel Holtmann @ 2013-10-31 11:54 UTC (permalink / raw)
  To: linux-bluetooth

The complete list of local features are available through debugfs and
so there is no need to add a debug print here.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 net/bluetooth/hci_event.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 5935f748c0f9..d75d51ff4fdd 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -538,12 +538,6 @@ static void hci_cc_read_local_features(struct hci_dev *hdev,
 
 	if (hdev->features[0][5] & LMP_EDR_3S_ESCO)
 		hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5);
-
-	BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name,
-	       hdev->features[0][0], hdev->features[0][1],
-	       hdev->features[0][2], hdev->features[0][3],
-	       hdev->features[0][4], hdev->features[0][5],
-	       hdev->features[0][6], hdev->features[0][7]);
 }
 
 static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
-- 
1.8.3.1


^ permalink raw reply related

* Re: [PATCH] android/client: Fix crash in get_profile_interface
From: Johan Hedberg @ 2013-10-31 11:52 UTC (permalink / raw)
  To: Jerzy Kasenberg; +Cc: linux-bluetooth
In-Reply-To: <1383216986-302-1-git-send-email-jerzy.kasenberg@tieto.com>

Hi Jerzy,

On Thu, Oct 31, 2013, Jerzy Kasenberg wrote:
> This fixes crash due to uncheck input from user.
> ---
>  android/client/if-bt.c |    7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)

Applied (after minor coding style fix to add an empty line after }).
Thanks.

Johan

^ permalink raw reply

* [PATCH] android/daemon: Fix error setting property
From: Andrei Emeltchenko @ 2013-10-31 11:52 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Do not return error setting property which is already set. This fixes
bug with set_scan_mode which might return HAL_STATUS_DONE.
---
 android/adapter.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/android/adapter.c b/android/adapter.c
index 98b2764..9d4da4e 100644
--- a/android/adapter.c
+++ b/android/adapter.c
@@ -917,7 +917,7 @@ void bt_adapter_handle_cmd(GIOChannel *io, uint8_t opcode, void *buf,
 		break;
 	case HAL_OP_SET_ADAPTER_PROP:
 		status = set_property(buf, len);
-		if (status != HAL_STATUS_SUCCESS)
+		if (status != HAL_STATUS_SUCCESS && status != HAL_STATUS_DONE)
 			goto error;
 
 		break;
-- 
1.7.10.4


^ permalink raw reply related

* Re: [PATCH] android: Always enable SSP if supported by controller
From: Marcel Holtmann @ 2013-10-31 11:35 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth@vger.kernel.org development
In-Reply-To: <1383216631-28187-1-git-send-email-szymon.janc@tieto.com>

Hi Szymon,

> There is no HAL function to enable/disable SSP so always enable it if
> supported by controller.
> ---
> android/adapter.c | 5 +++++
> 1 file changed, 5 insertions(+)
> 
> diff --git a/android/adapter.c b/android/adapter.c
> index a3f9aa6..9f2e019 100644
> --- a/android/adapter.c
> +++ b/android/adapter.c
> @@ -528,6 +528,11 @@ static void read_info_complete(uint8_t status, uint16_t length, const void *para
> 	load_link_keys(NULL);
> 
> 	set_io_capability();
> +
> +	if ((adapter->supported_settings & MGMT_SETTING_SSP) &&
> +			!(adapter->current_settings & MGMT_SETTING_SSP))
> +		set_mode(MGMT_OP_SET_SSP, 0x01);
> +

	missing_settings = current_settings ^ supported_settings;

	if (missing_setting & MGMT_SETTING_SSP)
		..

Regards

Marcel


^ permalink raw reply

* [PATCH] android/client: Fix crash in get_profile_interface
From: Jerzy Kasenberg @ 2013-10-31 10:56 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg

This fixes crash due to uncheck input from user.
---
 android/client/if-bt.c |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/android/client/if-bt.c b/android/client/if-bt.c
index a3d6286..9e01d65 100644
--- a/android/client/if-bt.c
+++ b/android/client/if-bt.c
@@ -804,11 +804,16 @@ static void get_profile_interface_c(int argc, const char **argv,
 
 static void get_profile_interface_p(int argc, const char **argv)
 {
-	const char *id = argv[2];
+	const char *id;
 	const void **pif = NULL;
 	const void *dummy = NULL;
 
 	RETURN_IF_NULL(if_bluetooth);
+	if (argc <= 2) {
+		haltest_error("No interface specified\n");
+		return;
+	}
+	id = argv[2];
 
 	if (strcmp(BT_PROFILE_HANDSFREE_ID, id) == 0)
 		pif = (const void **) &if_hf;
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH] android: Always enable SSP if supported by controller
From: Szymon Janc @ 2013-10-31 10:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

There is no HAL function to enable/disable SSP so always enable it if
supported by controller.
---
 android/adapter.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/android/adapter.c b/android/adapter.c
index a3f9aa6..9f2e019 100644
--- a/android/adapter.c
+++ b/android/adapter.c
@@ -528,6 +528,11 @@ static void read_info_complete(uint8_t status, uint16_t length, const void *para
 	load_link_keys(NULL);
 
 	set_io_capability();
+
+	if ((adapter->supported_settings & MGMT_SETTING_SSP) &&
+			!(adapter->current_settings & MGMT_SETTING_SSP))
+		set_mode(MGMT_OP_SET_SSP, 0x01);
+
 	set_mode(MGMT_OP_SET_PAIRABLE, 0x01);
 
 	return;
-- 
1.8.4.1


^ permalink raw reply related

* [PATCH 10/10] android/client: Add GATT server methods
From: Jerzy Kasenberg @ 2013-10-31 10:45 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1383216315-30627-1-git-send-email-jerzy.kasenberg@tieto.com>

This patch implements GATT server method calls.
---
 android/client/if-gatt.c |  256 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 246 insertions(+), 10 deletions(-)

diff --git a/android/client/if-gatt.c b/android/client/if-gatt.c
index a262b90..e90e58b 100644
--- a/android/client/if-gatt.c
+++ b/android/client/if-gatt.c
@@ -579,6 +579,9 @@ static const btgatt_client_callbacks_t btgatt_client_callbacks = {
 
 /* BT-GATT Server callbacks */
 
+/* Cache server_if and conn_id for tab completion */
+static char server_if_str[20];
+
 /* Callback invoked in response to register_server */
 static void gatts_register_server_cb(int status, int server_if,
 							bt_uuid_t *app_uuid)
@@ -599,6 +602,7 @@ static void gatts_connection_cb(int conn_id, int server_if, int connected,
 	haltest_info("%s: conn_id=%d server_if=%d connected=%d bda=%s\n",
 					__func__, conn_id, server_if, connected,
 					bt_bdaddr_t2str(bda, last_addr));
+	snprintf(conn_id_str, sizeof(conn_id_str), "%d", conn_id);
 }
 
 /* Callback invoked in response to create_service */
@@ -607,6 +611,8 @@ static void gatts_service_added_cb(int status, int server_if,
 {
 	char buf[MAX_SRVC_ID_STR_LEN];
 
+	snprintf(server_if_str, sizeof(server_if_str), "%d", server_if);
+
 	haltest_info("%s: status=%d server_if=%d srvc_id=%s handle=%x\n",
 			__func__, status, server_if,
 			btgatt_srvc_id_t2str(srvc_id, buf), srvc_handle);
@@ -1392,78 +1398,308 @@ const struct interface gatt_client_if = {
 
 static void gatts_register_server_p(int argc, const char *argv[])
 {
+	bt_uuid_t uuid;
+
+	RETURN_IF_NULL(if_gatt);
+
+	/* uuid */
+	if (argc <= 2)
+		gatt_str2bt_uuid_t("bed4babe", -1, &uuid);
+	else
+		gatt_str2bt_uuid_t(argv[2], -1, &uuid);
+
+	EXEC(if_gatt->server->register_server, &uuid);
 }
 
 /* unregister_server */
 
+static void gatts_unregister_server_c(int argc, const char **argv,
+					enum_func *enum_func, void **user)
+{
+	if (argc == 3) {
+		*user = server_if_str;
+		*enum_func = enum_one_string;
+	}
+}
+
 static void gatts_unregister_server_p(int argc, const char *argv[])
 {
+	int server_if;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_SERVER_IF(2, server_if);
+
+	EXEC(if_gatt->server->unregister_server, server_if);
 }
 
 /* connect */
 
+static void gatts_connect_c(int argc, const char **argv, enum_func *enum_func,
+								void **user)
+{
+	if (argc == 3) {
+		*user = server_if_str;
+		*enum_func = enum_one_string;
+	} else if (argc == 4) {
+		*user = NULL;
+		*enum_func = enum_devices;
+	}
+}
+
 static void gatts_connect_p(int argc, const char *argv[])
 {
+	int server_if;
+	bt_bdaddr_t bd_addr;
+	int is_direct = 1;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_SERVER_IF(2, server_if);
+	VERIFY_ADDR_ARG(3, &bd_addr);
+
+	/* is_direct */
+	if (argc > 4)
+		is_direct = atoi(argv[4]);
+
+	EXEC(if_gatt->server->connect, server_if, &bd_addr, is_direct);
 }
 
 /* disconnect */
 
+static void gatts_disconnect_c(int argc, const char **argv,
+					enum_func *enum_func, void **user)
+{
+	if (argc == 3) {
+		*user = server_if_str;
+		*enum_func = enum_one_string;
+	} else if (argc == 4) {
+		*user = last_addr;
+		*enum_func = enum_one_string;
+	} else if (argc == 5) {
+		*user = conn_id_str;
+		*enum_func = enum_one_string;
+	}
+}
+
 static void gatts_disconnect_p(int argc, const char *argv[])
 {
+	int server_if;
+	bt_bdaddr_t bd_addr;
+	int conn_id;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_SERVER_IF(2, server_if);
+	VERIFY_ADDR_ARG(3, &bd_addr);
+	VERIFY_CONN_ID(4, conn_id);
+
+	EXEC(if_gatt->server->disconnect, server_if, &bd_addr, conn_id);
 }
 
 /* add_service */
 
+/* Same completion as gatts_unregister_server_c */
+#define gatts_add_service_c gatts_unregister_server_c
+
 static void gatts_add_service_p(int argc, const char *argv[])
 {
+	int server_if;
+	btgatt_srvc_id_t srvc_id;
+	int num_handles;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_SERVER_IF(2, server_if);
+	VERIFY_SRVC_ID(3, &srvc_id);
+
+	/* num handles */
+	if (argc <= 4) {
+		haltest_error("No num_handles specified\n");
+		return;
+	}
+	num_handles = atoi(argv[4]);
+
+	EXEC(if_gatt->server->add_service, server_if, &srvc_id, num_handles);
 }
 
 /* add_included_service */
 
+/* Same completion as gatts_unregister_server_c */
+#define gatts_add_included_service_c gatts_unregister_server_c
+
 static void gatts_add_included_service_p(int argc, const char *argv[])
 {
+	int server_if;
+	int service_handle;
+	int included_handle;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_SERVER_IF(2, server_if);
+	VERIFY_SERVICE_HANDLE(3, service_handle);
+	VERIFY_HANDLE(4, included_handle);
+
+	EXEC(if_gatt->server->add_included_service, server_if, service_handle,
+							included_handle);
 }
 
 /* add_characteristic */
 
+/* Same completion as gatts_unregister_server_c */
+#define gatts_add_characteristic_c gatts_unregister_server_c
+
 static void gatts_add_characteristic_p(int argc, const char *argv[])
 {
+	int server_if;
+	int service_handle;
+	int properties;
+	int permissions;
+	bt_uuid_t uuid;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_SERVER_IF(2, server_if);
+	VERIFY_SERVICE_HANDLE(3, service_handle);
+	VERIFY_UUID(4, &uuid);
+
+	/* properties */
+	if (argc <= 5) {
+		haltest_error("No properties specified\n");
+		return;
+	}
+	properties = atoi(argv[5]);
+
+	/* permissions */
+	if (argc <= 6) {
+		haltest_error("No permissions specified\n");
+		return;
+	}
+	permissions = atoi(argv[6]);
+
+	EXEC(if_gatt->server->add_characteristic, server_if, service_handle,
+						&uuid, properties, permissions);
 }
 
 /* add_descriptor */
 
+/* Same completion as gatts_unregister_server_c */
+#define gatts_add_descriptor_c gatts_unregister_server_c
+
 static void gatts_add_descriptor_p(int argc, const char *argv[])
 {
+	int server_if;
+	int service_handle;
+	int permissions;
+	bt_uuid_t uuid;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_SERVER_IF(2, server_if);
+	VERIFY_SERVICE_HANDLE(3, service_handle);
+	VERIFY_UUID(4, &uuid);
+
+	/* permissions */
+	if (argc <= 5) {
+		haltest_error("No permissions specified\n");
+		return;
+	}
+	permissions = atoi(argv[5]);
+
+	EXEC(if_gatt->server->add_descriptor, server_if, service_handle, &uuid,
+								permissions);
 }
 
 /* start_service */
 
+/* Same completion as gatts_unregister_server_c */
+#define gatts_start_service_c gatts_unregister_server_c
+
 static void gatts_start_service_p(int argc, const char *argv[])
 {
+	int server_if;
+	int service_handle;
+	int transport;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_SERVER_IF(2, server_if);
+	VERIFY_SERVICE_HANDLE(3, service_handle);
+
+	/* transport */
+	if (argc <= 4) {
+		haltest_error("No transport specified\n");
+		return;
+	}
+	transport = atoi(argv[4]);
+
+	EXEC(if_gatt->server->start_service, server_if, service_handle,
+								transport);
 }
 
 /* stop_service */
 
+/* Same completion as gatts_unregister_server_c */
+#define gatts_stop_service_c gatts_unregister_server_c
+
 static void gatts_stop_service_p(int argc, const char *argv[])
 {
+	int server_if;
+	int service_handle;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_SERVER_IF(2, server_if);
+	VERIFY_SERVICE_HANDLE(3, service_handle);
+
+	EXEC(if_gatt->server->stop_service, server_if, service_handle);
 }
 
 /* delete_service */
 
+/* Same completion as gatts_unregister_server_c */
+#define gatts_delete_service_c gatts_unregister_server_c
+
 static void gatts_delete_service_p(int argc, const char *argv[])
 {
+	int server_if;
+	int service_handle;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_SERVER_IF(2, server_if);
+	VERIFY_SERVICE_HANDLE(3, service_handle);
+
+	EXEC(if_gatt->server->delete_service, server_if, service_handle);
 }
 
 /* send_indication */
 
 static void gatts_send_indication_p(int argc, const char *argv[])
 {
+	int server_if;
+	int attr_handle;
+	int conn_id;
+	int confirm;
+	char data[200];
+	int len = 0;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_SERVER_IF(2, server_if);
+	VERIFY_HANDLE(3, attr_handle);
+	VERIFY_CONN_ID(4, conn_id);
+
+	/* confirm */
+	if (argc <= 5) {
+		haltest_error("No transport specified\n");
+		return;
+	}
+	confirm = atoi(argv[5]);
+
+	if (argc > 6) {
+		len = strlen(argv[6]);
+		scan_field(argv[6], len, (uint8_t *) data, sizeof(data));
+	}
+
+	EXEC(if_gatt->server->send_indication, server_if, attr_handle, conn_id,
+							len, confirm, data);
 }
 
 /* send_response */
 
 static void gatts_send_response_p(int argc, const char *argv[])
 {
+	haltest_warn("%s is not implemented yet\n", __func__);
 }
 
 #define GATTS_METHODH(n, h) METHOD(#n, gatts_##n##_p, NULL, h)
@@ -1471,19 +1707,19 @@ static void gatts_send_response_p(int argc, const char *argv[])
 
 static struct method server_methods[] = {
 	GATTS_METHODH(register_server, "[<uuid>]"),
-	GATTS_METHODH(unregister_server, "<server_if>"),
-	GATTS_METHODH(connect, "<server_if> <addr> [<is_direct>]"),
-	GATTS_METHODH(disconnect, "<server_if> <addr> <conn_id>"),
-	GATTS_METHODH(add_service, "<server_if> <srvc_id> <num_handles>"),
-	GATTS_METHODH(add_included_service,
+	GATTS_METHODCH(unregister_server, "<server_if>"),
+	GATTS_METHODCH(connect, "<server_if> <addr> [<is_direct>]"),
+	GATTS_METHODCH(disconnect, "<server_if> <addr> <conn_id>"),
+	GATTS_METHODCH(add_service, "<server_if> <srvc_id> <num_handles>"),
+	GATTS_METHODCH(add_included_service,
 			"<server_if> <service_handle> <included_handle>"),
-	GATTS_METHODH(add_characteristic,
+	GATTS_METHODCH(add_characteristic,
 		"<server_if> <service_handle> <uuid> <properites> <permissions>"),
-	GATTS_METHODH(add_descriptor, "<server_if> <uuid> <permissions>"),
-	GATTS_METHODH(start_service,
+	GATTS_METHODCH(add_descriptor, "<server_if> <uuid> <permissions>"),
+	GATTS_METHODCH(start_service,
 				"<server_if> <service_handle> <transport>"),
-	GATTS_METHODH(stop_service, "<server_if> <service_handle>"),
-	GATTS_METHODH(delete_service, "<server_if> <service_handle>"),
+	GATTS_METHODCH(stop_service, "<server_if> <service_handle>"),
+	GATTS_METHODCH(delete_service, "<server_if> <service_handle>"),
 	GATTS_METHODH(send_indication,
 			"<server_if> <attr_handle> <conn_id> <confirm> [<data>]"),
 	GATTS_METHODH(send_response, "<conn_id> <trans_id> <status>"),
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 09/10] android/client: Add GATT server callbacks code
From: Jerzy Kasenberg @ 2013-10-31 10:45 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1383216315-30627-1-git-send-email-jerzy.kasenberg@tieto.com>

This patch adds callbacks code for GATT server interface.
---
 android/client/if-gatt.c |   49 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/android/client/if-gatt.c b/android/client/if-gatt.c
index 3fe55e8..a262b90 100644
--- a/android/client/if-gatt.c
+++ b/android/client/if-gatt.c
@@ -583,6 +583,10 @@ static const btgatt_client_callbacks_t btgatt_client_callbacks = {
 static void gatts_register_server_cb(int status, int server_if,
 							bt_uuid_t *app_uuid)
 {
+	char buf[MAX_UUID_STR_LEN];
+
+	haltest_info("%s: status=%d server_if=%d app_uuid=%s\n", __func__,
+			status, server_if, gatt_uuid_t2str(app_uuid, buf));
 }
 
 /*
@@ -592,12 +596,20 @@ static void gatts_register_server_cb(int status, int server_if,
 static void gatts_connection_cb(int conn_id, int server_if, int connected,
 							bt_bdaddr_t *bda)
 {
+	haltest_info("%s: conn_id=%d server_if=%d connected=%d bda=%s\n",
+					__func__, conn_id, server_if, connected,
+					bt_bdaddr_t2str(bda, last_addr));
 }
 
 /* Callback invoked in response to create_service */
 static void gatts_service_added_cb(int status, int server_if,
 				btgatt_srvc_id_t *srvc_id, int srvc_handle)
 {
+	char buf[MAX_SRVC_ID_STR_LEN];
+
+	haltest_info("%s: status=%d server_if=%d srvc_id=%s handle=%x\n",
+			__func__, status, server_if,
+			btgatt_srvc_id_t2str(srvc_id, buf), srvc_handle);
 }
 
 /* Callback indicating that an included service has been added to a service */
@@ -605,6 +617,9 @@ static void gatts_included_service_added_cb(int status, int server_if,
 							int srvc_handle,
 							int incl_srvc_handle)
 {
+	haltest_info("%s: status=%d server_if=%d srvc_handle=%x inc_srvc_handle=%x\n",
+						__func__, status, server_if,
+						srvc_handle, incl_srvc_handle);
 }
 
 /* Callback invoked when a characteristic has been added to a service */
@@ -613,6 +628,11 @@ static void gatts_characteristic_added_cb(int status, int server_if,
 								int srvc_handle,
 								int char_handle)
 {
+	char buf[MAX_SRVC_ID_STR_LEN];
+
+	haltest_info("%s: status=%d server_if=%d uuid=%s srvc_handle=%x char_handle=%x\n",
+			__func__, status, server_if, gatt_uuid_t2str(uuid, buf),
+			srvc_handle, char_handle);
 }
 
 /* Callback invoked when a descriptor has been added to a characteristic */
@@ -620,21 +640,32 @@ static void gatts_descriptor_added_cb(int status, int server_if,
 					bt_uuid_t *uuid, int srvc_handle,
 							int descr_handle)
 {
+	char buf[MAX_SRVC_ID_STR_LEN];
+
+	haltest_info("%s: status=%d server_if=%d uuid=%s srvc_handle=%x descr_handle=%x\n",
+			__func__, status, server_if, gatt_uuid_t2str(uuid, buf),
+			srvc_handle, descr_handle);
 }
 
 /* Callback invoked in response to start_service */
 static void gatts_service_started_cb(int status, int server_if, int srvc_handle)
 {
+	haltest_info("%s: status=%d server_if=%d srvc_handle=%x\n",
+				__func__, status, server_if, srvc_handle);
 }
 
 /* Callback invoked in response to stop_service */
 static void gatts_service_stopped_cb(int status, int server_if, int srvc_handle)
 {
+	haltest_info("%s: status=%d server_if=%d srvc_handle=%x\n",
+				__func__, status, server_if, srvc_handle);
 }
 
 /* Callback triggered when a service has been deleted */
 static void gatts_service_deleted_cb(int status, int server_if, int srvc_handle)
 {
+	haltest_info("%s: status=%d server_if=%d srvc_handle=%x\n",
+				__func__, status, server_if, srvc_handle);
 }
 
 /*
@@ -645,6 +676,11 @@ static void gatts_request_read_cb(int conn_id, int trans_id, bt_bdaddr_t *bda,
 						int attr_handle, int offset,
 						bool is_long)
 {
+	char buf[MAX_ADDR_STR_LEN];
+
+	haltest_info("%s: conn_id=%d trans_id=%d bda=%s attr_handle=%x offset=%d is_long=%d\n",
+			__func__, conn_id, trans_id, bt_bdaddr_t2str(bda, buf),
+			attr_handle, offset, is_long);
 }
 
 /*
@@ -656,12 +692,24 @@ static void gatts_request_write_cb(int conn_id, int trans_id, bt_bdaddr_t *bda,
 					bool need_rsp, bool is_prep,
 					uint8_t *value)
 {
+	char buf[MAX_ADDR_STR_LEN];
+	char valbuf[100];
+
+	haltest_info("%s: conn_id=%d trans_id=%d bda=%s attr_handle=%x offset=%d length=%d need_rsp=%d is_prep=%d value=%s\n",
+			__func__, conn_id, trans_id, bt_bdaddr_t2str(bda, buf),
+			attr_handle, offset, length, need_rsp, is_prep,
+			array2str(value, length, valbuf, sizeof(valbuf)));
 }
 
 /* Callback invoked when a previously prepared write is to be executed */
 static void gatts_request_exec_write_cb(int conn_id, int trans_id,
 					bt_bdaddr_t *bda, int exec_write)
 {
+	char buf[MAX_ADDR_STR_LEN];
+
+	haltest_info("%s: conn_id=%d trans_id=%d bda=%s exec_write=%d\n",
+			__func__, conn_id, trans_id, bt_bdaddr_t2str(bda, buf),
+			exec_write);
 }
 
 /*
@@ -670,6 +718,7 @@ static void gatts_request_exec_write_cb(int conn_id, int trans_id,
  */
 static void gatts_response_confirmation_cb(int status, int handle)
 {
+	haltest_info("%s: status=%d handle=%x\n", __func__, status, handle);
 }
 
 static const btgatt_server_callbacks_t btgatt_server_callbacks = {
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 08/10] android/client: Add tab completion to GATT client
From: Jerzy Kasenberg @ 2013-10-31 10:45 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1383216315-30627-1-git-send-email-jerzy.kasenberg@tieto.com>

This patch adds tab completion to GATT client methods.
---
 android/client/if-gatt.c |  209 +++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 187 insertions(+), 22 deletions(-)

diff --git a/android/client/if-gatt.c b/android/client/if-gatt.c
index 62e0a81..3fe55e8 100644
--- a/android/client/if-gatt.c
+++ b/android/client/if-gatt.c
@@ -356,12 +356,20 @@ static char *btgatt_read_params_t2str(const btgatt_read_params_t *data,
 
 /* BT-GATT Client callbacks. */
 
+/* Cache client_if and conn_id for tab completion */
+static char client_if_str[20];
+static char conn_id_str[20];
+/* Cache address for tab completion */
+static char last_addr[MAX_ADDR_STR_LEN];
+
 /* Callback invoked in response to register_client */
 static void gattc_register_client_cb(int status, int client_if,
 							bt_uuid_t *app_uuid)
 {
 	char buf[MAX_UUID_STR_LEN];
 
+	snprintf(client_if_str, sizeof(client_if_str), "%d", client_if);
+
 	haltest_info("%s: status=%d client_if=%d app_uuid=%s\n", __func__,
 						status, client_if,
 						gatt_uuid_t2str(app_uuid, buf));
@@ -380,11 +388,9 @@ static void gattc_scan_result_cb(bt_bdaddr_t *bda, int rssi, uint8_t *adv_data)
 static void gattc_connect_cb(int conn_id, int status, int client_if,
 							bt_bdaddr_t *bda)
 {
-	char buf[MAX_ADDR_STR_LEN];
-
 	haltest_info("%s: conn_id=%d status=%d, client_if=%d bda=%s\n",
 					__func__, conn_id, status, client_if,
-					bt_bdaddr_t2str(bda, buf));
+					bt_bdaddr_t2str(bda, last_addr));
 }
 
 /* Callback invoked in response to close */
@@ -740,6 +746,15 @@ static void register_client_p(int argc, const char **argv)
 
 /* unregister_client */
 
+static void unregister_client_c(int argc, const char **argv,
+					enum_func *enum_func, void **user)
+{
+	if (argc == 3) {
+		*user = client_if_str;
+		*enum_func = enum_one_string;
+	}
+}
+
 static void unregister_client_p(int argc, const char **argv)
 {
 	int client_if;
@@ -752,6 +767,9 @@ static void unregister_client_p(int argc, const char **argv)
 
 /* scan */
 
+/* Same completion as unregister for now, start stop is not auto completed */
+#define scan_c unregister_client_c
+
 static void scan_p(int argc, const char **argv)
 {
 	int client_if;
@@ -770,6 +788,18 @@ static void scan_p(int argc, const char **argv)
 
 /* connect */
 
+static void connect_c(int argc, const char **argv, enum_func *enum_func,
+								void **user)
+{
+	if (argc == 3) {
+		*user = client_if_str;
+		*enum_func = enum_one_string;
+	} else if (argc == 4) {
+		*user = NULL;
+		*enum_func = enum_devices;
+	}
+}
+
 static void connect_p(int argc, const char **argv)
 {
 	int client_if;
@@ -789,6 +819,21 @@ static void connect_p(int argc, const char **argv)
 
 /* disconnect */
 
+static void disconnect_c(int argc, const char **argv, enum_func *enum_func,
+								void **user)
+{
+	if (argc == 3) {
+		*user = client_if_str;
+		*enum_func = enum_one_string;
+	} else if (argc == 4) {
+		*user = last_addr;
+		*enum_func = enum_one_string;
+	} else if (argc == 5) {
+		*user = conn_id_str;
+		*enum_func = enum_one_string;
+	}
+}
+
 static void disconnect_p(int argc, const char **argv)
 {
 	int client_if;
@@ -805,6 +850,17 @@ static void disconnect_p(int argc, const char **argv)
 
 /* refresh */
 
+static void refresh_c(int argc, const char **argv, enum_func *enum_func,
+								void **user)
+{
+	if (argc == 3) {
+		*user = client_if_str;
+		*enum_func = enum_one_string;
+	} else if (argc == 4) {
+		*enum_func = enum_devices;
+	}
+}
+
 static void refresh_p(int argc, const char **argv)
 {
 	int client_if;
@@ -819,6 +875,15 @@ static void refresh_p(int argc, const char **argv)
 
 /* search_service */
 
+static void search_service_c(int argc, const char **argv, enum_func *enum_func,
+								void **user)
+{
+	if (argc == 3) {
+		*user = conn_id_str;
+		*enum_func = enum_one_string;
+	}
+}
+
 static void search_service_p(int argc, const char **argv)
 {
 	int conn_id;
@@ -839,6 +904,15 @@ static void search_service_p(int argc, const char **argv)
 
 /* get_included_service */
 
+static void get_included_service_c(int argc, const char **argv,
+					enum_func *enum_func, void **user)
+{
+	if (argc == 3) {
+		*user = conn_id_str;
+		*enum_func = enum_one_string;
+	}
+}
+
 static void get_included_service_p(int argc, const char **argv)
 {
 	int conn_id;
@@ -853,6 +927,9 @@ static void get_included_service_p(int argc, const char **argv)
 
 /* get_characteristic */
 
+/* Same completion as get_included_service_c */
+#define get_characteristic_c get_included_service_c
+
 static void get_characteristic_p(int argc, const char **argv)
 {
 	int conn_id;
@@ -867,6 +944,9 @@ static void get_characteristic_p(int argc, const char **argv)
 
 /* get_descriptor */
 
+/* Same completion as get_included_service_c */
+#define get_descriptor_c get_included_service_c
+
 static void get_descriptor_p(int argc, const char **argv)
 {
 	int conn_id;
@@ -884,6 +964,9 @@ static void get_descriptor_p(int argc, const char **argv)
 
 /* read_characteristic */
 
+/* Same completion as get_included_service_c */
+#define read_characteristic_c get_included_service_c
+
 static void read_characteristic_p(int argc, const char **argv)
 {
 	int conn_id;
@@ -906,6 +989,24 @@ static void read_characteristic_p(int argc, const char **argv)
 
 /* write_characteristic */
 
+static void write_characteristic_c(int argc, const char **argv,
+					enum_func *enum_func, void **user)
+{
+	/*
+	 * This should be from tGATT_WRITE_TYPE but it's burried
+	 * inside bluedroid guts
+	 */
+	static const char *wrtypes[] = { "1", "2", "3", NULL };
+
+	if (argc == 3) {
+		*user = conn_id_str;
+		*enum_func = enum_one_string;
+	} else if (argc == 6) {
+		*user = wrtypes;
+		*enum_func = enum_strings;
+	}
+}
+
 static void write_characteristic_p(int argc, const char **argv)
 {
 	int conn_id;
@@ -950,6 +1051,9 @@ static void write_characteristic_p(int argc, const char **argv)
 
 /* read_descriptor */
 
+/* Same completion as get_included_service_c */
+#define read_descriptor_c get_included_service_c
+
 static void read_descriptor_p(int argc, const char **argv)
 {
 	int conn_id;
@@ -974,6 +1078,24 @@ static void read_descriptor_p(int argc, const char **argv)
 
 /* write_descriptor */
 
+static void write_descriptor_c(int argc, const char **argv,
+					enum_func *enum_func, void **user)
+{
+	/*
+	 * This should be from tGATT_WRITE_TYPE but it's burried
+	 * inside bluedroid guts
+	 */
+	static const char *wrtypes[] = { "1", "2", "3", NULL };
+
+	if (argc == 3) {
+		*user = conn_id_str;
+		*enum_func = enum_one_string;
+	} else if (argc == 7) {
+		*user = wrtypes;
+		*enum_func = enum_strings;
+	}
+}
+
 static void write_descriptor_p(int argc, const char **argv)
 {
 	int conn_id;
@@ -1020,6 +1142,9 @@ static void write_descriptor_p(int argc, const char **argv)
 
 /* execute_write */
 
+/* Same completion as search_service */
+#define execute_write_c search_service_c
+
 static void execute_write_p(int argc, const char **argv)
 {
 	int conn_id;
@@ -1040,6 +1165,18 @@ static void execute_write_p(int argc, const char **argv)
 
 /* register_for_notification */
 
+static void register_for_notification_c(int argc, const char **argv,
+					enum_func *enum_func, void **user)
+{
+	if (argc == 3) {
+		*user = client_if_str;
+		*enum_func = enum_one_string;
+	} else if (argc == 4) {
+		*user = last_addr;
+		*enum_func = enum_one_string;
+	}
+}
+
 static void register_for_notification_p(int argc, const char **argv)
 {
 	int client_if;
@@ -1059,6 +1196,9 @@ static void register_for_notification_p(int argc, const char **argv)
 
 /* deregister_for_notification */
 
+/* Same completion as search_service */
+#define deregister_for_notification_c register_for_notification_c
+
 static void deregister_for_notification_p(int argc, const char **argv)
 {
 	int client_if;
@@ -1078,6 +1218,17 @@ static void deregister_for_notification_p(int argc, const char **argv)
 
 /* read_remote_rssi */
 
+static void read_remote_rssi_c(int argc, const char **argv,
+					enum_func *enum_func, void **user)
+{
+	if (argc == 3) {
+		*user = client_if_str;
+		*enum_func = enum_one_string;
+	} else if (argc == 4) {
+		*enum_func = enum_devices;
+	}
+}
+
 static void read_remote_rssi_p(int argc, const char **argv)
 {
 	int client_if;
@@ -1092,6 +1243,13 @@ static void read_remote_rssi_p(int argc, const char **argv)
 
 /* get_device_type */
 
+static void get_device_type_c(int argc, const char **argv, enum_func *enum_func,
+								void **user)
+{
+	if (argc == 3)
+		*enum_func = enum_devices;
+}
+
 static void get_device_type_p(int argc, const char **argv)
 {
 	bt_bdaddr_t bd_addr;
@@ -1106,6 +1264,13 @@ static void get_device_type_p(int argc, const char **argv)
 
 /* test_command */
 
+static void test_command_c(int argc, const char **argv, enum_func *enum_func,
+								void **user)
+{
+	if (argc == 4)
+		*enum_func = enum_devices;
+}
+
 static void test_command_p(int argc, const char **argv)
 {
 	int command;
@@ -1138,31 +1303,31 @@ static void test_command_p(int argc, const char **argv)
 
 static struct method client_methods[] = {
 	STD_METHODH(register_client, "[<uuid>]"),
-	STD_METHODH(unregister_client, "<client_if>"),
-	STD_METHODH(scan, "<client_if> [1|0]"),
-	STD_METHODH(connect, "<client_if> <addr> [<is_direct>]"),
-	STD_METHODH(disconnect, "<client_if> <addr> <conn_id>"),
-	STD_METHODH(refresh, "<client_if> <addr>"),
-	STD_METHODH(search_service, "<conn_id> [<uuid>]"),
-	STD_METHODH(get_included_service, "<conn_id> <srvc_id>"),
-	STD_METHODH(get_characteristic, "<conn_id> <srvc_id>"),
-	STD_METHODH(get_descriptor, "<conn_id> <srvc_id> <char_id>"),
-	STD_METHODH(read_characteristic,
+	STD_METHODCH(unregister_client, "<client_if>"),
+	STD_METHODCH(scan, "<client_if> [1|0]"),
+	STD_METHODCH(connect, "<client_if> <addr> [<is_direct>]"),
+	STD_METHODCH(disconnect, "<client_if> <addr> <conn_id>"),
+	STD_METHODCH(refresh, "<client_if> <addr>"),
+	STD_METHODCH(search_service, "<conn_id> [<uuid>]"),
+	STD_METHODCH(get_included_service, "<conn_id> <srvc_id>"),
+	STD_METHODCH(get_characteristic, "<conn_id> <srvc_id>"),
+	STD_METHODCH(get_descriptor, "<conn_id> <srvc_id> <char_id>"),
+	STD_METHODCH(read_characteristic,
 			"<conn_id> <srvc_id> <char_id> [<auth_req>]"),
-	STD_METHODH(write_characteristic,
+	STD_METHODCH(write_characteristic,
 			"<conn_id> <srvc_id> <char_id> <write_type> <hex_value> [<auth_req>]"),
-	STD_METHODH(read_descriptor,
+	STD_METHODCH(read_descriptor,
 			"<conn_id> <srvc_id> <char_id> <descr_id> [<auth_req>]"),
-	STD_METHODH(write_descriptor,
+	STD_METHODCH(write_descriptor,
 			"<conn_id> <srvc_id> <char_id> <descr_id> <write_type> <hex_value> [<auth_req>]"),
-	STD_METHODH(execute_write, "<conn_id> <execute>"),
-	STD_METHODH(register_for_notification,
+	STD_METHODCH(execute_write, "<conn_id> <execute>"),
+	STD_METHODCH(register_for_notification,
 			"<client_if> <addr> <srvc_id> <char_id>"),
-	STD_METHODH(deregister_for_notification,
+	STD_METHODCH(deregister_for_notification,
 			"<client_if> <addr> <srvc_id> <char_id>"),
-	STD_METHODH(read_remote_rssi, "<client_if> <addr>"),
-	STD_METHODH(get_device_type, "<addr>"),
-	STD_METHODH(test_command,
+	STD_METHODCH(read_remote_rssi, "<client_if> <addr>"),
+	STD_METHODCH(get_device_type, "<addr>"),
+	STD_METHODCH(test_command,
 			"<cmd> <addr> <uuid> [u1] [u2] [u3] [u4] [u5]"),
 	END_METHOD
 };
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 07/10] android/client: Add GATT complex type parsing
From: Jerzy Kasenberg @ 2013-10-31 10:45 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1383216315-30627-1-git-send-email-jerzy.kasenberg@tieto.com>

This patch adds code to parse: UUID, service ID, characteristic ID,
and general hex string filed.
---
 android/client/if-gatt.c |  119 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+)

diff --git a/android/client/if-gatt.c b/android/client/if-gatt.c
index 70dbb24..62e0a81 100644
--- a/android/client/if-gatt.c
+++ b/android/client/if-gatt.c
@@ -136,10 +136,79 @@ static char *gatt_uuid_t2str(const bt_uuid_t *uuid, char *buf)
  */
 static void scan_field(const char *str, int len, uint8_t *out, int out_size)
 {
+	int i;
+
+	memset(out, 0, out_size);
+	if (out_size * 2 > len + 1)
+		out_size = (len + 1) / 2;
+
+	for (i = 0; i < out_size && len > 0; ++i) {
+		len -= 2;
+		if (len >= 0)
+			sscanf(str + len, "%02hhx", &out[i]);
+		else
+			sscanf(str, "%1hhx", &out[i]);
+	}
 }
 
+/* Like strchr but with upper limit instead of 0 terminated string */
+static const char *strchrlimit(const char *p, const char *e, int c)
+{
+	while (p < e && *p != (char) c)
+		++p;
+
+	return p < e ? p : NULL;
+}
+
+/*
+ * converts string to uuid
+ * it accepts uuid in following forms:
+ *	123
+ *	0000123
+ *	0000123-0014-1234-0000-000056789abc
+ *	0000123001412340000000056789abc
+ *	123-14-1234-0-56789abc
+ */
 static void gatt_str2bt_uuid_t(const char *str, int len, bt_uuid_t *uuid)
 {
+	int dash_cnt = 0;
+	int dashes[6] = {-1}; /* indexes of '-' or \0 */
+	static uint8_t filed_offset[] = { 16, 12, 10, 8, 6, 0 };
+	const char *p = str;
+	const char *e;
+	int i;
+
+	e = str + ((len >= 0) ? len : (int) strlen(str));
+
+	while (p != NULL && dash_cnt < 5) {
+		const char *f = strchrlimit(p, e, '-');
+
+		if (f != NULL)
+			dashes[++dash_cnt] = f++ - str;
+		p = f;
+	}
+
+	/* get index of \0 to dashes table */
+	if (dash_cnt < 5)
+		dashes[++dash_cnt] = e - str;
+
+	memcpy(uuid, GATT_BASE_UUID, sizeof(bt_uuid_t));
+
+	/* whole uuid in one string without dashes */
+	if (dash_cnt == 1 && dashes[1] > 8) {
+		if (dashes[1] > 32)
+			dashes[1] = 32;
+		scan_field(str, dashes[1],
+				&uuid->uu[16 - (dashes[1] + 1) / 2],
+				(dashes[1] + 1) / 2);
+	} else {
+		for (i = 0; i < dash_cnt; ++i) {
+			scan_field(str + dashes[i] + 1,
+					dashes[i + 1] - dashes[i] - 1,
+					&uuid->uu[filed_offset[i + 1]],
+					filed_offset[i] - filed_offset[i + 1]);
+		}
+	}
 }
 
 /* char_id formating function */
@@ -155,6 +224,26 @@ static char *btgatt_char_id_t2str(const btgatt_char_id_t *char_id, char *buf)
 /* Parse btgatt_char_id_t */
 static void str2btgatt_char_id_t(const char *buf, btgatt_char_id_t *char_id)
 {
+	const char *e;
+
+	memcpy(&char_id->uuid, &GATT_BASE_UUID, sizeof(bt_uuid_t));
+	char_id->inst_id = 0;
+
+	if (*buf == '{')
+		buf++;
+	e = strpbrk(buf, " ,}");
+	if (e == NULL)
+		e = buf + strlen(buf);
+
+	gatt_str2bt_uuid_t(buf, e - buf, &char_id->uuid);
+	if (*e == ',') {
+		buf = e + 1;
+		e = strpbrk(buf, " ,}");
+		if (e == NULL)
+			e = buf + strlen(buf);
+		if (buf < e)
+			char_id->inst_id = atoi(buf);
+	}
 }
 
 /* service_id formating function */
@@ -170,6 +259,36 @@ static char *btgatt_srvc_id_t2str(const btgatt_srvc_id_t *srvc_id, char *buf)
 /* Parse btgatt_srvc_id_t */
 static void str2btgatt_srvc_id_t(const char *buf, btgatt_srvc_id_t *srvc_id)
 {
+	const char *e;
+
+	memcpy(&srvc_id->id.uuid, &GATT_BASE_UUID, sizeof(bt_uuid_t));
+	srvc_id->id.inst_id = 0;
+	srvc_id->is_primary = 1;
+
+	if (*buf == '{')
+		buf++;
+	e = strpbrk(buf, " ,}");
+	if (e == NULL)
+		e = buf + strlen(buf);
+
+	gatt_str2bt_uuid_t(buf, e - buf, &srvc_id->id.uuid);
+	if (*e == ',') {
+		buf = e + 1;
+		e = strpbrk(buf, " ,}");
+		if (e == NULL)
+			e = buf + strlen(buf);
+		if (buf < e)
+			srvc_id->id.inst_id = atoi(buf);
+	}
+
+	if (*e == ',') {
+		buf = e + 1;
+		e = strpbrk(buf, " ,}");
+		if (e == NULL)
+			e = buf + strlen(buf);
+		if (buf < e)
+			srvc_id->is_primary = atoi(buf);
+	}
 }
 
 /* Converts array of uint8_t to string representation */
-- 
1.7.9.5


^ permalink raw reply related


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