Linux bluetooth development
 help / color / mirror / Atom feed
* Re: [PATCH BlueZ V2 0/3] Remove remained local A2DP endpoints
From: Luiz Augusto von Dentz @ 2012-08-09  9:50 UTC (permalink / raw)
  To: chanyeol.park; +Cc: linux-bluetooth
In-Reply-To: <1344498344-19268-1-git-send-email-chanyeol.park@samsung.com>

Hi chanyeol,

On Thu, Aug 9, 2012 at 10:45 AM,  <chanyeol.park@samsung.com> wrote:
> From: Chan-yeol Park <chanyeol.park@samsung.com>
>
> Local A2DP endpoints(SBC,MPEG) are not used anymore.
> So references, structures, and functions related to them should be
> removed.
>
> Chan-yeol Park (3):
>   audio: Remove unused local A2DP endpoints reference
>   audio: Remove legacy SBC endpoint
>   audio: Remove legacy MPEG endpoint
>
>  audio/a2dp.c |  484 +---------------------------------------------------------
>  audio/a2dp.h |   99 ------------
>  2 files changed, 3 insertions(+), 580 deletions(-)
>
> --
> 1.7.9.5

All 3 patches are now upstream, thanks.

-- 
Luiz Augusto von Dentz

^ permalink raw reply

* Re: Obexd 0.46: PBAP and GetSize
From: Luiz Augusto von Dentz @ 2012-08-09  9:49 UTC (permalink / raw)
  To: Ludek Finstrle; +Cc: linux-bluetooth
In-Reply-To: <20120809094323.GB32525@pzkagis.cz>

Hi Ludek,

On Thu, Aug 9, 2012 at 12:43 PM, Ludek Finstrle <luf@pzkagis.cz> wrote:
> Hello,
>
>   I see strange behaviour with my obexd 0.46 on N900 (ARM) and pbap-client on notebook (x86_64):
>
> --- Select Phonebook CCH ---
>
>
> --- GetSize ---
>
> Size = 12802
>
>
> --- List vCard ---
>
> ...
> 562.vcf : Name
> BEGIN:VCARD
> VERSION:2.1
> N:Name
> Tel:Number
> END:VCARD
>
> --- PullAll ---
> ...
>
> Binary representation of the numbers:
> 12802
> 0011001000000010
> 562
> 0000001000110010
>
> (another numbers):
> 15360
> 0011110000000000
> 60
> 0000000000111100
>
> As you can see there is swapped bytes. Can someone reproduce the problem?
> Has anyone idea where should be the problem (it seems like little x big endians)?

Here it works fine but it might be because my machine is little
endian, anyway Im about the send some changes in the way we handle
application parameters like this.

-- 
Luiz Augusto von Dentz

^ permalink raw reply

* Obexd 0.46: PBAP and GetSize
From: Ludek Finstrle @ 2012-08-09  9:43 UTC (permalink / raw)
  To: linux-bluetooth

Hello,

  I see strange behaviour with my obexd 0.46 on N900 (ARM) and pbap-client on notebook (x86_64):

--- Select Phonebook CCH ---


--- GetSize ---

Size = 12802


--- List vCard ---

...
562.vcf : Name
BEGIN:VCARD
VERSION:2.1
N:Name
Tel:Number
END:VCARD

--- PullAll ---
...

Binary representation of the numbers:
12802
0011001000000010
562
0000001000110010

(another numbers):
15360
0011110000000000
60
0000000000111100

As you can see there is swapped bytes. Can someone reproduce the problem?
Has anyone idea where should be the problem (it seems like little x big endians)?

Best regards,

Luf

^ permalink raw reply

* [PATCH] irmc: Fix possible memory leak in handling of location
From: Ludek Finstrle @ 2012-08-09  9:01 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Ludek Finstrle

---
 plugins/irmc.c |   19 ++++++++++++-------
 1 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/plugins/irmc.c b/plugins/irmc.c
index 2a8c543..0a0dc93 100644
--- a/plugins/irmc.c
+++ b/plugins/irmc.c
@@ -401,6 +401,7 @@ static void *irmc_open(const char *name, int oflag, mode_t mode, void *context,
 {
 	struct irmc_session *irmc = context;
 	int ret = 0;
+	void *retp = NULL
 	char *path;
 
 	DBG("name %s context %p", name, context);
@@ -422,22 +423,26 @@ static void *irmc_open(const char *name, int oflag, mode_t mode, void *context,
 		path = g_build_filename("/", name, NULL);
 
 	if (g_str_equal(path, PB_DEVINFO))
-		return irmc_open_devinfo(irmc, err);
+		retp = irmc_open_devinfo(irmc, err);
 	else if (g_str_equal(path, PB_CONTACTS))
-		return irmc_open_pb(irmc, err);
+		retp = irmc_open_pb(irmc, err);
 	else if (g_str_equal(path, PB_INFO_LOG))
-		return irmc_open_info(irmc, err);
+		retp = irmc_open_info(irmc, err);
 	else if (g_str_equal(path, PB_CC_LOG))
-		return irmc_open_cc(irmc, err);
+		retp = irmc_open_cc(irmc, err);
 	else if (g_str_has_prefix(path, PB_CALENDAR_FOLDER))
-		return irmc_open_cal(irmc, err);
+		retp = irmc_open_cal(irmc, err);
 	else if (g_str_has_prefix(path, PB_NOTES_FOLDER))
-		return irmc_open_nt(irmc, err);
+		retp = irmc_open_nt(irmc, err);
 	else if (g_str_has_prefix(path, PB_LUID_FOLDER))
-		return irmc_open_luid(irmc, err);
+		retp = irmc_open_luid(irmc, err);
 	else
 		ret = -EBADR;
 
+	g_free(path);
+	if (retp)
+		return retp;
+
 fail:
 	if (err)
 		*err = ret;
-- 
1.7.1


^ permalink raw reply related

* [RFC BlueZ v2] mgmt-api: Add reason to device disconnect event
From: Mikel Astiz @ 2012-08-09  7:56 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz

From: Mikel Astiz <mikel.astiz@bmw-carit.de>

Extend the management API with the disconnect reason, as now reported
by the Kernel in MGMT_EV_DEVICE_DISCONNECTED.
---
Updated userland patch to test the recently submitted Kernel patches regarding ACL disconnect reason.

 doc/mgmt-api.txt  |   16 ++++++++++++++++
 lib/mgmt.h        |    6 ++++++
 monitor/control.c |   19 +++++++++++++++----
 src/mgmt.c        |   13 ++++++++-----
 4 files changed, 45 insertions(+), 9 deletions(-)

diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt
index 51c9b46..c25f377 100644
--- a/doc/mgmt-api.txt
+++ b/doc/mgmt-api.txt
@@ -973,12 +973,28 @@ Event Code		0x000C
 Controller Index:	<controller id>
 Event Parameters	Address (6 Octets)
 			Address_Type (1 Octet)
+			Reason (1 Octet)
 
 	Possible values for the Address_Type parameter:
 		0	BR/EDR
 		1	LE Public
 		2	LE Random
 
+	Possible values for the Reason parameter:
+		0	Unspecified
+		1	Connection timeout
+		2	Connection terminated by local host
+		3	Connection terminated by remote host
+
+	Note that the local/remote distinction just determines which side
+	terminated the low-level connection, regardless of the
+	disconnection of the higher-level profiles.
+
+	This can sometimes be misleading and thus must be used with care.
+	For example, some hardware combinations would report a locally
+	initiated disconnection even if the user turned Bluetooth off in
+	the remote side.
+
 
 Connect Failed Event
 ====================
diff --git a/lib/mgmt.h b/lib/mgmt.h
index 83dcd84..a2648bc 100644
--- a/lib/mgmt.h
+++ b/lib/mgmt.h
@@ -373,9 +373,15 @@ struct mgmt_ev_device_connected {
 	uint8_t eir[0];
 } __packed;
 
+#define MGMT_DEV_DISCONN_UNKNOWN	0x00
+#define MGMT_DEV_DISCONN_TIMEOUT	0x01
+#define MGMT_DEV_DISCONN_LOCAL_HOST	0x02
+#define MGMT_DEV_DISCONN_REMOTE		0x03
+
 #define MGMT_EV_DEVICE_DISCONNECTED	0x000C
 struct mgmt_ev_device_disconnected {
 	struct mgmt_addr_info addr;
+	uint8_t reason;
 } __packed;
 
 #define MGMT_EV_CONNECT_FAILED		0x000D
diff --git a/monitor/control.c b/monitor/control.c
index 159ba9d..c799327 100644
--- a/monitor/control.c
+++ b/monitor/control.c
@@ -226,18 +226,29 @@ static void mgmt_device_disconnected(uint16_t len, const void *buf)
 {
 	const struct mgmt_ev_device_disconnected *ev = buf;
 	char str[18];
+	uint8_t reason;
+	uint16_t l;
 
-	if (len < sizeof(*ev)) {
+	if (len < sizeof(struct mgmt_addr_info)) {
 		printf("* Malformed Device Disconnected control\n");
 		return;
 	}
 
+	if (len < sizeof(*ev)) {
+		reason = MGMT_DEV_DISCONN_UNKNOWN;
+		l = len;
+	} else {
+		reason = ev->reason;
+		l = sizeof(*ev);
+	}
+
 	ba2str(&ev->addr.bdaddr, str);
 
-	printf("@ Device Disconnected: %s (%d)\n", str, ev->addr.type);
+	printf("@ Device Disconnected: %s (%d) reason %u\n", str, ev->addr.type,
+									reason);
 
-	buf += sizeof(*ev);
-	len -= sizeof(*ev);
+	buf += l;
+	len -= l;
 
 	packet_hexdump(buf, len);
 }
diff --git a/src/mgmt.c b/src/mgmt.c
index c893972..131fe50 100644
--- a/src/mgmt.c
+++ b/src/mgmt.c
@@ -510,18 +510,21 @@ static void mgmt_device_connected(int sk, uint16_t index, void *buf, size_t len)
 static void mgmt_device_disconnected(int sk, uint16_t index, void *buf,
 								size_t len)
 {
-	struct mgmt_addr_info *ev = buf;
+	struct mgmt_ev_device_disconnected *ev = buf;
 	struct controller_info *info;
 	char addr[18];
 
-	if (len < sizeof(*ev)) {
+	if (len < sizeof(struct mgmt_addr_info)) {
 		error("Too small device_disconnected event");
 		return;
 	}
 
-	ba2str(&ev->bdaddr, addr);
+	if (len < sizeof(*ev))
+		memset((char *) buf + len, 0, sizeof(*ev) - len);
+
+	ba2str(&ev->addr.bdaddr, addr);
 
-	DBG("hci%u device %s disconnected", index, addr);
+	DBG("hci%u device %s disconnected reason %u", index, addr, ev->reason);
 
 	if (index > max_index) {
 		error("Unexpected index %u in device_disconnected event", index);
@@ -530,7 +533,7 @@ static void mgmt_device_disconnected(int sk, uint16_t index, void *buf,
 
 	info = &controllers[index];
 
-	btd_event_disconn_complete(&info->bdaddr, &ev->bdaddr);
+	btd_event_disconn_complete(&info->bdaddr, &ev->addr.bdaddr);
 }
 
 static void mgmt_connect_failed(int sk, uint16_t index, void *buf, size_t len)
-- 
1.7.7.6


^ permalink raw reply related

* [RFC v4 3/3] Bluetooth: mgmt: Add device disconnect reason
From: Mikel Astiz @ 2012-08-09  7:52 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz
In-Reply-To: <1344498750-2698-1-git-send-email-mikel.astiz.oss@gmail.com>

From: Mikel Astiz <mikel.astiz@bmw-carit.de>

MGMT_EV_DEVICE_DISCONNECTED will now expose the disconnection reason to
userland, distinguishing four possible values:

	0x00	Reason not known or unspecified
	0x01	Connection timeout
	0x02	Connection terminated by local host
	0x03	Connection terminated by remote host

Note that the local/remote distinction just determines which side
terminated the low-level connection, regardless of the disconnection of
the higher-level profiles.

This can sometimes be misleading and thus must be used with care. For
example, some hardware combinations would report a locally initiated
disconnection even if the user turned Bluetooth off in the remote side.

Signed-off-by: Mikel Astiz <mikel.astiz@bmw-carit.de>
---
 include/net/bluetooth/hci_core.h |    2 +-
 include/net/bluetooth/mgmt.h     |    9 +++++++++
 net/bluetooth/hci_event.c        |   26 +++++++++++++++++++++++---
 net/bluetooth/mgmt.c             |    9 +++++----
 4 files changed, 38 insertions(+), 8 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 41d9439..4fb0323 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1004,7 +1004,7 @@ int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
 			  u8 addr_type, u32 flags, u8 *name, u8 name_len,
 			  u8 *dev_class);
 int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
-			     u8 link_type, u8 addr_type);
+			     u8 link_type, u8 addr_type, u8 reason);
 int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
 			   u8 link_type, u8 addr_type, u8 status);
 int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 4348ee8..1b48eff 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -405,7 +405,16 @@ struct mgmt_ev_device_connected {
 	__u8	eir[0];
 } __packed;
 
+#define MGMT_DEV_DISCONN_UNKNOWN	0x00
+#define MGMT_DEV_DISCONN_TIMEOUT	0x01
+#define MGMT_DEV_DISCONN_LOCAL_HOST	0x02
+#define MGMT_DEV_DISCONN_REMOTE		0x03
+
 #define MGMT_EV_DEVICE_DISCONNECTED	0x000C
+struct mgmt_ev_device_disconnected {
+	struct mgmt_addr_info addr;
+	__u8	reason;
+} __packed;
 
 #define MGMT_EV_CONNECT_FAILED		0x000D
 struct mgmt_ev_connect_failed {
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 32fcc74..6e02c93 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -29,6 +29,7 @@
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/mgmt.h>
 
 /* Handle HCI Event packets */
 
@@ -1888,6 +1889,22 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 	}
 }
 
+static u8 hci_to_mgmt_reason(u8 err)
+{
+	switch (err) {
+	case HCI_ERROR_CONNECTION_TIMEOUT:
+		return MGMT_DEV_DISCONN_TIMEOUT;
+	case HCI_ERROR_REMOTE_USER_TERM:
+	case HCI_ERROR_REMOTE_LOW_RESOURCES:
+	case HCI_ERROR_REMOTE_POWER_OFF:
+		return MGMT_DEV_DISCONN_REMOTE;
+	case HCI_ERROR_LOCAL_HOST_TERM:
+		return MGMT_DEV_DISCONN_LOCAL_HOST;
+	default:
+		return MGMT_DEV_DISCONN_UNKNOWN;
+	}
+}
+
 static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_disconn_complete *ev = (void *) skb->data;
@@ -1906,12 +1923,15 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
 	if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) &&
 	    (conn->type == ACL_LINK || conn->type == LE_LINK)) {
-		if (ev->status)
+		if (ev->status) {
 			mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
 					       conn->dst_type, ev->status);
-		else
+		} else {
+			u8 reason = hci_to_mgmt_reason(ev->reason);
+
 			mgmt_device_disconnected(hdev, &conn->dst, conn->type,
-						 conn->dst_type);
+						 conn->dst_type, reason);
+		}
 	}
 
 	if (ev->status == 0) {
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index a3329cb..05d4b83 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -3077,16 +3077,17 @@ static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
 }
 
 int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
-			     u8 link_type, u8 addr_type)
+			     u8 link_type, u8 addr_type, u8 reason)
 {
-	struct mgmt_addr_info ev;
+	struct mgmt_ev_device_disconnected ev;
 	struct sock *sk = NULL;
 	int err;
 
 	mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
 
-	bacpy(&ev.bdaddr, bdaddr);
-	ev.type = link_to_bdaddr(link_type, addr_type);
+	bacpy(&ev.addr.bdaddr, bdaddr);
+	ev.addr.type = link_to_bdaddr(link_type, addr_type);
+	ev.reason = reason;
 
 	err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
 			 sk);
-- 
1.7.7.6


^ permalink raw reply related

* [RFC v4 2/3] Bluetooth: Fix minor coding style in hci_event.c
From: Mikel Astiz @ 2012-08-09  7:52 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz
In-Reply-To: <1344498750-2698-1-git-send-email-mikel.astiz.oss@gmail.com>

From: Mikel Astiz <mikel.astiz@bmw-carit.de>

Replace the status checks with the short form of the boolean expression.

Signed-off-by: Mikel Astiz <mikel.astiz@bmw-carit.de>
---
 net/bluetooth/hci_event.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 0386e1e..32fcc74 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -303,7 +303,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
 
 	hci_dev_lock(hdev);
 
-	if (status != 0) {
+	if (status) {
 		mgmt_write_scan_failed(hdev, param, status);
 		hdev->discov_timeout = 0;
 		goto done;
@@ -925,7 +925,7 @@ static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
 	if (test_bit(HCI_MGMT, &hdev->dev_flags))
 		mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status);
 
-	if (rp->status != 0)
+	if (rp->status)
 		goto unlock;
 
 	cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY);
@@ -1906,7 +1906,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
 	if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) &&
 	    (conn->type == ACL_LINK || conn->type == LE_LINK)) {
-		if (ev->status != 0)
+		if (ev->status)
 			mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
 					       conn->dst_type, ev->status);
 		else
@@ -3275,7 +3275,7 @@ static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
 	 * initiated the authentication. A traditional auth_complete
 	 * event gets always produced as initiator and is also mapped to
 	 * the mgmt_auth_failed event */
-	if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status != 0)
+	if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status)
 		mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type,
 				 ev->status);
 
-- 
1.7.7.6


^ permalink raw reply related

* [RFC v4 1/3] Bluetooth: Add more HCI error codes
From: Mikel Astiz @ 2012-08-09  7:52 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz
In-Reply-To: <1344498750-2698-1-git-send-email-mikel.astiz.oss@gmail.com>

From: Mikel Astiz <mikel.astiz@bmw-carit.de>

Add more HCI error codes as defined in the specification.

Signed-off-by: Mikel Astiz <mikel.astiz@bmw-carit.de>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
---
 include/net/bluetooth/hci.h |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 7f19556..7253bdd 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -302,8 +302,11 @@ enum {
 
 /* ---- HCI Error Codes ---- */
 #define HCI_ERROR_AUTH_FAILURE		0x05
+#define HCI_ERROR_CONNECTION_TIMEOUT	0x08
 #define HCI_ERROR_REJ_BAD_ADDR		0x0f
 #define HCI_ERROR_REMOTE_USER_TERM	0x13
+#define HCI_ERROR_REMOTE_LOW_RESOURCES	0x14
+#define HCI_ERROR_REMOTE_POWER_OFF	0x15
 #define HCI_ERROR_LOCAL_HOST_TERM	0x16
 #define HCI_ERROR_PAIRING_NOT_ALLOWED	0x18
 
-- 
1.7.7.6


^ permalink raw reply related

* [RFC v4 0/3] Disconnect reason in Kernel API
From: Mikel Astiz @ 2012-08-09  7:52 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz

From: Mikel Astiz <mikel.astiz@bmw-carit.de>

This patchset extends the management API to expose the low-level disconnect reason.

v4 integrates the feedback from Marcel, mainly:
- Fix minor coding style issue (patch v4 2/3)
- Remove references to "ACL" in mgmt terminology
- Add MGMT_DEV_DISCONN_UNKNOWN
- Add helper function to translate from HCI error codes to mgmt reason

Updated userland patch to be used for testing purposes will be submitted soon.

>From original patch:

During the BlueZ meeting in Brazil it was proposed to add two more values to this enum: "Connection terminated by local host" and "Connection terminated by remote host". However, after some testing, it seems the result can be quite misleading. Therefore and given that there are no known use-cases that need this information (local vs remote disconnection), these two values have been dropped.

Mikel Astiz (3):
  Bluetooth: Add more HCI error codes
  Bluetooth: Fix minor coding style in hci_event.c
  Bluetooth: mgmt: Add device disconnect reason

 include/net/bluetooth/hci.h      |    3 +++
 include/net/bluetooth/hci_core.h |    2 +-
 include/net/bluetooth/mgmt.h     |    9 +++++++++
 net/bluetooth/hci_event.c        |   32 ++++++++++++++++++++++++++------
 net/bluetooth/mgmt.c             |    9 +++++----
 5 files changed, 44 insertions(+), 11 deletions(-)

-- 
1.7.7.6


^ permalink raw reply

* [PATCH BlueZ V2 3/3] audio: Remove legacy MPEG endpoint
From: chanyeol.park @ 2012-08-09  7:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1344498344-19268-1-git-send-email-chanyeol.park@samsung.com>

From: Chan-yeol Park <chanyeol.park@samsung.com>

---
 audio/a2dp.c |  127 ----------------------------------------------------------
 audio/a2dp.h |   51 -----------------------
 2 files changed, 178 deletions(-)

diff --git a/audio/a2dp.c b/audio/a2dp.c
index 36fee09..a9546b7 100644
--- a/audio/a2dp.c
+++ b/audio/a2dp.c
@@ -411,105 +411,6 @@ done:
 	return FALSE;
 }
 
-static gboolean mpeg_setconf_ind(struct avdtp *session,
-					struct avdtp_local_sep *sep,
-					struct avdtp_stream *stream,
-					GSList *caps,
-					avdtp_set_configuration_cb cb,
-					void *user_data)
-{
-	struct a2dp_sep *a2dp_sep = user_data;
-	struct a2dp_setup *setup;
-
-	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		DBG("Sink %p: Set_Configuration_Ind", sep);
-	else
-		DBG("Source %p: Set_Configuration_Ind", sep);
-
-	setup = a2dp_setup_get(session);
-	if (!setup)
-		return FALSE;
-
-	a2dp_sep->stream = stream;
-	setup->sep = a2dp_sep;
-	setup->stream = stream;
-	setup->setconf_cb = cb;
-
-	for (; caps != NULL; caps = g_slist_next(caps)) {
-		struct avdtp_service_capability *cap = caps->data;
-
-		if (cap->category == AVDTP_DELAY_REPORTING &&
-					!a2dp_sep->delay_reporting) {
-			setup->err = g_new(struct avdtp_error, 1);
-			avdtp_error_init(setup->err, AVDTP_DELAY_REPORTING,
-					AVDTP_UNSUPPORTED_CONFIGURATION);
-			goto done;
-		}
-	}
-
-done:
-	g_idle_add(auto_config, setup);
-	return TRUE;
-}
-
-static gboolean mpeg_getcap_ind(struct avdtp *session,
-				struct avdtp_local_sep *sep,
-				gboolean get_all,
-				GSList **caps, uint8_t *err, void *user_data)
-{
-	struct a2dp_sep *a2dp_sep = user_data;
-	struct avdtp_service_capability *media_transport, *media_codec;
-	struct mpeg_codec_cap mpeg_cap;
-
-	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		DBG("Sink %p: Get_Capability_Ind", sep);
-	else
-		DBG("Source %p: Get_Capability_Ind", sep);
-
-	*caps = NULL;
-
-	media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
-						NULL, 0);
-
-	*caps = g_slist_append(*caps, media_transport);
-
-	memset(&mpeg_cap, 0, sizeof(struct mpeg_codec_cap));
-
-	mpeg_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
-	mpeg_cap.cap.media_codec_type = A2DP_CODEC_MPEG12;
-
-	mpeg_cap.frequency = ( MPEG_SAMPLING_FREQ_48000 |
-				MPEG_SAMPLING_FREQ_44100 |
-				MPEG_SAMPLING_FREQ_32000 |
-				MPEG_SAMPLING_FREQ_24000 |
-				MPEG_SAMPLING_FREQ_22050 |
-				MPEG_SAMPLING_FREQ_16000 );
-
-	mpeg_cap.channel_mode = ( MPEG_CHANNEL_MODE_JOINT_STEREO |
-					MPEG_CHANNEL_MODE_STEREO |
-					MPEG_CHANNEL_MODE_DUAL_CHANNEL |
-					MPEG_CHANNEL_MODE_MONO );
-
-	mpeg_cap.layer = ( MPEG_LAYER_MP3 | MPEG_LAYER_MP2 | MPEG_LAYER_MP1 );
-
-	mpeg_cap.bitrate = 0xFFFF;
-
-	media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &mpeg_cap,
-						sizeof(mpeg_cap));
-
-	*caps = g_slist_append(*caps, media_codec);
-
-	if (get_all) {
-		struct avdtp_service_capability *delay_reporting;
-		delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING,
-								NULL, 0);
-		*caps = g_slist_append(*caps, delay_reporting);
-	}
-
-	return TRUE;
-}
-
-
 static void endpoint_setconf_cb(struct a2dp_setup *setup, gboolean ret)
 {
 	if (ret == FALSE) {
@@ -1105,21 +1006,6 @@ static gboolean reconf_ind(struct avdtp *session, struct avdtp_local_sep *sep,
 	return TRUE;
 }
 
-static gboolean delayreport_ind(struct avdtp *session,
-				struct avdtp_local_sep *sep,
-				uint8_t rseid, uint16_t delay,
-				uint8_t *err, void *user_data)
-{
-	struct a2dp_sep *a2dp_sep = user_data;
-
-	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		DBG("Sink %p: DelayReport_Ind", sep);
-	else
-		DBG("Source %p: DelayReport_Ind", sep);
-
-	return TRUE;
-}
-
 static gboolean endpoint_delayreport_ind(struct avdtp *session,
 						struct avdtp_local_sep *sep,
 						uint8_t rseid, uint16_t delay,
@@ -1189,19 +1075,6 @@ static struct avdtp_sep_cfm cfm = {
 	.delay_report		= delay_report_cfm,
 };
 
-static struct avdtp_sep_ind mpeg_ind = {
-	.get_capability		= mpeg_getcap_ind,
-	.set_configuration	= mpeg_setconf_ind,
-	.get_configuration	= getconf_ind,
-	.open			= open_ind,
-	.start			= start_ind,
-	.suspend		= suspend_ind,
-	.close			= close_ind,
-	.abort			= abort_ind,
-	.reconfigure		= reconf_ind,
-	.delayreport		= delayreport_ind,
-};
-
 static struct avdtp_sep_ind endpoint_ind = {
 	.get_capability		= endpoint_getcap_ind,
 	.set_configuration	= endpoint_setconf_ind,
diff --git a/audio/a2dp.h b/audio/a2dp.h
index c9feac8..27b4a57 100644
--- a/audio/a2dp.h
+++ b/audio/a2dp.h
@@ -23,57 +23,6 @@
  *
  */
 
-#define A2DP_CODEC_SBC			0x00
-#define A2DP_CODEC_MPEG12		0x01
-#define A2DP_CODEC_MPEG24		0x02
-#define A2DP_CODEC_ATRAC		0x03
-
-#define MPEG_CHANNEL_MODE_MONO		(1 << 3)
-#define MPEG_CHANNEL_MODE_DUAL_CHANNEL	(1 << 2)
-#define MPEG_CHANNEL_MODE_STEREO	(1 << 1)
-#define MPEG_CHANNEL_MODE_JOINT_STEREO	1
-
-#define MPEG_LAYER_MP1			(1 << 2)
-#define MPEG_LAYER_MP2			(1 << 1)
-#define MPEG_LAYER_MP3			1
-
-#define MPEG_SAMPLING_FREQ_16000	(1 << 5)
-#define MPEG_SAMPLING_FREQ_22050	(1 << 4)
-#define MPEG_SAMPLING_FREQ_24000	(1 << 3)
-#define MPEG_SAMPLING_FREQ_32000	(1 << 2)
-#define MPEG_SAMPLING_FREQ_44100	(1 << 1)
-#define MPEG_SAMPLING_FREQ_48000	1
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-
-struct mpeg_codec_cap {
-	struct avdtp_media_codec_capability cap;
-	uint8_t channel_mode:4;
-	uint8_t crc:1;
-	uint8_t layer:3;
-	uint8_t frequency:6;
-	uint8_t mpf:1;
-	uint8_t rfa:1;
-	uint16_t bitrate;
-} __attribute__ ((packed));
-
-#elif __BYTE_ORDER == __BIG_ENDIAN
-
-struct mpeg_codec_cap {
-	struct avdtp_media_codec_capability cap;
-	uint8_t layer:3;
-	uint8_t crc:1;
-	uint8_t channel_mode:4;
-	uint8_t rfa:1;
-	uint8_t mpf:1;
-	uint8_t frequency:6;
-	uint16_t bitrate;
-} __attribute__ ((packed));
-
-#else
-#error "Unknown byte order"
-#endif
-
 struct a2dp_sep;
 struct a2dp_setup;
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH BlueZ V2 2/3] audio: Remove legacy SBC endpoint
From: chanyeol.park @ 2012-08-09  7:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1344498344-19268-1-git-send-email-chanyeol.park@samsung.com>

From: Chan-yeol Park <chanyeol.park@samsung.com>

---
 audio/a2dp.c |  283 ----------------------------------------------------------
 audio/a2dp.h |   46 ----------
 2 files changed, 329 deletions(-)

diff --git a/audio/a2dp.c b/audio/a2dp.c
index 4567ce0..36fee09 100644
--- a/audio/a2dp.c
+++ b/audio/a2dp.c
@@ -411,134 +411,6 @@ done:
 	return FALSE;
 }
 
-static gboolean sbc_setconf_ind(struct avdtp *session,
-					struct avdtp_local_sep *sep,
-					struct avdtp_stream *stream,
-					GSList *caps,
-					avdtp_set_configuration_cb cb,
-					void *user_data)
-{
-	struct a2dp_sep *a2dp_sep = user_data;
-	struct a2dp_setup *setup;
-
-	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		DBG("Sink %p: Set_Configuration_Ind", sep);
-	else
-		DBG("Source %p: Set_Configuration_Ind", sep);
-
-	setup = a2dp_setup_get(session);
-	if (!setup)
-		return FALSE;
-
-	a2dp_sep->stream = stream;
-	setup->sep = a2dp_sep;
-	setup->stream = stream;
-	setup->setconf_cb = cb;
-
-	/* Check valid settings */
-	for (; caps != NULL; caps = g_slist_next(caps)) {
-		struct avdtp_service_capability *cap = caps->data;
-		struct avdtp_media_codec_capability *codec_cap;
-		struct sbc_codec_cap *sbc_cap;
-
-		if (cap->category == AVDTP_DELAY_REPORTING &&
-					!a2dp_sep->delay_reporting) {
-			setup->err = g_new(struct avdtp_error, 1);
-			avdtp_error_init(setup->err, AVDTP_DELAY_REPORTING,
-						AVDTP_UNSUPPORTED_CONFIGURATION);
-			goto done;
-		}
-
-		if (cap->category != AVDTP_MEDIA_CODEC)
-			continue;
-
-		if (cap->length < sizeof(struct sbc_codec_cap))
-			continue;
-
-		codec_cap = (void *) cap->data;
-
-		if (codec_cap->media_codec_type != A2DP_CODEC_SBC)
-			continue;
-
-		sbc_cap = (void *) codec_cap;
-
-		if (sbc_cap->min_bitpool < MIN_BITPOOL ||
-					sbc_cap->max_bitpool > MAX_BITPOOL) {
-			setup->err = g_new(struct avdtp_error, 1);
-			avdtp_error_init(setup->err, AVDTP_MEDIA_CODEC,
-					AVDTP_UNSUPPORTED_CONFIGURATION);
-			goto done;
-		}
-	}
-
-done:
-	g_idle_add(auto_config, setup);
-	return TRUE;
-}
-
-static gboolean sbc_getcap_ind(struct avdtp *session, struct avdtp_local_sep *sep,
-				gboolean get_all, GSList **caps, uint8_t *err,
-				void *user_data)
-{
-	struct a2dp_sep *a2dp_sep = user_data;
-	struct avdtp_service_capability *media_transport, *media_codec;
-	struct sbc_codec_cap sbc_cap;
-
-	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		DBG("Sink %p: Get_Capability_Ind", sep);
-	else
-		DBG("Source %p: Get_Capability_Ind", sep);
-
-	*caps = NULL;
-
-	media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
-						NULL, 0);
-
-	*caps = g_slist_append(*caps, media_transport);
-
-	memset(&sbc_cap, 0, sizeof(struct sbc_codec_cap));
-
-	sbc_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
-	sbc_cap.cap.media_codec_type = A2DP_CODEC_SBC;
-
-	sbc_cap.frequency = ( SBC_SAMPLING_FREQ_48000 |
-				SBC_SAMPLING_FREQ_44100 |
-				SBC_SAMPLING_FREQ_32000 |
-				SBC_SAMPLING_FREQ_16000 );
-
-	sbc_cap.channel_mode = ( SBC_CHANNEL_MODE_JOINT_STEREO |
-					SBC_CHANNEL_MODE_STEREO |
-					SBC_CHANNEL_MODE_DUAL_CHANNEL |
-					SBC_CHANNEL_MODE_MONO );
-
-	sbc_cap.block_length = ( SBC_BLOCK_LENGTH_16 |
-					SBC_BLOCK_LENGTH_12 |
-					SBC_BLOCK_LENGTH_8 |
-					SBC_BLOCK_LENGTH_4 );
-
-	sbc_cap.subbands = ( SBC_SUBBANDS_8 | SBC_SUBBANDS_4 );
-
-	sbc_cap.allocation_method = ( SBC_ALLOCATION_LOUDNESS |
-					SBC_ALLOCATION_SNR );
-
-	sbc_cap.min_bitpool = MIN_BITPOOL;
-	sbc_cap.max_bitpool = MAX_BITPOOL;
-
-	media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &sbc_cap,
-						sizeof(sbc_cap));
-
-	*caps = g_slist_append(*caps, media_codec);
-
-	if (get_all) {
-		struct avdtp_service_capability *delay_reporting;
-		delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING,
-								NULL, 0);
-		*caps = g_slist_append(*caps, delay_reporting);
-	}
-
-	return TRUE;
-}
-
 static gboolean mpeg_setconf_ind(struct avdtp *session,
 					struct avdtp_local_sep *sep,
 					struct avdtp_stream *stream,
@@ -1317,19 +1189,6 @@ static struct avdtp_sep_cfm cfm = {
 	.delay_report		= delay_report_cfm,
 };
 
-static struct avdtp_sep_ind sbc_ind = {
-	.get_capability		= sbc_getcap_ind,
-	.set_configuration	= sbc_setconf_ind,
-	.get_configuration	= getconf_ind,
-	.open			= open_ind,
-	.start			= start_ind,
-	.suspend		= suspend_ind,
-	.close			= close_ind,
-	.abort			= abort_ind,
-	.reconfigure		= reconf_ind,
-	.delayreport		= delayreport_ind,
-};
-
 static struct avdtp_sep_ind mpeg_ind = {
 	.get_capability		= mpeg_getcap_ind,
 	.set_configuration	= mpeg_setconf_ind,
@@ -1672,148 +1531,6 @@ void a2dp_remove_sep(struct a2dp_sep *sep)
 	a2dp_unregister_sep(sep);
 }
 
-static uint8_t default_bitpool(uint8_t freq, uint8_t mode)
-{
-	switch (freq) {
-	case SBC_SAMPLING_FREQ_16000:
-	case SBC_SAMPLING_FREQ_32000:
-		return 53;
-	case SBC_SAMPLING_FREQ_44100:
-		switch (mode) {
-		case SBC_CHANNEL_MODE_MONO:
-		case SBC_CHANNEL_MODE_DUAL_CHANNEL:
-			return 31;
-		case SBC_CHANNEL_MODE_STEREO:
-		case SBC_CHANNEL_MODE_JOINT_STEREO:
-			return 53;
-		default:
-			error("Invalid channel mode %u", mode);
-			return 53;
-		}
-	case SBC_SAMPLING_FREQ_48000:
-		switch (mode) {
-		case SBC_CHANNEL_MODE_MONO:
-		case SBC_CHANNEL_MODE_DUAL_CHANNEL:
-			return 29;
-		case SBC_CHANNEL_MODE_STEREO:
-		case SBC_CHANNEL_MODE_JOINT_STEREO:
-			return 51;
-		default:
-			error("Invalid channel mode %u", mode);
-			return 51;
-		}
-	default:
-		error("Invalid sampling freq %u", freq);
-		return 53;
-	}
-}
-
-static gboolean select_sbc_params(struct sbc_codec_cap *cap,
-					struct sbc_codec_cap *supported)
-{
-	unsigned int max_bitpool, min_bitpool;
-
-	memset(cap, 0, sizeof(struct sbc_codec_cap));
-
-	cap->cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
-	cap->cap.media_codec_type = A2DP_CODEC_SBC;
-
-	if (supported->frequency & SBC_SAMPLING_FREQ_44100)
-		cap->frequency = SBC_SAMPLING_FREQ_44100;
-	else if (supported->frequency & SBC_SAMPLING_FREQ_48000)
-		cap->frequency = SBC_SAMPLING_FREQ_48000;
-	else if (supported->frequency & SBC_SAMPLING_FREQ_32000)
-		cap->frequency = SBC_SAMPLING_FREQ_32000;
-	else if (supported->frequency & SBC_SAMPLING_FREQ_16000)
-		cap->frequency = SBC_SAMPLING_FREQ_16000;
-	else {
-		error("No supported frequencies");
-		return FALSE;
-	}
-
-	if (supported->channel_mode & SBC_CHANNEL_MODE_JOINT_STEREO)
-		cap->channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO;
-	else if (supported->channel_mode & SBC_CHANNEL_MODE_STEREO)
-		cap->channel_mode = SBC_CHANNEL_MODE_STEREO;
-	else if (supported->channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL)
-		cap->channel_mode = SBC_CHANNEL_MODE_DUAL_CHANNEL;
-	else if (supported->channel_mode & SBC_CHANNEL_MODE_MONO)
-		cap->channel_mode = SBC_CHANNEL_MODE_MONO;
-	else {
-		error("No supported channel modes");
-		return FALSE;
-	}
-
-	if (supported->block_length & SBC_BLOCK_LENGTH_16)
-		cap->block_length = SBC_BLOCK_LENGTH_16;
-	else if (supported->block_length & SBC_BLOCK_LENGTH_12)
-		cap->block_length = SBC_BLOCK_LENGTH_12;
-	else if (supported->block_length & SBC_BLOCK_LENGTH_8)
-		cap->block_length = SBC_BLOCK_LENGTH_8;
-	else if (supported->block_length & SBC_BLOCK_LENGTH_4)
-		cap->block_length = SBC_BLOCK_LENGTH_4;
-	else {
-		error("No supported block lengths");
-		return FALSE;
-	}
-
-	if (supported->subbands & SBC_SUBBANDS_8)
-		cap->subbands = SBC_SUBBANDS_8;
-	else if (supported->subbands & SBC_SUBBANDS_4)
-		cap->subbands = SBC_SUBBANDS_4;
-	else {
-		error("No supported subbands");
-		return FALSE;
-	}
-
-	if (supported->allocation_method & SBC_ALLOCATION_LOUDNESS)
-		cap->allocation_method = SBC_ALLOCATION_LOUDNESS;
-	else if (supported->allocation_method & SBC_ALLOCATION_SNR)
-		cap->allocation_method = SBC_ALLOCATION_SNR;
-
-	min_bitpool = MAX(MIN_BITPOOL, supported->min_bitpool);
-	max_bitpool = MIN(default_bitpool(cap->frequency, cap->channel_mode),
-							supported->max_bitpool);
-
-	cap->min_bitpool = min_bitpool;
-	cap->max_bitpool = max_bitpool;
-
-	return TRUE;
-}
-
-static gboolean select_capabilities(struct avdtp *session,
-					struct avdtp_remote_sep *rsep,
-					GSList **caps)
-{
-	struct avdtp_service_capability *media_transport, *media_codec;
-	struct sbc_codec_cap sbc_cap;
-
-	media_codec = avdtp_get_codec(rsep);
-	if (!media_codec)
-		return FALSE;
-
-	select_sbc_params(&sbc_cap, (struct sbc_codec_cap *) media_codec->data);
-
-	media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
-						NULL, 0);
-
-	*caps = g_slist_append(*caps, media_transport);
-
-	media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &sbc_cap,
-						sizeof(sbc_cap));
-
-	*caps = g_slist_append(*caps, media_codec);
-
-	if (avdtp_get_delay_reporting(rsep)) {
-		struct avdtp_service_capability *delay_reporting;
-		delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING,
-								NULL, 0);
-		*caps = g_slist_append(*caps, delay_reporting);
-	}
-
-	return TRUE;
-}
-
 static void select_cb(struct a2dp_setup *setup, void *ret, int size)
 {
 	struct avdtp_service_capability *media_transport, *media_codec;
diff --git a/audio/a2dp.h b/audio/a2dp.h
index 3a677aa..c9feac8 100644
--- a/audio/a2dp.h
+++ b/audio/a2dp.h
@@ -28,27 +28,6 @@
 #define A2DP_CODEC_MPEG24		0x02
 #define A2DP_CODEC_ATRAC		0x03
 
-#define SBC_SAMPLING_FREQ_16000		(1 << 3)
-#define SBC_SAMPLING_FREQ_32000		(1 << 2)
-#define SBC_SAMPLING_FREQ_44100		(1 << 1)
-#define SBC_SAMPLING_FREQ_48000		1
-
-#define SBC_CHANNEL_MODE_MONO		(1 << 3)
-#define SBC_CHANNEL_MODE_DUAL_CHANNEL	(1 << 2)
-#define SBC_CHANNEL_MODE_STEREO		(1 << 1)
-#define SBC_CHANNEL_MODE_JOINT_STEREO	1
-
-#define SBC_BLOCK_LENGTH_4		(1 << 3)
-#define SBC_BLOCK_LENGTH_8		(1 << 2)
-#define SBC_BLOCK_LENGTH_12		(1 << 1)
-#define SBC_BLOCK_LENGTH_16		1
-
-#define SBC_SUBBANDS_4			(1 << 1)
-#define SBC_SUBBANDS_8			1
-
-#define SBC_ALLOCATION_SNR		(1 << 1)
-#define SBC_ALLOCATION_LOUDNESS		1
-
 #define MPEG_CHANNEL_MODE_MONO		(1 << 3)
 #define MPEG_CHANNEL_MODE_DUAL_CHANNEL	(1 << 2)
 #define MPEG_CHANNEL_MODE_STEREO	(1 << 1)
@@ -65,22 +44,8 @@
 #define MPEG_SAMPLING_FREQ_44100	(1 << 1)
 #define MPEG_SAMPLING_FREQ_48000	1
 
-#define MAX_BITPOOL 64
-#define MIN_BITPOOL 2
-
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 
-struct sbc_codec_cap {
-	struct avdtp_media_codec_capability cap;
-	uint8_t channel_mode:4;
-	uint8_t frequency:4;
-	uint8_t allocation_method:2;
-	uint8_t subbands:2;
-	uint8_t block_length:4;
-	uint8_t min_bitpool;
-	uint8_t max_bitpool;
-} __attribute__ ((packed));
-
 struct mpeg_codec_cap {
 	struct avdtp_media_codec_capability cap;
 	uint8_t channel_mode:4;
@@ -94,17 +59,6 @@ struct mpeg_codec_cap {
 
 #elif __BYTE_ORDER == __BIG_ENDIAN
 
-struct sbc_codec_cap {
-	struct avdtp_media_codec_capability cap;
-	uint8_t frequency:4;
-	uint8_t channel_mode:4;
-	uint8_t block_length:4;
-	uint8_t subbands:2;
-	uint8_t allocation_method:2;
-	uint8_t min_bitpool;
-	uint8_t max_bitpool;
-} __attribute__ ((packed));
-
 struct mpeg_codec_cap {
 	struct avdtp_media_codec_capability cap;
 	uint8_t layer:3;
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH BlueZ V2 1/3] audio: Remove unused local A2DP endpoints reference
From: chanyeol.park @ 2012-08-09  7:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1344498344-19268-1-git-send-email-chanyeol.park@samsung.com>

From: Chan-yeol Park <chanyeol.park@samsung.com>

---
 audio/a2dp.c |   74 +++-------------------------------------------------------
 audio/a2dp.h |    2 --
 2 files changed, 3 insertions(+), 73 deletions(-)

diff --git a/audio/a2dp.c b/audio/a2dp.c
index db4bb13..4567ce0 100644
--- a/audio/a2dp.c
+++ b/audio/a2dp.c
@@ -1562,7 +1562,6 @@ struct a2dp_sep *a2dp_add_sep(const bdaddr_t *src, uint8_t type,
 	GSList **l;
 	uint32_t *record_id;
 	sdp_record_t *record;
-	struct avdtp_sep_ind *ind;
 
 	server = find_server(servers, src);
 	if (server == NULL) {
@@ -1585,17 +1584,11 @@ struct a2dp_sep *a2dp_add_sep(const bdaddr_t *src, uint8_t type,
 
 	sep = g_new0(struct a2dp_sep, 1);
 
-	if (endpoint) {
-		ind = &endpoint_ind;
-		goto proceed;
-	}
-
-	ind = (codec == A2DP_CODEC_MPEG12) ? &mpeg_ind : &sbc_ind;
-
-proceed:
 	sep->lsep = avdtp_register_sep(&server->src, type,
 					AVDTP_MEDIA_TYPE_AUDIO, codec,
-					delay_reporting, ind, &cfm, sep);
+					delay_reporting, &endpoint_ind,
+					&cfm, sep);
+
 	if (sep->lsep == NULL) {
 		g_free(sep);
 		if (err)
@@ -1679,44 +1672,6 @@ void a2dp_remove_sep(struct a2dp_sep *sep)
 	a2dp_unregister_sep(sep);
 }
 
-struct a2dp_sep *a2dp_get(struct avdtp *session,
-				struct avdtp_remote_sep *rsep)
-{
-	GSList *l;
-	struct a2dp_server *server;
-	struct avdtp_service_capability *cap;
-	struct avdtp_media_codec_capability *codec_cap = NULL;
-	bdaddr_t src;
-
-	avdtp_get_peers(session, &src, NULL);
-	server = find_server(servers, &src);
-	if (!server)
-		return NULL;
-
-	cap = avdtp_get_codec(rsep);
-	codec_cap = (void *) cap->data;
-
-	if (avdtp_get_type(rsep) == AVDTP_SEP_TYPE_SINK)
-		l = server->sources;
-	else
-		l = server->sinks;
-
-	for (; l != NULL; l = l->next) {
-		struct a2dp_sep *sep = l->data;
-
-		if (sep->locked)
-			continue;
-
-		if (sep->codec != codec_cap->media_codec_type)
-			continue;
-
-		if (!sep->stream || avdtp_has_stream(session, sep->stream))
-			return sep;
-	}
-
-	return NULL;
-}
-
 static uint8_t default_bitpool(uint8_t freq, uint8_t mode)
 {
 	switch (freq) {
@@ -1889,15 +1844,6 @@ done:
 	finalize_select(setup);
 }
 
-static gboolean auto_select(gpointer data)
-{
-	struct a2dp_setup *setup = data;
-
-	finalize_select(setup);
-
-	return FALSE;
-}
-
 static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list,
 					const char *sender)
 {
@@ -1982,20 +1928,6 @@ unsigned int a2dp_select_capabilities(struct avdtp *session,
 		goto fail;
 	}
 
-	/* FIXME: Remove auto select when it is not longer possible to register
-	endpoint in the configuration file */
-	if (sep->endpoint == NULL) {
-		if (!select_capabilities(session, setup->rsep,
-					&setup->caps)) {
-			error("Unable to auto select remote SEP capabilities");
-			goto fail;
-		}
-
-		g_idle_add(auto_select, setup);
-
-		return cb_data->id;
-	}
-
 	service = avdtp_get_codec(setup->rsep);
 	codec = (struct avdtp_media_codec_capability *) service->data;
 
diff --git a/audio/a2dp.h b/audio/a2dp.h
index 887c5ac..3a677aa 100644
--- a/audio/a2dp.h
+++ b/audio/a2dp.h
@@ -171,8 +171,6 @@ struct a2dp_sep *a2dp_add_sep(const bdaddr_t *src, uint8_t type,
 				int *err);
 void a2dp_remove_sep(struct a2dp_sep *sep);
 
-struct a2dp_sep *a2dp_get(struct avdtp *session, struct avdtp_remote_sep *sep);
-
 unsigned int a2dp_select_capabilities(struct avdtp *session,
 					uint8_t type, const char *sender,
 					a2dp_select_cb_t cb,
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH BlueZ V2 0/3] Remove remained local A2DP endpoints
From: chanyeol.park @ 2012-08-09  7:45 UTC (permalink / raw)
  To: linux-bluetooth

From: Chan-yeol Park <chanyeol.park@samsung.com>

Local A2DP endpoints(SBC,MPEG) are not used anymore.
So references, structures, and functions related to them should be
removed.

Chan-yeol Park (3):
  audio: Remove unused local A2DP endpoints reference
  audio: Remove legacy SBC endpoint
  audio: Remove legacy MPEG endpoint

 audio/a2dp.c |  484 +---------------------------------------------------------
 audio/a2dp.h |   99 ------------
 2 files changed, 3 insertions(+), 580 deletions(-)

-- 
1.7.9.5


^ permalink raw reply

* Re: [RFC v3 2/2] Bluetooth: mgmt: Add device disconnect reason
From: Mikel Astiz @ 2012-08-09  7:43 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: linux-bluetooth, Mikel Astiz
In-Reply-To: <1344433958.2083.52.camel@aeonflux>

Hi Marcel,

On Wed, Aug 8, 2012 at 3:52 PM, Marcel Holtmann <marcel@holtmann.org> wrote:
> Hi Mikel,
>
>> MGMT_EV_DEVICE_DISCONNECTED will now expose the disconnection reason to
>> userland, distinguishing four possible values:
>>
>>       0x00    Reason not known or unspecified
>>       0x01    ACL connection timeout
>>       0x02    ACL connection terminated by local host
>>       0x03    ACL connection terminated by remote host
>
> I think we need to leave ACL out here. Since that is not how we defined
> what a connection is in mgmt terms.
>
>> Note that the local/remote distinction just determines which side
>> terminated the low-level ACL connection, regardless of the disconnection
>> of the higher-level profiles.
>>
>> This can sometimes be misleading and thus must be used with care. For
>> example, some hardware combinations would report a locally initiated
>> disconnection even if the user turned Bluetooth off in the remote side.
>
> Please make sure that this comment makes it also into the API
> description.

I will send an updated version soon, with all your suggestions, along
with the updated userland patch where you can see the API
documentation.

<snip>

>> @@ -1906,12 +1907,29 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
>>
>>       if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) &&
>>           (conn->type == ACL_LINK || conn->type == LE_LINK)) {
>> -             if (ev->status != 0)
>> +             if (ev->status != 0) {
>
> While at it, turn this into if (ev->status).

I will send a separate patch for this and other similar occurrences.
Let me know if you prefer to squash the change.

Cheers,
Mikel

^ permalink raw reply

* [PATCH 13/13] heartrate: Add Heart Rate test script
From: Rafal Garbat @ 2012-08-09  7:20 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344496816-4641-1-git-send-email-rafal.garbat@tieto.com>

---
 Makefile.tools      |    4 +--
 test/test-heartrate |   78 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 80 insertions(+), 2 deletions(-)
 create mode 100755 test/test-heartrate

diff --git a/Makefile.tools b/Makefile.tools
index 5579b86..77b0a3f 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -222,7 +222,7 @@ EXTRA_DIST += test/sap_client.py test/hsplay test/hsmicro \
 		test/test-network test/simple-agent test/simple-service \
 		test/simple-endpoint test/test-audio test/test-input \
 		test/test-sap-server test/test-oob test/test-attrib \
-		test/test-proximity test/test-thermometer test/test-health \
-		test/test-health-sink test/service-record.dtd \
+		test/test-proximity test/test-thermometer test/test-heartrate \
+		test/test-health test/test-health-sink test/service-record.dtd \
 		test/service-did.xml test/service-spp.xml test/service-opp.xml \
 		test/service-ftp.xml test/simple-player test/test-nap
diff --git a/test/test-heartrate b/test/test-heartrate
new file mode 100755
index 0000000..35c97a8
--- /dev/null
+++ b/test/test-heartrate
@@ -0,0 +1,78 @@
+#!/usr/bin/python
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+'''
+Heart Rate Monitor test script
+'''
+
+import gobject
+
+import sys
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+from optparse import OptionParser, make_option
+
+class Watcher(dbus.service.Object):
+	@dbus.service.method("org.bluez.HeartRateWatcher",
+					in_signature="a{sv}", out_signature="")
+	def MeasurementReceived(self, measure):
+		print("Measurement received")
+		print("Value", measure["Value"])
+		print("Energy", measure["Energy"])
+		print("Contact", measure["Contact"])
+		print("Location", measure["Location"])
+
+		for i in measure["Interval"]:
+			print("Interval", i)
+
+if __name__ == "__main__":
+	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+	bus = dbus.SystemBus()
+
+	manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+					"org.bluez.Manager")
+
+	option_list = [
+		make_option("-i", "--adapter", action="store",
+			type="string", dest="adapter"),
+		make_option("-b", "--device", action="store",
+			type="string", dest="address"),
+		]
+
+	parser = OptionParser(option_list=option_list)
+
+	(options, args) = parser.parse_args()
+
+	if not options.address:
+		print("Usage: %s [-i <adapter>] -b <bdaddr>" % (sys.argv[0]))
+		sys.exit(1)
+
+	if options.adapter:
+		adapter_path = manager.FindAdapter(options.adapter)
+	else:
+		adapter_path = manager.DefaultAdapter()
+
+	adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+							"org.bluez.Adapter")
+
+	device_path = adapter.FindDevice(options.address)
+
+	device = dbus.Interface(bus.get_object("org.bluez", device_path),
+							"org.bluez.Device")
+
+	heartrate = dbus.Interface(bus.get_object("org.bluez",
+					device_path), "org.bluez.HeartRate")
+
+	path = "/test/watcher"
+	watcher = Watcher(bus, path)
+
+	heartrate.RegisterWatcher(path)
+
+	properties = heartrate.GetProperties()
+	print("Reset Supported:", properties["ResetSupported"])
+
+	mainloop = gobject.MainLoop()
+	mainloop.run()
\ No newline at end of file
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 12/13] heartrate: Add org.bluez.HeartRateWatcher iface to default policy
From: Rafal Garbat @ 2012-08-09  7:20 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344496816-4641-1-git-send-email-rafal.garbat@tieto.com>

---
 src/bluetooth.conf |    1 +
 1 file changed, 1 insertion(+)

diff --git a/src/bluetooth.conf b/src/bluetooth.conf
index 664dbd9..77a9371 100644
--- a/src/bluetooth.conf
+++ b/src/bluetooth.conf
@@ -16,6 +16,7 @@
     <allow send_interface="org.bluez.MediaPlayer"/>
     <allow send_interface="org.bluez.Watcher"/>
     <allow send_interface="org.bluez.ThermometerWatcher"/>
+    <allow send_interface="org.bluez.HeartRateWatcher"/>
   </policy>
 
   <policy at_console="true">
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 11/13] heartrate: Add GetProperties method handle
From: Rafal Garbat @ 2012-08-09  7:20 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344496816-4641-1-git-send-email-rafal.garbat@tieto.com>

Add method to return Heart Rate Service properties.

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

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index a11733c..cfc2ee0 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -239,6 +239,33 @@ static struct descriptor *get_descriptor(struct characteristic *ch,
 	return l->data;
 }
 
+static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct heartrate *hr = data;
+	DBusMessageIter iter;
+	DBusMessageIter dict;
+	DBusMessage *reply;
+
+	reply = dbus_message_new_method_return(msg);
+	if (reply == NULL)
+		return NULL;
+
+	dbus_message_iter_init_append(reply, &iter);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+	dict_append_entry(&dict, "ResetSupported", DBUS_TYPE_BOOLEAN,
+							&hr->cp_reset);
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	return reply;
+}
+
 static void measurement_cb(guint8 status, const guint8 *pdu,
 						guint16 len, gpointer user_data)
 {
@@ -414,6 +441,9 @@ static DBusMessage *control_point_reset(DBusConnection *conn, DBusMessage *msg,
 }
 
 static const GDBusMethodTable heartrate_methods[] = {
+	{ GDBUS_METHOD("GetProperties",
+			NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+			get_properties) },
 	{ GDBUS_METHOD("RegisterWatcher",
 			GDBUS_ARGS({ "agent", "o" }), NULL,
 			watcher_register) },
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 10/13] heartrate: Add support for Control Point Reset
From: Rafal Garbat @ 2012-08-09  7:20 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344496816-4641-1-git-send-email-rafal.garbat@tieto.com>

Handle Control Point reset if server supports it.

---
 profiles/heartrate/heartrate.c |   50 ++++++++++++++++++++++++++++++++++++----
 1 file changed, 46 insertions(+), 4 deletions(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index b383eda..a11733c 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -63,6 +63,7 @@ struct heartrate {
 	GSList			*watchers; /*Watchers*/
 	gboolean		has_location;
 	uint8_t		location; /*Body Sensor location*/
+	gboolean		cp_reset; /*Control Point Reset support*/
 };
 
 struct characteristic {
@@ -375,6 +376,43 @@ static DBusMessage *watcher_unregister(DBusConnection *conn, DBusMessage *msg,
 	return dbus_message_new_method_return(msg);
 }
 
+static gint process_att_reset(struct heartrate *hr)
+{
+	struct characteristic *ch;
+	char *msg;
+	uint8_t atval;
+
+	if (hr->attrib == NULL)
+		return -1;
+
+	ch = get_characteristic(hr, HEART_RATE_CONTROL_POINT_UUID);
+	if (ch == NULL)
+		return -1;
+
+	atval = 0x01;
+	msg = g_strdup("Reset Control Point");
+
+	gatt_write_char(hr->attrib, ch->attr.value_handle, &atval, 1,
+						measurement_cb, msg);
+	return 0;
+}
+
+static DBusMessage *control_point_reset(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct heartrate *hr = data;
+
+	if (!hr->cp_reset)
+		return btd_error_not_supported(msg);
+
+	if (process_att_reset(hr) < 0)
+		return btd_error_not_available(msg);
+
+	DBG("Energy Expended Value has been reset");
+
+	return dbus_message_new_method_return(msg);
+}
+
 static const GDBusMethodTable heartrate_methods[] = {
 	{ GDBUS_METHOD("RegisterWatcher",
 			GDBUS_ARGS({ "agent", "o" }), NULL,
@@ -382,6 +420,8 @@ static const GDBusMethodTable heartrate_methods[] = {
 	{ GDBUS_METHOD("UnregisterWatcher",
 			GDBUS_ARGS({ "agent", "o" }), NULL,
 			watcher_unregister) },
+	{ GDBUS_METHOD("Reset", NULL, NULL,
+			control_point_reset) },
 	{ }
 };
 
@@ -417,12 +457,14 @@ static void read_sensor_location_cb(guint8 status, const guint8 *pdu,
 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 not supported by client");
-	 else if (g_strcmp0(ch->attr.uuid,
-					BODY_SENSOR_LOCATION_UUID) == 0)
+				HEART_RATE_CONTROL_POINT_UUID) == 0) {
+		ch->hr->cp_reset = TRUE;
+		DBG("Heart Rate Control Point reset supported by server");
+	 } else if (g_strcmp0(ch->attr.uuid,
+					BODY_SENSOR_LOCATION_UUID) == 0) {
 		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.9.5


^ permalink raw reply related

* [PATCH 09/13] heartrate: Process measurements
From: Rafal Garbat @ 2012-08-09  7:20 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344496816-4641-1-git-send-email-rafal.garbat@tieto.com>

Enable or disable measurement while watcher is registered
or unregistered. Process measurement data when notification
is received and update watcher.

---
 profiles/heartrate/heartrate.c |  307 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 296 insertions(+), 11 deletions(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index d5b3fb9..b383eda 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -46,6 +46,12 @@
 
 #define SENSOR_LOCATION_SIZE 1
 
+#define HR_VALUE_FORMAT	0x01
+#define SENSOR_SUPPORTED	0x02
+#define CONTACT_DETECTED	0x04
+#define ENERGY_EXP_STATUS	0x08
+#define RR_INTERVAL		0x16
+
 struct heartrate {
 	struct btd_device	*dev;  /*Device reference*/
 	DBusConnection		*conn; /*DBus conn*/
@@ -78,8 +84,39 @@ struct watcher {
 	char			*path;
 };
 
+struct measurement {
+	gboolean	u16_val_fmt; /*Heart Rate Value Format*/
+	uint16_t	value;
+	uint16_t	energy;
+	gboolean	energy_sup; /*Energy Status Supported*/
+	gboolean	contact;
+	char		*location;
+	gboolean	interval_sup; /*RR-Interval Supported*/
+	GSList		*interval;
+};
+
+const char *location_type[] = {
+	"<reserved>",
+	"Other",
+	"Chest",
+	"Wrist",
+	"Finger",
+	"Hand",
+	"Earlobe",
+	"Foot"
+};
+
 static GSList *hr_servers = NULL;
 
+static const gchar *location2str(uint8_t value)
+{
+	 if (value > 0 && value < G_N_ELEMENTS(location_type))
+		return location_type[value];
+
+	error("Location type %d reserved for future use", value);
+	return NULL;
+}
+
 static gint cmp_device(gconstpointer a, gconstpointer b)
 {
 	const struct heartrate *hr = a;
@@ -91,6 +128,30 @@ 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_char_val_handle(gconstpointer a, gconstpointer b)
+{
+	const struct characteristic *ch = a;
+	const uint16_t *handle = b;
+
+	return ch->attr.value_handle - *handle;
+}
+
+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;
@@ -153,6 +214,74 @@ static void heartrate_destroy(gpointer user_data)
 	g_free(hr);
 }
 
+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 measurement_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("Temperature 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;
+	}
+
+	atval[0] = enable ? 0x01 : 0x00;
+	atval[1] = 0x00;
+	msg = enable ? g_strdup("Enable measurement") :
+				g_strdup("Disable measurement");
+	gatt_write_char(hr->attrib, desc->handle, atval, 2,
+							measurement_cb, msg);
+
+}
+
 static void watcher_exit(DBusConnection *conn, void *user_data)
 {
 	struct watcher *watcher = user_data;
@@ -162,6 +291,9 @@ static void watcher_exit(DBusConnection *conn, void *user_data)
 
 	hr->watchers = g_slist_remove(hr->watchers, watcher);
 	g_dbus_remove_watch(watcher->hr->conn, watcher->id);
+
+	if (g_slist_length(hr->watchers) == 0)
+		measurement_toggle(hr, FALSE);
 }
 
 static struct watcher *watcher_find(GSList *list, const char *sender,
@@ -208,6 +340,9 @@ static DBusMessage *watcher_register(DBusConnection *conn, DBusMessage *msg,
 	watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
 						watcher, watcher_destroy);
 
+	if (g_slist_length(hr->watchers) == 0)
+		measurement_toggle(hr, TRUE);
+
 	hr->watchers = g_slist_prepend(hr->watchers, watcher);
 
 	return dbus_message_new_method_return(msg);
@@ -234,6 +369,9 @@ static DBusMessage *watcher_unregister(DBusConnection *conn, DBusMessage *msg,
 	hr->watchers = g_slist_remove(hr->watchers, watcher);
 	g_dbus_remove_watch(watcher->hr->conn, watcher->id);
 
+	if (g_slist_length(hr->watchers) == 0)
+		measurement_toggle(hr, FALSE);
+
 	return dbus_message_new_method_return(msg);
 }
 
@@ -287,17 +425,6 @@ static void process_heartrate_char(struct characteristic *ch)
 						read_sensor_location_cb, ch);
 }
 
-static void measurement_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 process_heartrate_desc(struct descriptor *desc)
 {
 	struct characteristic *ch = desc->ch;
@@ -412,12 +539,170 @@ static void configure_heartrate_cb(GSList *characteristics, guint8 status,
 	}
 }
 
+static void update_watcher(gpointer data, gpointer user_data)
+{
+	struct watcher *w = data;
+	struct measurement *m = user_data;
+	DBusConnection *conn = w->hr->conn;
+	DBusMessageIter iter;
+	DBusMessageIter dict;
+	DBusMessage *msg;
+	GSList *l;
+	uint16_t *interval;
+	guint n_elem;
+	guint i;
+
+	msg = dbus_message_new_method_call(w->srv, w->path,
+				"org.bluez.HeartRateWatcher",
+				"MeasurementReceived");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+	dict_append_entry(&dict, "Value", DBUS_TYPE_UINT16, &m->value);
+	dict_append_entry(&dict, "Energy", DBUS_TYPE_UINT16, &m->energy);
+	dict_append_entry(&dict, "Contact", DBUS_TYPE_BOOLEAN, &m->contact);
+	dict_append_entry(&dict, "Location", DBUS_TYPE_STRING, &m->location);
+
+	n_elem = g_slist_length(m->interval);
+
+	interval = g_new(uint16_t, n_elem);
+
+	if (interval != NULL) {
+
+		for (i = 0, l = m->interval; l; l = l->next, i++)
+			interval[i] =  GPOINTER_TO_UINT(l->data);
+
+		dict_append_array(&dict, "Interval", DBUS_TYPE_UINT16,
+							&interval, n_elem);
+	}
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	dbus_message_set_no_reply(msg, TRUE);
+	g_dbus_send_message(conn, msg);
+
+	if (interval != NULL)
+		g_free(interval);
+}
+
+static void recv_measurement(struct heartrate *hr, struct measurement *m)
+{
+	GSList *wlist = hr->watchers;
+
+	g_slist_foreach(wlist, update_watcher, m);
+}
+
+static void get_flags(struct measurement *m, uint8_t pdu)
+{
+	uint8_t flags = pdu;
+
+	if (flags & HR_VALUE_FORMAT)
+		m->u16_val_fmt = TRUE;  /*value format set to uint16*/
+
+	if ((flags & SENSOR_SUPPORTED) && (flags & CONTACT_DETECTED))
+		m->contact = TRUE;
+
+	if (flags & ENERGY_EXP_STATUS)
+		m->energy_sup = TRUE;
+
+	if (flags & RR_INTERVAL)
+		m->interval_sup = TRUE;
+}
+
+static void proc_measurement(struct heartrate *hr, const uint8_t *pdu,
+						uint16_t len)
+{
+	struct measurement m;
+	const char *loc;
+
+	if (len < 4) {
+		error("Mandatory flags are not provided");
+		return;
+	}
+
+	memset(&m, 0, sizeof(struct measurement));
+
+	get_flags(&m, pdu[3]);
+
+	if (len < 5) {
+		error("Heart Rate measurement value is not provided");
+		return;
+	}
+
+	m.value = m.u16_val_fmt ? pdu[4] :  att_get_u16(&pdu[4]);
+
+	if (m.energy_sup) {
+
+		if (len < 6) {
+			error("Can't get Energy Expended field");
+			return;
+		}
+		m.energy = pdu[5];
+	}
+
+	if (m.interval_sup) {
+		gint idx, i;
+
+		if (m.energy_sup && len >= 6) {
+			idx = 6;
+		} else if (!m.energy_sup && len >= 5) {
+			idx = 5;
+		} else {
+			error("Can't get RR-interval");
+			return;
+		}
+
+		for (i = len - idx; i > 0; i--) {
+			uint16_t val = att_get_u16(&pdu[idx++]);
+			m.interval = g_slist_append(m.interval,
+						GUINT_TO_POINTER(val));
+		}
+	}
+
+	if (hr->has_location) {
+		loc = location2str(hr->location);
+		m.location =  g_strdup(loc);
+	} else {
+		m.location = NULL;
+	}
+
+	recv_measurement(hr, &m);
+
+	g_free(m.location);
+
+	if (m.interval != NULL)
+		g_slist_free(m.interval);
+}
+
 static void notify_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
 {
+	struct heartrate *hr = user_data;
+	const struct characteristic *ch;
+	uint16_t handle;
+	GSList *l;
+
 	if (len < MIN_NOTIFICATION_LEN) {
 		error("Bad pdu received");
 		return;
 	}
+
+	handle = att_get_u16(&pdu[1]);
+	l = g_slist_find_custom(hr->chars, &handle, cmp_char_val_handle);
+	if (l == NULL) {
+		error("Unexpected handle: 0x%04x", handle);
+		return;
+	}
+
+	ch = l->data;
+	if (g_strcmp0(ch->attr.uuid, HEART_RATE_MEASUREMENT_UUID) == 0)
+		proc_measurement(hr, pdu, len);
 }
 
 static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 08/13] heartrate: Add notification support
From: Rafal Garbat @ 2012-08-09  7:20 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344496816-4641-1-git-send-email-rafal.garbat@tieto.com>

Add handling notification event.

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

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 2521b6a..d5b3fb9 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -42,6 +42,8 @@
 
 #define HEART_RATE_INTERFACE "org.bluez.HeartRate"
 
+#define MIN_NOTIFICATION_LEN 3  /* 1-byte opcode + 2-byte handle */
+
 #define SENSOR_LOCATION_SIZE 1
 
 struct heartrate {
@@ -49,6 +51,7 @@ struct heartrate {
 	DBusConnection		*conn; /*DBus conn*/
 	GAttrib			*attrib; /*GATT connection*/
 	guint			attioid; /*ATT watcher id*/
+	guint			attionotid; /*ATT notification watcher id*/
 	struct att_range	*svc_range; /*Heart Rate range*/
 	GSList			*chars; /*Characteristics*/
 	GSList			*watchers; /*Watchers*/
@@ -136,8 +139,10 @@ static void heartrate_destroy(gpointer user_data)
 	if (hr->attioid > 0)
 		btd_device_remove_attio_callback(hr->dev, hr->attioid);
 
-	if (hr->attrib != NULL)
+	if (hr->attrib != NULL) {
+		g_attrib_unregister(hr->attrib, hr->attionotid);
 		g_attrib_unref(hr->attrib);
+	}
 
 	if (hr->watchers != NULL)
 		g_slist_free_full(hr->watchers, watcher_remove);
@@ -407,6 +412,14 @@ static void configure_heartrate_cb(GSList *characteristics, guint8 status,
 	}
 }
 
+static void notify_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
+{
+	if (len < MIN_NOTIFICATION_LEN) {
+		error("Bad pdu received");
+		return;
+	}
+}
+
 static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 {
 	struct heartrate *hr = user_data;
@@ -415,6 +428,9 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 
 	hr->attrib = g_attrib_ref(attrib);
 
+	hr->attionotid = g_attrib_register(hr->attrib,
+			ATT_OP_HANDLE_NOTIFY, notify_handler, hr , NULL);
+
 	if (hr->chars == NULL)
 		gatt_discover_char(hr->attrib, hr->svc_range->start,
 						hr->svc_range->end, NULL,
@@ -427,6 +443,8 @@ static void attio_disconnected_cb(gpointer user_data)
 
 	DBG("GATT Disconnected");
 
+	g_attrib_unregister(hr->attrib, hr->attionotid);
+	hr->attionotid = 0;
 	g_attrib_unref(hr->attrib);
 	hr->attrib = NULL;
 }
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 07/13] heartrate: Process Heart Rate Characteristics
From: Rafal Garbat @ 2012-08-09  7:20 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344496816-4641-1-git-send-email-rafal.garbat@tieto.com>

Read and store Sensor Location characteristic.

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

diff --git a/lib/uuid.h b/lib/uuid.h
index 5d81856..5d1e091 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -65,6 +65,8 @@ extern "C" {
 
 #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"
 
 #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 b11f132..2521b6a 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -42,6 +42,8 @@
 
 #define HEART_RATE_INTERFACE "org.bluez.HeartRate"
 
+#define SENSOR_LOCATION_SIZE 1
+
 struct heartrate {
 	struct btd_device	*dev;  /*Device reference*/
 	DBusConnection		*conn; /*DBus conn*/
@@ -50,6 +52,8 @@ struct heartrate {
 	struct att_range	*svc_range; /*Heart Rate range*/
 	GSList			*chars; /*Characteristics*/
 	GSList			*watchers; /*Watchers*/
+	gboolean		has_location;
+	uint8_t		location; /*Body Sensor location*/
 };
 
 struct characteristic {
@@ -238,6 +242,46 @@ static const GDBusMethodTable heartrate_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[SENSOR_LOCATION_SIZE];
+	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[0];
+}
+
+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 not supported by client");
+	 else if (g_strcmp0(ch->attr.uuid,
+					BODY_SENSOR_LOCATION_UUID) == 0)
+		gatt_read_char(ch->hr->attrib, ch->attr.value_handle, 0,
+						read_sensor_location_cb, ch);
+}
+
 static void measurement_cb(guint8 status, const guint8 *pdu,
 						guint16 len, gpointer user_data)
 {
@@ -344,6 +388,8 @@ 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) {
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 06/13] heartrate: Add DBus connection logic
From: Rafal Garbat @ 2012-08-09  7:20 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344496816-4641-1-git-send-email-rafal.garbat@tieto.com>

Add DBus connection logic and watcher methods.

---
 profiles/heartrate/heartrate.c |  156 +++++++++++++++++++++++++++++++++++++++-
 profiles/heartrate/heartrate.h |    3 +-
 profiles/heartrate/main.c      |   18 ++++-
 profiles/heartrate/manager.c   |   19 ++++-
 profiles/heartrate/manager.h   |    2 +-
 5 files changed, 191 insertions(+), 7 deletions(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index f1668c7..b11f132 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -24,12 +24,15 @@
 #include <config.h>
 #endif
 
+#include <gdbus.h>
 #include <errno.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"
@@ -37,12 +40,16 @@
 #include "heartrate.h"
 #include "log.h"
 
+#define HEART_RATE_INTERFACE "org.bluez.HeartRate"
+
 struct heartrate {
 	struct btd_device	*dev;  /*Device reference*/
+	DBusConnection		*conn; /*DBus conn*/
 	GAttrib			*attrib; /*GATT connection*/
 	guint			attioid; /*ATT watcher id*/
 	struct att_range	*svc_range; /*Heart Rate range*/
 	GSList			*chars; /*Characteristics*/
+	GSList			*watchers; /*Watchers*/
 };
 
 struct characteristic {
@@ -57,6 +64,13 @@ struct descriptor {
 	bt_uuid_t		uuid;
 };
 
+struct watcher {
+	struct heartrate	*hr;
+	guint			id;
+	char			*srv;
+	char			*path;
+};
+
 static GSList *hr_servers = NULL;
 
 static gint cmp_device(gconstpointer a, gconstpointer b)
@@ -70,6 +84,35 @@ 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 void watcher_remove(gpointer user_data)
+{
+	struct watcher *watcher = user_data;
+
+	g_dbus_remove_watch(watcher->hr->conn, watcher->id);
+}
+
+static void watcher_destroy(gpointer user_data)
+{
+	struct watcher *watcher = user_data;
+
+	g_free(watcher->path);
+	g_free(watcher->srv);
+	g_free(watcher);
+}
+
 static void char_destroy(gpointer user_data)
 {
 	struct characteristic *c = user_data;
@@ -92,12 +135,109 @@ static void heartrate_destroy(gpointer user_data)
 	if (hr->attrib != NULL)
 		g_attrib_unref(hr->attrib);
 
+	if (hr->watchers != NULL)
+		g_slist_free_full(hr->watchers, watcher_remove);
+
 	btd_device_unref(hr->dev);
+	dbus_connection_unref(hr->conn);
 	g_free(hr->svc_range);
 	g_free(hr);
+}
+
+static void watcher_exit(DBusConnection *conn, void *user_data)
+{
+	struct watcher *watcher = user_data;
+	struct heartrate *hr = watcher->hr;
+
+	DBG("Heart Rate watcher %s disconnected", watcher->path);
+
+	hr->watchers = g_slist_remove(hr->watchers, watcher);
+	g_dbus_remove_watch(watcher->hr->conn, watcher->id);
+}
+
+static struct watcher *watcher_find(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);
+	watcher_destroy(match);
+
+	if (l != NULL)
+		return l->data;
+
+	return NULL;
+}
+
+static DBusMessage *watcher_register(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	const char *sender = dbus_message_get_sender(msg);
+	struct heartrate *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 = watcher_find(hr->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->hr = hr;
+	watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
+						watcher, watcher_destroy);
+
+	hr->watchers = g_slist_prepend(hr->watchers, watcher);
 
+	return dbus_message_new_method_return(msg);
 }
 
+static DBusMessage *watcher_unregister(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	const char *sender = dbus_message_get_sender(msg);
+	struct heartrate *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 = watcher_find(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(watcher->hr->conn, watcher->id);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable heartrate_methods[] = {
+	{ GDBUS_METHOD("RegisterWatcher",
+			GDBUS_ARGS({ "agent", "o" }), NULL,
+			watcher_register) },
+	{ GDBUS_METHOD("UnregisterWatcher",
+			GDBUS_ARGS({ "agent", "o" }), NULL,
+			watcher_unregister) },
+	{ }
+};
+
 static void measurement_cb(guint8 status, const guint8 *pdu,
 						guint16 len, gpointer user_data)
 {
@@ -245,17 +385,29 @@ static void attio_disconnected_cb(gpointer user_data)
 	hr->attrib = NULL;
 }
 
-int heartrate_register(struct btd_device *device, struct gatt_primary *pattr)
+int heartrate_register(DBusConnection *connection, struct btd_device *device,
+						struct gatt_primary *pattr)
 {
+	const gchar *path = device_get_path(device);
 	struct heartrate *hr;
 
 	hr = g_new0(struct heartrate, 1);
 	hr->dev = btd_device_ref(device);
 
+	hr->conn = dbus_connection_ref(connection);
 	hr->svc_range = g_new0(struct att_range, 1);
 	hr->svc_range->start = pattr->range.start;
 	hr->svc_range->end = pattr->range.end;
 
+	if (!g_dbus_register_interface(hr->conn, path, HEART_RATE_INTERFACE,
+						heartrate_methods, NULL, NULL,
+						hr, heartrate_destroy)) {
+		error("D-Bus failed to register %s interface",
+							HEART_RATE_INTERFACE);
+		heartrate_destroy(hr);
+		return -EIO;
+	}
+
 	hr_servers = g_slist_prepend(hr_servers, hr);
 
 	hr->attioid = btd_device_add_attio_callback(device,
@@ -276,5 +428,7 @@ void heartrate_unregister(struct btd_device *device)
 	hr = l->data;
 	hr_servers = g_slist_remove(hr_servers, hr);
 
+	g_dbus_unregister_interface(hr->conn, device_get_path(hr->dev),
+							HEART_RATE_INTERFACE);
 	heartrate_destroy(hr);
 }
diff --git a/profiles/heartrate/heartrate.h b/profiles/heartrate/heartrate.h
index 1d2ba89..08e2c92 100644
--- a/profiles/heartrate/heartrate.h
+++ b/profiles/heartrate/heartrate.h
@@ -20,5 +20,6 @@
  *
  */
 
-int heartrate_register(struct btd_device *device, struct gatt_primary *pattr);
+int heartrate_register(DBusConnection *connection, struct btd_device *device,
+						struct gatt_primary *tattr);
 void heartrate_unregister(struct btd_device *device);
diff --git a/profiles/heartrate/main.c b/profiles/heartrate/main.c
index 40f34bc..8e8fde9 100644
--- a/profiles/heartrate/main.c
+++ b/profiles/heartrate/main.c
@@ -27,12 +27,15 @@
 #include <stdint.h>
 #include <glib.h>
 #include <errno.h>
+#include <gdbus.h>
 
 #include "plugin.h"
 #include "manager.h"
 #include "hcid.h"
 #include "log.h"
 
+static DBusConnection *connection = NULL;
+
 static int heartrate_init(void)
 {
 	if (!main_opts.gatt_enabled) {
@@ -40,12 +43,25 @@ static int heartrate_init(void)
 		return -ENOTSUP;
 	}
 
-	return heartrate_manager_init();
+	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+	if (connection == NULL)
+		return -EIO;
+
+	if (heartrate_manager_init(connection) < 0) {
+		dbus_connection_unref(connection);
+		connection = NULL;
+		return -EIO;
+	}
+
+	return 0;
 }
 
 static void heartrate_exit(void)
 {
 	heartrate_manager_exit();
+
+	dbus_connection_unref(connection);
+	connection = NULL;
 }
 
 BLUETOOTH_PLUGIN_DEFINE(heartrate, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
diff --git a/profiles/heartrate/manager.c b/profiles/heartrate/manager.c
index 6ba059d..c373f86 100644
--- a/profiles/heartrate/manager.c
+++ b/profiles/heartrate/manager.c
@@ -32,6 +32,8 @@
 #include "heartrate.h"
 #include "manager.h"
 
+static DBusConnection *connection = NULL;
+
 static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
 {
 	const struct gatt_primary *prim = a;
@@ -54,7 +56,7 @@ static int heartrate_driver_probe(struct btd_device *device, GSList *uuids)
 
 	pattr = l->data;
 
-	return heartrate_register(device, pattr);
+	return heartrate_register(connection, device, pattr);
 }
 
 static void heartrate_driver_remove(struct btd_device *device)
@@ -69,12 +71,23 @@ static struct btd_device_driver heartrate_device_driver = {
 	.remove	= heartrate_driver_remove
 };
 
-int heartrate_manager_init(void)
+int heartrate_manager_init(DBusConnection *conn)
+
 {
-	return btd_register_device_driver(&heartrate_device_driver);
+	int ret;
+
+	ret = btd_register_device_driver(&heartrate_device_driver);
+	if (ret < 0)
+		return ret;
+
+	connection = dbus_connection_ref(conn);
+	return 0;
 }
 
 void heartrate_manager_exit(void)
 {
 	btd_unregister_device_driver(&heartrate_device_driver);
+
+	dbus_connection_unref(connection);
+	connection = NULL;
 }
diff --git a/profiles/heartrate/manager.h b/profiles/heartrate/manager.h
index de799f6..5e9c8b2 100644
--- a/profiles/heartrate/manager.h
+++ b/profiles/heartrate/manager.h
@@ -20,5 +20,5 @@
  *
  */
 
-int heartrate_manager_init(void);
+int heartrate_manager_init(DBusConnection *conn);
 void heartrate_manager_exit(void);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 05/13] heartrate: Process Heart Rate Descriptors
From: Rafal Garbat @ 2012-08-09  7:20 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344496816-4641-1-git-send-email-rafal.garbat@tieto.com>

Process Heart Rate service descriptors and write
client specific characteristic configuration.

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

diff --git a/lib/uuid.h b/lib/uuid.h
index 99b88cc..5d81856 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 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 e917f27..f1668c7 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -70,12 +70,21 @@ static gint cmp_device(gconstpointer a, gconstpointer b)
 	return -1;
 }
 
+static void char_destroy(gpointer user_data)
+{
+	struct characteristic *c = user_data;
+
+	g_slist_free_full(c->desc, g_free);
+
+	g_free(c);
+}
+
 static void heartrate_destroy(gpointer user_data)
 {
 	struct heartrate *hr = user_data;
 
 	if (hr->chars != NULL)
-		g_slist_free_full(hr->chars, g_free);
+		g_slist_free_full(hr->chars, char_destroy);
 
 	if (hr->attioid > 0)
 		btd_device_remove_attio_callback(hr->dev, hr->attioid);
@@ -89,6 +98,47 @@ static void heartrate_destroy(gpointer user_data)
 
 }
 
+static void measurement_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 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 &&
+		g_strcmp0(ch->attr.uuid,
+				HEART_RATE_MEASUREMENT_UUID) == 0) {
+
+		uint8_t atval[2];
+		uint16_t val;
+		char *msg;
+
+		val = GATT_CLIENT_CHARAC_CFG_NOTIF_BIT;
+		msg = g_strdup("Enable Heart Rate Measurement " \
+						"notification");
+		att_put_u16(val, atval);
+		gatt_write_char(ch->hr->attrib, desc->handle,
+					atval, 2, measurement_cb, msg);
+		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)
 {
@@ -122,6 +172,7 @@ 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.9.5


^ permalink raw reply related

* [PATCH 04/13] heartrate: Discover Characteristic Descriptors
From: Rafal Garbat @ 2012-08-09  7:20 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344496816-4641-1-git-send-email-rafal.garbat@tieto.com>

Discover and store each of the Heart Rate Service
characteristic descriptors.

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

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 1114cff..e917f27 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -47,9 +47,16 @@ struct heartrate {
 
 struct characteristic {
 	struct gatt_char	attr; /*Characteristic*/
+	GSList			*desc; /*Descriptors*/
 	struct heartrate	*hr; /*Parent Heart Rate Service*/
 };
 
+struct descriptor {
+	struct characteristic	*ch;
+	uint16_t		handle;
+	bt_uuid_t		uuid;
+};
+
 static GSList *hr_servers = NULL;
 
 static gint cmp_device(gconstpointer a, gconstpointer b)
@@ -82,6 +89,44 @@ static void heartrate_destroy(gpointer user_data)
 
 }
 
+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)
 {
@@ -97,6 +142,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;
@@ -106,6 +152,21 @@ static void configure_heartrate_cb(GSList *characteristics, guint8 status,
 		ch->hr = hr;
 
 		hr->chars = g_slist_append(hr->chars, 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.9.5


^ permalink raw reply related

* [PATCH 03/13] heartrate: Add conn logic and attio callbacks
From: Rafal Garbat @ 2012-08-09  7:20 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344496816-4641-1-git-send-email-rafal.garbat@tieto.com>

Handle connection to the remote device when the
Heart Rate plugin is loaded.

---
 profiles/heartrate/heartrate.c |   86 +++++++++++++++++++++++++++++++++++++++-
 profiles/heartrate/heartrate.h |    2 +-
 profiles/heartrate/manager.c   |   22 +++++++++-
 3 files changed, 107 insertions(+), 3 deletions(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 9bd93c5..1114cff 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -30,10 +30,24 @@
 
 #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 {
 	struct btd_device	*dev;  /*Device reference*/
+	GAttrib			*attrib; /*GATT connection*/
+	guint			attioid; /*ATT watcher id*/
+	struct att_range	*svc_range; /*Heart Rate range*/
+	GSList			*chars; /*Characteristics*/
+};
+
+struct characteristic {
+	struct gatt_char	attr; /*Characteristic*/
+	struct heartrate	*hr; /*Parent Heart Rate Service*/
 };
 
 static GSList *hr_servers = NULL;
@@ -53,19 +67,89 @@ static void heartrate_destroy(gpointer user_data)
 {
 	struct heartrate *hr = user_data;
 
+	if (hr->chars != NULL)
+		g_slist_free_full(hr->chars, g_free);
+
+	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->svc_range);
 	g_free(hr);
+
+}
+
+static void configure_heartrate_cb(GSList *characteristics, guint8 status,
+							gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+	GSList *l;
+
+	if (status != 0) {
+		error("Discover heartrate 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;
+
+	DBG("GATT Connected");
+
+	hr->attrib = g_attrib_ref(attrib);
+
+	if (hr->chars == NULL)
+		gatt_discover_char(hr->attrib, hr->svc_range->start,
+						hr->svc_range->end, NULL,
+						configure_heartrate_cb, hr);
 }
 
-int heartrate_register(struct btd_device *device)
+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_register(struct btd_device *device, struct gatt_primary *pattr)
 {
 	struct heartrate *hr;
 
 	hr = g_new0(struct heartrate, 1);
 	hr->dev = btd_device_ref(device);
 
+	hr->svc_range = g_new0(struct att_range, 1);
+	hr->svc_range->start = pattr->range.start;
+	hr->svc_range->end = pattr->range.end;
+
 	hr_servers = g_slist_prepend(hr_servers, hr);
 
+	hr->attioid = btd_device_add_attio_callback(device,
+						attio_connected_cb,
+						attio_disconnected_cb ,
+						hr);
 	return 0;
 }
 void heartrate_unregister(struct btd_device *device)
diff --git a/profiles/heartrate/heartrate.h b/profiles/heartrate/heartrate.h
index 8d4271c..1d2ba89 100644
--- a/profiles/heartrate/heartrate.h
+++ b/profiles/heartrate/heartrate.h
@@ -20,5 +20,5 @@
  *
  */
 
-int heartrate_register(struct btd_device *device);
+int heartrate_register(struct btd_device *device, struct gatt_primary *pattr);
 void heartrate_unregister(struct btd_device *device);
diff --git a/profiles/heartrate/manager.c b/profiles/heartrate/manager.c
index da6c7ef..6ba059d 100644
--- a/profiles/heartrate/manager.c
+++ b/profiles/heartrate/manager.c
@@ -32,9 +32,29 @@
 #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_driver_probe(struct btd_device *device, GSList *uuids)
 {
-	return heartrate_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_register(device, pattr);
 }
 
 static void heartrate_driver_remove(struct btd_device *device)
-- 
1.7.9.5


^ permalink raw reply related


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