Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH] Bluetooth: Add support for BCM20702A0 [04ca, 2003]
From: acho @ 2012-09-06  6:57 UTC (permalink / raw)
  To: marcel, gustavo, johan.hedberg, linux-bluetooth
  Cc: oneukum, acho, jlee, resler

From: "Cho, Yu-Chen" <acho@suse.com>

Add another vendor specific ID for BCM20702A0.

output of usb-devices:
T:  Bus=01 Lev=02 Prnt=02 Port=03 Cnt=02 Dev#=  4 Spd=12   MxCh= 0
D:  Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=04ca ProdID=2003 Rev= 1.12
S:  Manufacturer=Broadcom Corp
S:  Product=BCM20702A0
S:  SerialNumber=446D57861623
C:* #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr=  0mA
I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=1ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
I:  If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
I:  If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
I:  If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
I:  If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
I:  If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
E:  Ad=84(I) Atr=02(Bulk) MxPS=  32 Ivl=0ms
E:  Ad=04(O) Atr=02(Bulk) MxPS=  32 Ivl=0ms
I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)

Signed-off-by: Cho, Yu-Chen <acho@suse.com>
---
 drivers/bluetooth/btusb.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index f077f4d..75943c3 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -93,6 +93,7 @@ static struct usb_device_id btusb_table[] = {
 	{ USB_DEVICE(0x0c10, 0x0000) },
 
 	/* Broadcom BCM20702A0 */
+	{ USB_DEVICE(0x04ca, 0x2003) },
 	{ USB_DEVICE(0x0489, 0xe042) },
 	{ USB_DEVICE(0x0a5c, 0x21e3) },
 	{ USB_DEVICE(0x0a5c, 0x21e6) },
-- 
1.7.7

^ permalink raw reply related

* Re: [PATCH] Bluetooth: Add support for BCM20702A0 [04ca, 2003]
From: Al Cho @ 2012-09-06  7:32 UTC (permalink / raw)
  To: marcel, gustavo, johan.hedberg, linux-bluetooth
  Cc: oneukum, acho, jlee, resler
In-Reply-To: <1346914639-11040-1-git-send-email-acho@suse.com>

Sent a new patch that have new FROM tag

On Thu, Sep 6, 2012 at 2:57 PM,  <acho@suse.com> wrote:
> From: "Cho, Yu-Chen" <acho@suse.com>
>
> Add another vendor specific ID for BCM20702A0.
>
> output of usb-devices:
> T:  Bus=01 Lev=02 Prnt=02 Port=03 Cnt=02 Dev#=  4 Spd=12   MxCh= 0
> D:  Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
> P:  Vendor=04ca ProdID=2003 Rev= 1.12
> S:  Manufacturer=Broadcom Corp
> S:  Product=BCM20702A0
> S:  SerialNumber=446D57861623
> C:* #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr=  0mA
> I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=1ms
> E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
> E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
> I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
> I:  If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
> I:  If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
> I:  If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
> I:  If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
> I:  If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
> I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
> E:  Ad=84(I) Atr=02(Bulk) MxPS=  32 Ivl=0ms
> E:  Ad=04(O) Atr=02(Bulk) MxPS=  32 Ivl=0ms
> I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)
>
> Signed-off-by: Cho, Yu-Chen <acho@suse.com>
> ---
>  drivers/bluetooth/btusb.c |    1 +
>  1 files changed, 1 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> index f077f4d..75943c3 100644
> --- a/drivers/bluetooth/btusb.c
> +++ b/drivers/bluetooth/btusb.c
> @@ -93,6 +93,7 @@ static struct usb_device_id btusb_table[] = {
>         { USB_DEVICE(0x0c10, 0x0000) },
>
>         /* Broadcom BCM20702A0 */
> +       { USB_DEVICE(0x04ca, 0x2003) },
>         { USB_DEVICE(0x0489, 0xe042) },
>         { USB_DEVICE(0x0a5c, 0x21e3) },
>         { USB_DEVICE(0x0a5c, 0x21e6) },
> --
> 1.7.7
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>



-- 
Al Yu-Chen Cho
Software Engineer
Room B, 26/F, No. 216 Tun-Hwa S. Road, Sec. 2
Taipei, 106
+8862-2376-0010 X20031
acho@suse.com
SUSE

^ permalink raw reply

* [PATCH v2] Bluetooth: mgmt: Implement support for passkey notification
From: Johan Hedberg @ 2012-09-06  8:09 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1346832850-25061-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

This patch adds support for Secure Simple Pairing with devices that have
KeyboardOnly as their IO capability. Such devices will cause a passkey
notification on our side and optionally also keypress notifications.
Without this patch some keyboards cannot be paired using the mgmt
interface.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
v2: Make the keypress switch statement consistent with the rest of the code

 include/net/bluetooth/hci.h      |   18 ++++++++++
 include/net/bluetooth/hci_core.h |    5 +++
 include/net/bluetooth/mgmt.h     |    7 ++++
 net/bluetooth/hci_event.c        |   67 ++++++++++++++++++++++++++++++++++++++
 net/bluetooth/mgmt.c             |   16 +++++++++
 5 files changed, 113 insertions(+)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 0f28f70..76b2b6b 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1249,6 +1249,24 @@ struct hci_ev_simple_pair_complete {
 	bdaddr_t bdaddr;
 } __packed;
 
+#define HCI_EV_USER_PASSKEY_NOTIFY	0x3b
+struct hci_ev_user_passkey_notify {
+	bdaddr_t	bdaddr;
+	__le32		passkey;
+} __packed;
+
+#define HCI_KEYPRESS_STARTED		0
+#define HCI_KEYPRESS_ENTERED		1
+#define HCI_KEYPRESS_ERASED		2
+#define HCI_KEYPRESS_CLEARED		3
+#define HCI_KEYPRESS_COMPLETED		4
+
+#define HCI_EV_KEYPRESS_NOTIFY		0x3c
+struct hci_ev_keypress_notify {
+	bdaddr_t	bdaddr;
+	__u8		type;
+} __packed;
+
 #define HCI_EV_REMOTE_HOST_FEATURES	0x3d
 struct hci_ev_remote_host_features {
 	bdaddr_t bdaddr;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index fa807a3..b998b9c 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -303,6 +303,8 @@ struct hci_conn {
 	__u8		pin_length;
 	__u8		enc_key_size;
 	__u8		io_capability;
+	__u32		passkey_notify;
+	__u8		passkey_entered;
 	__u16		disc_timeout;
 	unsigned long	flags;
 
@@ -1016,6 +1018,9 @@ int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 				     u8 link_type, u8 addr_type, u8 status);
 int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 					 u8 link_type, u8 addr_type, u8 status);
+int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
+			     u8 link_type, u8 addr_type, u32 passkey,
+			     u8 entered);
 int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
 		     u8 addr_type, u8 status);
 int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status);
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 1b48eff..22980a7 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -478,3 +478,10 @@ struct mgmt_ev_device_unblocked {
 struct mgmt_ev_device_unpaired {
 	struct mgmt_addr_info addr;
 } __packed;
+
+#define MGMT_EV_PASSKEY_NOTIFY		0x0017
+struct mgmt_ev_passkey_notify {
+	struct mgmt_addr_info addr;
+	__le32	passkey;
+	__u8	entered;
+} __packed;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 48d7302..ccca88f 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3263,6 +3263,65 @@ static void hci_user_passkey_request_evt(struct hci_dev *hdev,
 		mgmt_user_passkey_request(hdev, &ev->bdaddr, ACL_LINK, 0);
 }
 
+static void hci_user_passkey_notify_evt(struct hci_dev *hdev,
+					struct sk_buff *skb)
+{
+	struct hci_ev_user_passkey_notify *ev = (void *) skb->data;
+	struct hci_conn *conn;
+
+	BT_DBG("%s", hdev->name);
+
+	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+	if (!conn)
+		return;
+
+	conn->passkey_notify = __le32_to_cpu(ev->passkey);
+	conn->passkey_entered = 0;
+
+	if (test_bit(HCI_MGMT, &hdev->dev_flags))
+		mgmt_user_passkey_notify(hdev, &conn->dst, conn->type,
+					 conn->dst_type, conn->passkey_notify,
+					 conn->passkey_entered);
+}
+
+static void hci_keypress_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_ev_keypress_notify *ev = (void *) skb->data;
+	struct hci_conn *conn;
+
+	BT_DBG("%s", hdev->name);
+
+	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+	if (!conn)
+		return;
+
+	switch (ev->type) {
+	case HCI_KEYPRESS_STARTED:
+		conn->passkey_entered = 0;
+		return;
+
+	case HCI_KEYPRESS_ENTERED:
+		conn->passkey_entered++;
+		break;
+
+	case HCI_KEYPRESS_ERASED:
+		conn->passkey_entered--;
+		break;
+
+	case HCI_KEYPRESS_CLEARED:
+		conn->passkey_entered = 0;
+		break;
+
+	case HCI_KEYPRESS_COMPLETED:
+		return;
+	}
+
+	if (test_bit(HCI_MGMT, &hdev->dev_flags))
+		mgmt_user_passkey_notify(hdev, &conn->dst, conn->type,
+					 conn->dst_type, conn->passkey_notify,
+					 conn->passkey_entered);
+}
+
 static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
 					 struct sk_buff *skb)
 {
@@ -3627,6 +3686,14 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 		hci_user_passkey_request_evt(hdev, skb);
 		break;
 
+	case HCI_EV_USER_PASSKEY_NOTIFY:
+		hci_user_passkey_notify_evt(hdev, skb);
+		break;
+
+	case HCI_EV_KEYPRESS_NOTIFY:
+		hci_keypress_notify_evt(hdev, skb);
+		break;
+
 	case HCI_EV_SIMPLE_PAIR_COMPLETE:
 		hci_simple_pair_complete_evt(hdev, skb);
 		break;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 05d4b83..4c04c1e 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -3276,6 +3276,22 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
 					  MGMT_OP_USER_PASSKEY_NEG_REPLY);
 }
 
+int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
+			     u8 link_type, u8 addr_type, u32 passkey,
+			     u8 entered)
+{
+	struct mgmt_ev_passkey_notify ev;
+
+	BT_DBG("%s", hdev->name);
+
+	bacpy(&ev.addr.bdaddr, bdaddr);
+	ev.addr.type = link_to_bdaddr(link_type, addr_type);
+	ev.passkey = __cpu_to_le32(passkey);
+	ev.entered = entered;
+
+	return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
+}
+
 int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
 		     u8 addr_type, u8 status)
 {
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH] gatt: Fix reading Service Changed CCC
From: Andrzej Kaczmarek @ 2012-09-06  9:15 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

Find Information Request is only sent when there are no more attributes
following Service Changed Value (incorrect) and thus will never find CCC.
---
 profiles/gatt/gas.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/profiles/gatt/gas.c b/profiles/gatt/gas.c
index ddd4e70..28d7fbf 100644
--- a/profiles/gatt/gas.c
+++ b/profiles/gatt/gas.c
@@ -245,7 +245,7 @@ static void gatt_characteristic_cb(GSList *characteristics, guint8 status,
 	start = chr->value_handle + 1;
 	end = gas->gatt.end;
 
-	if (start <= end) {
+	if (start > end) {
 		error("Inconsistent database: Service Changed CCC missing");
 		return;
 	}
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH obexd 1/7 v3] client: Add filters to Phonebook.PullAll
From: Luiz Augusto von Dentz @ 2012-09-06  9:25 UTC (permalink / raw)
  To: linux-bluetooth

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

This avoid D-Bus round trips and is more aligned with what has been
proposed for MessageAccess interface.
---
v3: Fix patch 2/7

 client/pbap.c | 255 +++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 209 insertions(+), 46 deletions(-)

diff --git a/client/pbap.c b/client/pbap.c
index ebd6320..f40f04b 100644
--- a/client/pbap.c
+++ b/client/pbap.c
@@ -351,18 +351,190 @@ send:
 	pending_request_free(request);
 }
 
+static GObexApparam *parse_format(GObexApparam *apparam, DBusMessageIter *iter)
+{
+	const char *string;
+	guint8 format;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+		return NULL;
+
+	dbus_message_iter_get_basic(iter, &string);
+
+	if (!string || g_str_equal(string, ""))
+		format = FORMAT_VCARD21;
+	else if (!g_ascii_strcasecmp(string, "vcard21"))
+		format = FORMAT_VCARD21;
+	else if (!g_ascii_strcasecmp(string, "vcard30"))
+		format = FORMAT_VCARD30;
+	else
+		return NULL;
+
+	return g_obex_apparam_set_uint8(apparam, FORMAT_TAG, format);
+}
+
+static GObexApparam *parse_order(GObexApparam *apparam, DBusMessageIter *iter)
+{
+	const char *string;
+	guint8 order;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+		return NULL;
+
+	dbus_message_iter_get_basic(iter, &string);
+
+	if (!string || g_str_equal(string, ""))
+		order = ORDER_INDEXED;
+	else if (!g_ascii_strcasecmp(string, "indexed"))
+		order = ORDER_INDEXED;
+	else if (!g_ascii_strcasecmp(string, "alphanumeric"))
+		order = ORDER_ALPHANUMERIC;
+	else if (!g_ascii_strcasecmp(string, "phonetic"))
+		order = ORDER_PHONETIC;
+	else
+		return NULL;
+
+	return g_obex_apparam_set_uint8(apparam, ORDER_TAG, order);
+}
+
+static GObexApparam *parse_offset(GObexApparam *apparam, DBusMessageIter *iter)
+{
+	guint16 num;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16)
+		return NULL;
+
+	dbus_message_iter_get_basic(iter, &num);
+
+	return g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG, num);
+}
+
+static GObexApparam *parse_max_count(GObexApparam *apparam,
+							DBusMessageIter *iter)
+{
+	guint16 num;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16)
+		return NULL;
+
+	dbus_message_iter_get_basic(iter, &num);
+
+	return g_obex_apparam_set_uint16(apparam, MAXLISTCOUNT_TAG, num);
+}
+
+static uint64_t get_filter_mask(const char *filterstr)
+{
+	int i, bit = -1;
+
+	if (!filterstr)
+		return 0;
+
+	if (!g_ascii_strcasecmp(filterstr, "ALL"))
+		return FILTER_ALL;
+
+	for (i = 0; filter_list[i] != NULL; i++)
+		if (!g_ascii_strcasecmp(filterstr, filter_list[i]))
+			return 1ULL << i;
+
+	if (strlen(filterstr) < 4 || strlen(filterstr) > 5
+			|| g_ascii_strncasecmp(filterstr, "bit", 3) != 0)
+		return 0;
+
+	sscanf(&filterstr[3], "%d", &bit);
+	if (bit >= 0 && bit <= FILTER_BIT_MAX)
+		return 1ULL << bit;
+	else
+		return 0;
+}
+
+static int set_field(guint64 *filter, const char *filterstr)
+{
+	guint64 mask;
+
+	mask = get_filter_mask(filterstr);
+
+	if (mask == 0)
+		return -EINVAL;
+
+	*filter |= mask;
+	return 0;
+}
+
+static GObexApparam *parse_fields(GObexApparam *apparam, DBusMessageIter *iter)
+{
+	DBusMessageIter array;
+	guint64 filter = 0;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+		return NULL;
+
+	dbus_message_iter_recurse(iter, &array);
+
+	while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
+		const char *string;
+
+		dbus_message_iter_get_basic(&array, &string);
+
+		if (set_field(&filter, string) < 0)
+			return NULL;
+
+		dbus_message_iter_next(&array);
+	}
+
+	return g_obex_apparam_set_uint64(apparam, FILTER_TAG, filter);
+}
+static GObexApparam *parse_filters(GObexApparam *apparam,
+							DBusMessageIter *iter)
+{
+	DBusMessageIter array;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+		return NULL;
+
+	dbus_message_iter_recurse(iter, &array);
+
+	while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
+		const char *key;
+		DBusMessageIter value, entry;
+
+		dbus_message_iter_recurse(&array, &entry);
+		dbus_message_iter_get_basic(&entry, &key);
+
+		dbus_message_iter_next(&entry);
+		dbus_message_iter_recurse(&entry, &value);
+
+		if (strcasecmp(key, "Format") == 0) {
+			if (parse_format(apparam, &value) == NULL)
+				return NULL;
+		} else if (strcasecmp(key, "Order") == 0) {
+			if (parse_order(apparam, &value) == NULL)
+				return NULL;
+		} else if (strcasecmp(key, "Offset") == 0) {
+			if (parse_offset(apparam, &value) == NULL)
+				return NULL;
+		} else if (strcasecmp(key, "MaxCount") == 0) {
+			if (parse_max_count(apparam, &value) == NULL)
+				return NULL;
+		} else if (strcasecmp(key, "Fields") == 0) {
+			if (parse_fields(apparam, &value) == NULL)
+				return NULL;
+		}
+
+		dbus_message_iter_next(&array);
+	}
+
+	return apparam;
+}
+
 static struct obc_transfer *pull_phonebook(struct pbap_data *pbap,
 						DBusMessage *message,
 						guint8 type, const char *name,
 						const char *targetfile,
-						uint64_t filter, guint8 format,
-						guint16 maxlistcount,
-						guint16 liststartoffset,
+						GObexApparam *apparam,
 						GError **err)
 {
 	struct pending_request *request;
 	struct obc_transfer *transfer;
-	GObexApparam *apparam;
 	guint8 buf[32];
 	gsize len;
 	session_callback_t func;
@@ -371,13 +543,6 @@ static struct obc_transfer *pull_phonebook(struct pbap_data *pbap,
 	if (transfer == NULL)
 		return NULL;
 
-	apparam = g_obex_apparam_set_uint64(NULL, FILTER_TAG, filter);
-	apparam = g_obex_apparam_set_uint8(apparam, FORMAT_TAG, format);
-	apparam = g_obex_apparam_set_uint16(apparam, MAXLISTCOUNT_TAG,
-							maxlistcount);
-	apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
-							liststartoffset);
-
 	switch (type) {
 	case PULLPHONEBOOK:
 		func = NULL;
@@ -396,8 +561,6 @@ static struct obc_transfer *pull_phonebook(struct pbap_data *pbap,
 
 	obc_transfer_set_params(transfer, buf, len);
 
-	g_obex_apparam_free(apparam);
-
 	if (!obc_session_queue(pbap->session, transfer, func, request, err)) {
 		if (request != NULL)
 			pending_request_free(request);
@@ -490,31 +653,6 @@ static int set_order(struct pbap_data *pbap, const char *orderstr)
 	return 0;
 }
 
-static uint64_t get_filter_mask(const char *filterstr)
-{
-	int i, bit = -1;
-
-	if (!filterstr)
-		return 0;
-
-	if (!g_ascii_strcasecmp(filterstr, "ALL"))
-		return FILTER_ALL;
-
-	for (i = 0; filter_list[i] != NULL; i++)
-		if (!g_ascii_strcasecmp(filterstr, filter_list[i]))
-			return 1ULL << i;
-
-	if (strlen(filterstr) < 4 || strlen(filterstr) > 5
-			|| g_ascii_strncasecmp(filterstr, "bit", 3) != 0)
-		return 0;
-
-	sscanf(&filterstr[3], "%d", &bit);
-	if (bit >= 0 && bit <= FILTER_BIT_MAX)
-		return 1ULL << bit;
-	else
-		return 0;
-}
-
 static int add_filter(struct pbap_data *pbap, const char *filterstr)
 {
 	uint64_t mask;
@@ -618,25 +756,41 @@ static DBusMessage *pbap_pull_all(DBusConnection *connection,
 	struct obc_transfer *transfer;
 	const char *targetfile;
 	char *name;
+	GObexApparam *apparam;
 	GError *err = NULL;
+	DBusMessageIter args;
 
 	if (!pbap->path)
 		return g_dbus_create_error(message,
 					ERROR_INTERFACE ".Forbidden",
 					"Call Select first of all");
 
-	if (dbus_message_get_args(message, NULL,
-			DBUS_TYPE_STRING, &targetfile,
-			DBUS_TYPE_INVALID) == FALSE)
+	dbus_message_iter_init(message, &args);
+
+	if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
 		return g_dbus_create_error(message,
 				ERROR_INTERFACE ".InvalidArguments", NULL);
 
+	dbus_message_iter_get_basic(&args, &targetfile);
+	dbus_message_iter_next(&args);
+
+	apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG,
+							DEFAULT_COUNT);
+	apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+							DEFAULT_OFFSET);
+
+	if (parse_filters(apparam, &args) == NULL) {
+		g_obex_apparam_free(apparam);
+		return g_dbus_create_error(message,
+				ERROR_INTERFACE ".InvalidArguments", NULL);
+	}
+
 	name = g_strconcat(pbap->path, ".vcf", NULL);
 
 	transfer = pull_phonebook(pbap, message, PULLPHONEBOOK, name,
-				targetfile, pbap->filter, pbap->format,
-				DEFAULT_COUNT, DEFAULT_OFFSET, &err);
+						targetfile, apparam, &err);
 	g_free(name);
+	g_obex_apparam_free(apparam);
 
 	if (transfer == NULL) {
 		DBusMessage *reply = g_dbus_create_error(message,
@@ -754,20 +908,28 @@ static DBusMessage *pbap_get_size(DBusConnection *connection,
 	DBusMessage *reply;
 	struct obc_transfer *transfer;
 	char *name;
+	GObexApparam *apparam;
 	GError *err = NULL;
+	DBusMessageIter args;
 
 	if (!pbap->path)
 		return g_dbus_create_error(message,
 					ERROR_INTERFACE ".Forbidden",
 					"Call Select first of all");
 
+	dbus_message_iter_init(message, &args);
+
 	name = g_strconcat(pbap->path, ".vcf", NULL);
 
+	apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG, 0);
+	apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+							DEFAULT_OFFSET);
+
 	transfer = pull_phonebook(pbap, message, GETPHONEBOOKSIZE, name, NULL,
-				pbap->filter, pbap->format, 0,
-				DEFAULT_OFFSET, &err);
+								apparam, &err);
 
 	g_free(name);
+	g_obex_apparam_free(apparam);
 
 	if (transfer != NULL)
 		return NULL;
@@ -891,7 +1053,8 @@ static const GDBusMethodTable pbap_methods[] = {
 			GDBUS_ARGS({ "location", "s" }, { "phonebook", "s" }),
 			NULL, pbap_select) },
 	{ GDBUS_METHOD("PullAll",
-			GDBUS_ARGS({ "targetfile", "s" }),
+			GDBUS_ARGS({ "targetfile", "s" },
+					{ "filters", "a{sv}" }),
 			GDBUS_ARGS({ "transfer", "o" },
 					{ "properties", "a{sv}" }),
 			pbap_pull_all) },
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH obexd 2/7 v2] client: Add filters to PhonebookAccess.Pull
From: Luiz Augusto von Dentz @ 2012-09-06  9:25 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1346923562-2654-1-git-send-email-luiz.dentz@gmail.com>

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

This avoid D-Bus round trips and is more aligned with what has been
proposed for MessageAccess interface.
---
 client/pbap.c | 78 +++++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 52 insertions(+), 26 deletions(-)

diff --git a/client/pbap.c b/client/pbap.c
index f40f04b..3fb1443 100644
--- a/client/pbap.c
+++ b/client/pbap.c
@@ -803,43 +803,25 @@ static DBusMessage *pbap_pull_all(DBusConnection *connection,
 	return obc_transfer_create_dbus_reply(transfer, message);
 }
 
-static DBusMessage *pbap_pull_vcard(DBusConnection *connection,
-					DBusMessage *message, void *user_data)
+static DBusMessage *pull_vcard(struct pbap_data *pbap, DBusMessage *message,
+				const char *name, const char *targetfile,
+				GObexApparam *apparam)
 {
-	struct pbap_data *pbap = user_data;
 	struct obc_transfer *transfer;
-	GObexApparam *apparam;
-	guint8 buf[32];
-	gsize len;
-	const char *name, *targetfile;
 	DBusMessage *reply;
 	GError *err = NULL;
+	guint8 buf[32];
+	gsize len;
 
-	if (!pbap->path)
-		return g_dbus_create_error(message,
-				ERROR_INTERFACE ".Forbidden",
-				"Call Select first of all");
-
-	if (dbus_message_get_args(message, NULL,
-			DBUS_TYPE_STRING, &name,
-			DBUS_TYPE_STRING, &targetfile,
-			DBUS_TYPE_INVALID) == FALSE)
-		return g_dbus_create_error(message,
-				ERROR_INTERFACE ".InvalidArguments", NULL);
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+	g_obex_apparam_free(apparam);
 
 	transfer = obc_transfer_get("x-bt/vcard", name, targetfile, &err);
 	if (transfer == NULL)
 		goto fail;
 
-	apparam = g_obex_apparam_set_uint64(NULL, FILTER_TAG, pbap->filter);
-	apparam = g_obex_apparam_set_uint8(apparam, FORMAT_TAG, pbap->format);
-
-	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
-
 	obc_transfer_set_params(transfer, buf, len);
 
-	g_obex_apparam_free(apparam);
-
 	if (!obc_session_queue(pbap->session, transfer, NULL, NULL, &err))
 		goto fail;
 
@@ -852,6 +834,49 @@ fail:
 	return reply;
 }
 
+static DBusMessage *pbap_pull_vcard(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	struct pbap_data *pbap = user_data;
+	GObexApparam *apparam;
+	const char *name, *targetfile;
+	DBusMessageIter args;
+
+	if (!pbap->path)
+		return g_dbus_create_error(message,
+				ERROR_INTERFACE ".Forbidden",
+				"Call Select first of all");
+
+	dbus_message_iter_init(message, &args);
+
+	if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+		return g_dbus_create_error(message,
+				ERROR_INTERFACE ".InvalidArguments", NULL);
+
+	dbus_message_iter_get_basic(&args, &name);
+	dbus_message_iter_next(&args);
+
+	if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+		return g_dbus_create_error(message,
+				ERROR_INTERFACE ".InvalidArguments", NULL);
+
+	dbus_message_iter_get_basic(&args, &targetfile);
+	dbus_message_iter_next(&args);
+
+	apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG,
+							DEFAULT_COUNT);
+	apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+							DEFAULT_OFFSET);
+
+	if (parse_filters(apparam, &args) == NULL) {
+		g_obex_apparam_free(apparam);
+		return g_dbus_create_error(message,
+				ERROR_INTERFACE ".InvalidArguments", NULL);
+	}
+
+	return pull_vcard(pbap, message, name, targetfile, apparam);
+}
+
 static DBusMessage *pbap_list(DBusConnection *connection,
 					DBusMessage *message, void *user_data)
 {
@@ -1059,7 +1084,8 @@ static const GDBusMethodTable pbap_methods[] = {
 					{ "properties", "a{sv}" }),
 			pbap_pull_all) },
 	{ GDBUS_METHOD("Pull",
-			GDBUS_ARGS({ "vcard", "s" }, { "targetfile", "s" }),
+			GDBUS_ARGS({ "vcard", "s" }, { "targetfile", "s" },
+					{ "filters", "a{sv}" }),
 			GDBUS_ARGS({ "transfer", "o" },
 					{ "properties", "a{sv}" }),
 			pbap_pull_vcard) },
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH obexd 3/7 v3] client: Add filters to PhonebookAccess.List and PhonebookAccess.Search
From: Luiz Augusto von Dentz @ 2012-09-06  9:25 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1346923562-2654-1-git-send-email-luiz.dentz@gmail.com>

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

This avoid D-Bus round trips and is more aligned with what has been
proposed for MessageAccess interface.
---
 client/pbap.c | 115 ++++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 76 insertions(+), 39 deletions(-)

diff --git a/client/pbap.c b/client/pbap.c
index 3fb1443..b1157e3 100644
--- a/client/pbap.c
+++ b/client/pbap.c
@@ -574,35 +574,24 @@ static struct obc_transfer *pull_phonebook(struct pbap_data *pbap,
 
 static DBusMessage *pull_vcard_listing(struct pbap_data *pbap,
 					DBusMessage *message, const char *name,
-					guint8 order, char *searchval, guint8 attrib,
-					guint16 count, guint16 offset)
+					GObexApparam *apparam)
 {
 	struct pending_request *request;
 	struct obc_transfer *transfer;
 	guint8 buf[272];
 	gsize len;
 	GError *err = NULL;
-	GObexApparam *apparam;
 	DBusMessage *reply;
 
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+	g_obex_apparam_free(apparam);
+
 	transfer = obc_transfer_get("x-bt/vcard-listing", name, NULL, &err);
 	if (transfer == NULL)
 		goto fail;
 
-	apparam = g_obex_apparam_set_uint8(NULL, ORDER_TAG, order);
-	apparam = g_obex_apparam_set_uint8(apparam, SEARCHATTRIB_TAG, attrib);
-	apparam = g_obex_apparam_set_string(apparam, SEARCHVALUE_TAG,
-								searchval);
-	apparam = g_obex_apparam_set_uint16(apparam, MAXLISTCOUNT_TAG, count);
-	apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
-								offset);
-
-	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
-
 	obc_transfer_set_params(transfer, buf, len);
 
-	g_obex_apparam_free(apparam);
-
 	request = pending_request_new(pbap, message);
 	if (obc_session_queue(pbap->session, transfer,
 				pull_vcard_listing_callback, request, &err))
@@ -881,34 +870,33 @@ static DBusMessage *pbap_list(DBusConnection *connection,
 					DBusMessage *message, void *user_data)
 {
 	struct pbap_data *pbap = user_data;
+	GObexApparam *apparam;
+	DBusMessageIter args;
 
 	if (!pbap->path)
 		return g_dbus_create_error(message,
 					ERROR_INTERFACE ".Forbidden",
 					"Call Select first of all");
 
-	return pull_vcard_listing(pbap, message, "", pbap->order, "",
-				ATTRIB_NAME, DEFAULT_COUNT, DEFAULT_OFFSET);
-}
+	dbus_message_iter_init(message, &args);
 
-static DBusMessage *pbap_search(DBusConnection *connection,
-					DBusMessage *message, void *user_data)
-{
-	struct pbap_data *pbap = user_data;
-	char *field, *value;
-	guint8 attrib;
+	apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG,
+							DEFAULT_COUNT);
+	apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+							DEFAULT_OFFSET);
 
-	if (dbus_message_get_args(message, NULL,
-			DBUS_TYPE_STRING, &field,
-			DBUS_TYPE_STRING, &value,
-			DBUS_TYPE_INVALID) == FALSE)
+	if (parse_filters(apparam, &args) == NULL) {
+		g_obex_apparam_free(apparam);
 		return g_dbus_create_error(message,
 				ERROR_INTERFACE ".InvalidArguments", NULL);
+	}
 
-	if (!pbap->path)
-		return g_dbus_create_error(message,
-					ERROR_INTERFACE ".Forbidden",
-					"Call Select first of all");
+	return pull_vcard_listing(pbap, message, "", apparam);
+}
+
+static GObexApparam *parse_attribute(GObexApparam *apparam, const char *field)
+{
+	guint8 attrib;
 
 	if (!field || g_str_equal(field, ""))
 		attrib = ATTRIB_NAME;
@@ -919,11 +907,58 @@ static DBusMessage *pbap_search(DBusConnection *connection,
 	else if (!g_ascii_strcasecmp(field, "sound"))
 		attrib = ATTRIB_SOUND;
 	else
+		return NULL;
+
+	return g_obex_apparam_set_uint8(apparam, SEARCHATTRIB_TAG, attrib);
+}
+
+static DBusMessage *pbap_search(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	struct pbap_data *pbap = user_data;
+	char *field, *value;
+	GObexApparam *apparam;
+	DBusMessageIter args;
+
+	if (!pbap->path)
+		return g_dbus_create_error(message,
+					ERROR_INTERFACE ".Forbidden",
+					"Call Select first of all");
+
+	dbus_message_iter_init(message, &args);
+
+	if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+		return g_dbus_create_error(message,
+				ERROR_INTERFACE ".InvalidArguments", NULL);
+
+	dbus_message_iter_get_basic(&args, &field);
+	dbus_message_iter_next(&args);
+
+	apparam = parse_attribute(NULL, field);
+	if (apparam == NULL)
+		return g_dbus_create_error(message,
+				ERROR_INTERFACE ".InvalidArguments", NULL);
+
+	if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+		return g_dbus_create_error(message,
+				ERROR_INTERFACE ".InvalidArguments", NULL);
+
+	dbus_message_iter_get_basic(&args, &value);
+	dbus_message_iter_next(&args);
+
+	apparam = g_obex_apparam_set_uint16(apparam, MAXLISTCOUNT_TAG,
+							DEFAULT_COUNT);
+	apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+							DEFAULT_OFFSET);
+	apparam = g_obex_apparam_set_string(apparam, SEARCHVALUE_TAG, value);
+
+	if (parse_filters(apparam, &args) == NULL) {
+		g_obex_apparam_free(apparam);
 		return g_dbus_create_error(message,
 				ERROR_INTERFACE ".InvalidArguments", NULL);
+	}
 
-	return pull_vcard_listing(pbap, message, "", pbap->order, value,
-					attrib, DEFAULT_COUNT, DEFAULT_OFFSET);
+	return pull_vcard_listing(pbap, message, "", apparam);
 }
 
 static DBusMessage *pbap_get_size(DBusConnection *connection,
@@ -1090,12 +1125,14 @@ static const GDBusMethodTable pbap_methods[] = {
 					{ "properties", "a{sv}" }),
 			pbap_pull_vcard) },
 	{ GDBUS_ASYNC_METHOD("List",
-				NULL, GDBUS_ARGS({ "vcard_listing", "a(ss)" }),
-				pbap_list) },
+			GDBUS_ARGS({ "filters", "a{sv}" }),
+			GDBUS_ARGS({ "vcard_listing", "a(ss)" }),
+			pbap_list) },
 	{ GDBUS_ASYNC_METHOD("Search",
-				GDBUS_ARGS({ "field", "s" }, { "value", "s" }),
-				GDBUS_ARGS({ "vcard_listing", "a(ss)" }),
-				pbap_search) },
+			GDBUS_ARGS({ "field", "s" }, { "value", "s" },
+					{ "filters", "a{sv}" }),
+			GDBUS_ARGS({ "vcard_listing", "a(ss)" }),
+			pbap_search) },
 	{ GDBUS_ASYNC_METHOD("GetSize",
 				NULL, GDBUS_ARGS({ "size", "q" }),
 				pbap_get_size) },
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH obexd 4/7 v3] client: Remove deprecated methods from PhonebookAccess
From: Luiz Augusto von Dentz @ 2012-09-06  9:25 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1346923562-2654-1-git-send-email-luiz.dentz@gmail.com>

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

SetFormat, SetOrder, SetFilter and GetFilter methods are no longer
necessary as other methods now take them as parameters to avoid round
trips.
---
 client/pbap.c | 197 +++++-----------------------------------------------------
 1 file changed, 14 insertions(+), 183 deletions(-)

diff --git a/client/pbap.c b/client/pbap.c
index b1157e3..a90d515 100644
--- a/client/pbap.c
+++ b/client/pbap.c
@@ -116,9 +116,6 @@ static const char *filter_list[] = {
 struct pbap_data {
 	struct obc_session *session;
 	char *path;
-	guint8 format;
-	guint8 order;
-	uint64_t filter;
 };
 
 struct pending_request {
@@ -606,91 +603,6 @@ fail:
 	return reply;
 }
 
-static int set_format(struct pbap_data *pbap, const char *formatstr)
-{
-	if (!formatstr || g_str_equal(formatstr, "")) {
-		pbap->format = FORMAT_VCARD21;
-		return 0;
-	}
-
-	if (!g_ascii_strcasecmp(formatstr, "vcard21"))
-		pbap->format = FORMAT_VCARD21;
-	else if (!g_ascii_strcasecmp(formatstr, "vcard30"))
-		pbap->format = FORMAT_VCARD30;
-	else
-		return -EINVAL;
-
-	return 0;
-}
-
-static int set_order(struct pbap_data *pbap, const char *orderstr)
-{
-	if (!orderstr || g_str_equal(orderstr, "")) {
-		pbap->order = ORDER_INDEXED;
-		return 0;
-	}
-
-	if (!g_ascii_strcasecmp(orderstr, "indexed"))
-		pbap->order = ORDER_INDEXED;
-	else if (!g_ascii_strcasecmp(orderstr, "alphanumeric"))
-		pbap->order = ORDER_ALPHANUMERIC;
-	else if (!g_ascii_strcasecmp(orderstr, "phonetic"))
-		pbap->order = ORDER_PHONETIC;
-	else
-		return -EINVAL;
-
-	return 0;
-}
-
-static int add_filter(struct pbap_data *pbap, const char *filterstr)
-{
-	uint64_t mask;
-
-	mask = get_filter_mask(filterstr);
-
-	if (mask == 0)
-		return -EINVAL;
-
-	pbap->filter |= mask;
-	return 0;
-}
-
-static int remove_filter(struct pbap_data *pbap, const char *filterstr)
-{
-	uint64_t mask;
-
-	mask = get_filter_mask(filterstr);
-
-	if (mask == 0)
-		return -EINVAL;
-
-	pbap->filter &= ~mask;
-	return 0;
-}
-
-static gchar **get_filter_strs(uint64_t filter, gint *size)
-{
-	gchar **list, **item;
-	gint i;
-	gint filter_list_size = sizeof(filter_list) / sizeof(filter_list[0]) - 1;
-
-	list = g_malloc0(sizeof(gchar **) * (FILTER_BIT_MAX + 2));
-
-	item = list;
-
-	for (i = 0; i < filter_list_size; i++)
-		if (filter & (1ULL << i))
-			*(item++) = g_strdup(filter_list[i]);
-
-	for (i = filter_list_size; i <= FILTER_BIT_MAX; i++)
-		if (filter & (1ULL << i))
-			*(item++) = g_strdup_printf("%s%d", "BIT", i);
-
-	*item = NULL;
-	*size = item - list;
-	return list;
-}
-
 static DBusMessage *pbap_select(DBusConnection *connection,
 					DBusMessage *message, void *user_data)
 {
@@ -1000,95 +912,26 @@ static DBusMessage *pbap_get_size(DBusConnection *connection,
 	return reply;
 }
 
-static DBusMessage *pbap_set_format(DBusConnection *connection,
-					DBusMessage *message, void *user_data)
-{
-	struct pbap_data *pbap = user_data;
-	const char *format;
-
-	if (dbus_message_get_args(message, NULL,
-			DBUS_TYPE_STRING, &format,
-			DBUS_TYPE_INVALID) == FALSE)
-		return g_dbus_create_error(message,
-				ERROR_INTERFACE ".InvalidArguments", NULL);
-
-	if (set_format(pbap, format) < 0)
-		return g_dbus_create_error(message,
-					ERROR_INTERFACE ".InvalidArguments",
-					"InvalidFormat");
-
-	return dbus_message_new_method_return(message);
-}
-
-static DBusMessage *pbap_set_order(DBusConnection *connection,
-					DBusMessage *message, void *user_data)
-{
-	struct pbap_data *pbap = user_data;
-	const char *order;
-
-	if (dbus_message_get_args(message, NULL,
-			DBUS_TYPE_STRING, &order,
-			DBUS_TYPE_INVALID) == FALSE)
-		return g_dbus_create_error(message,
-				ERROR_INTERFACE ".InvalidArguments", NULL);
-
-	if (set_order(pbap, order) < 0)
-		return g_dbus_create_error(message,
-					ERROR_INTERFACE ".InvalidArguments",
-					"InvalidFilter");
-
-	return dbus_message_new_method_return(message);
-}
-
-static DBusMessage *pbap_set_filter(DBusConnection *connection,
-					DBusMessage *message, void *user_data)
+static gchar **get_filter_strs(uint64_t filter, gint *size)
 {
-	struct pbap_data *pbap = user_data;
-	char **filters, **item;
-	gint size;
-	uint64_t oldfilter = pbap->filter;
-
-	if (dbus_message_get_args(message, NULL, DBUS_TYPE_ARRAY,
-			DBUS_TYPE_STRING, &filters, &size,
-			DBUS_TYPE_INVALID) == FALSE)
-		return g_dbus_create_error(message,
-				ERROR_INTERFACE ".InvalidArguments", NULL);
-
-	remove_filter(pbap, "ALL");
-	if (size == 0)
-		goto done;
+	gchar **list, **item;
+	gint i;
 
-	for (item = filters; *item; item++) {
-		if (add_filter(pbap, *item) < 0) {
-			pbap->filter = oldfilter;
-			g_strfreev(filters);
-			return g_dbus_create_error(message,
-					ERROR_INTERFACE ".InvalidArguments",
-					"InvalidFilters");
-		}
-	}
+	list = g_malloc0(sizeof(gchar **) * (FILTER_BIT_MAX + 2));
 
-done:
-	g_strfreev(filters);
-	return dbus_message_new_method_return(message);
-}
+	item = list;
 
-static DBusMessage *pbap_get_filter(DBusConnection *connection,
-					DBusMessage *message, void *user_data)
-{
-	struct pbap_data *pbap = user_data;
-	gchar **filters = NULL;
-	gint size;
-	DBusMessage *reply;
+	for (i = 0; filter_list[i] != NULL; i++)
+		if (filter & (1ULL << i))
+			*(item++) = g_strdup(filter_list[i]);
 
-	filters = get_filter_strs(pbap->filter, &size);
-	reply = dbus_message_new_method_return(message);
-	dbus_message_append_args(reply, DBUS_TYPE_ARRAY,
-				DBUS_TYPE_STRING, &filters, size,
-				DBUS_TYPE_INVALID);
+	for (; i <= FILTER_BIT_MAX; i++)
+		if (filter & (1ULL << i))
+			*(item++) = g_strdup_printf("%s%d", "BIT", i);
 
-	g_strfreev(filters);
-	return reply;
+	*item = NULL;
+	*size = item - list;
+	return list;
 }
 
 static DBusMessage *pbap_list_filter_fields(DBusConnection *connection,
@@ -1136,18 +979,6 @@ static const GDBusMethodTable pbap_methods[] = {
 	{ GDBUS_ASYNC_METHOD("GetSize",
 				NULL, GDBUS_ARGS({ "size", "q" }),
 				pbap_get_size) },
-	{ GDBUS_METHOD("SetFormat",
-				GDBUS_ARGS({ "format", "s" }), NULL,
-				pbap_set_format) },
-	{ GDBUS_METHOD("SetOrder",
-				GDBUS_ARGS({ "order", "s" }), NULL,
-				pbap_set_order) },
-	{ GDBUS_METHOD("SetFilter",
-				GDBUS_ARGS({ "fields", "as" }), NULL,
-				pbap_set_filter) },
-	{ GDBUS_METHOD("GetFilter",
-				NULL, GDBUS_ARGS({ "fields", "as" }),
-				pbap_get_filter) },
 	{ GDBUS_METHOD("ListFilterFields",
 				NULL, GDBUS_ARGS({ "fields", "as" }),
 				pbap_list_filter_fields) },
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH obexd 5/7 v3] test: Update pbap-client to work with changes in PhonebookAcess
From: Luiz Augusto von Dentz @ 2012-09-06  9:26 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1346923562-2654-1-git-send-email-luiz.dentz@gmail.com>

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

---
 test/pbap-client | 21 +++++++++------------
 1 file changed, 9 insertions(+), 12 deletions(-)

diff --git a/test/pbap-client b/test/pbap-client
index 498f8a3..7dd54ef 100755
--- a/test/pbap-client
+++ b/test/pbap-client
@@ -70,16 +70,16 @@ class PbapClient:
 		print "Transfer finished with error %s: %s" % (code, message)
 		mainloop.quit()
 
-	def pull(self, vcard, func):
+	def pull(self, vcard, params, func):
 		req = Transfer(func)
-		self.pbap.Pull(vcard, "",
+		self.pbap.Pull(vcard, "", params,
 				reply_handler=lambda r: self.register(r, req),
 				error_handler=self.error)
 		self.transfers += 1
 
-	def pull_all(self, func):
+	def pull_all(self, params, func):
 		req = Transfer(func)
-		self.pbap.PullAll("",
+		self.pbap.PullAll("", params,
 				reply_handler=lambda r: self.register(r, req),
 				error_handler=self.error)
 		self.transfers += 1
@@ -135,18 +135,15 @@ if  __name__ == '__main__':
 		print "Size = %d\n" % (ret)
 
 		print "\n--- List vCard ---\n"
-		ret = pbap_client.interface().List()
+		ret = pbap_client.interface().List(dbus.Dictionary())
+		params = dbus.Dictionary({ "Format" : "vcard30",
+					"Fields" : [ "VERSION", "FN", "TEL"] })
 		for item in ret:
 			print "%s : %s" % (item[0], item[1])
-			pbap_client.interface().SetFormat("vcard30")
-			pbap_client.interface().SetFilter(["VERSION", "FN",
-								"TEL"]);
-			pbap_client.pull(item[0],
+			pbap_client.pull(item[0], params,
 					lambda x: process_result(x, None))
 
-		pbap_client.interface().SetFormat("vcard30")
-		pbap_client.interface().SetFilter(["VERSION", "FN", "TEL"]);
-		pbap_client.pull_all(lambda x: process_result(x,
+		pbap_client.pull_all(params, lambda x: process_result(x,
 							"\n--- PullAll ---\n"))
 
 		pbap_client.flush_transfers(lambda: test_paths(paths[1:]))
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH obexd 6/7 v3] client: Move common code to pull_phonebook
From: Luiz Augusto von Dentz @ 2012-09-06  9:26 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1346923562-2654-1-git-send-email-luiz.dentz@gmail.com>

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

---
 client/pbap.c | 79 +++++++++++++++++++++++------------------------------------
 1 file changed, 30 insertions(+), 49 deletions(-)

diff --git a/client/pbap.c b/client/pbap.c
index a90d515..16778f8 100644
--- a/client/pbap.c
+++ b/client/pbap.c
@@ -523,22 +523,29 @@ static GObexApparam *parse_filters(GObexApparam *apparam,
 	return apparam;
 }
 
-static struct obc_transfer *pull_phonebook(struct pbap_data *pbap,
+static DBusMessage *pull_phonebook(struct pbap_data *pbap,
 						DBusMessage *message,
-						guint8 type, const char *name,
+						guint8 type,
 						const char *targetfile,
-						GObexApparam *apparam,
-						GError **err)
+						GObexApparam *apparam)
 {
 	struct pending_request *request;
 	struct obc_transfer *transfer;
+	char *name;
 	guint8 buf[32];
 	gsize len;
 	session_callback_t func;
+	DBusMessage *reply;
+	GError *err = NULL;
+
+	name = g_strconcat(pbap->path, ".vcf", NULL);
+
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+	g_obex_apparam_free(apparam);
 
-	transfer = obc_transfer_get("x-bt/phonebook", name, targetfile, err);
+	transfer = obc_transfer_get("x-bt/phonebook", name, targetfile, &err);
 	if (transfer == NULL)
-		return NULL;
+		goto fail;
 
 	switch (type) {
 	case PULLPHONEBOOK:
@@ -554,19 +561,28 @@ static struct obc_transfer *pull_phonebook(struct pbap_data *pbap,
 		return NULL;
 	}
 
-	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
-
 	obc_transfer_set_params(transfer, buf, len);
 
-	if (!obc_session_queue(pbap->session, transfer, func, request, err)) {
+	if (!obc_session_queue(pbap->session, transfer, func, request, &err)) {
 		if (request != NULL)
 			pending_request_free(request);
 
-		return NULL;
+		goto fail;
 	}
 
+	g_free(name);
+
+	if (targetfile == NULL)
+		return NULL;
 
-	return transfer;
+	return obc_transfer_create_dbus_reply(transfer, message);
+
+fail:
+	g_free(name);
+	reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
+								err->message);
+	g_error_free(err);
+	return reply;
 }
 
 static DBusMessage *pull_vcard_listing(struct pbap_data *pbap,
@@ -654,11 +670,8 @@ static DBusMessage *pbap_pull_all(DBusConnection *connection,
 					DBusMessage *message, void *user_data)
 {
 	struct pbap_data *pbap = user_data;
-	struct obc_transfer *transfer;
 	const char *targetfile;
-	char *name;
 	GObexApparam *apparam;
-	GError *err = NULL;
 	DBusMessageIter args;
 
 	if (!pbap->path)
@@ -686,22 +699,8 @@ static DBusMessage *pbap_pull_all(DBusConnection *connection,
 				ERROR_INTERFACE ".InvalidArguments", NULL);
 	}
 
-	name = g_strconcat(pbap->path, ".vcf", NULL);
-
-	transfer = pull_phonebook(pbap, message, PULLPHONEBOOK, name,
-						targetfile, apparam, &err);
-	g_free(name);
-	g_obex_apparam_free(apparam);
-
-	if (transfer == NULL) {
-		DBusMessage *reply = g_dbus_create_error(message,
-					ERROR_INTERFACE ".Failed", "%s",
-					err->message);
-		g_error_free(err);
-		return reply;
-	}
-
-	return obc_transfer_create_dbus_reply(transfer, message);
+	return pull_phonebook(pbap, message, PULLPHONEBOOK, targetfile,
+								apparam);
 }
 
 static DBusMessage *pull_vcard(struct pbap_data *pbap, DBusMessage *message,
@@ -877,11 +876,7 @@ static DBusMessage *pbap_get_size(DBusConnection *connection,
 					DBusMessage *message, void *user_data)
 {
 	struct pbap_data *pbap = user_data;
-	DBusMessage *reply;
-	struct obc_transfer *transfer;
-	char *name;
 	GObexApparam *apparam;
-	GError *err = NULL;
 	DBusMessageIter args;
 
 	if (!pbap->path)
@@ -891,25 +886,11 @@ static DBusMessage *pbap_get_size(DBusConnection *connection,
 
 	dbus_message_iter_init(message, &args);
 
-	name = g_strconcat(pbap->path, ".vcf", NULL);
-
 	apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG, 0);
 	apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
 							DEFAULT_OFFSET);
 
-	transfer = pull_phonebook(pbap, message, GETPHONEBOOKSIZE, name, NULL,
-								apparam, &err);
-
-	g_free(name);
-	g_obex_apparam_free(apparam);
-
-	if (transfer != NULL)
-		return NULL;
-
-	reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
-								err->message);
-	g_error_free(err);
-	return reply;
+	return pull_phonebook(pbap, message, GETPHONEBOOKSIZE, NULL, apparam);
 }
 
 static gchar **get_filter_strs(uint64_t filter, gint *size)
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH obexd 7/7 v3] client-doc: Update documentation of PhonebookAccess interface
From: Luiz Augusto von Dentz @ 2012-09-06  9:26 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1346923562-2654-1-git-send-email-luiz.dentz@gmail.com>

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

---
 doc/client-api.txt | 62 +++++++++++++++++++++++++++++++-----------------------
 1 file changed, 36 insertions(+), 26 deletions(-)

diff --git a/doc/client-api.txt b/doc/client-api.txt
index 7ca65cc..f447789 100644
--- a/doc/client-api.txt
+++ b/doc/client-api.txt
@@ -206,7 +206,7 @@ Methods		void Select(string location, string phonebook)
 				"mch":	missing call history
 				"cch":	combination of ich och mch
 
-		object, dict PullAll(string targetfile)
+		object, dict PullAll(string targetfile, dict filters)
 
 			Return the entire phonebook object from the PSE server
 			in plain string with vcard format, and store it in
@@ -222,14 +222,21 @@ Methods		void Select(string location, string phonebook)
 			The properties of this transfer are also returned along
 			with the object path, to avoid a call to GetProperties.
 
-		array{string vcard, string name} List()
+			Possible filters: Format, Order, Offset, MaxCount and
+			Fields
+
+		array{string vcard, string name} List(dict filters)
 
 			Return an array of vcard-listing data where every entry
 			consists of a pair of strings containing the vcard
 			handle and the contact name. For example:
 				"1.vcf" : "John"
 
-		object, dict Pull(string vcard, string targetfile)
+			Possible filters: Order, Offset and MaxCount
+
+
+		object, dict
+		Pull(string vcard, string targetfile, dict filters)
 
 			Given a vcard handle, retrieve the vcard in the current
 			phonebook object and store it in a local file.
@@ -244,8 +251,11 @@ Methods		void Select(string location, string phonebook)
 			The properties of this transfer are also returned along
 			with the object path, to avoid a call to GetProperties.
 
+			Possbile filters: Format and Fields
+
+
 		array{string vcard, string name}
-		Search(string field, string value)
+		Search(string field, string value, dict filters)
 
 			Search for entries matching the given condition and
 			return an array of vcard-listing data where every entry
@@ -258,47 +268,47 @@ Methods		void Select(string location, string phonebook)
 				{ "name" (default) | "number" | "sound" }
 			value : the string value to search for
 
+
+			Possible filters: Order, Offset and MaxCount
+
 		uint16 GetSize()
 
 			Return the number of entries in the selected phonebook
 			object that are actually used (i.e. indexes that
 			correspond to non-NULL entries).
 
-		void SetFormat(string format)
+		array{string} ListFilterFields()
 
-			Indicate the format of the vcard that should be return
-			by related methods.
+			Return All Available fields that can be used in Fields
+			filter.
 
-			format : { "vcard21" (default) | "vcard30" }
+Filter:		string Format:
 
-		void SetOrder(string order)
+			Items vcard format
 
-			Indicate the sorting method of the vcard-listing data
-			returned by List and Search methods.
+			Possible values: "vcard21" (default) or "vcard30"
 
-			order : { "indexed" (default) | "alphanumeric" |
-					"phonetic" }
+		string Order:
 
-		void SetFilter(array{string})
+			Items order
 
-			Indicate fields that should be contained in vcards
-			return by related methods.
+			Possible values: "indexed" (default), "alphanumeric" or
+			"phonetic"
 
-			Give an empty array will clear the filter and return
-			all fields available in vcards. And this is the default
-			behavior.
+		uint16 Offset:
 
-			Possible filter fields : "VERSION", "FN", ..., "ALL",
-			"bit[0-63]"
+			Offset of the first item, default is 0
 
-		array{string} ListFilterFields()
+		uint16 MaxCount:
+
+			Maximum number of items, default is unlimited (65535)
+
+		array{string} Fields:
 
-			Return All Available fields that can be used in
-			SetFilter method.
+			Item vcard fields, default is all values.
 
-		array{string} GetFilter()
+			Possible values can be query with ListFilterFields.
 
-			Return the current filter setting
 
 Synchronization hierarchy
 =======================
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH] gatt: Remove reading Service Changed characteristic after connected
From: Andrzej Kaczmarek @ 2012-09-06 10:53 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

Service Changed characteristic is a control-point attribute thus it cannot be
read and attempting to do so will fail. Instead, server shall send indication
once enabled in CCC.
---
 profiles/gatt/gas.c | 37 -------------------------------------
 1 file changed, 37 deletions(-)

diff --git a/profiles/gatt/gas.c b/profiles/gatt/gas.c
index 28d7fbf..d189221 100644
--- a/profiles/gatt/gas.c
+++ b/profiles/gatt/gas.c
@@ -161,37 +161,6 @@ static void indication_cb(const uint8_t *pdu, uint16_t len, gpointer user_data)
 	btd_device_gatt_set_service_changed(gas->device, start, end);
 }
 
-static void gatt_service_changed_cb(guint8 status, const guint8 *pdu,
-					guint16 plen, gpointer user_data)
-{
-	struct gas *gas = user_data;
-	uint16_t start, end;
-
-	if (status) {
-		error("Read GATT Service Changed failed: %s",
-						att_ecode2str(status));
-		return;
-	}
-
-	if (plen != 5) {
-		error("Service Changed: PDU length mismatch");
-		return;
-	}
-
-	start = att_get_u16(&pdu[1]);
-	end = att_get_u16(&pdu[3]);
-
-	if (gas->changed.start == start && gas->changed.end == end)
-		return;
-
-	gas->changed.start = start;
-	gas->changed.end = end;
-
-	DBG("GATT Service Changed start: 0x%04X end: 0x%04X", start, end);
-
-	btd_device_gatt_set_service_changed(gas->device, start, end);
-}
-
 static void gatt_descriptors_cb(guint8 status, const guint8 *pdu, guint16 len,
 							gpointer user_data)
 {
@@ -311,8 +280,6 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 	/* TODO: Read other GAP characteristics - See Core spec page 1739 */
 
 	/*
-	 * Always read the characteristic value in the first connection
-	 * since attribute handles caching is not supported at the moment.
 	 * When re-connecting <<Service Changed>> handle and characteristic
 	 * value doesn't need to read again: known information from the
 	 * previous interaction.
@@ -322,10 +289,6 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 
 		bt_uuid16_create(&uuid, GATT_CHARAC_SERVICE_CHANGED);
 
-		gatt_read_char_by_uuid(gas->attrib, gas->gatt.start,
-						gas->gatt.end, &uuid,
-						gatt_service_changed_cb, gas);
-
 		gatt_discover_char(gas->attrib, gas->gatt.start, gas->gatt.end,
 					&uuid, gatt_characteristic_cb, gas);
 	}
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH] Fix endian safe issue, make driver work on both little and big endian cpu.
From: Peng Chen @ 2012-09-06 11:30 UTC (permalink / raw)
  To: gustavo; +Cc: linux-bluetooth, marcel, Peng Chen


Signed-off-by: Peng Chen <pengchen@qca.qualcomm.com>
---
 drivers/bluetooth/ath3k.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 10308cd..e63aee1 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -299,7 +299,7 @@ static int ath3k_load_patch(struct usb_device *udev)
 	}
 
 	snprintf(filename, ATH3K_NAME_LEN, "ar3k/AthrBT_0x%08x.dfu",
-		fw_version.rom_version);
+		le32_to_cpu(fw_version.rom_version));
 
 	ret = request_firmware(&firmware, filename, &udev->dev);
 	if (ret < 0) {
@@ -361,7 +361,7 @@ static int ath3k_load_syscfg(struct usb_device *udev)
 	}
 
 	snprintf(filename, ATH3K_NAME_LEN, "ar3k/ramps_0x%08x_%d%s",
-		fw_version.rom_version, clk_value, ".dfu");
+		le32_to_cpu(fw_version.rom_version), clk_value, ".dfu");
 
 	ret = request_firmware(&firmware, filename, &udev->dev);
 	if (ret < 0) {
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v3 00/17] Heart Rate Profile plugin
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

Hi,

Changes since v2:
* rewritten MeasurementReceived description in API
* minor coding style fix
(both suggested by Vinicius, thanks)


Andrzej Kaczmarek (6):
  heartrate: Add attio callbacks
  heartrate: Enable measurement when watchers are registered
  heartrate: Read Heart Rate Control Point characteristics
  heartrate: Handle characteristics value changed notification
  heartrate: Process Heart Rate Measurement characteristics
  heartrate: Add Reset method

Rafal Garbat (10):
  heartrate: Add Heart Rate Profile client
  heartrate: Discover characteristics
  heartrate: Process characteristics
  heartrate: Discover characteristics descriptors
  heartrate: Process characteristics descriptors
  heartrate: Add HeartRateManager interface
  heartrate: Read Body Sensor Location characteristics
  heartrate: Add GetProperties method
  heartrate: Add HeartRateWatcher interface to default policy
  heartrate: Add test script

Santiago Carot-Nemesio (1):
  Heart Rate Profile API

 Makefile.am                    |   9 +-
 Makefile.tools                 |   4 +-
 doc/heartrate-api.txt          |  84 ++++
 lib/uuid.h                     |   5 +
 profiles/heartrate/heartrate.c | 971 +++++++++++++++++++++++++++++++++++++++++
 profiles/heartrate/heartrate.h |  27 ++
 profiles/heartrate/main.c      |  52 +++
 profiles/heartrate/manager.c   |  95 ++++
 profiles/heartrate/manager.h   |  24 +
 src/bluetooth.conf             |   1 +
 test/test-heartrate            | 103 +++++
 11 files changed, 1371 insertions(+), 4 deletions(-)
 create mode 100644 doc/heartrate-api.txt
 create mode 100644 profiles/heartrate/heartrate.c
 create mode 100644 profiles/heartrate/heartrate.h
 create mode 100644 profiles/heartrate/main.c
 create mode 100644 profiles/heartrate/manager.c
 create mode 100644 profiles/heartrate/manager.h
 create mode 100755 test/test-heartrate

-- 
1.7.11.3


^ permalink raw reply

* [PATCH v3 01/17] Heart Rate Profile API
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1346931171-18968-1-git-send-email-andrzej.kaczmarek@tieto.com>

From: Santiago Carot-Nemesio <sancane@gmail.com>

---
 doc/heartrate-api.txt | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)
 create mode 100644 doc/heartrate-api.txt

diff --git a/doc/heartrate-api.txt b/doc/heartrate-api.txt
new file mode 100644
index 0000000..4ce96d8
--- /dev/null
+++ b/doc/heartrate-api.txt
@@ -0,0 +1,84 @@
+			 Heart Rate API description
+****************************************
+
+Copyright (C) 2012	Santiago Carot-Nemesio <sancane@gmail.com>
+Copyright (C) 2012	Tieto Poland
+
+Heart Rate Manager hierarchy
+============================
+
+Service		org.bluez
+Interface	org.bluez.HeartRateManager
+Object path	[variable prefix]/{hci0,hci1,...}
+
+Methods		RegisterWatcher(object agent)
+
+			Registers a watcher to monitor heart rate measurements.
+
+			Possible Errors: org.bluez.Error.InvalidArguments
+
+		UnregisterWatcher(object agent)
+
+			Unregisters a watcher.
+
+Heart Rate Profile hierarchy
+============================
+
+Service		org.bluez
+Interface	org.bluez.HeartRate
+Object path	[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+
+Methods		dict GetProperties()
+
+			Returns all properties for the interface. See the
+			Properties section for the available properties.
+
+		Reset()
+
+			Restart the accumulation of energy expended from zero.
+
+			Possible Errors: org.bluez.Error.NotSupported
+
+Properties	String Location (optional) [readonly]
+
+			Possible values: "Other", "Chest", "Wrist","Finger",
+					"Hand", "Earlobe", "Foot"
+
+		boolean ResetSupported [readonly]
+
+			True if energy expended is supported.
+
+Heart Rate Watcher hierarchy
+
+============================
+Service		unique name
+Interface	org.bluez.HeartRateWatcher
+Object path	freely definable
+
+Methods		void MeasurementReceived(object device, dict measurement)
+
+			This callback is called whenever a heart rate
+			measurement is received from the heart rate device.
+
+			Measurement:
+
+				uint16 Value:
+
+					Measurement value expressed in beats per
+					minute (bpm)
+
+				uint16 Energy (optional):
+
+					Accumulated energy expended in kilo Joules
+
+				boolean Contact (optional):
+
+					true if skin contact is detected by sensor,
+					false otherwise
+
+				array{uint16} Interval (optional):
+
+					RR-Interval values which represent the time
+					between two consecutive R waves in an ECG.
+					Values are ordered starting from oldest to
+					most recent.
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v3 02/17] heartrate: Add Heart Rate Profile client
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346931171-18968-1-git-send-email-andrzej.kaczmarek@tieto.com>

From: Rafal Garbat <rafal.garbat@tieto.com>

This patch adds initial support for the Heart Rate Profile client.

---
 Makefile.am                    |   9 ++-
 lib/uuid.h                     |   2 +
 profiles/heartrate/heartrate.c | 165 +++++++++++++++++++++++++++++++++++++++++
 profiles/heartrate/heartrate.h |  26 +++++++
 profiles/heartrate/main.c      |  52 +++++++++++++
 profiles/heartrate/manager.c   |  75 +++++++++++++++++++
 profiles/heartrate/manager.h   |  24 ++++++
 7 files changed, 351 insertions(+), 2 deletions(-)
 create mode 100644 profiles/heartrate/heartrate.c
 create mode 100644 profiles/heartrate/heartrate.h
 create mode 100644 profiles/heartrate/main.c
 create mode 100644 profiles/heartrate/manager.c
 create mode 100644 profiles/heartrate/manager.h

diff --git a/Makefile.am b/Makefile.am
index 4977a05..cb36d91 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -212,7 +212,7 @@ endif
 
 if GATTMODULES
 builtin_modules += thermometer alert time gatt_example proximity deviceinfo \
-			gatt
+			gatt heartrate
 builtin_sources += profiles/thermometer/main.c \
 			profiles/thermometer/manager.h \
 			profiles/thermometer/manager.c \
@@ -241,7 +241,12 @@ builtin_sources += profiles/thermometer/main.c \
 			profiles/deviceinfo/deviceinfo.c \
 			profiles/gatt/main.c profiles/gatt/manager.h \
 			profiles/gatt/manager.c profiles/gatt/gas.h \
-			profiles/gatt/gas.c
+			profiles/gatt/gas.c \
+			profiles/heartrate/main.c \
+			profiles/heartrate/manager.c \
+			profiles/heartrate/manager.h \
+			profiles/heartrate/heartrate.c \
+			profiles/heartrate/heartrate.h
 endif
 
 builtin_modules += formfactor
diff --git a/lib/uuid.h b/lib/uuid.h
index aa6efdf..3488e66 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -63,6 +63,8 @@ extern "C" {
 
 #define SAP_UUID		"0000112D-0000-1000-8000-00805f9b34fb"
 
+#define HEART_RATE_UUID			"0000180d-0000-1000-8000-00805f9b34fb"
+
 #define HEALTH_THERMOMETER_UUID		"00001809-0000-1000-8000-00805f9b34fb"
 #define TEMPERATURE_MEASUREMENT_UUID	"00002a1c-0000-1000-8000-00805f9b34fb"
 #define TEMPERATURE_TYPE_UUID		"00002a1d-0000-1000-8000-00805f9b34fb"
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
new file mode 100644
index 0000000..17514c0
--- /dev/null
+++ b/profiles/heartrate/heartrate.c
@@ -0,0 +1,165 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Tieto Poland
+ *
+ *  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
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdbool.h>
+#include <glib.h>
+#include <bluetooth/uuid.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "heartrate.h"
+
+struct heartrate_adapter {
+	struct btd_adapter	*adapter;
+	GSList			*devices;
+};
+
+struct heartrate {
+	struct btd_device		*dev;
+	struct heartrate_adapter	*hra;
+};
+
+static GSList *heartrate_adapters = NULL;
+
+static gint cmp_adapter(gconstpointer a, gconstpointer b)
+{
+	const struct heartrate_adapter *hra = a;
+	const struct btd_adapter *adapter = b;
+
+	if (adapter == hra->adapter)
+		return 0;
+
+	return -1;
+}
+
+static gint cmp_device(gconstpointer a, gconstpointer b)
+{
+	const struct heartrate *hr = a;
+	const struct btd_device *dev = b;
+
+	if (dev == hr->dev)
+		return 0;
+
+	return -1;
+}
+
+static struct heartrate_adapter *
+find_heartrate_adapter(struct btd_adapter *adapter)
+{
+	GSList *l = g_slist_find_custom(heartrate_adapters, adapter,
+								cmp_adapter);
+	if (!l)
+		return NULL;
+
+	return l->data;
+}
+
+static void destroy_heartrate_device(gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+
+	btd_device_unref(hr->dev);
+	g_free(hr);
+}
+
+static void destroy_heartrate_adapter(gpointer user_data)
+{
+	struct heartrate_adapter *hra = user_data;
+
+	g_free(hra);
+}
+
+int heartrate_adapter_register(struct btd_adapter *adapter)
+{
+	struct heartrate_adapter *hra;
+
+	hra = g_new0(struct heartrate_adapter, 1);
+	hra->adapter = adapter;
+
+	heartrate_adapters = g_slist_prepend(heartrate_adapters, hra);
+
+	return 0;
+}
+
+void heartrate_adapter_unregister(struct btd_adapter *adapter)
+{
+	struct heartrate_adapter *hra;
+
+	hra = find_heartrate_adapter(adapter);
+	if (hra == NULL)
+		return;
+
+	heartrate_adapters = g_slist_remove(heartrate_adapters, hra);
+
+	destroy_heartrate_adapter(hra);
+}
+
+int heartrate_device_register(struct btd_device *device)
+{
+	struct heartrate_adapter *hra;
+	struct btd_adapter *adapter;
+	struct heartrate *hr;
+
+	adapter = device_get_adapter(device);
+
+	hra = find_heartrate_adapter(adapter);
+
+	if (hra == NULL)
+		return -1;
+
+	hr = g_new0(struct heartrate, 1);
+	hr->dev = btd_device_ref(device);
+	hr->hra = hra;
+
+	hra->devices = g_slist_prepend(hra->devices, hr);
+
+	return 0;
+}
+
+void heartrate_device_unregister(struct btd_device *device)
+{
+	struct heartrate_adapter *hra;
+	struct btd_adapter *adapter;
+	struct heartrate *hr;
+	GSList *l;
+
+	adapter = device_get_adapter(device);
+
+	hra = find_heartrate_adapter(adapter);
+	if (hra == NULL)
+		return;
+
+	l = g_slist_find_custom(hra->devices, device, cmp_device);
+	if (l == NULL)
+		return;
+
+	hr = l->data;
+
+	hra->devices = g_slist_remove(hra->devices, hr);
+
+	destroy_heartrate_device(hr);
+}
diff --git a/profiles/heartrate/heartrate.h b/profiles/heartrate/heartrate.h
new file mode 100644
index 0000000..486f5b3
--- /dev/null
+++ b/profiles/heartrate/heartrate.h
@@ -0,0 +1,26 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Tieto Poland
+ *
+ *  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
+ *
+ */
+
+int heartrate_adapter_register(struct btd_adapter *adapter);
+void heartrate_adapter_unregister(struct btd_adapter *adapter);
+int heartrate_device_register(struct btd_device *device);
+void heartrate_device_unregister(struct btd_device *device);
diff --git a/profiles/heartrate/main.c b/profiles/heartrate/main.c
new file mode 100644
index 0000000..40f34bc
--- /dev/null
+++ b/profiles/heartrate/main.c
@@ -0,0 +1,52 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Tieto Poland
+ *
+ *  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
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <glib.h>
+#include <errno.h>
+
+#include "plugin.h"
+#include "manager.h"
+#include "hcid.h"
+#include "log.h"
+
+static int heartrate_init(void)
+{
+	if (!main_opts.gatt_enabled) {
+		DBG("GATT is disabled");
+		return -ENOTSUP;
+	}
+
+	return heartrate_manager_init();
+}
+
+static void heartrate_exit(void)
+{
+	heartrate_manager_exit();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(heartrate, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+					heartrate_init, heartrate_exit)
diff --git a/profiles/heartrate/manager.c b/profiles/heartrate/manager.c
new file mode 100644
index 0000000..9d2446c
--- /dev/null
+++ b/profiles/heartrate/manager.c
@@ -0,0 +1,75 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Tieto Poland
+ *
+ *  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 <gdbus.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <bluetooth/uuid.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+#include "heartrate.h"
+#include "manager.h"
+
+static int heartrate_adapter_probe(struct btd_adapter *adapter)
+{
+	return heartrate_adapter_register(adapter);
+}
+
+static void heartrate_adapter_remove(struct btd_adapter *adapter)
+{
+	heartrate_adapter_unregister(adapter);
+}
+
+static int heartrate_device_probe(struct btd_device *device, GSList *uuids)
+{
+	return heartrate_device_register(device);
+}
+
+static void heartrate_device_remove(struct btd_device *device)
+{
+	heartrate_device_unregister(device);
+}
+
+static struct btd_profile hrp_profile = {
+	.name		= "Heart Rate GATT Driver",
+	.remote_uuids	= BTD_UUIDS(HEART_RATE_UUID),
+
+	.device_probe	= heartrate_device_probe,
+	.device_remove	= heartrate_device_remove,
+
+	.adapter_probe	= heartrate_adapter_probe,
+	.adapter_remove	= heartrate_adapter_remove,
+};
+
+int heartrate_manager_init(void)
+{
+	return btd_profile_register(&hrp_profile);
+}
+
+void heartrate_manager_exit(void)
+{
+	btd_profile_unregister(&hrp_profile);
+}
diff --git a/profiles/heartrate/manager.h b/profiles/heartrate/manager.h
new file mode 100644
index 0000000..de799f6
--- /dev/null
+++ b/profiles/heartrate/manager.h
@@ -0,0 +1,24 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Tieto Poland
+ *
+ *  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
+ *
+ */
+
+int heartrate_manager_init(void);
+void heartrate_manager_exit(void);
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v3 03/17] heartrate: Add attio callbacks
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1346931171-18968-1-git-send-email-andrzej.kaczmarek@tieto.com>

---
 profiles/heartrate/heartrate.c | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 17514c0..918546e 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -31,7 +31,12 @@
 
 #include "adapter.h"
 #include "device.h"
+#include "gattrib.h"
+#include "attio.h"
+#include "att.h"
+#include "gatt.h"
 #include "heartrate.h"
+#include "log.h"
 
 struct heartrate_adapter {
 	struct btd_adapter	*adapter;
@@ -41,6 +46,8 @@ struct heartrate_adapter {
 struct heartrate {
 	struct btd_device		*dev;
 	struct heartrate_adapter	*hra;
+	GAttrib				*attrib;
+	guint				attioid;
 };
 
 static GSList *heartrate_adapters = NULL;
@@ -82,6 +89,12 @@ static void destroy_heartrate_device(gpointer user_data)
 {
 	struct heartrate *hr = user_data;
 
+	if (hr->attioid > 0)
+		btd_device_remove_attio_callback(hr->dev, hr->attioid);
+
+	if (hr->attrib != NULL)
+		g_attrib_unref(hr->attrib);
+
 	btd_device_unref(hr->dev);
 	g_free(hr);
 }
@@ -90,9 +103,31 @@ static void destroy_heartrate_adapter(gpointer user_data)
 {
 	struct heartrate_adapter *hra = user_data;
 
+	if (hra->devices != NULL)
+		g_slist_free_full(hra->devices, destroy_heartrate_device);
+
 	g_free(hra);
 }
 
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+
+	DBG("GATT Connected");
+
+	hr->attrib = g_attrib_ref(attrib);
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+
+	DBG("GATT Disconnected");
+
+	g_attrib_unref(hr->attrib);
+	hr->attrib = NULL;
+}
+
 int heartrate_adapter_register(struct btd_adapter *adapter)
 {
 	struct heartrate_adapter *hra;
@@ -137,6 +172,11 @@ int heartrate_device_register(struct btd_device *device)
 
 	hra->devices = g_slist_prepend(hra->devices, hr);
 
+	hr->attioid = btd_device_add_attio_callback(device,
+						attio_connected_cb,
+						attio_disconnected_cb,
+						hr);
+
 	return 0;
 }
 
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v3 04/17] heartrate: Discover characteristics
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346931171-18968-1-git-send-email-andrzej.kaczmarek@tieto.com>

From: Rafal Garbat <rafal.garbat@tieto.com>

This patch adds support to discover Heart Rate Service characteristics when
connected to remote device.

---
 profiles/heartrate/heartrate.c | 49 +++++++++++++++++++++++++++++++++++++++++-
 profiles/heartrate/heartrate.h |  3 ++-
 profiles/heartrate/manager.c   | 22 ++++++++++++++++++-
 3 files changed, 71 insertions(+), 3 deletions(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 918546e..e4147cf 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -48,6 +48,13 @@ struct heartrate {
 	struct heartrate_adapter	*hra;
 	GAttrib				*attrib;
 	guint				attioid;
+	struct att_range		*svc_range;
+	GSList				*chars;
+};
+
+struct characteristic {
+	struct gatt_char	attr;
+	struct heartrate	*hr;
 };
 
 static GSList *heartrate_adapters = NULL;
@@ -95,7 +102,11 @@ static void destroy_heartrate_device(gpointer user_data)
 	if (hr->attrib != NULL)
 		g_attrib_unref(hr->attrib);
 
+	if (hr->chars != NULL)
+		g_slist_free_full(hr->chars, g_free);
+
 	btd_device_unref(hr->dev);
+	g_free(hr->svc_range);
 	g_free(hr);
 }
 
@@ -109,6 +120,33 @@ static void destroy_heartrate_adapter(gpointer user_data)
 	g_free(hra);
 }
 
+static void configure_heartrate_cb(GSList *characteristics, guint8 status,
+							gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+	GSList *l;
+
+	if (status != 0) {
+		error("Discover Heart Rate characteristics: %s",
+							att_ecode2str(status));
+		return;
+	}
+
+	for (l = characteristics; l; l = l->next) {
+		struct gatt_char *c = l->data;
+		struct characteristic *ch;
+
+		ch = g_new0(struct characteristic, 1);
+		ch->attr.handle = c->handle;
+		ch->attr.properties = c->properties;
+		ch->attr.value_handle = c->value_handle;
+		memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
+		ch->hr = hr;
+
+		hr->chars = g_slist_append(hr->chars, ch);
+	}
+}
+
 static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 {
 	struct heartrate *hr = user_data;
@@ -116,6 +154,10 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 	DBG("GATT Connected");
 
 	hr->attrib = g_attrib_ref(attrib);
+
+	gatt_discover_char(hr->attrib, hr->svc_range->start,
+					hr->svc_range->end, NULL,
+					configure_heartrate_cb, hr);
 }
 
 static void attio_disconnected_cb(gpointer user_data)
@@ -153,7 +195,8 @@ void heartrate_adapter_unregister(struct btd_adapter *adapter)
 	destroy_heartrate_adapter(hra);
 }
 
-int heartrate_device_register(struct btd_device *device)
+int heartrate_device_register(struct btd_device *device,
+						struct gatt_primary *pattr)
 {
 	struct heartrate_adapter *hra;
 	struct btd_adapter *adapter;
@@ -172,6 +215,10 @@ int heartrate_device_register(struct btd_device *device)
 
 	hra->devices = g_slist_prepend(hra->devices, hr);
 
+	hr->svc_range = g_new0(struct att_range, 1);
+	hr->svc_range->start = pattr->range.start;
+	hr->svc_range->end = pattr->range.end;
+
 	hr->attioid = btd_device_add_attio_callback(device,
 						attio_connected_cb,
 						attio_disconnected_cb,
diff --git a/profiles/heartrate/heartrate.h b/profiles/heartrate/heartrate.h
index 486f5b3..ec3ed7a 100644
--- a/profiles/heartrate/heartrate.h
+++ b/profiles/heartrate/heartrate.h
@@ -22,5 +22,6 @@
 
 int heartrate_adapter_register(struct btd_adapter *adapter);
 void heartrate_adapter_unregister(struct btd_adapter *adapter);
-int heartrate_device_register(struct btd_device *device);
+int heartrate_device_register(struct btd_device *device,
+						struct gatt_primary *pattr);
 void heartrate_device_unregister(struct btd_device *device);
diff --git a/profiles/heartrate/manager.c b/profiles/heartrate/manager.c
index 9d2446c..ff2da21 100644
--- a/profiles/heartrate/manager.c
+++ b/profiles/heartrate/manager.c
@@ -33,6 +33,14 @@
 #include "heartrate.h"
 #include "manager.h"
 
+static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
+{
+	const struct gatt_primary *prim = a;
+	const char *uuid = b;
+
+	return g_strcmp0(prim->uuid, uuid);
+}
+
 static int heartrate_adapter_probe(struct btd_adapter *adapter)
 {
 	return heartrate_adapter_register(adapter);
@@ -45,7 +53,19 @@ static void heartrate_adapter_remove(struct btd_adapter *adapter)
 
 static int heartrate_device_probe(struct btd_device *device, GSList *uuids)
 {
-	return heartrate_device_register(device);
+	struct gatt_primary *pattr;
+	GSList *primaries, *l;
+
+	primaries = btd_device_get_primaries(device);
+
+	l = g_slist_find_custom(primaries, HEART_RATE_UUID,
+							primary_uuid_cmp);
+	if (l == NULL)
+		return -EINVAL;
+
+	pattr = l->data;
+
+	return heartrate_device_register(device, pattr);
 }
 
 static void heartrate_device_remove(struct btd_device *device)
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v3 05/17] heartrate: Process characteristics
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346931171-18968-1-git-send-email-andrzej.kaczmarek@tieto.com>

From: Rafal Garbat <rafal.garbat@tieto.com>

This patch adds stub to process discovered characteristics.

---
 lib/uuid.h                     |  2 ++
 profiles/heartrate/heartrate.c | 10 ++++++++++
 2 files changed, 12 insertions(+)

diff --git a/lib/uuid.h b/lib/uuid.h
index 3488e66..0a9db51 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -64,6 +64,8 @@ extern "C" {
 #define SAP_UUID		"0000112D-0000-1000-8000-00805f9b34fb"
 
 #define HEART_RATE_UUID			"0000180d-0000-1000-8000-00805f9b34fb"
+#define HEART_RATE_CONTROL_POINT_UUID	"00002a39-0000-1000-8000-00805f9b34fb"
+#define BODY_SENSOR_LOCATION_UUID	"00002a38-0000-1000-8000-00805f9b34fb"
 
 #define HEALTH_THERMOMETER_UUID		"00001809-0000-1000-8000-00805f9b34fb"
 #define TEMPERATURE_MEASUREMENT_UUID	"00002a1c-0000-1000-8000-00805f9b34fb"
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index e4147cf..02a4617 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -120,6 +120,14 @@ static void destroy_heartrate_adapter(gpointer user_data)
 	g_free(hra);
 }
 
+static void process_heartrate_char(struct characteristic *ch)
+{
+	if (g_strcmp0(ch->attr.uuid, HEART_RATE_CONTROL_POINT_UUID) == 0)
+		DBG("Heart Rate Control Point supported by client");
+	 else if (g_strcmp0(ch->attr.uuid, BODY_SENSOR_LOCATION_UUID) == 0)
+		DBG("Body Sensor Location supported by client");
+}
+
 static void configure_heartrate_cb(GSList *characteristics, guint8 status,
 							gpointer user_data)
 {
@@ -144,6 +152,8 @@ static void configure_heartrate_cb(GSList *characteristics, guint8 status,
 		ch->hr = hr;
 
 		hr->chars = g_slist_append(hr->chars, ch);
+
+		process_heartrate_char(ch);
 	}
 }
 
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v3 06/17] heartrate: Discover characteristics descriptors
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346931171-18968-1-git-send-email-andrzej.kaczmarek@tieto.com>

From: Rafal Garbat <rafal.garbat@tieto.com>

---
 profiles/heartrate/heartrate.c | 72 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 71 insertions(+), 1 deletion(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 02a4617..69d6d51 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -55,6 +55,13 @@ struct heartrate {
 struct characteristic {
 	struct gatt_char	attr;
 	struct heartrate	*hr;
+	GSList			*desc;
+};
+
+struct descriptor {
+	struct characteristic	*ch;
+	uint16_t		handle;
+	bt_uuid_t		uuid;
 };
 
 static GSList *heartrate_adapters = NULL;
@@ -92,6 +99,15 @@ find_heartrate_adapter(struct btd_adapter *adapter)
 	return l->data;
 }
 
+static void destroy_char(gpointer user_data)
+{
+	struct characteristic *c = user_data;
+
+	g_slist_free_full(c->desc, g_free);
+
+	g_free(c);
+}
+
 static void destroy_heartrate_device(gpointer user_data)
 {
 	struct heartrate *hr = user_data;
@@ -103,7 +119,7 @@ static void destroy_heartrate_device(gpointer user_data)
 		g_attrib_unref(hr->attrib);
 
 	if (hr->chars != NULL)
-		g_slist_free_full(hr->chars, g_free);
+		g_slist_free_full(hr->chars, destroy_char);
 
 	btd_device_unref(hr->dev);
 	g_free(hr->svc_range);
@@ -128,6 +144,44 @@ static void process_heartrate_char(struct characteristic *ch)
 		DBG("Body Sensor Location supported by client");
 }
 
+static void discover_desc_cb(guint8 status, const guint8 *pdu,
+					guint16 len, gpointer user_data)
+{
+	struct characteristic *ch = user_data;
+	struct att_data_list *list;
+	uint8_t format;
+	int i;
+
+	if (status != 0) {
+		error("Discover all characteristic descriptors failed [%s]: %s",
+					ch->attr.uuid, att_ecode2str(status));
+		return;
+	}
+
+	list = dec_find_info_resp(pdu, len, &format);
+	if (list == NULL)
+		return;
+
+	for (i = 0; i < list->num; i++) {
+		struct descriptor *desc;
+		uint8_t *value;
+
+		value = list->data[i];
+		desc = g_new0(struct descriptor, 1);
+		desc->handle = att_get_u16(value);
+		desc->ch = ch;
+
+		if (format == 0x01)
+			desc->uuid = att_get_uuid16(value + 2);
+		else
+			desc->uuid = att_get_uuid128(value + 2);
+
+		ch->desc = g_slist_append(ch->desc, desc);
+	}
+
+	att_data_list_free(list);
+}
+
 static void configure_heartrate_cb(GSList *characteristics, guint8 status,
 							gpointer user_data)
 {
@@ -143,6 +197,7 @@ static void configure_heartrate_cb(GSList *characteristics, guint8 status,
 	for (l = characteristics; l; l = l->next) {
 		struct gatt_char *c = l->data;
 		struct characteristic *ch;
+		uint16_t start, end;
 
 		ch = g_new0(struct characteristic, 1);
 		ch->attr.handle = c->handle;
@@ -154,6 +209,21 @@ static void configure_heartrate_cb(GSList *characteristics, guint8 status,
 		hr->chars = g_slist_append(hr->chars, ch);
 
 		process_heartrate_char(ch);
+
+		start = c->value_handle + 1;
+
+		if (l->next != NULL) {
+			struct gatt_char *c = l->next->data;
+			if (start == c->handle)
+				continue;
+			end = c->handle - 1;
+		} else if (c->value_handle != hr->svc_range->end) {
+			end = hr->svc_range->end;
+		} else {
+			continue;
+		}
+
+		gatt_find_info(hr->attrib, start, end, discover_desc_cb, ch);
 	}
 }
 
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v3 07/17] heartrate: Process characteristics descriptors
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346931171-18968-1-git-send-email-andrzej.kaczmarek@tieto.com>

From: Rafal Garbat <rafal.garbat@tieto.com>

This patch adds stub to process discovered characteristics descriptors.

---
 lib/uuid.h                     |  1 +
 profiles/heartrate/heartrate.c | 18 ++++++++++++++++++
 2 files changed, 19 insertions(+)

diff --git a/lib/uuid.h b/lib/uuid.h
index 0a9db51..15a80a0 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -64,6 +64,7 @@ extern "C" {
 #define SAP_UUID		"0000112D-0000-1000-8000-00805f9b34fb"
 
 #define HEART_RATE_UUID			"0000180d-0000-1000-8000-00805f9b34fb"
+#define HEART_RATE_MEASUREMENT_UUID	"00002a37-0000-1000-8000-00805f9b34fb"
 #define HEART_RATE_CONTROL_POINT_UUID	"00002a39-0000-1000-8000-00805f9b34fb"
 #define BODY_SENSOR_LOCATION_UUID	"00002a38-0000-1000-8000-00805f9b34fb"
 
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 69d6d51..eec8ae0 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -144,6 +144,22 @@ static void process_heartrate_char(struct characteristic *ch)
 		DBG("Body Sensor Location supported by client");
 }
 
+static void process_heartrate_desc(struct descriptor *desc)
+{
+	struct characteristic *ch = desc->ch;
+	char uuidstr[MAX_LEN_UUID_STR];
+	bt_uuid_t btuuid;
+
+	bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+
+	if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0)
+		return;
+
+	bt_uuid_to_string(&desc->uuid, uuidstr, MAX_LEN_UUID_STR);
+	DBG("Ignored descriptor %s in characteristic %s", uuidstr,
+							ch->attr.uuid);
+}
+
 static void discover_desc_cb(guint8 status, const guint8 *pdu,
 					guint16 len, gpointer user_data)
 {
@@ -177,6 +193,8 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu,
 			desc->uuid = att_get_uuid128(value + 2);
 
 		ch->desc = g_slist_append(ch->desc, desc);
+
+		process_heartrate_desc(desc);
 	}
 
 	att_data_list_free(list);
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v3 08/17] heartrate: Add HeartRateManager interface
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346931171-18968-1-git-send-email-andrzej.kaczmarek@tieto.com>

From: Rafal Garbat <rafal.garbat@tieto.com>

This patch adds support for org.bluez.HeartRateManager interface on adapters
which allows to register and unregister per-adapter watcher.

---
 profiles/heartrate/heartrate.c | 155 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 154 insertions(+), 1 deletion(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index eec8ae0..a223fe0 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -24,13 +24,16 @@
 #include <config.h>
 #endif
 
+#include <gdbus.h>
 #include <errno.h>
 #include <stdbool.h>
 #include <glib.h>
 #include <bluetooth/uuid.h>
 
 #include "adapter.h"
+#include "dbus-common.h"
 #include "device.h"
+#include "error.h"
 #include "gattrib.h"
 #include "attio.h"
 #include "att.h"
@@ -38,9 +41,12 @@
 #include "heartrate.h"
 #include "log.h"
 
+#define HEART_RATE_MANAGER_IFACE "org.bluez.HeartRateManager"
+
 struct heartrate_adapter {
 	struct btd_adapter	*adapter;
 	GSList			*devices;
+	GSList			*watchers;
 };
 
 struct heartrate {
@@ -64,6 +70,13 @@ struct descriptor {
 	bt_uuid_t		uuid;
 };
 
+struct watcher {
+	struct heartrate_adapter	*hra;
+	guint				id;
+	char				*srv;
+	char				*path;
+};
+
 static GSList *heartrate_adapters = NULL;
 
 static gint cmp_adapter(gconstpointer a, gconstpointer b)
@@ -88,6 +101,19 @@ static gint cmp_device(gconstpointer a, gconstpointer b)
 	return -1;
 }
 
+static gint cmp_watcher(gconstpointer a, gconstpointer b)
+{
+	const struct watcher *watcher = a;
+	const struct watcher *match = b;
+	int ret;
+
+	ret = g_strcmp0(watcher->srv, match->srv);
+	if (ret != 0)
+		return ret;
+
+	return g_strcmp0(watcher->path, match->path);
+}
+
 static struct heartrate_adapter *
 find_heartrate_adapter(struct btd_adapter *adapter)
 {
@@ -108,6 +134,22 @@ static void destroy_char(gpointer user_data)
 	g_free(c);
 }
 
+static void remove_watcher(gpointer user_data)
+{
+	struct watcher *watcher = user_data;
+
+	g_dbus_remove_watch(get_dbus_connection(), watcher->id);
+}
+
+static void destroy_watcher(gpointer user_data)
+{
+	struct watcher *watcher = user_data;
+
+	g_free(watcher->path);
+	g_free(watcher->srv);
+	g_free(watcher);
+}
+
 static void destroy_heartrate_device(gpointer user_data)
 {
 	struct heartrate *hr = user_data;
@@ -133,9 +175,106 @@ static void destroy_heartrate_adapter(gpointer user_data)
 	if (hra->devices != NULL)
 		g_slist_free_full(hra->devices, destroy_heartrate_device);
 
+	if (hra->watchers != NULL)
+		g_slist_free_full(hra->watchers, remove_watcher);
+
 	g_free(hra);
 }
 
+static void watcher_exit(DBusConnection *conn, void *user_data)
+{
+	struct watcher *watcher = user_data;
+	struct heartrate_adapter *hr = watcher->hra;
+
+	DBG("Heart Rate watcher %s disconnected", watcher->path);
+
+	hr->watchers = g_slist_remove(hr->watchers, watcher);
+	g_dbus_remove_watch(conn, watcher->id);
+}
+
+static struct watcher *find_watcher(GSList *list, const char *sender,
+							const char *path)
+{
+	struct watcher *match;
+	GSList *l;
+
+	match = g_new0(struct watcher, 1);
+	match->srv = g_strdup(sender);
+	match->path = g_strdup(path);
+
+	l = g_slist_find_custom(list, match, cmp_watcher);
+	destroy_watcher(match);
+
+	if (l != NULL)
+		return l->data;
+
+	return NULL;
+}
+
+static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	const char *sender = dbus_message_get_sender(msg);
+	struct heartrate_adapter *hra = data;
+	struct watcher *watcher;
+	char *path;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+							DBUS_TYPE_INVALID))
+		return btd_error_invalid_args(msg);
+
+	watcher = find_watcher(hra->watchers, sender, path);
+	if (watcher != NULL)
+		return btd_error_already_exists(msg);
+
+	DBG("Heart Rate watcher %s registered", path);
+
+	watcher = g_new0(struct watcher, 1);
+	watcher->srv = g_strdup(sender);
+	watcher->path = g_strdup(path);
+	watcher->hra = hra;
+	watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
+						watcher, destroy_watcher);
+
+	hra->watchers = g_slist_prepend(hra->watchers, watcher);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	const char *sender = dbus_message_get_sender(msg);
+	struct heartrate_adapter *hr = data;
+	struct watcher *watcher;
+	char *path;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+							DBUS_TYPE_INVALID))
+		return btd_error_invalid_args(msg);
+
+	watcher = find_watcher(hr->watchers, sender, path);
+	if (watcher == NULL)
+		return btd_error_does_not_exist(msg);
+
+	DBG("Heart Rate watcher %s unregistered", path);
+
+	hr->watchers = g_slist_remove(hr->watchers, watcher);
+	g_dbus_remove_watch(get_dbus_connection(), watcher->id);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable heartrate_manager_methods[] = {
+	{ GDBUS_METHOD("RegisterWatcher",
+			GDBUS_ARGS({ "agent", "o" }), NULL,
+			register_watcher) },
+	{ GDBUS_METHOD("UnregisterWatcher",
+			GDBUS_ARGS({ "agent", "o" }), NULL,
+			unregister_watcher) },
+	{ }
+};
+
 static void process_heartrate_char(struct characteristic *ch)
 {
 	if (g_strcmp0(ch->attr.uuid, HEART_RATE_CONTROL_POINT_UUID) == 0)
@@ -275,6 +414,18 @@ int heartrate_adapter_register(struct btd_adapter *adapter)
 	hra = g_new0(struct heartrate_adapter, 1);
 	hra->adapter = adapter;
 
+	if (!g_dbus_register_interface(get_dbus_connection(),
+						adapter_get_path(adapter),
+						HEART_RATE_MANAGER_IFACE,
+						heartrate_manager_methods,
+						NULL, NULL, hra,
+						destroy_heartrate_adapter)) {
+		error("D-Bus failed to register %s interface",
+						HEART_RATE_MANAGER_IFACE);
+		destroy_heartrate_adapter(hra);
+		return -EIO;
+	}
+
 	heartrate_adapters = g_slist_prepend(heartrate_adapters, hra);
 
 	return 0;
@@ -290,7 +441,9 @@ void heartrate_adapter_unregister(struct btd_adapter *adapter)
 
 	heartrate_adapters = g_slist_remove(heartrate_adapters, hra);
 
-	destroy_heartrate_adapter(hra);
+	g_dbus_unregister_interface(get_dbus_connection(),
+						adapter_get_path(hra->adapter),
+						HEART_RATE_MANAGER_IFACE);
 }
 
 int heartrate_device_register(struct btd_device *device,
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v3 09/17] heartrate: Enable measurement when watchers are registered
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1346931171-18968-1-git-send-email-andrzej.kaczmarek@tieto.com>

This patch will enable measurement notification when first watcher is
registered or when device is connected and watcher is already registered.

Measurement will be disabled when last watcher is unregistered.

---
 profiles/heartrate/heartrate.c | 129 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 128 insertions(+), 1 deletion(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index a223fe0..9d29ee0 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -101,6 +101,22 @@ static gint cmp_device(gconstpointer a, gconstpointer b)
 	return -1;
 }
 
+static gint cmp_char_uuid(gconstpointer a, gconstpointer b)
+{
+	const struct characteristic *ch = a;
+	const char *uuid = b;
+
+	return g_strcmp0(ch->attr.uuid, uuid);
+}
+
+static gint cmp_descriptor(gconstpointer a, gconstpointer b)
+{
+	const struct descriptor *desc = a;
+	const bt_uuid_t *uuid = b;
+
+	return bt_uuid_cmp(&desc->uuid, uuid);
+}
+
 static gint cmp_watcher(gconstpointer a, gconstpointer b)
 {
 	const struct watcher *watcher = a;
@@ -181,6 +197,91 @@ static void destroy_heartrate_adapter(gpointer user_data)
 	g_free(hra);
 }
 
+static struct characteristic *get_characteristic(struct heartrate *hr,
+							const char *uuid)
+{
+	GSList *l;
+
+	l = g_slist_find_custom(hr->chars, uuid, cmp_char_uuid);
+	if (l == NULL)
+		return NULL;
+
+	return l->data;
+}
+
+static struct descriptor *get_descriptor(struct characteristic *ch,
+							const bt_uuid_t *uuid)
+{
+	GSList *l;
+
+	l = g_slist_find_custom(ch->desc, uuid, cmp_descriptor);
+	if (l == NULL)
+		return NULL;
+
+	return l->data;
+}
+
+static void char_write_cb(guint8 status, const guint8 *pdu, guint16 len,
+							gpointer user_data)
+{
+	char *msg = user_data;
+
+	if (status != 0)
+		error("%s failed", msg);
+
+	g_free(msg);
+}
+
+static void measurement_toggle(struct heartrate *hr, gboolean enable)
+{
+	struct characteristic *ch;
+	struct descriptor *desc;
+	bt_uuid_t btuuid;
+	uint8_t atval[2];
+	char *msg;
+
+	if (hr->attrib == NULL)
+		return;
+
+	ch = get_characteristic(hr, HEART_RATE_MEASUREMENT_UUID);
+	if (ch == NULL) {
+		DBG("Heart Rate Measurement characteristic not found");
+		return;
+	}
+
+	bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+	desc = get_descriptor(ch, &btuuid);
+	if (desc == NULL) {
+		DBG("Client Characteristic Configuration descriptor not found");
+		return;
+	}
+
+	if (enable) {
+		att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, atval);
+		msg = g_strdup("Enable measurement");
+	} else {
+		att_put_u16(0x0000, atval);
+		msg = g_strdup("Disable measurement");
+	}
+
+	gatt_write_char(hr->attrib, desc->handle, atval, 2, char_write_cb, msg);
+
+}
+
+static void measurement_enable(gpointer data, gpointer user_data)
+{
+	struct heartrate *hr = data;
+
+	measurement_toggle(hr, TRUE);
+}
+
+static void measurement_disable(gpointer data, gpointer user_data)
+{
+	struct heartrate *hr = data;
+
+	measurement_toggle(hr, FALSE);
+}
+
 static void watcher_exit(DBusConnection *conn, void *user_data)
 {
 	struct watcher *watcher = user_data;
@@ -190,6 +291,9 @@ static void watcher_exit(DBusConnection *conn, void *user_data)
 
 	hr->watchers = g_slist_remove(hr->watchers, watcher);
 	g_dbus_remove_watch(conn, watcher->id);
+
+	if (g_slist_length(hr->watchers) == 0)
+		g_slist_foreach(hr->devices, measurement_disable, 0);
 }
 
 static struct watcher *find_watcher(GSList *list, const char *sender,
@@ -236,6 +340,9 @@ static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
 	watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
 						watcher, destroy_watcher);
 
+	if (g_slist_length(hra->watchers) == 0)
+		g_slist_foreach(hra->devices, measurement_enable, 0);
+
 	hra->watchers = g_slist_prepend(hra->watchers, watcher);
 
 	return dbus_message_new_method_return(msg);
@@ -262,6 +369,9 @@ static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
 	hr->watchers = g_slist_remove(hr->watchers, watcher);
 	g_dbus_remove_watch(get_dbus_connection(), watcher->id);
 
+	if (g_slist_length(hr->watchers) == 0)
+		g_slist_foreach(hr->devices, measurement_disable, 0);
+
 	return dbus_message_new_method_return(msg);
 }
 
@@ -291,9 +401,26 @@ static void process_heartrate_desc(struct descriptor *desc)
 
 	bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
 
-	if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0)
+	if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0) {
+		uint8_t atval[2];
+		char *msg;
+
+		if (g_strcmp0(ch->attr.uuid, HEART_RATE_MEASUREMENT_UUID) != 0)
+			goto done;
+
+		if (g_slist_length(ch->hr->hra->watchers) == 0)
+			return;
+
+		att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, atval);
+		msg = g_strdup("Enable measurement");
+
+		gatt_write_char(ch->hr->attrib, desc->handle,
+					atval, 2, char_write_cb, msg);
+
 		return;
+	}
 
+done:
 	bt_uuid_to_string(&desc->uuid, uuidstr, MAX_LEN_UUID_STR);
 	DBG("Ignored descriptor %s in characteristic %s", uuidstr,
 							ch->attr.uuid);
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v3 10/17] heartrate: Read Body Sensor Location characteristics
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346931171-18968-1-git-send-email-andrzej.kaczmarek@tieto.com>

From: Rafal Garbat <rafal.garbat@tieto.com>

This patch reads and stores Body Sensor Location characteristics value.

---
 profiles/heartrate/heartrate.c | 40 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 37 insertions(+), 3 deletions(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 9d29ee0..150a675 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -56,6 +56,8 @@ struct heartrate {
 	guint				attioid;
 	struct att_range		*svc_range;
 	GSList				*chars;
+	gboolean			has_location;
+	uint8_t				location;
 };
 
 struct characteristic {
@@ -385,12 +387,44 @@ static const GDBusMethodTable heartrate_manager_methods[] = {
 	{ }
 };
 
+static void read_sensor_location_cb(guint8 status, const guint8 *pdu,
+						guint16 len, gpointer user_data)
+{
+	struct characteristic *ch = user_data;
+	struct heartrate *hr = ch->hr;
+	uint8_t value;
+	ssize_t vlen;
+
+	if (status != 0) {
+		error("Body Sensor Location value read failed: %s",
+							att_ecode2str(status));
+		return;
+	}
+
+	vlen = dec_read_resp(pdu, len, &value, sizeof(value));
+	if (vlen < 0) {
+		error("Protocol error.");
+		return;
+	}
+
+	if (vlen != 1) {
+		error("Invalid length for Body Sensor Location");
+		return;
+	}
+
+	hr->has_location = TRUE;
+	hr->location = value;
+}
+
 static void process_heartrate_char(struct characteristic *ch)
 {
-	if (g_strcmp0(ch->attr.uuid, HEART_RATE_CONTROL_POINT_UUID) == 0)
-		DBG("Heart Rate Control Point supported by client");
-	 else if (g_strcmp0(ch->attr.uuid, BODY_SENSOR_LOCATION_UUID) == 0)
+	if (g_strcmp0(ch->attr.uuid, HEART_RATE_CONTROL_POINT_UUID) == 0) {
+		DBG("Heart Rate Control Point reset supported by client");
+	} else if (g_strcmp0(ch->attr.uuid, BODY_SENSOR_LOCATION_UUID) == 0) {
 		DBG("Body Sensor Location supported by client");
+		gatt_read_char(ch->hr->attrib, ch->attr.value_handle, 0,
+						read_sensor_location_cb, ch);
+	}
 }
 
 static void process_heartrate_desc(struct descriptor *desc)
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v3 11/17] heartrate: Read Heart Rate Control Point characteristics
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1346931171-18968-1-git-send-email-andrzej.kaczmarek@tieto.com>

This patch reads and stores Heart Rate Control Point characteristics value.

---
 profiles/heartrate/heartrate.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 150a675..4591e56 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -58,6 +58,7 @@ struct heartrate {
 	GSList				*chars;
 	gboolean			has_location;
 	uint8_t				location;
+	gboolean			has_cp_reset;
 };
 
 struct characteristic {
@@ -420,6 +421,7 @@ static void process_heartrate_char(struct characteristic *ch)
 {
 	if (g_strcmp0(ch->attr.uuid, HEART_RATE_CONTROL_POINT_UUID) == 0) {
 		DBG("Heart Rate Control Point reset supported by client");
+		ch->hr->has_cp_reset = TRUE;
 	} else if (g_strcmp0(ch->attr.uuid, BODY_SENSOR_LOCATION_UUID) == 0) {
 		DBG("Body Sensor Location supported by client");
 		gatt_read_char(ch->hr->attrib, ch->attr.value_handle, 0,
-- 
1.7.11.3


^ permalink raw reply related


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