Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH 3/7] Bluetooth: Introduce flag for limited discoverable mode
From: Marcel Holtmann @ 2013-10-15 13:33 UTC (permalink / raw)
  To: linux-bluetooth

Add a new flag that can be set when in limited discoverable mode. This
flag will cause the limited discoverable bit in the class of device
value to bet set.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 include/net/bluetooth/hci.h | 1 +
 net/bluetooth/mgmt.c        | 3 +++
 2 files changed, 4 insertions(+)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index b096f5f..f4650a8 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -125,6 +125,7 @@ enum {
 	HCI_ADVERTISING,
 	HCI_CONNECTABLE,
 	HCI_DISCOVERABLE,
+	HCI_LIMITED_DISCOVERABLE,
 	HCI_LINK_SECURITY,
 	HCI_PERIODIC_INQ,
 	HCI_FAST_CONNECTABLE,
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 285d571..d5eaa28 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -724,6 +724,9 @@ static void update_class(struct hci_request *req)
 	cod[1] = hdev->major_class;
 	cod[2] = get_service_classes(hdev);
 
+	if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
+		cod[1] |= 0x20;
+
 	if (memcmp(cod, hdev->dev_class, 3) == 0)
 		return;
 
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH 2/7] Bluetooth: Update advertising data based on management commands
From: Marcel Holtmann @ 2013-10-15 13:33 UTC (permalink / raw)
  To: linux-bluetooth

Magically updating the advertising data when some random command enables
advertising in the controller is not really a good idea. It also caused
a bit of complicated code with the exported hci_udpate_ad function that
is shared from many places.

This patch consolidates the advertising data update into the management
core. It also makes sure that when powering on with LE enabled or later
on enabling LE the controller has a good default for advertising data.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 include/net/bluetooth/hci_core.h |   2 -
 net/bluetooth/hci_core.c         |  87 +--------------------------
 net/bluetooth/hci_event.c        |   8 ---
 net/bluetooth/mgmt.c             | 126 +++++++++++++++++++++++++++++++++++----
 4 files changed, 116 insertions(+), 107 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 4e20842..4a186ec 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1183,8 +1183,6 @@ struct hci_sec_filter {
 #define hci_req_lock(d)		mutex_lock(&d->req_lock)
 #define hci_req_unlock(d)	mutex_unlock(&d->req_lock)
 
-void hci_update_ad(struct hci_request *req);
-
 void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
 					u16 latency, u16 to_multiplier);
 void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index c53f7f9..a49ca48 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -685,10 +685,8 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt)
 	if (hdev->commands[5] & 0x10)
 		hci_setup_link_policy(req);
 
-	if (lmp_le_capable(hdev)) {
+	if (lmp_le_capable(hdev))
 		hci_set_le_support(req);
-		hci_update_ad(req);
-	}
 
 	/* Read features beyond page 1 if available */
 	for (p = 2; p < HCI_MAX_PAGES && p <= hdev->max_page; p++) {
@@ -1127,89 +1125,6 @@ done:
 	return err;
 }
 
-static u8 create_ad(struct hci_dev *hdev, u8 *ptr)
-{
-	u8 ad_len = 0, flags = 0;
-	size_t name_len;
-
-	if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
-		flags |= LE_AD_GENERAL;
-
-	if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
-		if (lmp_le_br_capable(hdev))
-			flags |= LE_AD_SIM_LE_BREDR_CTRL;
-		if (lmp_host_le_br_capable(hdev))
-			flags |= LE_AD_SIM_LE_BREDR_HOST;
-	} else {
-		flags |= LE_AD_NO_BREDR;
-	}
-
-	if (flags) {
-		BT_DBG("adv flags 0x%02x", flags);
-
-		ptr[0] = 2;
-		ptr[1] = EIR_FLAGS;
-		ptr[2] = flags;
-
-		ad_len += 3;
-		ptr += 3;
-	}
-
-	if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
-		ptr[0] = 2;
-		ptr[1] = EIR_TX_POWER;
-		ptr[2] = (u8) hdev->adv_tx_power;
-
-		ad_len += 3;
-		ptr += 3;
-	}
-
-	name_len = strlen(hdev->dev_name);
-	if (name_len > 0) {
-		size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
-
-		if (name_len > max_len) {
-			name_len = max_len;
-			ptr[1] = EIR_NAME_SHORT;
-		} else
-			ptr[1] = EIR_NAME_COMPLETE;
-
-		ptr[0] = name_len + 1;
-
-		memcpy(ptr + 2, hdev->dev_name, name_len);
-
-		ad_len += (name_len + 2);
-		ptr += (name_len + 2);
-	}
-
-	return ad_len;
-}
-
-void hci_update_ad(struct hci_request *req)
-{
-	struct hci_dev *hdev = req->hdev;
-	struct hci_cp_le_set_adv_data cp;
-	u8 len;
-
-	if (!lmp_le_capable(hdev))
-		return;
-
-	memset(&cp, 0, sizeof(cp));
-
-	len = create_ad(hdev, cp.data);
-
-	if (hdev->adv_data_len == len &&
-	    memcmp(cp.data, hdev->adv_data, len) == 0)
-		return;
-
-	memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
-	hdev->adv_data_len = len;
-
-	cp.length = len;
-
-	hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
-}
-
 static int hci_dev_do_open(struct hci_dev *hdev)
 {
 	int ret = 0;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 5391469..7b133f0 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -939,14 +939,6 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
 			clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
 	}
 
-	if (*sent && !test_bit(HCI_INIT, &hdev->flags)) {
-		struct hci_request req;
-
-		hci_req_init(&req, hdev);
-		hci_update_ad(&req);
-		hci_req_run(&req, NULL);
-	}
-
 	hci_dev_unlock(hdev);
 }
 
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index c071708..285d571 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -536,6 +536,89 @@ static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
 	return ptr;
 }
 
+static u8 create_ad(struct hci_dev *hdev, u8 *ptr)
+{
+	u8 ad_len = 0, flags = 0;
+	size_t name_len;
+
+	if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
+		flags |= LE_AD_GENERAL;
+
+	if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
+		if (lmp_le_br_capable(hdev))
+			flags |= LE_AD_SIM_LE_BREDR_CTRL;
+		if (lmp_host_le_br_capable(hdev))
+			flags |= LE_AD_SIM_LE_BREDR_HOST;
+	} else {
+		flags |= LE_AD_NO_BREDR;
+	}
+
+	if (flags) {
+		BT_DBG("adv flags 0x%02x", flags);
+
+		ptr[0] = 2;
+		ptr[1] = EIR_FLAGS;
+		ptr[2] = flags;
+
+		ad_len += 3;
+		ptr += 3;
+	}
+
+	if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
+		ptr[0] = 2;
+		ptr[1] = EIR_TX_POWER;
+		ptr[2] = (u8) hdev->adv_tx_power;
+
+		ad_len += 3;
+		ptr += 3;
+	}
+
+	name_len = strlen(hdev->dev_name);
+	if (name_len > 0) {
+		size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
+
+		if (name_len > max_len) {
+			name_len = max_len;
+			ptr[1] = EIR_NAME_SHORT;
+		} else
+			ptr[1] = EIR_NAME_COMPLETE;
+
+		ptr[0] = name_len + 1;
+
+		memcpy(ptr + 2, hdev->dev_name, name_len);
+
+		ad_len += (name_len + 2);
+		ptr += (name_len + 2);
+	}
+
+	return ad_len;
+}
+
+static void update_ad(struct hci_request *req)
+{
+	struct hci_dev *hdev = req->hdev;
+	struct hci_cp_le_set_adv_data cp;
+	u8 len;
+
+	if (!lmp_le_capable(hdev))
+		return;
+
+	memset(&cp, 0, sizeof(cp));
+
+	len = create_ad(hdev, cp.data);
+
+	if (hdev->adv_data_len == len &&
+	    memcmp(cp.data, hdev->adv_data, len) == 0)
+		return;
+
+	memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
+	hdev->adv_data_len = len;
+
+	cp.length = len;
+
+	hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
+}
+
 static void create_eir(struct hci_dev *hdev, u8 *data)
 {
 	u8 *ptr = data;
@@ -1555,6 +1638,23 @@ static void le_enable_complete(struct hci_dev *hdev, u8 status)
 
 	if (match.sk)
 		sock_put(match.sk);
+
+	/* Make sure the controller has a good default for
+	 * advertising data. Restrict the update to when LE
+	 * has actually been enabled. During power on, the
+	 * update in powered_update_hci will take care of it.
+	 */
+	if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
+		struct hci_request req;
+
+		hci_dev_lock(hdev);
+
+		hci_req_init(&req, hdev);
+		update_ad(&req);
+		hci_req_run(&req, NULL);
+
+		hci_dev_unlock(hdev);
+	}
 }
 
 static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
@@ -1622,18 +1722,18 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 		goto unlock;
 	}
 
+	hci_req_init(&req, hdev);
+
 	memset(&hci_cp, 0, sizeof(hci_cp));
 
 	if (val) {
 		hci_cp.le = val;
 		hci_cp.simul = lmp_le_br_capable(hdev);
+	} else {
+		if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
+			disable_advertising(&req);
 	}
 
-	hci_req_init(&req, hdev);
-
-	if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) && !val)
-		disable_advertising(&req);
-
 	hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
 		    &hci_cp);
 
@@ -2772,7 +2872,7 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
 	}
 
 	if (lmp_le_capable(hdev))
-		hci_update_ad(&req);
+		update_ad(&req);
 
 	err = hci_req_run(&req, set_name_complete);
 	if (err < 0)
@@ -3724,7 +3824,7 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 		goto unlock;
 	}
 
-	/* We need to flip the bit already here so that hci_update_ad
+	/* We need to flip the bit already here so that update_ad
 	 * generates the correct flags.
 	 */
 	set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
@@ -3734,7 +3834,7 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 	if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
 		set_bredr_scan(&req);
 
-	hci_update_ad(&req);
+	update_ad(&req);
 
 	err = hci_req_run(&req, set_bredr_complete);
 	if (err < 0)
@@ -4035,9 +4135,6 @@ static int powered_update_hci(struct hci_dev *hdev)
 		    cp.simul != lmp_host_le_br_capable(hdev))
 			hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
 				    sizeof(cp), &cp);
-
-		/* In case BR/EDR was toggled during the AUTO_OFF phase */
-		hci_update_ad(&req);
 	}
 
 	if (lmp_le_capable(hdev)) {
@@ -4046,6 +4143,13 @@ static int powered_update_hci(struct hci_dev *hdev)
 			hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
 				    &hdev->static_addr);
 
+		/* Make sure the controller has a good default for
+		 * advertising data. This also applies to the case
+		 * where BR/EDR was toggled during the AUTO_OFF phase.
+		 */
+		if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
+			update_ad(&req);
+
 		if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
 			enable_advertising(&req);
 	}
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH 1/7] Bluetooth: Use hci_request for discoverable timeout handling
From: Marcel Holtmann @ 2013-10-15 13:33 UTC (permalink / raw)
  To: linux-bluetooth

When the discoverable timeout triggers and it is time to turn inquiry
scan back off, use the HCI request framework to do it.

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

diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 7add9c9..c53f7f9 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1789,6 +1789,7 @@ static void hci_power_off(struct work_struct *work)
 static void hci_discov_off(struct work_struct *work)
 {
 	struct hci_dev *hdev;
+	struct hci_request req;
 	u8 scan = SCAN_PAGE;
 
 	hdev = container_of(work, struct hci_dev, discov_off.work);
@@ -1797,7 +1798,9 @@ static void hci_discov_off(struct work_struct *work)
 
 	hci_dev_lock(hdev);
 
-	hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
+	hci_req_init(&req, hdev);
+	hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
+	hci_req_run(&req, NULL);
 
 	hdev->discov_timeout = 0;
 
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH 1/2] Bluetooth: Add support for entering limited discoverable mode
From: Marcel Holtmann @ 2013-10-15 13:33 UTC (permalink / raw)
  To: linux-bluetooth

The limited discoverable mode should be used when a device is only
discoverable for a certain amount of time and after that it returns
back into being non-discoverable.

The management interface allows to specify a timeout parameter when
makeing a device discoverable. If such a timeout is specified or
changed, enter limited discoverable mode. Otherwise enter general
discoverable mode.

Devices in limited discoverable mode can still be found by the
general discovery procedure. It is mandatory that a device sets
both GIAC and LIAC when entering limited discoverable mode.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 include/net/bluetooth/hci.h |  6 ++++++
 net/bluetooth/mgmt.c        | 41 +++++++++++++++++++++++++++++++++++++----
 2 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index b096f5f..ab96f3b 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -823,6 +823,12 @@ struct hci_rp_read_num_supported_iac {
 
 #define HCI_OP_READ_CURRENT_IAC_LAP	0x0c39
 
+#define HCI_OP_WRITE_CURRENT_IAC_LAP	0x0c3a
+struct hci_cp_write_current_iac_lap {
+	__u8	num_iac;
+	__u8	iac_lap[6];
+} __packed;
+
 #define HCI_OP_WRITE_INQUIRY_MODE	0x0c45
 
 #define HCI_MAX_EIR_LENGTH		240
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 861e389..cba15da 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1041,6 +1041,8 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
 	}
 
 	if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
+		u16 current_timeout = hdev->discov_timeout;
+
 		if (hdev->discov_timeout > 0) {
 			cancel_delayed_work(&hdev->discov_off);
 			hdev->discov_timeout = 0;
@@ -1052,8 +1054,16 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
 				msecs_to_jiffies(hdev->discov_timeout * 1000));
 		}
 
-		err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
-		goto failed;
+		/* A change in timeout means that the device is switching
+		 * from one discoverable mode to another. In that case
+		 * the IAC LAP needs to be changed.
+		 */
+		if ((current_timeout > 0 && timeout > 0) ||
+		    (current_timeout == 0 && timeout == 0)) {
+			err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE,
+						hdev);
+			goto failed;
+		}
 	}
 
 	cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
@@ -1066,10 +1076,33 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
 
 	scan = SCAN_PAGE;
 
-	if (cp->val)
+	if (cp->val) {
+		struct hci_cp_write_current_iac_lap cp;
+
+		if (timeout > 0) {
+			/* Limited discoverable mode */
+			cp.num_iac = 2;
+			cp.iac_lap[0] = 0x00;	/* LIAC */
+			cp.iac_lap[1] = 0x8b;
+			cp.iac_lap[2] = 0x9e;
+			cp.iac_lap[3] = 0x33;	/* GIAC */
+			cp.iac_lap[4] = 0x8b;
+			cp.iac_lap[5] = 0x9e;
+		} else {
+			/* General discoverable mode */
+			cp.num_iac = 1;
+			cp.iac_lap[0] = 0x33;	/* GIAC */
+			cp.iac_lap[1] = 0x8b;
+			cp.iac_lap[2] = 0x9e;
+		}
+
+		hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
+			    (cp.num_iac * 3) + 1, &cp);
+
 		scan |= SCAN_INQUIRY;
-	else
+	} else {
 		cancel_delayed_work(&hdev->discov_off);
+	}
 
 	hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
 
-- 
1.8.3.1


^ permalink raw reply related

* BlueZ and Android - question
From: Kevin Wilson @ 2013-10-15 13:16 UTC (permalink / raw)
  To: linux-bluetooth

Hello all,
I have a question:

I saw in several places on the web text which says, in some
variations,  that "BlueZ has been removed starting from Android  4.2
and the  Broadcom-supplied Bluetooth stack (bluedroid) has replaced
it. It says also that the bluedroid
stack relies on HAL-loading like most other hardware types.

On the other hand I see in the official page,
http://www.bluez.org/
something which I am not sure how to interpret.


I want to resolve my confusion.
So here is my question:
In Android 4.2 and above - is the BlueZ removed ? is the BlueDroid
used instead ? or are they both used?


Regads,
Kevin

^ permalink raw reply

* [PATCH v2 5/5] android: Add calls to adapter methods in haltest
From: Jerzy Kasenberg @ 2013-10-15 13:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1381842800-3554-1-git-send-email-jerzy.kasenberg@tieto.com>

This is first code that actually calls HAL functions.
Functions defined in bt_interface_t can be executed.
---
 android/Android.mk           |    1 +
 android/hal-client/haltest.c |   79 +++++-
 android/hal-client/if_bt.c   |  631 ++++++++++++++++++++++++++++++++++++++++++
 android/hal-client/if_main.h |   99 +++++++
 4 files changed, 809 insertions(+), 1 deletion(-)
 create mode 100644 android/hal-client/if_bt.c
 create mode 100644 android/hal-client/if_main.h

diff --git a/android/Android.mk b/android/Android.mk
index d2cbdac..229f106 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -62,6 +62,7 @@ LOCAL_SRC_FILES := \
 	hal-client/terminal.c \
 	hal-client/history.c \
 	hal-client/textconv.c \
+	hal-client/if_bt.c \
 
 LOCAL_SHARED_LIBRARIES := libhardware
 
diff --git a/android/hal-client/haltest.c b/android/hal-client/haltest.c
index edde0ee..ca80d66 100644
--- a/android/hal-client/haltest.c
+++ b/android/hal-client/haltest.c
@@ -16,11 +16,53 @@
  */
 
 #include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
 #include <poll.h>
 #include <unistd.h>
 
+#include "if_main.h"
 #include "terminal.h"
 #include "pollhandler.h"
+#include "history.h"
+
+const struct interface *interfaces[] = {
+	&bluetooth_if,
+	NULL
+};
+
+int haltest_error(const char *format, ...)
+{
+	va_list args;
+	int ret;
+	va_start(args, format);
+	ret = terminal_vprint(format, args);
+	va_end(args);
+	return ret;
+}
+
+int haltest_info(const char *format, ...)
+{
+	va_list args;
+	int ret;
+	va_start(args, format);
+	ret = terminal_vprint(format, args);
+	va_end(args);
+	return ret;
+}
+
+int haltest_warn(const char *format, ...)
+{
+	va_list args;
+	int ret;
+	va_start(args, format);
+	ret = terminal_vprint(format, args);
+	va_end(args);
+	return ret;
+}
 
 /*
  * This function changes input parameter line_buffer so it has
@@ -48,10 +90,44 @@ static void process_line(char *line_buffer)
 {
 	char *argv[10];
 	int argc;
+	int i = 0;
+	int j;
 
 	argc = command_line_to_argv(line_buffer, argv, 10);
+	if (argc < 1)
+		return;
+
+	while (interfaces[i] != NULL) {
+		if (strcmp(interfaces[i]->name, argv[0])) {
+			i++;
+			continue;
+		}
+		if (argc < 2 || strcmp(argv[1], "?") == 0) {
+			j = 0;
+			while (strcmp(interfaces[i]->methods[j].name, "")) {
+				haltest_info("%s %s\n", argv[0],
+						interfaces[i]->methods[j].name);
+				++j;
+			}
+			return;
+		}
+		j = 0;
+		while (strcmp(interfaces[i]->methods[j].name, "")) {
+			if (strcmp(interfaces[i]->methods[j].name, argv[1])) {
+				j++;
+				continue;
+			}
+			interfaces[i]->methods[j].func(argc,
+							(const char **)argv);
+			break;
+		}
+		if (strcmp(interfaces[i]->methods[j].name, "") == 0)
+			printf("No function %s found\n", argv[1]);
+		break;
+	}
 
-	/* TODO: process command line */
+	if (interfaces[i] == NULL)
+		printf("No such interface %s\n", argv[0]);
 }
 
 /* called when there is something on stdin */
@@ -74,6 +150,7 @@ static void stdin_handler(struct pollfd *pollfd)
 int main(int argc, char **argv)
 {
 	terminal_setup();
+	history_restore(".haltest_history");
 
 	/* Register command line handler */
 	poll_register_fd(0, POLLIN, stdin_handler);
diff --git a/android/hal-client/if_bt.c b/android/hal-client/if_bt.c
new file mode 100644
index 0000000..fa65737
--- /dev/null
+++ b/android/hal-client/if_bt.c
@@ -0,0 +1,631 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "if_main.h"
+
+const bt_interface_t *if_bluetooth;
+
+static char *bdaddr2str(const bt_bdaddr_t *bd_addr)
+{
+	static char buf[18];
+
+	return bt_bdaddr_t2str(bd_addr, buf);
+}
+
+static char *btuuid2str(const bt_uuid_t *uuid)
+{
+	static char buf[39];
+
+	return bt_uuid_t2str(uuid, buf);
+}
+
+static bt_scan_mode_t str2btscanmode(const char *str)
+{
+	bt_scan_mode_t v = str2bt_scan_mode_t(str);
+
+	if ((int)v != -1)
+		return v;
+
+	haltest_warn("WARN: %s cannot convert %s\n", __func__, str);
+	return (bt_scan_mode_t)atoi(str);
+}
+
+static bt_ssp_variant_t str2btsspvariant(const char *str)
+{
+	bt_ssp_variant_t v = str2bt_ssp_variant_t(str);
+
+	if ((int)v != -1)
+		return v;
+
+	haltest_warn("WARN: %s cannot convert %s\n", __func__, str);
+	return (bt_ssp_variant_t)atoi(str);
+}
+
+static bt_property_type_t str2btpropertytype(const char *str)
+{
+	bt_property_type_t v = str2bt_property_type_t(str);
+
+	if ((int)v != -1)
+		return v;
+
+	haltest_warn("WARN: %s cannot convert %s\n", __func__, str);
+	return (bt_property_type_t)atoi(str);
+}
+
+static char *btproperty2str(bt_property_t property)
+{
+	static char buf[4096];
+	char *p;
+
+	p = buf + sprintf(buf, "type=%s len=%d val=",
+			  bt_property_type_t2str(property.type), property.len);
+
+	switch (property.type) {
+	case BT_PROPERTY_BDNAME:
+	case BT_PROPERTY_REMOTE_FRIENDLY_NAME:
+		sprintf(p, "%*s", property.len,
+			((bt_bdname_t *) property.val)->name);
+		break;
+
+	case BT_PROPERTY_BDADDR:
+		sprintf(p, "%s", bdaddr2str((bt_bdaddr_t *)property.val));
+		break;
+
+	case BT_PROPERTY_CLASS_OF_DEVICE:
+		sprintf(p, "%06x", *((int *)property.val));
+		break;
+
+	case BT_PROPERTY_TYPE_OF_DEVICE:
+		sprintf(p, "%s", bt_device_type_t2str(
+					*((bt_device_type_t *)property.val)));
+		break;
+
+	case BT_PROPERTY_REMOTE_RSSI:
+		sprintf(p, "%d", *((char *)property.val));
+		break;
+
+	case BT_PROPERTY_ADAPTER_SCAN_MODE:
+		sprintf(p, "%s",
+			bt_scan_mode_t2str(*((bt_scan_mode_t *)property.val)));
+		break;
+
+	case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+		sprintf(p, "%d", *((int *)property.val));
+		break;
+
+	case BT_PROPERTY_ADAPTER_BONDED_DEVICES:
+		{
+			int count = property.len / sizeof(bt_bdaddr_t);
+			char *ptr = property.val;
+
+			strcat(p, "{");
+
+			while (count--) {
+				strcat(p, bdaddr2str((bt_bdaddr_t *)ptr));
+				if (count)
+					strcat(p, ", ");
+				ptr += sizeof(bt_bdaddr_t);
+			}
+
+			strcat(p, "}");
+
+		}
+		break;
+
+	case BT_PROPERTY_UUIDS:
+		{
+			int count = property.len / sizeof(bt_uuid_t);
+			char *ptr = property.val;
+
+			strcat(p, "{");
+
+			while (count--) {
+				strcat(p, btuuid2str((bt_uuid_t *)ptr));
+				if (count)
+					strcat(p, ", ");
+				ptr += sizeof(bt_uuid_t);
+			}
+
+			strcat(p, "}");
+
+		}
+		break;
+
+	case BT_PROPERTY_SERVICE_RECORD:
+		{
+			bt_service_record_t *rec = property.val;
+
+			sprintf(p, "{%s, %d, %s}", btuuid2str(&rec->uuid),
+				rec->channel, rec->name);
+		}
+		break;
+
+	default:
+		sprintf(p, "%p", property.val);
+	}
+
+	return buf;
+}
+
+static void dump_properties(int num_properties, bt_property_t *properties)
+{
+	int i;
+
+	for (i = 0; i < num_properties; i++) {
+		/*
+		 * properities sometimes come unaligned hence memcp to
+		 * aligned buffer
+		 */
+		bt_property_t prop;
+		memcpy(&prop, properties + i, sizeof(prop));
+
+		haltest_info("prop: %s\n", btproperty2str(prop));
+	}
+}
+
+static void adapter_state_changed_cb(bt_state_t state)
+{
+	haltest_info("%s: state=%s\n", __func__, bt_state_t2str(state));
+}
+
+static void adapter_properties_cb(bt_status_t status,
+	int num_properties, bt_property_t *properties)
+{
+	haltest_info("%s: status=%s num_properties=%d\n",
+	       __func__, bt_status_t2str(status), num_properties);
+
+	dump_properties(num_properties, properties);
+}
+
+static void remote_device_properties_cb(bt_status_t status,
+	bt_bdaddr_t *bd_addr, int num_properties, bt_property_t *properties)
+{
+	haltest_info("%s: status=%s bd_addr=%s num_properties=%d\n",
+	       __func__, bt_status_t2str(status), bdaddr2str(bd_addr),
+	       num_properties);
+
+	dump_properties(num_properties, properties);
+}
+
+static void device_found_cb(int num_properties, bt_property_t *properties)
+{
+	haltest_info("%s: num_properties=%d\n", __func__, num_properties);
+
+	dump_properties(num_properties, properties);
+}
+
+static void discovery_state_changed_cb(bt_discovery_state_t state)
+{
+	haltest_info("%s: state=%s\n", __func__,
+		bt_discovery_state_t2str(state));
+}
+
+static void pin_request_cb(bt_bdaddr_t *remote_bd_addr, bt_bdname_t *bd_name,
+	uint32_t cod)
+{
+	haltest_info("%s: remote_bd_addr=%s bd_name=%s cod=%06x\n", __func__,
+			       bdaddr2str(remote_bd_addr), bd_name->name, cod);
+}
+
+static void ssp_request_cb(bt_bdaddr_t *remote_bd_addr, bt_bdname_t *bd_name,
+				uint32_t cod, bt_ssp_variant_t pairing_variant,
+				uint32_t pass_key)
+{
+	haltest_info("%s: remote_bd_addr=%s bd_name=%s cod=%06x pairing_variant=%s pass_key=%d\n",
+		     __func__, bdaddr2str(remote_bd_addr), bd_name->name, cod,
+		     bt_ssp_variant_t2str(pairing_variant), pass_key);
+}
+
+static void bond_state_changed_cb(bt_status_t status,
+					bt_bdaddr_t *remote_bd_addr,
+					bt_bond_state_t state)
+{
+	haltest_info("%s: status=%s remote_bd_addr=%s state=%s\n", __func__,
+		       bt_status_t2str(status), bdaddr2str(remote_bd_addr),
+		       bt_bond_state_t2str(state));
+}
+
+static void acl_state_changed_cb(bt_status_t status,
+					bt_bdaddr_t *remote_bd_addr,
+					bt_acl_state_t state)
+{
+	haltest_info("%s: status=%s remote_bd_addr=%s state=%s\n", __func__,
+		       bt_status_t2str(status), bdaddr2str(remote_bd_addr),
+		       bt_acl_state_t2str(state));
+}
+
+static void thread_evt_cb(bt_cb_thread_evt evt)
+{
+	haltest_info("%s: evt=%s\n", __func__, bt_cb_thread_evt2str(evt));
+}
+
+static void dut_mode_recv_cb(uint16_t opcode, uint8_t *buf, uint8_t len)
+{
+	haltest_info("%s\n", __func__);
+}
+
+static void le_test_mode_cb(bt_status_t status, uint16_t num_packets)
+{
+	haltest_info("%s %s %d\n", __func__, bt_state_t2str(status),
+								num_packets);
+}
+
+static bt_callbacks_t bt_callbacks = {
+	sizeof(bt_callbacks),
+	adapter_state_changed_cb,
+	adapter_properties_cb,
+	remote_device_properties_cb,
+	device_found_cb,
+	discovery_state_changed_cb,
+	pin_request_cb,
+	ssp_request_cb,
+	bond_state_changed_cb,
+	acl_state_changed_cb,
+	thread_evt_cb,
+	dut_mode_recv_cb,
+	le_test_mode_cb
+};
+
+static void init_p(int argc, const char **argv)
+{
+	int err;
+	const hw_module_t *module;
+	hw_device_t *device;
+
+	err = hw_get_module(BT_HARDWARE_MODULE_ID, &module);
+	if (err) {
+		haltest_error("he_get_module returned %d\n", err);
+		return;
+	}
+
+	err = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
+	if (err) {
+		haltest_error("module->methods->open returned %d\n", err);
+		return;
+	}
+
+	if_bluetooth =
+	    ((bluetooth_device_t *)device)->get_bluetooth_interface();
+	if (!if_bluetooth) {
+		haltest_error("get_bluetooth_interface returned NULL\n");
+		return;
+	}
+
+	EXEC(if_bluetooth->init, &bt_callbacks);
+}
+
+static void cleanup_p(int argc, const char **argv)
+{
+	RETURN_IF_NULL(if_bluetooth);
+
+	EXECV(if_bluetooth->cleanup);
+
+	if_bluetooth = NULL;
+}
+
+static void enable_p(int argc, const char **argv)
+{
+	RETURN_IF_NULL(if_bluetooth);
+
+	EXEC(if_bluetooth->enable);
+}
+
+static void disable_p(int argc, const char **argv)
+{
+	RETURN_IF_NULL(if_bluetooth);
+
+	EXEC(if_bluetooth->disable);
+}
+
+static void get_adapter_properties_p(int argc, const char **argv)
+{
+	RETURN_IF_NULL(if_bluetooth);
+
+	EXEC(if_bluetooth->get_adapter_properties);
+}
+
+static void get_adapter_property_p(int argc, const char **argv)
+{
+	int type = str2btpropertytype(argv[2]);
+
+	RETURN_IF_NULL(if_bluetooth);
+
+	EXEC(if_bluetooth->get_adapter_property, type);
+}
+
+static void set_adapter_property_p(int argc, const char **argv)
+{
+	bt_property_t property;
+	bt_scan_mode_t mode;
+	int timeout;
+
+	RETURN_IF_NULL(if_bluetooth);
+
+	property.type = str2btpropertytype(argv[2]);
+
+	switch (property.type) {
+	case BT_PROPERTY_BDNAME:
+		property.len = strlen(argv[3]) + 1;
+		property.val = (char *)argv[3];
+		break;
+
+	case BT_PROPERTY_ADAPTER_SCAN_MODE:
+		mode = str2btscanmode(argv[3]);
+		property.len = sizeof(bt_scan_mode_t);
+		property.val = &mode;
+		break;
+
+	case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+		timeout = atoi(argv[3]);
+		property.val = &timeout;
+		property.len = sizeof(timeout);
+		break;
+
+	default:
+		haltest_error("Invalid property %s\n", argv[3]);
+		return;
+	}
+
+	EXEC(if_bluetooth->set_adapter_property, &property);
+}
+
+static void get_remote_device_properties_p(int argc, const char **argv)
+{
+	bt_bdaddr_t addr;
+
+	RETURN_IF_NULL(if_bluetooth);
+
+	str2bt_bdaddr_t(argv[2], &addr);
+
+	EXEC(if_bluetooth->get_remote_device_properties, &addr);
+}
+
+static void get_remote_device_property_p(int argc, const char **argv)
+{
+	bt_property_type_t type;
+	bt_bdaddr_t addr;
+
+	RETURN_IF_NULL(if_bluetooth);
+
+	str2bt_bdaddr_t(argv[2], &addr);
+	type = str2btpropertytype(argv[3]);
+
+	EXEC(if_bluetooth->get_remote_device_property, &addr, type);
+}
+
+static void set_remote_device_property_p(int argc, const char **argv)
+{
+	bt_property_t property;
+	bt_bdaddr_t addr;
+
+	RETURN_IF_NULL(if_bluetooth);
+
+	str2bt_bdaddr_t(argv[2], &addr);
+	property.type = str2btpropertytype(argv[3]);
+
+	switch (property.type) {
+	case BT_PROPERTY_REMOTE_FRIENDLY_NAME:
+		property.len = strlen(argv[4]);
+		property.val = (char *)argv[4];
+		break;
+
+	default:
+		return;
+	}
+
+	EXEC(if_bluetooth->set_remote_device_property, &addr, &property);
+}
+
+static void get_remote_service_record_p(int argc, const char **argv)
+{
+	bt_bdaddr_t addr;
+	bt_uuid_t uuid;
+
+	RETURN_IF_NULL(if_bluetooth);
+
+	str2bt_bdaddr_t(argv[2], &addr);
+	str2bt_uuid_t(argv[3], &uuid);
+
+	EXEC(if_bluetooth->get_remote_service_record, &addr, &uuid);
+}
+
+static void get_remote_services_p(int argc, const char **argv)
+{
+	bt_bdaddr_t addr;
+
+	RETURN_IF_NULL(if_bluetooth);
+
+	str2bt_bdaddr_t(argv[2], &addr);
+
+	EXEC(if_bluetooth->get_remote_services, &addr);
+}
+
+static void start_discovery_p(int argc, const char **argv)
+{
+	RETURN_IF_NULL(if_bluetooth);
+
+	EXEC(if_bluetooth->start_discovery);
+}
+
+static void cancel_discovery_p(int argc, const char **argv)
+{
+	RETURN_IF_NULL(if_bluetooth);
+
+	EXEC(if_bluetooth->cancel_discovery);
+}
+
+static void create_bond_p(int argc, const char **argv)
+{
+	bt_bdaddr_t addr;
+
+	RETURN_IF_NULL(if_bluetooth);
+
+	str2bt_bdaddr_t(argv[2], &addr);
+
+	EXEC(if_bluetooth->create_bond, &addr);
+}
+
+static void remove_bond_p(int argc, const char **argv)
+{
+	bt_bdaddr_t addr;
+
+	RETURN_IF_NULL(if_bluetooth);
+
+	str2bt_bdaddr_t(argv[2], &addr);
+
+	EXEC(if_bluetooth->remove_bond, &addr);
+}
+
+static void cancel_bond_p(int argc, const char **argv)
+{
+	bt_bdaddr_t addr;
+
+	RETURN_IF_NULL(if_bluetooth);
+
+	str2bt_bdaddr_t(argv[2], &addr);
+
+	EXEC(if_bluetooth->cancel_bond, &addr);
+}
+
+static void pin_reply_p(int argc, const char **argv)
+{
+	bt_bdaddr_t addr;
+	bt_pin_code_t pin;
+	int pin_len = 0;
+	int accept;
+
+	RETURN_IF_NULL(if_bluetooth);
+
+	if (argc < 3) {
+		haltest_error("No address specified\n");
+		return;
+	}
+	str2bt_bdaddr_t(argv[2], &addr);
+
+	if (argc >= 4) {
+		accept = 1;
+		pin_len = strlen(argv[3]);
+		memcpy(pin.pin, argv[3], pin_len);
+	}
+
+	EXEC(if_bluetooth->pin_reply, &addr, accept, pin_len, &pin);
+}
+
+static void ssp_reply_p(int argc, const char **argv)
+{
+	bt_bdaddr_t addr;
+	bt_ssp_variant_t var;
+	int accept;
+	int passkey;
+
+	RETURN_IF_NULL(if_bluetooth);
+
+	if (argc < 3) {
+		haltest_error("No address specified\n");
+		return;
+	}
+	str2bt_bdaddr_t(argv[2], &addr);
+	if (argc < 4) {
+		haltest_error("No ssp variant specified\n");
+		return;
+	}
+	var = str2btsspvariant(argv[3]);
+	if (argc < 5) {
+		haltest_error("No accept value specified\n");
+		return;
+	}
+	accept = atoi(argv[4]);
+	passkey = 0;
+
+	if (accept && var == BT_SSP_VARIANT_PASSKEY_ENTRY && argc >= 5)
+		passkey = atoi(argv[4]);
+
+	EXEC(if_bluetooth->ssp_reply, &addr, var, accept, passkey);
+}
+
+static void get_profile_interface_p(int argc, const char **argv)
+{
+	const char *id = argv[2];
+	const void **pif = NULL;
+	const void *dummy = NULL;
+
+	RETURN_IF_NULL(if_bluetooth);
+
+	if (strcmp(BT_PROFILE_HANDSFREE_ID, id) == 0)
+		pif = &dummy; /* TODO: chenge when if_hf is there */
+	else if (strcmp(BT_PROFILE_ADVANCED_AUDIO_ID, id) == 0)
+		pif = &dummy; /* TODO: chenge when if_av is there */
+	else if (strcmp(BT_PROFILE_HEALTH_ID, id) == 0)
+		pif = &dummy; /* TODO: chenge when if_hl is there */
+	else if (strcmp(BT_PROFILE_SOCKETS_ID, id) == 0)
+		pif = &dummy; /* TODO: chenge when if_sock is there */
+	else if (strcmp(BT_PROFILE_HIDHOST_ID, id) == 0)
+		pif = &dummy; /* TODO: chenge when if_hh is there */
+	else if (strcmp(BT_PROFILE_PAN_ID, id) == 0)
+		pif = &dummy; /* TODO: chenge when if_pan is there */
+	else if (strcmp(BT_PROFILE_AV_RC_ID, id) == 0)
+		pif = &dummy; /* TODO: chenge when if_rc is there */
+	else
+		haltest_error("%s is not correct for get_profile_interface\n",
+		     id);
+
+	if (pif != NULL) {
+		*pif = if_bluetooth->get_profile_interface(id);
+		haltest_info("get_profile_interface(%s) : %p\n", id, *pif);
+	}
+}
+
+static void dut_mode_configure_p(int argc, const char **argv)
+{
+	uint8_t mode;
+
+	RETURN_IF_NULL(if_bluetooth);
+
+	mode = strtol(argv[2], NULL, 0);
+
+	EXEC(if_bluetooth->dut_mode_configure, mode);
+}
+
+static struct method methods[] = {
+	STD_METHOD(init),
+	STD_METHOD(cleanup),
+	STD_METHOD(enable),
+	STD_METHOD(disable),
+	STD_METHOD(get_adapter_properties),
+	STD_METHOD(get_adapter_property),
+	STD_METHOD(set_adapter_property),
+	STD_METHOD(get_remote_device_properties),
+	STD_METHOD(get_remote_device_property),
+	STD_METHOD(set_remote_device_property),
+	STD_METHOD(get_remote_service_record),
+	STD_METHOD(get_remote_services),
+	STD_METHOD(start_discovery),
+	STD_METHOD(cancel_discovery),
+	STD_METHOD(create_bond),
+	STD_METHOD(remove_bond),
+	STD_METHOD(cancel_bond),
+	STD_METHOD(pin_reply),
+	STD_METHOD(ssp_reply),
+	STD_METHOD(get_profile_interface),
+	STD_METHOD(dut_mode_configure),
+	END_METHOD
+};
+
+const struct interface bluetooth_if = {
+	.name = "adapter",
+	.methods = methods
+};
diff --git a/android/hal-client/if_main.h b/android/hal-client/if_main.h
new file mode 100644
index 0000000..9cac7ef
--- /dev/null
+++ b/android/hal-client/if_main.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <poll.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_av.h>
+#include <hardware/bt_hh.h>
+#include <hardware/bt_pan.h>
+#include <hardware/bt_sock.h>
+#include <hardware/bt_hf.h>
+#include <hardware/bt_hl.h>
+#include <hardware/bt_rc.h>
+
+#include "textconv.h"
+
+/* Interfaces from hal that can be populated during application lifetime */
+extern const bt_interface_t *if_bluetooth;
+
+/*
+ * Structure defines top level interfaces that can be used in test tool
+ * this will contain values as: adapter, av, gatt, sock, pan...
+ */
+struct interface {
+	const char *name; /* interface name */
+	struct method *methods; /* methods available for this interface */
+};
+
+extern const struct interface bluetooth_if;
+
+/* Interfaces that will show up in tool (first part of command line) */
+extern const struct interface *interfaces[];
+
+#define METHOD(name, func) {name, func}
+#define STD_METHOD(m) {#m, m##_p}
+#define END_METHOD {"", NULL}
+
+/*
+ * Function to parse argument for function, argv[0] and argv[1] are already
+ * parsed before this function is called and contain interface and method name
+ * up to argc - 1 arguments are finished and should be used to decide which
+ * function enumeration function to return
+ */
+typedef void (*parse_and_call)(int argc, const char **argv);
+
+/*
+ * For each method there is name and two functions to parse command line
+ * and call proper hal function on.
+ */
+struct method {
+	const char *name;
+	parse_and_call func;
+};
+
+int haltest_error(const char *format, ...);
+int haltest_info(const char *format, ...);
+int haltest_warn(const char *format, ...);
+
+/* Helper macro for executing function on interface and printing BT_STATUS */
+#define EXEC(f, ...) \
+	{ \
+		int err = f(__VA_ARGS__); \
+		haltest_info("%s: %s\n", #f, bt_status_t2str(err)); \
+	}
+
+/* Helper macro for executing void function on interface */
+#define EXECV(f, ...) \
+	{ \
+		(void) f(__VA_ARGS__); \
+		haltest_info("%s: void\n", #f); \
+	}
+
+#define RETURN_IF_NULL(x) \
+	do { if (!x) { haltest_error("%s is NULL\n", #x); return; } } while (0)
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 4/5] android: Add text conversion helpers to haltest
From: Jerzy Kasenberg @ 2013-10-15 13:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1381842800-3554-1-git-send-email-jerzy.kasenberg@tieto.com>

Application uses a lot of text in the form of defines found in header
files to represent arguments and output.
Conversion helpers keep functionality of converting string as
bt_status_t or uuid in one place.
---
 android/Android.mk            |    1 +
 android/hal-client/textconv.c |  205 +++++++++++++++++++++++++++++++++++++++++
 android/hal-client/textconv.h |  113 +++++++++++++++++++++++
 3 files changed, 319 insertions(+)
 create mode 100644 android/hal-client/textconv.c
 create mode 100644 android/hal-client/textconv.h

diff --git a/android/Android.mk b/android/Android.mk
index a8daf92..d2cbdac 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -61,6 +61,7 @@ LOCAL_SRC_FILES := \
 	hal-client/pollhandler.c \
 	hal-client/terminal.c \
 	hal-client/history.c \
+	hal-client/textconv.c \
 
 LOCAL_SHARED_LIBRARIES := libhardware
 
diff --git a/android/hal-client/textconv.c b/android/hal-client/textconv.c
new file mode 100644
index 0000000..2de729d
--- /dev/null
+++ b/android/hal-client/textconv.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <hardware/bluetooth.h>
+
+#include "textconv.h"
+
+/*
+ * Following are maps of defines found in bluetooth header files to strings
+ *
+ * Those mappings are used to accurately use defines as input parameters in
+ * command line as well as for printing of statuses
+ */
+
+INTMAP(bt_status_t, -1, "(unknown)")
+	DELEMENT(BT_STATUS_SUCCESS),
+	DELEMENT(BT_STATUS_FAIL),
+	DELEMENT(BT_STATUS_NOT_READY),
+	DELEMENT(BT_STATUS_NOMEM),
+	DELEMENT(BT_STATUS_BUSY),
+	DELEMENT(BT_STATUS_DONE),
+	DELEMENT(BT_STATUS_UNSUPPORTED),
+	DELEMENT(BT_STATUS_PARM_INVALID),
+	DELEMENT(BT_STATUS_UNHANDLED),
+	DELEMENT(BT_STATUS_AUTH_FAILURE),
+	DELEMENT(BT_STATUS_RMT_DEV_DOWN),
+ENDMAP
+
+INTMAP(bt_state_t, -1, "(unknown)")
+	DELEMENT(BT_STATE_OFF),
+	DELEMENT(BT_STATE_ON),
+ENDMAP
+
+INTMAP(bt_device_type_t, -1, "(unknown)")
+	DELEMENT(BT_DEVICE_DEVTYPE_BREDR),
+	DELEMENT(BT_DEVICE_DEVTYPE_BLE),
+	DELEMENT(BT_DEVICE_DEVTYPE_DUAL),
+ENDMAP
+
+INTMAP(bt_scan_mode_t, -1, "(unknown)")
+	DELEMENT(BT_SCAN_MODE_NONE),
+	DELEMENT(BT_SCAN_MODE_CONNECTABLE),
+	DELEMENT(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE),
+ENDMAP
+
+INTMAP(bt_discovery_state_t, -1, "(unknown)")
+	DELEMENT(BT_DISCOVERY_STOPPED),
+	DELEMENT(BT_DISCOVERY_STARTED),
+ENDMAP
+
+INTMAP(bt_acl_state_t, -1, "(unknown)")
+	DELEMENT(BT_ACL_STATE_CONNECTED),
+	DELEMENT(BT_ACL_STATE_DISCONNECTED),
+ENDMAP
+
+INTMAP(bt_bond_state_t, -1, "(unknown)")
+	DELEMENT(BT_BOND_STATE_NONE),
+	DELEMENT(BT_BOND_STATE_BONDING),
+	DELEMENT(BT_BOND_STATE_BONDED),
+ENDMAP
+
+INTMAP(bt_ssp_variant_t, -1, "(unknown)")
+	DELEMENT(BT_SSP_VARIANT_PASSKEY_CONFIRMATION),
+	DELEMENT(BT_SSP_VARIANT_PASSKEY_ENTRY),
+	DELEMENT(BT_SSP_VARIANT_CONSENT),
+	DELEMENT(BT_SSP_VARIANT_PASSKEY_NOTIFICATION),
+ENDMAP
+
+INTMAP(bt_property_type_t, -1, "(unknown)")
+	DELEMENT(BT_PROPERTY_BDNAME),
+	DELEMENT(BT_PROPERTY_BDADDR),
+	DELEMENT(BT_PROPERTY_UUIDS),
+	DELEMENT(BT_PROPERTY_CLASS_OF_DEVICE),
+	DELEMENT(BT_PROPERTY_TYPE_OF_DEVICE),
+	DELEMENT(BT_PROPERTY_SERVICE_RECORD),
+	DELEMENT(BT_PROPERTY_ADAPTER_SCAN_MODE),
+	DELEMENT(BT_PROPERTY_ADAPTER_BONDED_DEVICES),
+	DELEMENT(BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT),
+	DELEMENT(BT_PROPERTY_REMOTE_FRIENDLY_NAME),
+	DELEMENT(BT_PROPERTY_REMOTE_RSSI),
+	DELEMENT(BT_PROPERTY_REMOTE_VERSION_INFO),
+	DELEMENT(BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP),
+ENDMAP
+
+INTMAP(bt_cb_thread_evt, -1, "(unknown)")
+	DELEMENT(ASSOCIATE_JVM),
+	DELEMENT(DISASSOCIATE_JVM),
+ENDMAP
+
+/* Find first index of given value in table m */
+int int2str_findint(int v, const struct int2str m[])
+{
+	int i;
+
+	for (i = 0; m[i].str; ++i) {
+		if (m[i].val == v)
+			return i;
+	}
+	return -1;
+}
+
+/* Find first index of given string in table m */
+int int2str_findstr(const char *str, const struct int2str m[])
+{
+	int i;
+
+	for (i = 0; m[i].str; ++i) {
+		if (strcmp(m[i].str, str) == 0)
+			return i;
+	}
+	return -1;
+}
+
+/*
+ * convert bd_addr to string
+ * buf must be at least 18 char long
+ *
+ * returns buf
+ */
+char *bt_bdaddr_t2str(const bt_bdaddr_t *bd_addr, char *buf)
+{
+	const char *p = (const char *)bd_addr;
+
+	snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
+					p[0], p[1], p[2], p[3], p[4], p[5]);
+
+	return buf;
+}
+
+/* converts string to bt_bdaddr_t */
+void str2bt_bdaddr_t(const char *str, bt_bdaddr_t *bd_addr)
+{
+	char *p = (char *)bd_addr;
+
+	sscanf(str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+			       &p[0], &p[1], &p[2], &p[3], &p[4], &p[5]);
+}
+
+static const char BT_BASE_UUID[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+	0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
+};
+
+/*
+ * converts uuid to string
+ * buf should be at least 39 bytes
+ *
+ * returns string representation of uuid
+ */
+char *bt_uuid_t2str(const bt_uuid_t *uuid, char *buf)
+{
+	int shift = 0;
+	int i;
+	int is_bt;
+
+	is_bt = !memcmp(&uuid->uu[4], &BT_BASE_UUID[4], sizeof(bt_uuid_t) - 4);
+
+	for (i = 0; i < (int)sizeof(bt_uuid_t); i++) {
+		if (i == 4 && is_bt)
+			break;
+
+		if (i == 4 || i == 6 || i == 8 || i == 10) {
+			buf[i * 2 + shift] = '-';
+			shift++;
+		}
+		sprintf(buf + i * 2 + shift, "%02x", uuid->uu[i]);
+	}
+
+	return buf;
+}
+
+/* converts string to uuid */
+void str2bt_uuid_t(const char *str, bt_uuid_t *uuid)
+{
+	int i = 0;
+
+	memcpy(uuid, BT_BASE_UUID, sizeof(bt_uuid_t));
+
+	while (*str && i < (int)sizeof(bt_uuid_t)) {
+		while (*str == '-')
+			str++;
+
+		if (sscanf(str, "%02hhx", &uuid->uu[i]) != 1)
+			break;
+
+		i++;
+		str += 2;
+	}
+}
diff --git a/android/hal-client/textconv.h b/android/hal-client/textconv.h
new file mode 100644
index 0000000..80aaf7b
--- /dev/null
+++ b/android/hal-client/textconv.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/**
+ * Begin mapping section
+ *
+ * There are some mappings between integer values (enums) and strings
+ * to be presented to user. To make it easier to convert between those two
+ * set of macros is given. It is specially useful when we want to have
+ * strings that match constants from header files like:
+ *  BT_STATUS_SUCCESS (0) and corresponding "BT_STATUS_SUCCESS"
+ * Example of usage:
+ *
+ * INTMAP(int, -1, "invalid")
+ *   DELEMENT(BT_STATUS_SUCCESS)
+ *   DELEMENT(BT_STATUS_FAIL)
+ *   MELEMENT(123, "Some strange value")
+ * ENDMAP
+ *
+ * Just by doing this we have mapping table plus two functions:
+ *  int str2int(const char *str);
+ *  const char *int2str(int v);
+ *
+ * second argument to INTMAP specifies value to be returned from
+ * str2int function when there is not mapping for such number
+ * third argument specifies default value to be returned from int2str
+ *
+ * If same mapping is to be used in several source files put
+ * INTMAP in c file and DECINTMAP in h file.
+ *
+ * For mappings that are to be used in single file only
+ * use SINTMAP which will create the same but everything will be marked
+ * as static.
+ */
+
+struct int2str {
+	int val;		/* int value */
+	const char *str;	/* corresponding string */
+};
+
+int int2str_findint(int v, const struct int2str m[]);
+int int2str_findstr(const char *str, const struct int2str m[]);
+
+#define DECINTMAP(type) \
+extern struct int2str __##type##2str[]; \
+const char *type##2##str(type v); \
+type str##2##type(const char *str); \
+
+#define INTMAP(type, deft, defs) \
+const char *type##2##str(type v) \
+{ \
+	int i = int2str_findint((int)v, __##type##2str); \
+	return (i < 0) ? defs : __##type##2str[i].str; \
+} \
+type str##2##type(const char *str) \
+{ \
+	int i = int2str_findstr(str, __##type##2str); \
+	return (i < 0) ? (type)deft : (type)(__##type##2str[i].val); \
+} \
+struct int2str __##type##2str[] = {
+
+#define SINTMAP(type, deft, defs) \
+static struct int2str __##type##2str[]; \
+static inline const char *type##2##str(type v) \
+{ \
+	int i = int2str_findint((int)v, __##type##2str); \
+	return (i < 0) ? defs : __##type##2str[i].str; \
+} \
+static inline type str##2##type(const char *str) \
+{ \
+	int i = int2str_findstr(str, __##type##2str); \
+	return (i < 0) ? (type)deft : (type)(__##type##2str[i].val); \
+} \
+static struct int2str __##type##2str[] = {
+
+#define ENDMAP {0, NULL} };
+
+/* use this to generate string from header file constant */
+#define MELEMENT(v, s) {v, s}
+/* use this to have arbitrary mapping from int to string */
+#define DELEMENT(s) {s, #s}
+/* End of mapping section */
+
+char *bt_bdaddr_t2str(const bt_bdaddr_t *bd_addr, char *buf);
+void str2bt_bdaddr_t(const char *str, bt_bdaddr_t *bd_addr);
+
+char *bt_uuid_t2str(const bt_uuid_t *uuid, char *buf);
+void str2bt_uuid_t(const char *str, bt_uuid_t *uuid);
+
+DECINTMAP(bt_status_t);
+DECINTMAP(bt_state_t);
+DECINTMAP(bt_device_type_t);
+DECINTMAP(bt_scan_mode_t);
+DECINTMAP(bt_discovery_state_t);
+DECINTMAP(bt_acl_state_t);
+DECINTMAP(bt_bond_state_t);
+DECINTMAP(bt_ssp_variant_t);
+DECINTMAP(bt_property_type_t);
+DECINTMAP(bt_cb_thread_evt);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 3/5] android: Add history to line editor in haltest
From: Jerzy Kasenberg @ 2013-10-15 13:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1381842800-3554-1-git-send-email-jerzy.kasenberg@tieto.com>

Added simple history to editor to save time.
---
 android/Android.mk            |    1 +
 android/hal-client/history.c  |   98 +++++++++++++++++++++++++++++++++++++
 android/hal-client/history.h  |   21 ++++++++
 android/hal-client/terminal.c |  106 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 226 insertions(+)
 create mode 100644 android/hal-client/history.c
 create mode 100644 android/hal-client/history.h

diff --git a/android/Android.mk b/android/Android.mk
index 292c50e..a8daf92 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -60,6 +60,7 @@ LOCAL_SRC_FILES := \
 	hal-client/haltest.c \
 	hal-client/pollhandler.c \
 	hal-client/terminal.c \
+	hal-client/history.c \
 
 LOCAL_SHARED_LIBRARIES := libhardware
 
diff --git a/android/hal-client/history.c b/android/hal-client/history.c
new file mode 100644
index 0000000..90d9952
--- /dev/null
+++ b/android/hal-client/history.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "history.h"
+
+/*
+ * Very simple history storage for easy usage of tool
+ */
+
+#define HISTORY_DEPTH 20
+#define LINE_SIZE 100
+static char lines[HISTORY_DEPTH][LINE_SIZE];
+static int last_line = 0;
+static int history_size = 0;
+
+/* TODO: Storing history not implemented yet */
+void history_store(const char *filename)
+{
+}
+
+/* Restoring history from file */
+void history_restore(const char *filename)
+{
+	char line[1000];
+	FILE *f = fopen(filename, "rt");
+
+	if (f == NULL)
+		return;
+
+	for (;;) {
+		if (fgets(line, 1000, f) != NULL) {
+			int l = strlen(line);
+			while (l > 0 && isspace(line[--l]))
+				line[l] = 0;
+			if (l > 0)
+				history_add_line(line);
+		} else
+			break;
+	}
+	fclose(f);
+}
+
+/* Add new line to history buffer */
+void history_add_line(const char *line)
+{
+	if (line == NULL || strlen(line) == 0)
+		return;
+
+	if (strcmp(line, lines[last_line]) == 0)
+		return;
+
+	last_line = (last_line + 1) % HISTORY_DEPTH;
+	strncpy(&lines[last_line][0], line, LINE_SIZE - 1);
+	if (history_size < HISTORY_DEPTH)
+		history_size++;
+}
+
+/*
+ * Get n-th line from history
+ * 0 - means latest
+ * -1 - means oldest
+ * return -1 if there is no such line
+ */
+int history_get_line(int n, char *buf, int buf_size)
+{
+	if (n == -1)
+		n = history_size - 1;
+
+	if (n >= history_size || buf_size == 0 || n < 0)
+		return -1;
+
+	strncpy(buf,
+		&lines[(HISTORY_DEPTH + last_line - n) % HISTORY_DEPTH][0],
+		buf_size - 1);
+	buf[buf_size - 1] = 0;
+
+	return n;
+}
+
diff --git a/android/hal-client/history.h b/android/hal-client/history.h
new file mode 100644
index 0000000..26085b5
--- /dev/null
+++ b/android/hal-client/history.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+void history_store(const char *filename);
+void history_restore(const char *filename);
+void history_add_line(const char *line);
+int history_get_line(int n, char *buf, int buf_size);
diff --git a/android/hal-client/terminal.c b/android/hal-client/terminal.c
index e449c71..a18d31c 100644
--- a/android/hal-client/terminal.c
+++ b/android/hal-client/terminal.c
@@ -22,6 +22,7 @@
 #include <termios.h>
 
 #include "terminal.h"
+#include "history.h"
 
 /*
  * Character sequences recognized by code in this file
@@ -107,6 +108,9 @@ static int line_buf_ix = 0;
 /* current length of input line */
 static int line_len = 0;
 
+/* line index used for fetching lines from history */
+static int line_index = 0;
+
 /*
  * Moves cursor to right or left
  *
@@ -187,6 +191,86 @@ int terminal_vprint(const char *format, va_list args)
 }
 
 /*
+ * Call this when text in line_buf was changed
+ * and line needs to be redrawn
+ */
+static void terminal_line_replaced(void)
+{
+	int len = strlen(line_buf);
+
+	/* line is shorter that previous */
+	if (len < line_len) {
+		/* if new line is shorter move cursor to end of new end */
+		while (line_buf_ix > len) {
+			putchar('\b');
+			line_buf_ix--;
+		}
+		/* If cursor was not at the end, move it to the end */
+		if (line_buf_ix < line_len)
+			printf("%.*s", line_len - line_buf_ix,
+					line_buf + line_buf_ix);
+		/* over write end of previous line */
+		while (line_len >= len++)
+			putchar(' ');
+	}
+	/* draw new line */
+	printf("\r>%s", line_buf);
+	/* set up indexes to new line */
+	line_len = line_buf_ix = strlen(line_buf);
+}
+
+/*
+ * Function tries to replace current line with specified line in history
+ * new_line_index - new line to show, -1 to show oldest
+ */
+static void terminal_get_line_from_history(int new_line_index)
+{
+	new_line_index = history_get_line(new_line_index,
+						line_buf, LINE_BUF_MAX);
+
+	if (new_line_index >= 0) {
+		terminal_line_replaced();
+		line_index = new_line_index;
+	}
+}
+
+/*
+ * Function searches history back or forward for command line that starts
+ * with characters up to cursor position
+ *
+ * back - true - searches backward
+ * back - false - searches forward (more recent commands)
+ */
+static void terminal_match_hitory(bool back)
+{
+	char buf[line_buf_ix + 1];
+	int line;
+	int matching_line = -1;
+	int dir = back ? 1 : -1;
+
+	line = line_index + dir;
+	while (matching_line == -1 && line >= 0) {
+		int new_line_index;
+
+		new_line_index = history_get_line(line, buf, line_buf_ix + 1);
+		if (new_line_index < 0)
+			break;
+
+		if (0 == strncmp(line_buf, buf, line_buf_ix))
+			matching_line = line;
+		line += dir;
+	}
+
+	if (matching_line >= 0) {
+		int pos = line_buf_ix;
+		terminal_get_line_from_history(matching_line);
+		/* move back to cursor position to origianl place */
+		line_buf_ix = pos;
+		terminal_move_cursor(pos - line_len);
+	}
+}
+
+/*
  * Converts terminal character sequences to single value representing
  * keyboard keys
  */
@@ -333,12 +417,29 @@ void terminal_process_char(int c, void (*process_line)(char *line))
 			printf("%.*s", (int)(line_buf_ix - old_pos),
 				line_buf + old_pos);
 		break;
+	case KEY_SUP:
+		terminal_get_line_from_history(-1);
+		break;
+	case KEY_SDOWN:
+		if (line_index > 0)
+			terminal_get_line_from_history(0);
+		break;
 	case KEY_UP:
+		terminal_get_line_from_history(line_index + 1);
+		break;
 	case KEY_DOWN:
+		if (line_index > 0)
+			terminal_get_line_from_history(line_index - 1);
 		break;
 	case '\n':
 	case '\r':
+		/*
+		 * On new line add line to history
+		 * forget history position
+		 */
+		history_add_line(line_buf);
 		line_len = line_buf_ix = 0;
+		line_index = -1;
 		/* print new line */
 		putchar(c);
 		process_line(line_buf);
@@ -380,7 +481,12 @@ void terminal_process_char(int c, void (*process_line)(char *line))
 	case KEY_MDOWN:
 	case KEY_STAB:
 	case KEY_M_n:
+		/* Search history forward */
+		terminal_match_hitory(false);
+		break;
 	case KEY_M_p:
+		/* Search history backward */
+		terminal_match_hitory(true);
 		break;
 	default:
 		if (!isprint(c)) {
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 2/5] android: Add line editing to haltest
From: Jerzy Kasenberg @ 2013-10-15 13:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1381842800-3554-1-git-send-email-jerzy.kasenberg@tieto.com>

Android does not have readline.
This patch allows to edit command line.
---
 android/Android.mk            |    1 +
 android/hal-client/haltest.c  |   39 +++-
 android/hal-client/terminal.c |  428 +++++++++++++++++++++++++++++++++++++++++
 android/hal-client/terminal.h |   59 ++++++
 4 files changed, 524 insertions(+), 3 deletions(-)
 create mode 100644 android/hal-client/terminal.c
 create mode 100644 android/hal-client/terminal.h

diff --git a/android/Android.mk b/android/Android.mk
index c84fbe3..292c50e 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -59,6 +59,7 @@ include $(CLEAR_VARS)
 LOCAL_SRC_FILES := \
 	hal-client/haltest.c \
 	hal-client/pollhandler.c \
+	hal-client/terminal.c \
 
 LOCAL_SHARED_LIBRARIES := libhardware
 
diff --git a/android/hal-client/haltest.c b/android/hal-client/haltest.c
index 11cdd97..edde0ee 100644
--- a/android/hal-client/haltest.c
+++ b/android/hal-client/haltest.c
@@ -19,8 +19,40 @@
 #include <poll.h>
 #include <unistd.h>
 
+#include "terminal.h"
 #include "pollhandler.h"
 
+/*
+ * This function changes input parameter line_buffer so it has
+ * null termination after each token (due to strtok)
+ * Output argv is filled with pointers to arguments
+ * returns number of tokens parsed - argc
+ */
+static int command_line_to_argv(char *line_buffer,
+				char *argv[], int argv_size)
+{
+	static const char *token_breaks = "\r\n\t ";
+	char *token;
+	int argc = 0;
+
+	token = strtok(line_buffer, token_breaks);
+	while (token != NULL && argc < (int)argv_size) {
+		argv[argc++] = token;
+		token = strtok(NULL, token_breaks);
+	}
+
+	return argc;
+}
+
+static void process_line(char *line_buffer)
+{
+	char *argv[10];
+	int argc;
+
+	argc = command_line_to_argv(line_buffer, argv, 10);
+
+	/* TODO: process command line */
+}
 
 /* called when there is something on stdin */
 static void stdin_handler(struct pollfd *pollfd)
@@ -33,15 +65,16 @@ static void stdin_handler(struct pollfd *pollfd)
 		if (count > 0) {
 			int i;
 
-			for (i = 0; i < count; ++i) {
-				/* TODO: process input */
-			}
+			for (i = 0; i < count; ++i)
+				terminal_process_char(buf[i], process_line);
 		}
 	}
 }
 
 int main(int argc, char **argv)
 {
+	terminal_setup();
+
 	/* Register command line handler */
 	poll_register_fd(0, POLLIN, stdin_handler);
 
diff --git a/android/hal-client/terminal.c b/android/hal-client/terminal.c
new file mode 100644
index 0000000..e449c71
--- /dev/null
+++ b/android/hal-client/terminal.c
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <termios.h>
+
+#include "terminal.h"
+
+/*
+ * Character sequences recognized by code in this file
+ * Leading ESC 0x1B is not included
+ */
+#define SEQ_INSERT "[2~"
+#define SEQ_DELETE "[3~"
+#define SEQ_HOME   "OH"
+#define SEQ_END    "OF"
+#define SEQ_PGUP   "[5~"
+#define SEQ_PGDOWN "[6~"
+#define SEQ_LEFT   "[D"
+#define SEQ_RIGHT  "[C"
+#define SEQ_UP     "[A"
+#define SEQ_DOWN   "[B"
+#define SEQ_STAB   "[Z"
+#define SEQ_M_n    "n"
+#define SEQ_M_p    "p"
+#define SEQ_CLEFT  "[1;5D"
+#define SEQ_CRIGHT "[1;5C"
+#define SEQ_CUP    "[1;5A"
+#define SEQ_CDOWN  "[1;5B"
+#define SEQ_SLEFT  "[1;2D"
+#define SEQ_SRIGHT "[1;2C"
+#define SEQ_SUP    "[1;2A"
+#define SEQ_SDOWN  "[1;2B"
+#define SEQ_MLEFT  "[1;3D"
+#define SEQ_MRIGHT "[1;3C"
+#define SEQ_MUP    "[1;3A"
+#define SEQ_MDOWN  "[1;3B"
+
+#define KEY_SEQUENCE(k) { KEY_##k, SEQ_##k }
+struct ansii_sequence {
+	int code;
+	const char *sequence;
+};
+
+/* Table connects single int key codes with character sequences */
+static const struct ansii_sequence ansii_sequnces[] = {
+	KEY_SEQUENCE(INSERT),
+	KEY_SEQUENCE(DELETE),
+	KEY_SEQUENCE(HOME),
+	KEY_SEQUENCE(END),
+	KEY_SEQUENCE(PGUP),
+	KEY_SEQUENCE(PGDOWN),
+	KEY_SEQUENCE(LEFT),
+	KEY_SEQUENCE(RIGHT),
+	KEY_SEQUENCE(UP),
+	KEY_SEQUENCE(DOWN),
+	KEY_SEQUENCE(CLEFT),
+	KEY_SEQUENCE(CRIGHT),
+	KEY_SEQUENCE(CUP),
+	KEY_SEQUENCE(CDOWN),
+	KEY_SEQUENCE(SLEFT),
+	KEY_SEQUENCE(SRIGHT),
+	KEY_SEQUENCE(SUP),
+	KEY_SEQUENCE(SDOWN),
+	KEY_SEQUENCE(MLEFT),
+	KEY_SEQUENCE(MRIGHT),
+	KEY_SEQUENCE(MUP),
+	KEY_SEQUENCE(MDOWN),
+	KEY_SEQUENCE(STAB),
+	KEY_SEQUENCE(M_p),
+	KEY_SEQUENCE(M_n),
+	{ 0, NULL }
+};
+
+#define isseqence(c) ((c) == 0x1B)
+
+/*
+ * Number of characters that consist of ANSII sequence
+ * Should not be less then longest string in ansii_sequnces
+ */
+#define MAX_ASCII_SEQUENCE 10
+
+static char current_sequence[MAX_ASCII_SEQUENCE];
+static int current_sequence_len = -1;
+
+/* single line typed by user goes here */
+static char line_buf[LINE_BUF_MAX];
+/* index of cursor in input line */
+static int line_buf_ix = 0;
+/* current length of input line */
+static int line_len = 0;
+
+/*
+ * Moves cursor to right or left
+ *
+ * n - positive - moves cursor right
+ * n - negative - moves cursor left
+ */
+static void terminal_move_cursor(int n)
+{
+	if (n < 0) {
+		for (; n < 0; n++)
+			putchar('\b');
+	} else if (n > 0)
+		printf("%*s", n, line_buf + line_buf_ix);
+}
+
+/* Draw command line */
+void terminal_draw_command_line(void)
+{
+	/*
+	 * this needs to be checked here since line_buf is not cleard
+	 * before parsing event though line_len and line_buf_ix are
+	 */
+	if (line_len > 0)
+		printf(">%s", line_buf);
+	else
+		putchar('>');
+
+	/* move cursor to it's place */
+	terminal_move_cursor(line_len - line_buf_ix);
+}
+
+/* inserts string into command line at cursor position */
+void terminal_insert_into_command_line(const char *p)
+{
+	int len = strlen(p);
+
+	if (line_len == line_buf_ix) {
+		strcat(line_buf, p);
+		printf("%s", p);
+		line_buf_ix = line_len = line_len + len;
+	} else {
+		memmove(line_buf + line_buf_ix + len,
+			line_buf + line_buf_ix, line_len - line_buf_ix + 1);
+		memmove(line_buf + line_buf_ix, p, len);
+		printf("%s", line_buf + line_buf_ix);
+		line_buf_ix += len;
+		line_len += len;
+		terminal_move_cursor(line_buf_ix - line_len);
+	}
+}
+
+/* Prints string and redraws command line */
+int terminal_print(const char *format, ...)
+{
+	va_list args;
+	int ret;
+
+	va_start(args, format);
+
+	ret = terminal_vprint(format, args);
+
+	va_end(args);
+	return ret;
+}
+
+/* Prints string and redraws command line */
+int terminal_vprint(const char *format, va_list args)
+{
+	int ret;
+
+	printf("\r%*s\r", (int)line_len + 1, " ");
+
+	ret = vprintf(format, args);
+
+	terminal_draw_command_line();
+
+	return ret;
+}
+
+/*
+ * Converts terminal character sequences to single value representing
+ * keyboard keys
+ */
+static int terminal_convert_sequence(int c)
+{
+	int i;
+
+	/* Not in sequence yet? */
+	if (current_sequence_len == -1) {
+		/* Is ansii sequence detected by 0x1B ? */
+		if (isseqence(c)) {
+			current_sequence_len++;
+			return 0;
+	       }
+	       return c;
+	}
+	/* Inside sequence */
+	current_sequence[current_sequence_len++] = c;
+	current_sequence[current_sequence_len] = '\0';
+	for (i = 0; ansii_sequnces[i].code; ++i) {
+		/* Matches so far? */
+		if (0 != strncmp(current_sequence,
+			ansii_sequnces[i].sequence, current_sequence_len))
+			continue;
+
+		/* Matches as a whole? */
+		if (ansii_sequnces[i].sequence[current_sequence_len] == 0) {
+			current_sequence_len = -1;
+			return ansii_sequnces[i].code;
+		}
+		/* partial match (not whole sequence yet) */
+		return 0;
+	}
+	terminal_print("ansii char 0x%X %c\n", c);
+	/*
+	 * Sequence does not match
+	 * mark that no in sequence any more, return char
+	 */
+	current_sequence_len = -1;
+	return c;
+}
+
+void terminal_process_char(int c, void (*process_line)(char *line))
+{
+	int refresh_from = -1;
+	int old_pos;
+
+	c = terminal_convert_sequence(c);
+
+	switch (c) {
+	case 0:
+		break;
+	case KEY_LEFT:
+		/* if not at the beginning move to previous character */
+		if (line_buf_ix <= 0)
+			break;
+		line_buf_ix--;
+		terminal_move_cursor(-1);
+		break;
+	case KEY_RIGHT:
+		/*
+		 * If not at the end, just print current character
+		 * and modify position
+		 */
+		if (line_buf_ix < line_len)
+			putchar(line_buf[line_buf_ix++]);
+		break;
+	case KEY_HOME:
+		/* move to beginning of line and update position */
+		putchar('\r');
+		putchar('>');
+		line_buf_ix = 0;
+		break;
+	case KEY_END:
+		/* if not at the end of line */
+		if (line_buf_ix < line_len) {
+			/* print everything from cursor */
+			printf("%s", line_buf + line_buf_ix);
+			/* just modify current position */
+			line_buf_ix = line_len;
+		}
+		break;
+	case KEY_DELETE:
+		/* delete character under cursor if not at the very end */
+		if (line_buf_ix >= line_len)
+			break;
+		/*
+		 * Prepare buffer with one character missing
+		 * trailing 0 is moved
+		 */
+		line_len--;
+		memmove(line_buf + line_buf_ix,
+			line_buf + line_buf_ix + 1,
+			line_len - line_buf_ix + 1);
+		/* print rest of line from current cursor position */
+		printf("%s \b", line_buf + line_buf_ix);
+		/* move back cursor */
+		terminal_move_cursor(line_buf_ix - line_len);
+		break;
+	case KEY_CLEFT:
+		/*
+		 * Move by word left
+		 *
+		 * Are we at the beginning of line?
+		 */
+		if (line_buf_ix <= 0)
+			break;
+
+		old_pos = line_buf_ix;
+		line_buf_ix--;
+		/* skip spaces left */
+		while (line_buf_ix && isspace(line_buf[line_buf_ix]))
+			line_buf_ix--;
+		/* skip all non spaces to the left */
+		while (line_buf_ix > 0 &&
+		       !isspace(line_buf[line_buf_ix - 1]))
+			line_buf_ix--;
+		/* move cursor to new position */
+		terminal_move_cursor(line_buf_ix - old_pos);
+		break;
+	case KEY_CRIGHT:
+		/*
+		 * Move by word right
+		 *
+		 * are we at the end of line?
+		 */
+		if (line_buf_ix >= line_len)
+			break;
+
+		old_pos = line_buf_ix;
+		/* skip all spaces */
+		while (line_buf_ix < line_len &&
+			isspace(line_buf[line_buf_ix]))
+			line_buf_ix++;
+		/* skip all non spaces */
+		while (line_buf_ix < line_len &&
+			!isspace(line_buf[line_buf_ix]))
+			line_buf_ix++;
+		/*
+		 * Move cursor to right by printing text
+		 * between old cursor and new
+		 */
+		if (line_buf_ix > old_pos)
+			printf("%.*s", (int)(line_buf_ix - old_pos),
+				line_buf + old_pos);
+		break;
+	case KEY_UP:
+	case KEY_DOWN:
+		break;
+	case '\n':
+	case '\r':
+		line_len = line_buf_ix = 0;
+		/* print new line */
+		putchar(c);
+		process_line(line_buf);
+		/* clear current line */
+		line_buf[0] = '\0';
+		putchar('>');
+		break;
+	case '\t':
+		/* tab processing */
+		/* TODO Add completion here */
+		break;
+	case KEY_BACKSPACE:
+		if (line_buf_ix <= 0)
+			break;
+
+		if (line_buf_ix == line_len) {
+			printf("\b \b");
+			line_len = --line_buf_ix;
+			line_buf[line_len] = 0;
+		} else {
+			putchar('\b');
+			refresh_from = --line_buf_ix;
+			line_len--;
+			memmove(line_buf + line_buf_ix,
+				line_buf + line_buf_ix + 1,
+				line_len - line_buf_ix + 1);
+		}
+		break;
+	case KEY_INSERT:
+	case KEY_PGUP:
+	case KEY_PGDOWN:
+	case KEY_CUP:
+	case KEY_CDOWN:
+	case KEY_SLEFT:
+	case KEY_SRIGHT:
+	case KEY_MLEFT:
+	case KEY_MRIGHT:
+	case KEY_MUP:
+	case KEY_MDOWN:
+	case KEY_STAB:
+	case KEY_M_n:
+	case KEY_M_p:
+		break;
+	default:
+		if (!isprint(c)) {
+			/*
+			 * TODO: remove this print once all meaningful sequences
+			 * are identified
+			 */
+			printf("char-0x%02x\n", c);
+			break;
+		}
+		if (line_buf_ix < LINE_BUF_MAX - 1) {
+			if (line_len == line_buf_ix) {
+				putchar(c);
+				line_buf[line_buf_ix++] = (char)c;
+				line_len++;
+				line_buf[line_len] = '\0';
+			} else {
+				memmove(line_buf + line_buf_ix + 1,
+					line_buf + line_buf_ix,
+					line_len - line_buf_ix + 1);
+				line_buf[line_buf_ix] = c;
+				refresh_from = line_buf_ix++;
+				line_len++;
+			}
+		}
+		break;
+	}
+
+	if (refresh_from >= 0) {
+		printf("%s \b", line_buf + refresh_from);
+		terminal_move_cursor(line_buf_ix - line_len);
+	}
+}
+
+void terminal_setup(void)
+{
+	struct termios tios;
+
+	/* Turn off echo since all editing is done by hand */
+	tcgetattr(0, &tios);
+	tios.c_lflag &= ~(ICANON | ECHO);
+	tcsetattr(0, TCSANOW, &tios);
+	putchar('>');
+}
+
diff --git a/android/hal-client/terminal.h b/android/hal-client/terminal.h
new file mode 100644
index 0000000..e53750f
--- /dev/null
+++ b/android/hal-client/terminal.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdarg.h>
+
+/* size of supported line */
+#define LINE_BUF_MAX 1024
+
+enum key_codes {
+	KEY_BACKSPACE = 0x7F,
+	KEY_INSERT = 1000, /* arbitrary value */
+	KEY_DELETE,
+	KEY_HOME,
+	KEY_END,
+	KEY_PGUP,
+	KEY_PGDOWN,
+	KEY_LEFT,
+	KEY_RIGHT,
+	KEY_UP,
+	KEY_DOWN,
+	KEY_CLEFT,
+	KEY_CRIGHT,
+	KEY_CUP,
+	KEY_CDOWN,
+	KEY_SLEFT,
+	KEY_SRIGHT,
+	KEY_SUP,
+	KEY_SDOWN,
+	KEY_MLEFT,
+	KEY_MRIGHT,
+	KEY_MUP,
+	KEY_MDOWN,
+	KEY_STAB,
+	KEY_M_p,
+	KEY_M_n
+};
+
+void terminal_setup(void);
+int terminal_print(const char *format, ...);
+int terminal_vprint(const char *format, va_list args);
+void terminal_process_char(int c, void (*process_line)(char *line));
+void terminal_insert_into_command_line(const char *p);
+void terminal_draw_command_line(void);
+
+void process_tab(const char *line, int len);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 1/5] android: Add haltest skeleton
From: Jerzy Kasenberg @ 2013-10-15 13:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1381842800-3554-1-git-send-email-jerzy.kasenberg@tieto.com>

This tool will be used to test Android Bluetooth HAL implementation.
---
 android/Android.mk               |   17 ++++++
 android/hal-client/haltest.c     |   51 ++++++++++++++++
 android/hal-client/pollhandler.c |  123 ++++++++++++++++++++++++++++++++++++++
 android/hal-client/pollhandler.h |   26 ++++++++
 4 files changed, 217 insertions(+)
 create mode 100644 android/hal-client/haltest.c
 create mode 100644 android/hal-client/pollhandler.c
 create mode 100644 android/hal-client/pollhandler.h

diff --git a/android/Android.mk b/android/Android.mk
index 0e025ac..c84fbe3 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -49,3 +49,20 @@ LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_CLASS := SHARED_LIBRARIES
 
 include $(BUILD_SHARED_LIBRARY)
+
+#
+# haltest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	hal-client/haltest.c \
+	hal-client/pollhandler.c \
+
+LOCAL_SHARED_LIBRARIES := libhardware
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := haltest
+
+include $(BUILD_EXECUTABLE)
diff --git a/android/hal-client/haltest.c b/android/hal-client/haltest.c
new file mode 100644
index 0000000..11cdd97
--- /dev/null
+++ b/android/hal-client/haltest.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdlib.h>
+#include <poll.h>
+#include <unistd.h>
+
+#include "pollhandler.h"
+
+
+/* called when there is something on stdin */
+static void stdin_handler(struct pollfd *pollfd)
+{
+	char buf[10];
+
+	if (pollfd->revents & POLLIN) {
+		int count = read(0, buf, 10);
+
+		if (count > 0) {
+			int i;
+
+			for (i = 0; i < count; ++i) {
+				/* TODO: process input */
+			}
+		}
+	}
+}
+
+int main(int argc, char **argv)
+{
+	/* Register command line handler */
+	poll_register_fd(0, POLLIN, stdin_handler);
+
+	poll_dispatch_loop();
+
+	return 0;
+}
diff --git a/android/hal-client/pollhandler.c b/android/hal-client/pollhandler.c
new file mode 100644
index 0000000..4e982b8
--- /dev/null
+++ b/android/hal-client/pollhandler.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <poll.h>
+
+#include "pollhandler.h"
+
+/*
+ * Code that allows to poll multiply file descriptors for events
+ * File descriptors can be added and removed at runtime
+ *
+ * Call poll_register_fd function first to add file descriptors to monitor
+ * Then call poll_dispatch_loop that will poll all registered file descriptors
+ * as long as they are not unregistered.
+ *
+ * When event happen on given fd appropriate user supplied handler is called
+ */
+
+/* Maximum number of files to monitor */
+#define MAX_OPEN_FD 10
+
+/* Storage for pollfd structures for monitored file descriptors */
+static struct pollfd fds[MAX_OPEN_FD];
+static poll_handler fds_handler[MAX_OPEN_FD];
+/* Number of registered file descriptors */
+static int fds_count = 0;
+
+/*
+ * Function polls file descriptor in loop and calls appropriate handler
+ * on event. Function returns when there is no more file descriptor to
+ * monitor
+ */
+void poll_dispatch_loop(void)
+{
+	while (fds_count > 0) {
+		int i;
+		int cur_fds_count = fds_count;
+		int ready = poll(fds, fds_count, 1000);
+
+		for (i = 0; i < fds_count && ready > 0; ++i) {
+			if (fds[i].revents == 0)
+				continue;
+
+			fds_handler[i](fds + i);
+			ready--;
+			/*
+			 * If handler was remove from table
+			 * just skip the rest and poll again
+			 * This is due to reordering of tables in
+			 * register/unregister functions
+			 */
+			if (cur_fds_count != fds_count)
+				break;
+		}
+		/*
+		 * This seems to be needed for correct output handling
+		 * when all waiting is performed in poll
+		 */
+		fflush(stdout);
+	}
+}
+
+/*
+ * Registers file descriptor to be monitored for events (see man poll(2))
+ * for events.
+ *
+ * return non negative value on success
+ * -EMFILE when there are to much descriptors
+ */
+int poll_register_fd(int fd, short events, poll_handler ph)
+{
+	if (fds_count >= MAX_OPEN_FD)
+		return -EMFILE;
+
+	fds_handler[fds_count] = ph;
+	fds[fds_count].fd = fd;
+	fds[fds_count].events = events;
+	fds_count++;
+
+	return fds_count;
+}
+
+/*
+ * Unregisters file descriptor
+ * Both fd and ph must match previously registered data
+ *
+ * return 0 if unregister succeeded
+ * -EBADF if arguments do not match any register handler
+ */
+int poll_unregister_fd(int fd, poll_handler ph)
+{
+	int i;
+
+	for (i = 0; i < fds_count; ++i) {
+		if (fds_handler[i] == ph && fds[i].fd == fd) {
+			fds_count--;
+			if (i < fds_count) {
+				fds[i].fd = fds[fds_count].fd;
+				fds[i].events = fds[fds_count].events;
+				fds_handler[i] = fds_handler[fds_count];
+			}
+			return 0;
+		}
+	}
+	return -EBADF;
+}
+
diff --git a/android/hal-client/pollhandler.h b/android/hal-client/pollhandler.h
new file mode 100644
index 0000000..e2f22df
--- /dev/null
+++ b/android/hal-client/pollhandler.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <poll.h>
+
+/* Function to be called when there are event for some descriptor */
+typedef void (*poll_handler)(struct pollfd *pollfd);
+
+int poll_register_fd(int fd, short events, poll_handler ph);
+int poll_unregister_fd(int fd, poll_handler ph);
+
+void poll_dispatch_loop(void);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 0/5] Stack independent BT HAL test tool
From: Jerzy Kasenberg @ 2013-10-15 13:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg

v2:
 - license changed to apache
 - source folder changed to hal-client (underscore to dash)
v1:
This tool is for testing Android HAL interfaces from command line.
Due to lack of readline on Android simple equivalent is hand coded.
This tool can be used with bluedroid stack so no glib dependency.

Tool source code is in folder hal_client, please comment if it should be
somewhere else.

Comments welcome.

Best regards
Jerzy Kasenberg

Jerzy Kasenberg (5):
  android: Add haltest skeleton
  android: Add line editing to haltest
  android: Add history to line editor in haltest
  android: Add text conversion helpers to haltest
  android: Add calls to adapter methods in haltest

 android/Android.mk               |   21 ++
 android/hal-client/haltest.c     |  161 ++++++++++
 android/hal-client/history.c     |   98 ++++++
 android/hal-client/history.h     |   21 ++
 android/hal-client/if_bt.c       |  631 ++++++++++++++++++++++++++++++++++++++
 android/hal-client/if_main.h     |   99 ++++++
 android/hal-client/pollhandler.c |  123 ++++++++
 android/hal-client/pollhandler.h |   26 ++
 android/hal-client/terminal.c    |  534 ++++++++++++++++++++++++++++++++
 android/hal-client/terminal.h    |   59 ++++
 android/hal-client/textconv.c    |  205 +++++++++++++
 android/hal-client/textconv.h    |  113 +++++++
 12 files changed, 2091 insertions(+)
 create mode 100644 android/hal-client/haltest.c
 create mode 100644 android/hal-client/history.c
 create mode 100644 android/hal-client/history.h
 create mode 100644 android/hal-client/if_bt.c
 create mode 100644 android/hal-client/if_main.h
 create mode 100644 android/hal-client/pollhandler.c
 create mode 100644 android/hal-client/pollhandler.h
 create mode 100644 android/hal-client/terminal.c
 create mode 100644 android/hal-client/terminal.h
 create mode 100644 android/hal-client/textconv.c
 create mode 100644 android/hal-client/textconv.h

-- 
1.7.9.5


^ permalink raw reply

* [PATCHv1 5/5] android: Add cap to bind to port < 1024
From: Andrei Emeltchenko @ 2013-10-15 10:37 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1381833423-862-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

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

For SDP server we need to bind to lower port, acquire this capability.
---
 android/main.c |   71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 configure.ac   |    4 ++++
 2 files changed, 75 insertions(+)

diff --git a/android/main.c b/android/main.c
index 2b8675d..5206d3d 100644
--- a/android/main.c
+++ b/android/main.c
@@ -32,6 +32,22 @@
 #include <stdlib.h>
 #include <stdbool.h>
 #include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/prctl.h>
+#include <linux/capability.h>
+
+/**
+ * Include <sys/capability.h> for host build and
+ * also for Android 4.3 when it is added to bionic
+ */
+#if !defined(ANDROID) || (PLATFORM_SDK_VERSION > 17)
+#include <sys/capability.h>
+#endif
+
+#if defined(ANDROID)
+#include <private/android_filesystem_config.h>
+#endif
 
 #include <glib.h>
 
@@ -232,6 +248,58 @@ static void cleanup_mgmt_interface(void)
 	mgmt_if = NULL;
 }
 
+static bool android_set_aid_and_cap(void)
+{
+	struct __user_cap_header_struct header;
+	struct __user_cap_data_struct cap;
+#if defined(ANDROID)
+	gid_t groups[] = {AID_NET_BT, AID_NET_BT_ADMIN, AID_NET_ADMIN};
+#endif
+
+	DBG("pid %d uid %d gid %d", getpid(), getuid(), getgid());
+
+	header.version = _LINUX_CAPABILITY_VERSION;
+
+	prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+
+#if defined(ANDROID)
+	if (setgid(AID_BLUETOOTH) < 0)
+		warn("%s: setgid(): %s", __func__, strerror(errno));
+
+	if (setuid(AID_BLUETOOTH) < 0)
+		warn("%s: setuid(): %s", __func__, strerror(errno));
+#endif
+
+	header.version = _LINUX_CAPABILITY_VERSION;
+	header.pid = 0;
+
+	cap.effective = cap.permitted =
+		CAP_TO_MASK(CAP_SETGID) |
+		CAP_TO_MASK(CAP_NET_RAW) |
+		CAP_TO_MASK(CAP_NET_ADMIN) |
+		CAP_TO_MASK(CAP_NET_BIND_SERVICE);
+	cap.inheritable = 0;
+
+	if (capset(&header, &cap) < 0) {
+		error("%s: capset(): %s", __func__, strerror(errno));
+		return false;
+	}
+
+#if defined(ANDROID)
+	if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) < 0)
+		warn("%s: setgroups: %s", __func__, strerror(errno));
+#endif
+	if (capget(&header, &cap) < 0)
+		error("%s: capget(): %s", __func__, strerror(errno));
+	else
+		DBG("Caps: eff: 0x%x, perm: 0x%x, inh: 0x%x", cap.effective,
+					cap.permitted, cap.inheritable);
+
+	DBG("pid %d uid %d gid %d", getpid(), getuid(), getgid());
+
+	return true;
+}
+
 int main(int argc, char *argv[])
 {
 	GOptionContext *context;
@@ -265,6 +333,9 @@ int main(int argc, char *argv[])
 	sigaction(SIGINT, &sa, NULL);
 	sigaction(SIGTERM, &sa, NULL);
 
+	if (!android_set_aid_and_cap())
+		return EXIT_FAILURE;
+
 	if (!init_mgmt_interface())
 		return EXIT_FAILURE;
 
diff --git a/configure.ac b/configure.ac
index 7b1f64a..5406434 100644
--- a/configure.ac
+++ b/configure.ac
@@ -247,4 +247,8 @@ AC_ARG_ENABLE(android, AC_HELP_STRING([--enable-android],
 					[enable_android=${enableval}])
 AM_CONDITIONAL(ANDROID, test "${enable_android}" = "yes")
 
+if (test "${android_daemon}" = "yes"); then
+	AC_CHECK_LIB(cap, capget, dummy=yes, AC_MSG_ERROR(libcap is required))
+fi
+
 AC_OUTPUT(Makefile src/bluetoothd.8 lib/bluez.pc)
-- 
1.7.10.4


^ permalink raw reply related

* [PATCHv1 4/5] android: sdp: Reuse BlueZ SDP server in Android
From: Andrei Emeltchenko @ 2013-10-15 10:37 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1381833423-862-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

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

Reuse existing SDP server code in Android GPL daemon.
---
 Makefile.android   |    4 +++-
 android/Android.mk |    8 ++++++++
 android/main.c     |    5 +++++
 3 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/Makefile.android b/Makefile.android
index 7371a77..48af2e2 100644
--- a/Makefile.android
+++ b/Makefile.android
@@ -2,9 +2,11 @@ if ANDROID
 noinst_PROGRAMS += android/bluetoothd
 
 android_bluetoothd_SOURCES = android/main.c src/log.c \
+				src/sdpd-database.c src/sdpd-server.c \
+				src/sdpd-service.c src/sdpd-request.c \
 				src/shared/util.h src/shared/util.c \
 				src/shared/mgmt.h src/shared/mgmt.c
-android_bluetoothd_LDADD = @GLIB_LIBS@
+android_bluetoothd_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
 endif
 
 EXTRA_DIST += android/Android.mk android/log.c
diff --git a/android/Android.mk b/android/Android.mk
index 4996080..560fb0a 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -17,6 +17,13 @@ LOCAL_SRC_FILES := \
 	log.c \
 	../src/shared/mgmt.c \
 	../src/shared/util.c \
+	../src/sdpd-database.c \
+	../src/sdpd-service.c \
+	../src/sdpd-request.c \
+	../src/sdpd-server.c \
+	../lib/sdp.c \
+	../lib/bluetooth.c \
+	../lib/hci.c \
 
 LOCAL_C_INCLUDES := \
 	$(call include-path-for, glib) \
@@ -25,6 +32,7 @@ LOCAL_C_INCLUDES := \
 LOCAL_C_INCLUDES += \
 	$(LOCAL_PATH)/../ \
 	$(LOCAL_PATH)/../src \
+	$(LOCAL_PATH)/../lib \
 
 LOCAL_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\"
 
diff --git a/android/main.c b/android/main.c
index ba25b84..2b8675d 100644
--- a/android/main.c
+++ b/android/main.c
@@ -36,6 +36,7 @@
 #include <glib.h>
 
 #include "log.h"
+#include "sdpd.h"
 
 #include "lib/bluetooth.h"
 #include "lib/mgmt.h"
@@ -267,10 +268,14 @@ int main(int argc, char *argv[])
 	if (!init_mgmt_interface())
 		return EXIT_FAILURE;
 
+	/* Use params: mtu = 0, flags = 0 */
+	start_sdp_server(0, 0);
+
 	DBG("Entering main loop");
 
 	g_main_loop_run(event_loop);
 
+	stop_sdp_server();
 	cleanup_mgmt_interface();
 	g_main_loop_unref(event_loop);
 
-- 
1.7.10.4


^ permalink raw reply related

* [PATCHv1 3/5] android: Add adapter and device struct for BlueZ daemon
From: Andrei Emeltchenko @ 2013-10-15 10:37 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1381833423-862-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

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

Adapter structure in BlueZ daemon keeps track of default adapter
and device structure keeps track about found devices.
---
 android/adapter.c |   63 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 android/adapter.h |   36 ++++++++++++++++++++++++++++++
 android/device.c  |   29 ++++++++++++++++++++++++
 android/device.h  |   24 ++++++++++++++++++++
 4 files changed, 152 insertions(+)
 create mode 100644 android/adapter.c
 create mode 100644 android/adapter.h
 create mode 100644 android/device.c
 create mode 100644 android/device.h

diff --git a/android/adapter.c b/android/adapter.c
new file mode 100644
index 0000000..b97a7c7
--- /dev/null
+++ b/android/adapter.c
@@ -0,0 +1,63 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include "src/shared/mgmt.h"
+#include "log.h"
+#include "adapter.h"
+
+struct bt_adapter {
+	struct mgmt *mgmt;
+	bdaddr_t bdaddr;
+	uint32_t dev_class;
+
+	char *name;
+
+	uint32_t supported_settings;
+	uint32_t current_settings;
+
+	GList *found_devices;
+};
+
+struct bt_adapter *bt_adapter_new(uint16_t index, struct mgmt *mgmt_if)
+{
+	struct bt_adapter *adapter;
+
+	adapter = g_new0(struct bt_adapter, 1);
+
+	adapter->mgmt = mgmt_ref(mgmt_if);
+
+	return adapter;
+}
+
+void bt_adapter_start(struct bt_adapter *adapter)
+{
+	DBG("");
+
+	/* TODO: CB: report scan mode */
+	/* TODO: CB: report state on */
+}
+
+void bt_adapter_stop(struct bt_adapter *adapter)
+{
+	DBG("");
+}
diff --git a/android/adapter.h b/android/adapter.h
new file mode 100644
index 0000000..0f1445a
--- /dev/null
+++ b/android/adapter.h
@@ -0,0 +1,36 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+
+struct bt_adapter;
+
+struct bt_adapter *bt_adapter_new(uint16_t index, struct mgmt *mgmt_if);
+
+void bt_adapter_start(struct bt_adapter *adapter);
+void bt_adapter_stop(struct bt_adapter *adapter);
diff --git a/android/device.c b/android/device.c
new file mode 100644
index 0000000..224a317
--- /dev/null
+++ b/android/device.c
@@ -0,0 +1,29 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+struct bt_device {
+	bdaddr_t bdaddr;
+	uint8_t bdaddr_type;
+	uint32_t cod;
+	char *name;
+};
diff --git a/android/device.h b/android/device.h
new file mode 100644
index 0000000..f5b1da6
--- /dev/null
+++ b/android/device.h
@@ -0,0 +1,24 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+struct bt_device;
-- 
1.7.10.4


^ permalink raw reply related

* [PATCHv1 2/5] android: Add basic mgmt initialization sequence
From: Andrei Emeltchenko @ 2013-10-15 10:37 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1381833423-862-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

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

Initialize bluetooth controller via mgmt interface.
---
 Makefile.android   |    4 +-
 android/Android.mk |    5 ++
 android/main.c     |  168 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 176 insertions(+), 1 deletion(-)

diff --git a/Makefile.android b/Makefile.android
index 3ceefd8..7371a77 100644
--- a/Makefile.android
+++ b/Makefile.android
@@ -1,7 +1,9 @@
 if ANDROID
 noinst_PROGRAMS += android/bluetoothd
 
-android_bluetoothd_SOURCES = android/main.c src/log.c
+android_bluetoothd_SOURCES = android/main.c src/log.c \
+				src/shared/util.h src/shared/util.c \
+				src/shared/mgmt.h src/shared/mgmt.c
 android_bluetoothd_LDADD = @GLIB_LIBS@
 endif
 
diff --git a/android/Android.mk b/android/Android.mk
index 0e025ac..4996080 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -15,10 +15,15 @@ include $(CLEAR_VARS)
 LOCAL_SRC_FILES := \
 	main.c \
 	log.c \
+	../src/shared/mgmt.c \
+	../src/shared/util.c \
 
 LOCAL_C_INCLUDES := \
 	$(call include-path-for, glib) \
 	$(call include-path-for, glib)/glib \
+
+LOCAL_C_INCLUDES += \
+	$(LOCAL_PATH)/../ \
 	$(LOCAL_PATH)/../src \
 
 LOCAL_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\"
diff --git a/android/main.c b/android/main.c
index f75b0a8..ba25b84 100644
--- a/android/main.c
+++ b/android/main.c
@@ -25,6 +25,7 @@
 #include <config.h>
 #endif
 
+#include <stdbool.h>
 #include <signal.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -36,9 +37,17 @@
 
 #include "log.h"
 
+#include "lib/bluetooth.h"
+#include "lib/mgmt.h"
+#include "src/shared/mgmt.h"
+
 #define SHUTDOWN_GRACE_SECONDS 10
 
 static GMainLoop *event_loop;
+static struct mgmt *mgmt_if = NULL;
+
+static uint8_t mgmt_version = 0;
+static uint8_t mgmt_revision = 0;
 
 static gboolean quit_eventloop(gpointer user_data)
 {
@@ -67,6 +76,161 @@ static GOptionEntry options[] = {
 	{ NULL }
 };
 
+static void read_info_complete(uint8_t status, uint16_t length,
+					const void *param, void *user_data)
+{
+	/* TODO: Store Controller information */
+
+	/* TODO: Register all event notification handlers */
+}
+
+
+static void mgmt_index_added_event(uint16_t index, uint16_t length,
+					const void *param, void *user_data)
+{
+	DBG("index %u", index);
+
+	if (mgmt_send(mgmt_if, MGMT_OP_READ_INFO, index, 0, NULL,
+					read_info_complete, NULL, NULL) > 0)
+		return;
+
+	error("Failed to read adapter info for index %u", index);
+
+}
+
+static void mgmt_index_removed_event(uint16_t index, uint16_t length,
+					const void *param, void *user_data)
+{
+	DBG("index %u", index);
+}
+
+static void read_index_list_complete(uint8_t status, uint16_t length,
+					const void *param, void *user_data)
+{
+	const struct mgmt_rp_read_index_list *rp = param;
+	uint16_t num;
+	int i;
+
+	info(__func__);
+
+	if (!status) {
+		error("%s: Failed to read index list: %s (0x%02x)",
+					__func__, mgmt_errstr(status), status);
+		return;
+	}
+
+	if (length < sizeof(*rp)) {
+		error("%s: Wrong size of read index list response", __func__);
+		return;
+	}
+
+	num = btohs(rp->num_controllers);
+
+	DBG("%s: Number of controllers: %u", __func__, num);
+
+	if (num * sizeof(uint16_t) + sizeof(*rp) != length) {
+		error("%s: Incorrect pkt size for index list rsp", __func__);
+		return;
+	}
+
+	for (i = 0; i < num; i++) {
+		uint16_t index;
+
+		index = btohs(rp->index[i]);
+
+		/**
+		 * Use index added event notification.
+		 */
+		mgmt_index_added_event(index, 0, NULL, NULL);
+	}
+}
+
+static void read_commands_complete(uint8_t status, uint16_t length,
+					const void *param, void *user_data)
+{
+	const struct mgmt_rp_read_commands *rp = param;
+
+	DBG("");
+
+	if (!status) {
+		error("Failed to read supported commands: %s (0x%02x)",
+						mgmt_errstr(status), status);
+		return;
+	}
+
+	if (length < sizeof(*rp)) {
+		error("Wrong size response");
+		return;
+	}
+}
+
+static void read_version_complete(uint8_t status, uint16_t length,
+					const void *param, void *user_data)
+{
+	const struct mgmt_rp_read_version *rp = param;
+
+	DBG("");
+
+	if (!status) {
+		error("Failed to read version information: %s (0x%02x)",
+						mgmt_errstr(status), status);
+		return;
+	}
+
+	if (length < sizeof(*rp)) {
+		error("Wrong size response");
+		return;
+	}
+
+	mgmt_version = rp->version;
+	mgmt_revision = btohs(rp->revision);
+
+	info("Bluetooth management interface %u.%u initialized",
+						mgmt_version, mgmt_revision);
+
+	if (mgmt_version < 1) {
+		error("Version 1.0 or later of management interface required");
+		abort();
+	}
+
+	mgmt_send(mgmt_if, MGMT_OP_READ_COMMANDS, MGMT_INDEX_NONE, 0, NULL,
+					read_commands_complete, NULL, NULL);
+
+	mgmt_register(mgmt_if, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
+					mgmt_index_added_event, NULL, NULL);
+	mgmt_register(mgmt_if, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE,
+					mgmt_index_removed_event, NULL, NULL);
+
+	if (mgmt_send(mgmt_if, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0,
+			NULL, read_index_list_complete, NULL, NULL) > 0)
+		return;
+
+	error("Failed to read controller index list");
+}
+
+static bool init_mgmt_interface(void)
+{
+	mgmt_if = mgmt_new_default();
+	if (!mgmt_if) {
+		error("Failed to access management interface");
+		return false;
+	}
+
+	if (mgmt_send(mgmt_if, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE, 0, NULL,
+				read_version_complete, NULL, NULL) == 0) {
+		error("Error sending READ_VERSION mgmt command");
+		return false;
+	}
+
+	return true;
+}
+
+static void cleanup_mgmt_interface(void)
+{
+	mgmt_unref(mgmt_if);
+	mgmt_if = NULL;
+}
+
 int main(int argc, char *argv[])
 {
 	GOptionContext *context;
@@ -100,10 +264,14 @@ int main(int argc, char *argv[])
 	sigaction(SIGINT, &sa, NULL);
 	sigaction(SIGTERM, &sa, NULL);
 
+	if (!init_mgmt_interface())
+		return EXIT_FAILURE;
+
 	DBG("Entering main loop");
 
 	g_main_loop_run(event_loop);
 
+	cleanup_mgmt_interface();
 	g_main_loop_unref(event_loop);
 
 	info("Exit");
-- 
1.7.10.4


^ permalink raw reply related

* [PATCHv1 1/5] android: Create HAL API header skeleton
From: Andrei Emeltchenko @ 2013-10-15 10:36 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1381833423-862-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

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

Header describes the protocol between Android HAL threads and BlueZ
daemon.

Change-Id: Idfba8c6ebe6234340d1b0258756ee2bedfc315d7
---
 android/hal_msg.h |  246 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 246 insertions(+)
 create mode 100644 android/hal_msg.h

diff --git a/android/hal_msg.h b/android/hal_msg.h
new file mode 100644
index 0000000..4c5ca69
--- /dev/null
+++ b/android/hal_msg.h
@@ -0,0 +1,246 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+struct hal_msg_hdr {
+	uint8_t service_id;
+	uint8_t opcode;
+	uint16_t len;
+} __attribute__((packed));
+
+#define HAL_SERVICE_ID_CORE		0
+#define HAL_SERVICE_ID_BLUETOOTH	1
+#define HAL_SERVICE_ID_SOCK		2
+#define HAL_SERVICE_ID_HIDHOST		3
+#define HAL_SERVICE_ID_PAN		4
+#define HAL_SERVICE_ID_HANDSFREE	5
+#define HAL_SERVICE_ID_AD2P		6
+#define HAL_SERVICE_ID_HEALTH		7
+#define HAL_SERVICE_ID_AVRCP		8
+#define HAL_SERVICE_ID_GATT		9
+
+/* Core Service */
+
+#define HAL_MSG_OP_ERROR		0x00
+struct hal_msg_rsp_error {
+	uint8_t status;
+} __attribute__((packed));
+
+#define HAL_MSG_OP_REGISTER_MODULE	0x01
+struct hal_msg_cmd_register_module {
+	uint8_t service_id;
+} __attribute__((packed));
+struct hal_msg_rsp_register_module {
+	uint8_t service_id;
+} __attribute__((packed));
+
+#define HAL_MSG_OP_UNREGISTER_MODULE	0x02
+struct hal_msg_cmd_unregister_module {
+	uint8_t service_id;
+} __attribute__((packed));
+
+/* Bluetooth Core HAL API */
+
+#define HAL_MSG_OP_BT_ENABLE		0x01
+
+#define HAL_MSG_OP_BT_DISABLE		0x02
+
+#define HAL_MSG_OP_BT_GET_ADAPTER_PROPS	0x03
+
+#define HAL_MSG_OP_BT_GET_ADAPTER_PROP	0x04
+struct hal_msg_cmd_bt_get_adapter_prop {
+	uint8_t type;
+} __attribute__((packed));
+
+#define HAL_MSG_OP_BT_SET_ADAPTER_PROP	0x05
+struct hal_msg_cmd_bt_set_adapter_prop {
+	uint8_t  type;
+	uint16_t len;
+	uint8_t  val[0];
+} __attribute__((packed));
+
+#define HAL_MSG_OP_BT_GET_REMOTE_DEVICE_PROPS	0x06
+struct hal_msg_cmd_bt_get_remote_device_props {
+	uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_MSG_OP_BT_GET_REMOTE_DEVICE_PROP	0x07
+struct hal_msg_cmd_bt_get_remote_device_prop {
+	uint8_t bdaddr[6];
+	uint8_t type;
+} __attribute__((packed));
+
+#define HAL_MSG_OP_BT_SET_REMOTE_DEVICE_PROP	0x08
+struct hal_msg_cmd_bt_set_remote_device_prop {
+	uint8_t  bdaddr[6];
+	uint8_t  type;
+	uint16_t len;
+	uint8_t  val[0];
+} __attribute__((packed));
+
+#define HAL_MSG_OP_BT_GET_REMOTE_SERVICE_REC	0x09
+struct hal_msg_cmd_bt_get_remote_service_rec {
+	uint8_t bdaddr[6];
+	uint8_t uuid[16];
+} __attribute__((packed));
+
+#define HAL_MSG_OP_BT_GET_REMOTE_SERVICE	0x0a
+struct hal_msg_cmd_bt_get_remote_service {
+	uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_MSG_OP_BT_START_DISCOVERY	0x0b
+
+#define HAL_MSG_OP_BT_CANCEL_DISCOVERY	0x0c
+
+#define HAL_MSG_OP_BT_CREATE_BOND	0x0d
+struct hal_msg_cmd_bt_create_bond {
+	uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_MSG_OP_BT_REMOVE_BOND	0x0d
+struct hal_msg_cmd_bt_remove_bond {
+	uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_MSG_OP_BT_CANCEL_BOND	0x0f
+struct hal_msg_cmd_bt_cancel_bond {
+	uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_MSG_OP_BT_PIN_REPLY		0x10
+struct hal_msg_cmd_bt_pin_reply {
+	uint8_t bdaddr[6];
+	uint8_t accept;
+	uint8_t pin_len;
+	uint8_t pin_code[16];
+} __attribute__((packed));
+
+#define HAL_MSG_OP_BT_SSP_REPLY		0x11
+struct hal_msg_cmd_bt_ssp_reply {
+	uint8_t  bdaddr[6];
+	uint8_t  ssp_variant;
+	uint8_t  accept;
+	uint32_t passkey;
+} __attribute__((packed));
+
+#define HAL_MSG_OP_BT_DUT_MODE_CONF	0x12
+struct hal_msg_cmd_bt_dut_mode_conf {
+	uint8_t enable;
+} __attribute__((packed));
+
+#define HAL_MSG_OP_BT_DUT_MODE_SEND	0x13
+struct hal_msg_cmd_bt_dut_mode_send {
+	uint16_t opcode;
+	uint8_t  len;
+	uint8_t  data[0];
+} __attribute__((packed));
+
+#define HAL_MSG_OP_BT_LE_TEST_MODE	0x14
+struct hal_msg_cmd_bt_le_test_mode {
+	uint16_t opcode;
+	uint8_t  len;
+	uint8_t  data[0];
+} __attribute__((packed));
+
+/* Notifications and confirmations */
+
+#define HAL_MSG_EV_BT_ERROR			0x80
+
+#define HAL_MSG_EV_BT_ADAPTER_STATE_CHANGED	0x81
+struct hal_msg_ev_bt_adapter_state_changed {
+	uint8_t state;
+} __attribute__((packed));
+
+#define HAL_MSG_EV_BT_ADAPTER_PROPS_CHANGED	0x82
+struct hal_property {
+	uint8_t  type;
+	uint16_t len;
+	uint8_t  val[0];
+} __attribute__((packed));
+struct hal_msg_ev_bt_adapter_props_changed {
+	uint8_t              status;
+	uint8_t              num_props;
+	struct  hal_property props[0];
+} __attribute__((packed));
+
+#define HAL_MSG_EV_BT_REMOTE_DEVICE_PROPS	0x83
+struct hal_msg_ev_bt_remote_device_props {
+	uint8_t             status;
+	uint8_t             bdaddr[6];
+	uint8_t             num_props;
+	struct hal_property props[0];
+} __attribute__((packed));
+
+#define HAL_MSG_EV_BT_DEVICE_FOUND		0x84
+struct hal_msg_ev_bt_device_found {
+	uint8_t             num_props;
+	struct hal_property props[0];
+} __attribute__((packed));
+
+#define HAL_MSG_EV_BT_DISCOVERY_STATE_CHANGED	0x85
+struct hal_msg_ev_bt_discovery_state_changed {
+	uint8_t state;
+} __attribute__((packed));
+
+#define HAL_MSG_EV_BT_PIN_REQUEST		0x86
+struct hal_msg_ev_bt_pin_request {
+	uint8_t bdaddr[6];
+	uint8_t name[249 - 1];
+	uint8_t class_of_dev[3];
+} __attribute__((packed));
+
+#define HAL_MSG_EV_BT_SSP_REQUEST		0x87
+struct hal_msg_ev_bt_ssp_request {
+	uint8_t  bdaddr[6];
+	uint8_t  name[249 - 1];
+	uint8_t  class_of_dev[3];
+	uint8_t  pairing_variant;
+	uint32_t passkey;
+} __attribute__((packed));
+
+#define HAL_MSG_EV_BT_BOND_STATE_CHANGED	0x88
+struct hal_msg_ev_bt_bond_state_changed {
+	uint8_t status;
+	uint8_t bdaddr[6];
+	uint8_t state;
+} __attribute__((packed));
+
+#define HAL_MSG_EV_BT_ACL_STATE_CHANGED		0x89
+struct hal_msg_ev_bt_acl_state_changed {
+	uint8_t status;
+	uint8_t bdaddr[6];
+	uint8_t state;
+} __attribute__((packed));
+
+#define HAL_MSG_EV_BT_DUT_MODE_RECEIVE		0x8a
+struct hal_msg_ev_bt_dut_mode_receive {
+	uint16_t opcode;
+	uint8_t  len;
+	uint8_t  data[0];
+} __attribute__((packed));
+
+#define HAL_MSG_EV_BT_LE_TEST_MODE		0x8b
+struct hal_msg_ev_bt_le_test_mode {
+	uint8_t  status;
+	uint16_t num_packets;
+} __attribute__((packed));
-- 
1.7.10.4


^ permalink raw reply related

* [PATCHv1 0/5] Initial Android BlueZ patches
From: Andrei Emeltchenko @ 2013-10-15 10:36 UTC (permalink / raw)
  To: linux-bluetooth

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

This is second chunk from my initial big patch set. Fixed style issues commented
by Marcel.

Note that due to Marcel comment this cannot be built unless you include my patch
for Android bionic library:
http://code.google.com/p/android-bluez/source/detail?r=77a07e7703b63e280d9880baad30b3375e7df079&repo=bionic#

Andrei Emeltchenko (5):
  android: Create HAL API header skeleton
  android: Add basic mgmt initialization sequence
  android: Add adapter and device struct for BlueZ daemon
  android: sdp: Reuse BlueZ SDP server in Android
  android: Add cap to bind to port < 1024

 Makefile.android   |    8 +-
 android/Android.mk |   13 +++
 android/adapter.c  |   63 ++++++++++++++
 android/adapter.h  |   36 ++++++++
 android/device.c   |   29 +++++++
 android/device.h   |   24 +++++
 android/hal_msg.h  |  246 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 android/main.c     |  244 +++++++++++++++++++++++++++++++++++++++++++++++++++
 configure.ac       |    4 +
 9 files changed, 665 insertions(+), 2 deletions(-)
 create mode 100644 android/adapter.c
 create mode 100644 android/adapter.h
 create mode 100644 android/device.c
 create mode 100644 android/device.h
 create mode 100644 android/hal_msg.h

-- 
1.7.10.4


^ permalink raw reply

* Re: [PATCH BlueZ 1/3] audio/media: Add support for tracking Seeked signal
From: Luiz Augusto von Dentz @ 2013-10-15 10:11 UTC (permalink / raw)
  To: linux-bluetooth@vger.kernel.org
In-Reply-To: <1381492404-25765-1-git-send-email-luiz.dentz@gmail.com>

Hi,

On Fri, Oct 11, 2013 at 2:53 PM, Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> This tracks Seeked signal and update the position in case it happens.
> ---
>  profiles/audio/media.c | 21 +++++++++++++++++++++
>  1 file changed, 21 insertions(+)
>
> diff --git a/profiles/audio/media.c b/profiles/audio/media.c
> index 9c72b8d..646c76a 100644
> --- a/profiles/audio/media.c
> +++ b/profiles/audio/media.c
> @@ -96,6 +96,7 @@ struct media_player {
>         guint                   watch;
>         guint                   properties_watch;
>         guint                   track_watch;
> +       guint                   seek_watch;
>         char                    *status;
>         uint32_t                position;
>         uint32_t                duration;
> @@ -949,6 +950,7 @@ static void media_player_free(gpointer data)
>         g_dbus_remove_watch(conn, mp->watch);
>         g_dbus_remove_watch(conn, mp->properties_watch);
>         g_dbus_remove_watch(conn, mp->track_watch);
> +       g_dbus_remove_watch(conn, mp->seek_watch);
>
>         if (mp->track)
>                 g_hash_table_unref(mp->track);
> @@ -1681,6 +1683,21 @@ static gboolean properties_changed(DBusConnection *connection, DBusMessage *msg,
>         return TRUE;
>  }
>
> +static gboolean position_changed(DBusConnection *connection, DBusMessage *msg,
> +                                                       void *user_data)
> +{
> +       struct media_player *mp = user_data;
> +       DBusMessageIter iter;
> +
> +       DBG("sender=%s path=%s", mp->sender, mp->path);
> +
> +       dbus_message_iter_init(msg, &iter);
> +
> +       set_position(mp, &iter);
> +
> +       return TRUE;
> +}
> +
>  static struct media_player *media_player_create(struct media_adapter *adapter,
>                                                 const char *sender,
>                                                 const char *path,
> @@ -1702,6 +1719,10 @@ static struct media_player *media_player_create(struct media_adapter *adapter,
>                                                 path, MEDIA_PLAYER_INTERFACE,
>                                                 properties_changed,
>                                                 mp, NULL);
> +       mp->seek_watch = g_dbus_add_signal_watch(conn, sender,
> +                                               path, MEDIA_PLAYER_INTERFACE,
> +                                               "Seeked", position_changed,
> +                                               mp, NULL);
>         mp->player = avrcp_register_player(adapter->btd_adapter, &player_cb,
>                                                         mp, media_player_free);
>         if (!mp->player) {
> --
> 1.8.3.1

Pushed.


-- 
Luiz Augusto von Dentz

^ permalink raw reply

* Re: [PATCH] Bluetooth: Add support for entering limited discoverable mode
From: Marcel Holtmann @ 2013-10-15 10:02 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <20131015094905.GA5788@x220.p-661hnu-f1>

Hi Johan,

>>>>>> +	if (cp->val) {
>>>>>> +		struct hci_cp_write_current_iac_lap cp;
>>>>>> +
>>>>>> +		if (timeout > 0) {
>>>>>> +			/* Limited discoverable mode */
>>>>> 
>>>>> Wouldn't we want to follow the recommendation from the Core spec
>>>>> here, volume 3, part C, section 4.1.2.1:
>>>>> 
>>>>> "A Bluetooth device should not be in limited discoverable mode for
>>>>> more than TGAP(104)"
>>>>> 
>>>>> TGAP(104) in turn is defined as 1 minute (vol 3, part C, Appendix A).
>>>> 
>>>> I was not going to be this strict. So yes, userspace can violate
>>>> the GAP part here, but it might be a good idea to ensure that when
>>>> a too large value is entered we stick with general discoverable
>>>> mode.  However is this really worth it.
>>> 
>>> For Advertising the max value is actually not just a recommendation
>>> but a requirement (check my other mail), so at least there we should
>>> probably enforce it. And if we have to enforce it for LE we might as
>>> well do it for BR/EDR too. It's anyway a rather simple change to the
>>> if-statement.
>>> 
>>>> Another option is to just reject too large timeout values as
>>>> invalid parameters and force userspace to implement large timeouts
>>>> with general discoverable mode in userspace.
>>> 
>>> I don't think it's a good idea to force this kind of special
>>> handling to user space (not just the requirement to know where the
>>> limits go but also the need to implement a separate timer).
>> 
>> This sounds also a bit like black magic. Userspace needs to know that
>> a small value enters limited discoverable mode and a large one sticks
>> with general discoverable mode. We might should have added a flag to
>> the command in the first place. However I think our general intention
>> was that with a timeout we do limited discoverable mode and without a
>> timeout we do general discoverable mode.
>> 
>> I was complaining on why we bothered with a timeout for this parameter
>> when building src/share/mgmt.[ch] and cleaning up some of the core
>> adapter handling. Mainly because for PairableTimeout D-Bus property we
>> have to run our own timer and for DiscoverableTimeout property we rely
>> on the kernel. And in the end just running your own timeout was a lot
>> simpler, then integrating with the kernel.
>> 
>> So I would be actually fine just saying with timeout that is limited
>> discoverable mode. If you want general discoverable mode with a
>> timeout, then you have to run this by yourself.
> 
> Fair enough, and I really don't want to complicate this more by adding a
> new 0x02 value either. The patch has now been pushed to bluetooth-next.

and I was tending towards reworking the patch to add a new 0x02 mode. In that mode we enforce the correct timeout values ahead of time.

I am no longer convinced that we are doing the right thing here. I was 100% sure yesterday and today, I would start exploring other options.

Regards

Marcel


^ permalink raw reply

* Re: [PATCH] Bluetooth: Add support for entering limited discoverable mode
From: Johan Hedberg @ 2013-10-15  9:49 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: linux-bluetooth
In-Reply-To: <F77D26AD-3835-4A7B-BD9F-CF5F5ACA7F4A@holtmann.org>

Hi Marcel,

On Tue, Oct 15, 2013, Marcel Holtmann wrote:
> >>>> +	if (cp->val) {
> >>>> +		struct hci_cp_write_current_iac_lap cp;
> >>>> +
> >>>> +		if (timeout > 0) {
> >>>> +			/* Limited discoverable mode */
> >>> 
> >>> Wouldn't we want to follow the recommendation from the Core spec
> >>> here, volume 3, part C, section 4.1.2.1:
> >>> 
> >>> "A Bluetooth device should not be in limited discoverable mode for
> >>> more than TGAP(104)"
> >>> 
> >>> TGAP(104) in turn is defined as 1 minute (vol 3, part C, Appendix A).
> >> 
> >> I was not going to be this strict. So yes, userspace can violate
> >> the GAP part here, but it might be a good idea to ensure that when
> >> a too large value is entered we stick with general discoverable
> >> mode.  However is this really worth it.
> > 
> > For Advertising the max value is actually not just a recommendation
> > but a requirement (check my other mail), so at least there we should
> > probably enforce it. And if we have to enforce it for LE we might as
> > well do it for BR/EDR too. It's anyway a rather simple change to the
> > if-statement.
> > 
> >> Another option is to just reject too large timeout values as
> >> invalid parameters and force userspace to implement large timeouts
> >> with general discoverable mode in userspace.
> > 
> > I don't think it's a good idea to force this kind of special
> > handling to user space (not just the requirement to know where the
> > limits go but also the need to implement a separate timer).
> 
> This sounds also a bit like black magic. Userspace needs to know that
> a small value enters limited discoverable mode and a large one sticks
> with general discoverable mode. We might should have added a flag to
> the command in the first place. However I think our general intention
> was that with a timeout we do limited discoverable mode and without a
> timeout we do general discoverable mode.
> 
> I was complaining on why we bothered with a timeout for this parameter
> when building src/share/mgmt.[ch] and cleaning up some of the core
> adapter handling. Mainly because for PairableTimeout D-Bus property we
> have to run our own timer and for DiscoverableTimeout property we rely
> on the kernel. And in the end just running your own timeout was a lot
> simpler, then integrating with the kernel.
> 
> So I would be actually fine just saying with timeout that is limited
> discoverable mode. If you want general discoverable mode with a
> timeout, then you have to run this by yourself.

Fair enough, and I really don't want to complicate this more by adding a
new 0x02 value either. The patch has now been pushed to bluetooth-next.

Johan

^ permalink raw reply

* Re: [PATCH] Bluetooth: Add support for entering limited discoverable mode
From: Marcel Holtmann @ 2013-10-15  9:30 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <20131015091658.GA4930@x220.p-661hnu-f1>

Hi Johan,

>>>> +	if (cp->val) {
>>>> +		struct hci_cp_write_current_iac_lap cp;
>>>> +
>>>> +		if (timeout > 0) {
>>>> +			/* Limited discoverable mode */
>>> 
>>> Wouldn't we want to follow the recommendation from the Core spec here,
>>> volume 3, part C, section 4.1.2.1:
>>> 
>>> "A Bluetooth device should not be in limited discoverable mode for more than
>>> TGAP(104)"
>>> 
>>> TGAP(104) in turn is defined as 1 minute (vol 3, part C, Appendix A).
>> 
>> I was not going to be this strict. So yes, userspace can violate the
>> GAP part here, but it might be a good idea to ensure that when a too
>> large value is entered we stick with general discoverable mode.
>> However is this really worth it.
> 
> For Advertising the max value is actually not just a recommendation but
> a requirement (check my other mail), so at least there we should
> probably enforce it. And if we have to enforce it for LE we might as
> well do it for BR/EDR too. It's anyway a rather simple change to the
> if-statement.
> 
>> Another option is to just reject too large timeout values as invalid
>> parameters and force userspace to implement large timeouts with
>> general discoverable mode in userspace.
> 
> I don't think it's a good idea to force this kind of special handling to
> user space (not just the requirement to know where the limits go but
> also the need to implement a separate timer).

This sounds also a bit like black magic. Userspace needs to know that a small value enters limited discoverable mode and a large one sticks with general discoverable mode. We might should have added a flag to the command in the first place. However I think our general intention was that with a timeout we do limited discoverable mode and without a timeout we do general discoverable mode.

I was complaining on why we bothered with a timeout for this parameter when building src/share/mgmt.[ch] and cleaning up some of the core adapter handling. Mainly because for PairableTimeout D-Bus property we have to run our own timer and for DiscoverableTimeout property we rely on the kernel. And in the end just running your own timeout was a lot simpler, then integrating with the kernel.

So I would be actually fine just saying with timeout that is limited discoverable mode. If you want general discoverable mode with a timeout, then you have to run this by yourself.

Then again, nothing stops us from introducing mode 0x02 for limited discoverable if you feel that we should keep the general discoverable mode with a timeout.

Regards

Marcel


^ permalink raw reply

* Re: [PATCH] Bluetooth: Add support for entering limited discoverable mode
From: Johan Hedberg @ 2013-10-15  9:16 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: linux-bluetooth
In-Reply-To: <66F13BAB-8341-44B5-9D84-A55DFDD6C324@holtmann.org>

Hi Marcel,

On Tue, Oct 15, 2013, Marcel Holtmann wrote:
> >> +	if (cp->val) {
> >> +		struct hci_cp_write_current_iac_lap cp;
> >> +
> >> +		if (timeout > 0) {
> >> +			/* Limited discoverable mode */
> > 
> > Wouldn't we want to follow the recommendation from the Core spec here,
> > volume 3, part C, section 4.1.2.1:
> > 
> > "A Bluetooth device should not be in limited discoverable mode for more than
> > TGAP(104)"
> > 
> > TGAP(104) in turn is defined as 1 minute (vol 3, part C, Appendix A).
> 
> I was not going to be this strict. So yes, userspace can violate the
> GAP part here, but it might be a good idea to ensure that when a too
> large value is entered we stick with general discoverable mode.
> However is this really worth it.

For Advertising the max value is actually not just a recommendation but
a requirement (check my other mail), so at least there we should
probably enforce it. And if we have to enforce it for LE we might as
well do it for BR/EDR too. It's anyway a rather simple change to the
if-statement.

> Another option is to just reject too large timeout values as invalid
> parameters and force userspace to implement large timeouts with
> general discoverable mode in userspace.

I don't think it's a good idea to force this kind of special handling to
user space (not just the requirement to know where the limits go but
also the need to implement a separate timer).

Johan

^ permalink raw reply

* Re: [PATCH] Bluetooth: Add support for entering limited discoverable mode
From: Marcel Holtmann @ 2013-10-15  8:52 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <20131015073157.GA24495@x220.p-661hnu-f1>

Hi Johan,

>> +	if (cp->val) {
>> +		struct hci_cp_write_current_iac_lap cp;
>> +
>> +		if (timeout > 0) {
>> +			/* Limited discoverable mode */
> 
> Wouldn't we want to follow the recommendation from the Core spec here,
> volume 3, part C, section 4.1.2.1:
> 
> "A Bluetooth device should not be in limited discoverable mode for more than
> TGAP(104)"
> 
> TGAP(104) in turn is defined as 1 minute (vol 3, part C, Appendix A).

I was not going to be this strict. So yes, userspace can violate the GAP part here, but it might be a good idea to ensure that when a too large value is entered we stick with general discoverable mode. However is this really worth it.

Another option is to just reject too large timeout values as invalid parameters and force userspace to implement large timeouts with general discoverable mode in userspace.

Regards

Marcel


^ permalink raw reply

* Re: [RFC BlueZ v0] doc: Add GATT API
From: Johan Hedberg @ 2013-10-15  8:35 UTC (permalink / raw)
  To: Claudio Takahasi; +Cc: linux-bluetooth
In-Reply-To: <1381777790-28891-1-git-send-email-claudio.takahasi@openbossa.org>

Hi Claudio,

On Mon, Oct 14, 2013, Claudio Takahasi wrote:
> +Service Manager hierarchy
> +=========================
> +
> +ServiceManager allows external applications to register GATT based services.
> +Services should follow the API for Service and Characteristic described above.
> +
> +For GATT local services, services and characteristics definitions are
> +discovered automatically using D-Bus Object Manager.
> +
> +Service		org.bluez
> +Interface	org.bluez.ServiceManager1 [Experimental]
> +Object path	/org/bluez
> +
> +Methods		RegisterApplication(object application, dict options)
> +
> +			Registers remote application services exported under
> +			the interface Service1. Characteristic objects must
> +			be hierarchical to their service and must use the
> +			interface Characteristic1. D-Bus Object Manager is
> +			used to fetch the exported objects.
> +
> +			"application" object path together with the D-Bus system
> +			bus connection ID define the identification of the
> +			application registering a GATT based service.
> +
> +			Possible errors: org.bluez.Error.InvalidArguments
> +					 org.bluez.Error.AlreadyExists
> +
> +		UnregisterApplication(object application)
> +
> +			This unregisters the application that has been
> +			previously registered. The object path parameter
> +			must match the same value that has been used
> +			on registration.
> +
> +			Possible errors: org.bluez.Error.DoesNotExist
> +
> +Service Agent hierarchy
> +=======================
> +
> +Service		org.bluez

I suppose this should not be "org.bluez" since it's the agent that's
providing it.

> +Interface	org.bluez.ServiceAgent1 [Experimental]
> +Object path	freely definable

If this is the object registered by ServiceManager1.RegisterApplication
I think we need some renaming. Either this interface should be called
org.bluez.ServiceApplication1 or the registration method shoud be
renamed to RegisterAgent.

Or is the idea that an "application" is a set of objects and interfaces
(services, characteristics, etc.) and as a minimum there must be this
ServiceAgent1 interface at the root object? In that case the naming
might make sense.

Johan

^ permalink raw reply

* Re: [PATCH] Bluetooth: Fix minor coding style issue in set_connectable()
From: Johan Hedberg @ 2013-10-15  8:28 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: linux-bluetooth
In-Reply-To: <1381793925-14134-1-git-send-email-marcel@holtmann.org>

Hi Marcel,

On Mon, Oct 14, 2013, Marcel Holtmann wrote:
> There is a minor coding style violation and so just fix it. No actual
> logic has changed.
> 
> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
> ---
>  net/bluetooth/mgmt.c | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)

Applied to bluetooth-next. Thanks.

Johan

^ permalink raw reply


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