Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH 00/14] Thermometer watchers API change + fixes
From: Andrzej Kaczmarek @ 2012-09-25 14:52 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

Hi,

Here's series of patches to move watchers from per-device to per-adapter
interface (basically the same as done for HRP, see other series of patches).
This applies to both final and intermediate temperature watchers - once
watcher is registered, all connected devices are setup to send measurement
notifications and the opposite when last watcher is unregistered.

This major change is done in patches 1-6.

Patches 7-11 contain some code and documentation refactoring, i.e. to
remove duplicated code.

Patches 12-14 are trival coding style fixes.

Unfortunately, I wasn't able to fully test this code due to lack of proper
thermometer device and sample device from CC2540 devkit does not quite
work as expected (e.g. I can see CCC is written properly when watcher is
registered but remote does not send any indications for unknown reason).



Andrzej Kaczmarek (14):
  thermometer: Store thermometer devices per-adapter
  thermometer: Register ThermometerManager interface on adapter path
  thermometer: Move watcher logic to adapter interface
  thermometer: Include remote device information in MeasurementReceived
  thermometer: Update API document
  thermometer: Update test script
  thermometer: Reformat MeasurementReceived description
  thermometer: Update driver naming style
  thermometer: Add constant definition for watcher interface name
  thermometer: Add common function to write characteristics CCC
  thermometer: Refactor processing of measurement characteristic value
  thermometer: Fix whitespace
  thermometer: Fix indentation
  thermometer: Fix missing braces

 doc/thermometer-api.txt            | 126 +++++-----
 profiles/thermometer/manager.c     |  24 +-
 profiles/thermometer/thermometer.c | 486 +++++++++++++++++++++----------------
 profiles/thermometer/thermometer.h |   2 +
 test/test-thermometer              |  16 +-
 5 files changed, 372 insertions(+), 282 deletions(-)

-- 
1.7.11.3


^ permalink raw reply

* Re: [PATCH v3] HID: Add support for Sony PS3 BD Remote Control
From: David Dillow @ 2012-09-25 14:43 UTC (permalink / raw)
  To: Antonio Ospite
  Cc: linux-bluetooth, David Herrmann, Luiz Augusto von Dentz,
	Bastien Nocera, linux-input, jkosina
In-Reply-To: <1348583447-31820-1-git-send-email-ospite@studenti.unina.it>

On Tue, 2012-09-25 at 16:30 +0200, Antonio Ospite wrote:
> +static int ps3remote_mapping(struct hid_device *hdev, struct hid_input *hi,
> +			     struct hid_field *field, struct hid_usage *usage,
> +			     unsigned long **bit, int *max)
> +{
> +	unsigned int key = usage->hid & HID_USAGE;

The size check below should be moved into the switch statement, and
modified for each, as you could access beyond the joypad_buttons array
as-is. The usage page check can stay outside the switch.

> +	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_BUTTON ||
> +	    key >= ARRAY_SIZE(ps3remote_keymap_remote_buttons))
> +		return -1;
> +
> +	switch (usage->collection_index) {
> +	case 1:
> +		key = ps3remote_keymap_joypad_buttons[key];
> +		if (!key)
> +			return -1;
> +		break;
> +	case 2:
> +		key = ps3remote_keymap_remote_buttons[key];
> +		if (!key)
> +			return -1;
> +		break;
> +	default:
> +		return -1;
> +	}
> +
> +	hid_map_usage_clear(hi, usage, bit, max, EV_KEY, key);
> +	return 1;
> +}


^ permalink raw reply

* [PATCH v3] HID: Add support for Sony PS3 BD Remote Control
From: Antonio Ospite @ 2012-09-25 14:30 UTC (permalink / raw)
  To: David Dillow
  Cc: linux-bluetooth, David Herrmann, Luiz Augusto von Dentz,
	Bastien Nocera, linux-input, jkosina, Antonio Ospite
In-Reply-To: <20120925132136.985de0b203fd342bce6dc77d@studenti.unina.it>

From: David Dillow <dave@thedillows.org>

The Sony PS3 Blue-ray Disc Remote Control used to be supported by the
BlueZ project's user space, but the code that handled it was recently
removed as its functionality conflicted with a real HSP implementation
and the mapping was thought to be better handled in the kernel. This is
a port of the mapping logic from the fakehid driver by Marcel Holtmann
to the in-kernel HID layer.

We also add support for the Logitech Harmony Adapter for PS3, which
emulates the BD Remote.

Signed-off-by: David Dillow <dave@thedillows.org>
Signed-off-by: Antonio Ospite <ospite@studenti.unina.it>
---
 drivers/hid/Kconfig         |   13 ++-
 drivers/hid/Makefile        |    1 +
 drivers/hid/hid-core.c      |    2 +
 drivers/hid/hid-ids.h       |    2 +
 drivers/hid/hid-ps3remote.c |  210 +++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 227 insertions(+), 1 deletion(-)
 create mode 100644 drivers/hid/hid-ps3remote.c

Changes since v2:

  - new HID descriptor to handle multiple keypresses for joypad buttons,
    the descriptor has been designed with gHID:
    http://code.google.com/p/ghid/

    Descriptor changes:
      + Mark the first byte as constant

      + Describe bytes 2nd to 4th used for joypad buttons

      + Split the constant 0xff bytes (bytes from 6th to 10th) so they
        are marked as constant in the descriptor too

      + split the data into two collections, to map them
        independently

  - move the descriptor definition before the keymaps, as the keymaps refer
    to UsageMinimum and UsageMaximum as defined in the descriptor

  - sort keymaps according to their index, as this reflects the Usage
    number

  - use spaces to align stuff in ps3remote_driver struct

  - add myself in the author field

  - reformat description in Kconfig

  - sort symbolic constants trying to match the ordering criterion used
    for other entries

  - add a note about the setup maneuver

TODO (but I think we could merge the driver as it is now regardless):
  - verify that battery strength is reported via the power_supply class
  - see how to handle disconnection on idle timeout

Jiri, are we still in time for 3.7 ?

Thanks,
   Antonio Ospite
   http://ao2.it

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index fbf4950..378be0b 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -534,6 +534,15 @@ config HID_PRIMAX
 	Support for Primax devices that are not fully compliant with the
 	HID standard.
 
+config HID_PS3REMOTE
+	tristate "Sony PS3 BD Remote Control"
+	depends on BT_HIDP
+	---help---
+	Support for the Sony PS3 Blue-ray Disk Remote Control and Logitech
+	Harmony Adapter for PS3, which connect over Bluetooth.
+
+	Support for the 6-axis controllers is provided by HID_SONY.
+
 config HID_ROCCAT
 	tristate "Roccat device support"
 	depends on USB_HID
@@ -561,7 +570,9 @@ config HID_SONY
 	tristate "Sony PS3 controller"
 	depends on USB_HID
 	---help---
-	Support for Sony PS3 controller.
+	Support for Sony PS3 6-axis controllers.
+
+	Support for the Sony PS3 BD Remote is provided by HID_PS3REMOTE.
 
 config HID_SPEEDLINK
 	tristate "Speedlink VAD Cezanne mouse support"
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index f975485..333ed6c 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_HID_PANTHERLORD)	+= hid-pl.o
 obj-$(CONFIG_HID_PETALYNX)	+= hid-petalynx.o
 obj-$(CONFIG_HID_PICOLCD)	+= hid-picolcd.o
 obj-$(CONFIG_HID_PRIMAX)	+= hid-primax.o
+obj-$(CONFIG_HID_PS3REMOTE)	+= hid-ps3remote.o
 obj-$(CONFIG_HID_ROCCAT)	+= hid-roccat.o hid-roccat-common.o \
 	hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \
 	hid-roccat-koneplus.o hid-roccat-kovaplus.o hid-roccat-pyra.o \
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 8bcd168..e4275d4 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1566,6 +1566,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER) },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI) },
@@ -1639,6 +1640,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 1dcb76f..40411c9 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -496,6 +496,7 @@
 #define USB_DEVICE_ID_LOGITECH_RECEIVER	0xc101
 #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST  0xc110
 #define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f
+#define USB_DEVICE_ID_LOGITECH_HARMONY_PS3 0x0306
 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD	0xc20a
 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD	0xc211
 #define USB_DEVICE_ID_LOGITECH_EXTREME_3D	0xc215
@@ -683,6 +684,7 @@
 
 #define USB_VENDOR_ID_SONY			0x054c
 #define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE	0x024b
+#define USB_DEVICE_ID_SONY_PS3_BDREMOTE		0x0306
 #define USB_DEVICE_ID_SONY_PS3_CONTROLLER	0x0268
 #define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER	0x042f
 
diff --git a/drivers/hid/hid-ps3remote.c b/drivers/hid/hid-ps3remote.c
new file mode 100644
index 0000000..4c92e24
--- /dev/null
+++ b/drivers/hid/hid-ps3remote.c
@@ -0,0 +1,210 @@
+/*
+ * HID driver for Sony PS3 BD Remote Control
+ *
+ * Copyright (c) 2012 David Dillow <dave@thedillows.org>
+ * Based on a blend of the bluez fakehid user-space code by Marcel Holtmann
+ * and other kernel HID drivers.
+ */
+
+/*
+ * 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.
+ */
+
+/* NOTE: in order for the Sony PS3 BD Remote Control to be found by
+ * a Bluetooth host, the key combination Start+Enter has to be kept pressed
+ * for about 7 seconds with the Bluetooth Host Controller in discovering mode.
+ *
+ * There will be no PIN request from the device.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static __u8 ps3remote_rdesc[] = {
+	0x05, 0x01,          /* GUsagePage Generic Desktop */
+	0x09, 0x05,          /* LUsage 0x05 [Game Pad] */
+	0xA1, 0x01,          /* MCollection Application (mouse, keyboard) */
+
+	 /* Use collection 1 for joypad buttons */
+	 0xA1, 0x02,         /* MCollection Logical (interrelated data) */
+
+	  /* Ignore the 1st byte, maybe it is used for a controller
+	   * number but it's not needed for correct operation */
+	  0x75, 0x08,        /* GReportSize 0x08 [8] */
+	  0x95, 0x01,        /* GReportCount 0x01 [1] */
+	  0x81, 0x01,        /* MInput 0x01 (Const[0] Arr[1] Abs[2]) */
+
+	  /* Bytes from 2nd to 4th are a bitmap for joypad buttons, for these
+	   * buttons multiple keypresses are allowed */
+	  0x05, 0x09,        /* GUsagePage Button */
+	  0x19, 0x01,        /* LUsageMinimum 0x01 [Button 1 (primary/trigger)] */
+	  0x29, 0x18,        /* LUsageMaximum 0x18 [Button 24] */
+	  0x14,              /* GLogicalMinimum [0] */
+	  0x25, 0x01,        /* GLogicalMaximum 0x01 [1] */
+	  0x75, 0x01,        /* GReportSize 0x01 [1] */
+	  0x95, 0x18,        /* GReportCount 0x18 [24] */
+	  0x81, 0x02,        /* MInput 0x02 (Data[0] Var[1] Abs[2]) */
+
+	  0xC0,              /* MEndCollection */
+
+	 /* Use collection 2 for remote control buttons */
+	 0xA1, 0x02,         /* MCollection Logical (interrelated data) */
+
+	  /* 5th byte is used for remote control buttons */
+	  0x05, 0x09,        /* GUsagePage Button */
+	  0x18,              /* LUsageMinimum [No button pressed] */
+	  0x29, 0xFE,        /* LUsageMaximum 0xFE [Button 254] */
+	  0x14,              /* GLogicalMinimum [0] */
+	  0x26, 0xFE, 0x00,  /* GLogicalMaximum 0x00FE [254] */
+	  0x75, 0x08,        /* GReportSize 0x08 [8] */
+	  0x95, 0x01,        /* GReportCount 0x01 [1] */
+	  0x80,              /* MInput  */
+
+	  /* Ignore bytes from 6th to 11th, 6th to 10th are always constant at
+	   * 0xff and 11th is for press indication */
+	  0x75, 0x08,        /* GReportSize 0x08 [8] */
+	  0x95, 0x06,        /* GReportCount 0x06 [6] */
+	  0x81, 0x01,        /* MInput 0x01 (Const[0] Arr[1] Abs[2]) */
+
+	  /* 12th byte is for battery strength */
+	  0x05, 0x06,        /* GUsagePage Generic Device Controls */
+	  0x09, 0x20,        /* LUsage 0x20 [Battery Strength] */
+	  0x14,              /* GLogicalMinimum [0] */
+	  0x25, 0x05,        /* GLogicalMaximum 0x05 [5] */
+	  0x75, 0x08,        /* GReportSize 0x08 [8] */
+	  0x95, 0x01,        /* GReportCount 0x01 [1] */
+	  0x81, 0x02,        /* MInput 0x02 (Data[0] Var[1] Abs[2]) */
+
+	  0xC0,              /* MEndCollection */
+
+	 0xC0                /* MEndCollection [Game Pad] */
+};
+
+static const unsigned int ps3remote_keymap_joypad_buttons[] = {
+	[0x01] = KEY_SELECT,
+	[0x02] = BTN_THUMBL,		/* L3 */
+	[0x03] = BTN_THUMBR,		/* R3 */
+	[0x04] = BTN_START,
+	[0x05] = KEY_UP,
+	[0x06] = KEY_RIGHT,
+	[0x07] = KEY_DOWN,
+	[0x08] = KEY_LEFT,
+	[0x09] = BTN_TL2,		/* L2 */
+	[0x0a] = BTN_TR2,		/* R2 */
+	[0x0b] = BTN_TL,		/* L1 */
+	[0x0c] = BTN_TR,		/* R1 */
+	[0x0d] = KEY_OPTION,		/* options/triangle */
+	[0x0e] = KEY_BACK,		/* back/circle */
+	[0x0f] = BTN_0,			/* cross */
+	[0x10] = KEY_SCREEN,		/* view/square */
+	[0x11] = KEY_HOMEPAGE,		/* PS button */
+	[0x14] = KEY_ENTER,
+};
+static const unsigned int ps3remote_keymap_remote_buttons[] = {
+	[0x00] = KEY_1,
+	[0x01] = KEY_2,
+	[0x02] = KEY_3,
+	[0x03] = KEY_4,
+	[0x04] = KEY_5,
+	[0x05] = KEY_6,
+	[0x06] = KEY_7,
+	[0x07] = KEY_8,
+	[0x08] = KEY_9,
+	[0x09] = KEY_0,
+	[0x0e] = KEY_ESC,		/* return */
+	[0x0f] = KEY_CLEAR,
+	[0x16] = KEY_EJECTCD,
+	[0x1a] = KEY_MENU,		/* top menu */
+	[0x28] = KEY_TIME,
+	[0x30] = KEY_PREVIOUS,
+	[0x31] = KEY_NEXT,
+	[0x32] = KEY_PLAY,
+	[0x33] = KEY_REWIND,		/* scan back */
+	[0x34] = KEY_FORWARD,		/* scan forward */
+	[0x38] = KEY_STOP,
+	[0x39] = KEY_PAUSE,
+	[0x40] = KEY_CONTEXT_MENU,	/* pop up/menu */
+	[0x60] = KEY_FRAMEBACK,		/* slow/step back */
+	[0x61] = KEY_FRAMEFORWARD,	/* slow/step forward */
+	[0x63] = KEY_SUBTITLE,
+	[0x64] = KEY_AUDIO,
+	[0x65] = KEY_ANGLE,
+	[0x70] = KEY_INFO,		/* display */
+	[0x80] = KEY_BLUE,
+	[0x81] = KEY_RED,
+	[0x82] = KEY_GREEN,
+	[0x83] = KEY_YELLOW,
+};
+
+static __u8 *ps3remote_fixup(struct hid_device *hdev, __u8 *rdesc,
+			     unsigned int *rsize)
+{
+	*rsize = sizeof(ps3remote_rdesc);
+	return ps3remote_rdesc;
+}
+
+static int ps3remote_mapping(struct hid_device *hdev, struct hid_input *hi,
+			     struct hid_field *field, struct hid_usage *usage,
+			     unsigned long **bit, int *max)
+{
+	unsigned int key = usage->hid & HID_USAGE;
+
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_BUTTON ||
+	    key >= ARRAY_SIZE(ps3remote_keymap_remote_buttons))
+		return -1;
+
+	switch (usage->collection_index) {
+	case 1:
+		key = ps3remote_keymap_joypad_buttons[key];
+		if (!key)
+			return -1;
+		break;
+	case 2:
+		key = ps3remote_keymap_remote_buttons[key];
+		if (!key)
+			return -1;
+		break;
+	default:
+		return -1;
+	}
+
+	hid_map_usage_clear(hi, usage, bit, max, EV_KEY, key);
+	return 1;
+}
+
+static const struct hid_device_id ps3remote_devices[] = {
+	/* PS3 BD Remote Control */
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) },
+	/* Logitech Harmony Adapter for PS3 */
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, ps3remote_devices);
+
+static struct hid_driver ps3remote_driver = {
+	.name          = "ps3_remote",
+	.id_table      = ps3remote_devices,
+	.report_fixup  = ps3remote_fixup,
+	.input_mapping = ps3remote_mapping,
+};
+
+static int __init ps3remote_init(void)
+{
+	return hid_register_driver(&ps3remote_driver);
+}
+
+static void __exit ps3remote_exit(void)
+{
+	hid_unregister_driver(&ps3remote_driver);
+}
+
+module_init(ps3remote_init);
+module_exit(ps3remote_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Dillow <dave@thedillows.org>, Antonio Ospite <ospite@studenti.unina.it>");
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH v8 13/13] heartrate: Add test script
From: Andrzej Kaczmarek @ 2012-09-25 14:27 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1348583267-16816-1-git-send-email-andrzej.kaczmarek@tieto.com>

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

---
 Makefile.tools      |   3 +-
 test/test-heartrate | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+), 1 deletion(-)
 create mode 100755 test/test-heartrate

diff --git a/Makefile.tools b/Makefile.tools
index 15fe4e2..81feb75 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -212,4 +212,5 @@ EXTRA_DIST += test/sap_client.py test/hsplay test/hsmicro \
 		test/test-proximity test/test-thermometer test/test-profile \
 		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
+		test/service-ftp.xml test/simple-player test/test-nap \
+		test/test-heartrate
diff --git a/test/test-heartrate b/test/test-heartrate
new file mode 100755
index 0000000..316375d
--- /dev/null
+++ b/test/test-heartrate
@@ -0,0 +1,103 @@
+#!/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="oa{sv}", out_signature="")
+	def MeasurementReceived(self, device, measure):
+		print("Measurement received from %s" % device)
+		print("Value: ", measure["Value"])
+
+		if "Energy" in measure:
+			print("Energy: ", measure["Energy"])
+
+		if "Contact" in measure:
+			print("Contact: ", measure["Contact"])
+
+		if "Interval" in measure:
+			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> [cmd]" % (sys.argv[0]))
+		print("Possible commands:")
+		print("\tReset")
+		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")
+
+	heartrateManager = dbus.Interface(bus.get_object("org.bluez",
+				adapter_path), "org.bluez.HeartRateManager")
+
+	path = "/test/watcher"
+	heartrateManager.RegisterWatcher(path)
+
+	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")
+
+	watcher = Watcher(bus, path)
+
+	properties = heartrate.GetProperties()
+
+	if "Location" in properties:
+		print("Sensor location: %s" % properties["Location"])
+	else:
+		print("Sensor location is not supported")
+
+	if len(args) > 0:
+		if args[0] == "Reset":
+			reset_sup = properties["ResetSupported"]
+			if reset_sup:
+				heartrate.Reset()
+			else:
+				print("Reset not supported")
+				sys.exit(1)
+		else:
+			print("unknown command")
+			sys.exit(1)
+
+	mainloop = gobject.MainLoop()
+	mainloop.run()
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v8 12/13] heartrate: Add HeartRateWatcher interface to default policy
From: Andrzej Kaczmarek @ 2012-09-25 14:27 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1348583267-16816-1-git-send-email-andrzej.kaczmarek@tieto.com>

From: Rafal Garbat <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.11.3


^ permalink raw reply related

* [PATCH v8 11/13] heartrate: Add GetProperties method
From: Andrzej Kaczmarek @ 2012-09-25 14:27 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1348583267-16816-1-git-send-email-andrzej.kaczmarek@tieto.com>

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

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

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index add34b8..81dd5cc 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -94,6 +94,25 @@ struct measurement {
 
 static GSList *heartrate_adapters = NULL;
 
+static const char * const location_enum[] = {
+	"Other",
+	"Chest",
+	"Wrist",
+	"Finger",
+	"Hand",
+	"Earlobe",
+	"Foot",
+};
+
+static const gchar *location2str(uint8_t value)
+{
+	 if (value < G_N_ELEMENTS(location_enum))
+		return location_enum[value];
+
+	error("Body Sensor Location [%d] is RFU", value);
+	return NULL;
+}
+
 static gint cmp_adapter(gconstpointer a, gconstpointer b)
 {
 	const struct heartrate_adapter *hradapter = a;
@@ -629,6 +648,45 @@ static const GDBusMethodTable heartrate_manager_methods[] = {
 	{ }
 };
 
+static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct heartrate *hr = data;
+	DBusMessageIter iter;
+	DBusMessageIter dict;
+	DBusMessage *reply;
+	gboolean has_reset;
+
+	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);
+
+	if (hr->has_location) {
+		char *loc = g_strdup(location2str(hr->location));
+
+		if (loc) {
+			dict_append_entry(&dict, "Location",
+						DBUS_TYPE_STRING, &loc);
+			g_free(loc);
+		}
+	}
+
+	has_reset = !!hr->hrcp_val_handle;
+	dict_append_entry(&dict, "ResetSupported", DBUS_TYPE_BOOLEAN,
+								&has_reset);
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	return reply;
+}
+
 static DBusMessage *hrcp_reset(DBusConnection *conn, DBusMessage *msg,
 								void *data)
 {
@@ -653,6 +711,9 @@ static DBusMessage *hrcp_reset(DBusConnection *conn, DBusMessage *msg,
 }
 
 static const GDBusMethodTable heartrate_device_methods[] = {
+	{ GDBUS_METHOD("GetProperties",
+			NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+			get_properties) },
 	{ GDBUS_METHOD("Reset", NULL, NULL,
 			hrcp_reset) },
 	{ }
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v8 10/13] heartrate: Add support to reset Energy Expended
From: Andrzej Kaczmarek @ 2012-09-25 14:27 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1348583267-16816-1-git-send-email-andrzej.kaczmarek@tieto.com>

This patch adds Reset method on HeartRate interface to reset Energy
Expended.
---
 profiles/heartrate/heartrate.c | 45 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 44 insertions(+), 1 deletion(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index ba1c1fa..add34b8 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -41,6 +41,7 @@
 #include "log.h"
 #include "heartrate.h"
 
+#define HEART_RATE_INTERFACE		"org.bluez.HeartRate"
 #define HEART_RATE_MANAGER_INTERFACE	"org.bluez.HeartRateManager"
 #define HEART_RATE_WATCHER_INTERFACE	"org.bluez.HeartRateWatcher"
 
@@ -628,6 +629,35 @@ static const GDBusMethodTable heartrate_manager_methods[] = {
 	{ }
 };
 
+static DBusMessage *hrcp_reset(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct heartrate *hr = data;
+	uint8_t value;
+	char *vmsg;
+
+	if (!hr->hrcp_val_handle)
+		return btd_error_not_supported(msg);
+
+	if (!hr->attrib)
+		return btd_error_not_available(msg);
+
+	value = 0x01;
+	vmsg = g_strdup("Reset Control Point");
+	gatt_write_char(hr->attrib, hr->hrcp_val_handle, &value,
+					sizeof(value), char_write_cb, vmsg);
+
+	DBG("Energy Expended Value has been reset");
+
+	return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable heartrate_device_methods[] = {
+	{ GDBUS_METHOD("Reset", NULL, NULL,
+			hrcp_reset) },
+	{ }
+};
+
 int heartrate_adapter_register(struct btd_adapter *adapter)
 {
 	struct heartrate_adapter *hradapter;
@@ -685,6 +715,18 @@ int heartrate_device_register(struct btd_device *device,
 	hr->dev = btd_device_ref(device);
 	hr->hradapter = hradapter;
 
+	if (!g_dbus_register_interface(btd_get_dbus_connection(),
+						device_get_path(device),
+						HEART_RATE_INTERFACE,
+						heartrate_device_methods,
+						NULL, NULL, hr,
+						destroy_heartrate)) {
+		error("D-Bus failed to register %s interface",
+						HEART_RATE_INTERFACE);
+		destroy_heartrate(hr);
+		return -EIO;
+	}
+
 	hr->svc_range = g_new0(struct att_range, 1);
 	hr->svc_range->start = prim->range.start;
 	hr->svc_range->end = prim->range.end;
@@ -718,5 +760,6 @@ void heartrate_device_unregister(struct btd_device *device)
 
 	hradapter->devices = g_slist_remove(hradapter->devices, hr);
 
-	destroy_heartrate(hr);
+	g_dbus_unregister_interface(btd_get_dbus_connection(),
+				device_get_path(device), HEART_RATE_INTERFACE);
 }
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v8 09/13] heartrate: Process measurement notifications
From: Andrzej Kaczmarek @ 2012-09-25 14:27 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1348583267-16816-1-git-send-email-andrzej.kaczmarek@tieto.com>

This patch adds processing of received Heart Rate Measurement
characteristic notifications and sends processed data to registered
watchers.
---
 profiles/heartrate/heartrate.c | 167 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 166 insertions(+), 1 deletion(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index dda030b..ba1c1fa 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -42,6 +42,13 @@
 #include "heartrate.h"
 
 #define HEART_RATE_MANAGER_INTERFACE	"org.bluez.HeartRateManager"
+#define HEART_RATE_WATCHER_INTERFACE	"org.bluez.HeartRateWatcher"
+
+#define HR_VALUE_FORMAT		0x01
+#define SENSOR_CONTACT_DETECTED	0x02
+#define SENSOR_CONTACT_SUPPORT	0x04
+#define ENERGY_EXP_STATUS	0x08
+#define RR_INTERVAL		0x10
 
 struct heartrate_adapter {
 	struct btd_adapter	*adapter;
@@ -54,6 +61,7 @@ struct heartrate {
 	struct heartrate_adapter	*hradapter;
 	GAttrib				*attrib;
 	guint				attioid;
+	guint				attionotid;
 
 	struct att_range		*svc_range;	/* primary svc range */
 
@@ -72,6 +80,17 @@ struct watcher {
 	char				*path;
 };
 
+struct measurement {
+	struct heartrate	*hr;
+	uint16_t		value;
+	gboolean		has_energy;
+	uint16_t		energy;
+	gboolean		has_contact;
+	gboolean		contact;
+	uint16_t		num_interval;
+	uint16_t		*interval;
+};
+
 static GSList *heartrate_adapters = NULL;
 
 static gint cmp_adapter(gconstpointer a, gconstpointer b)
@@ -155,8 +174,10 @@ static void destroy_heartrate(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);
+	}
 
 	btd_device_unref(hr->dev);
 	g_free(hr->svc_range);
@@ -357,6 +378,142 @@ static void disable_measurement(gpointer data, gpointer user_data)
 							char_write_cb, msg);
 }
 
+static void update_watcher(gpointer data, gpointer user_data)
+{
+	struct watcher *w = data;
+	struct measurement *m = user_data;
+	struct heartrate *hr = m->hr;
+	const gchar *path = device_get_path(hr->dev);
+	DBusMessageIter iter;
+	DBusMessageIter dict;
+	DBusMessage *msg;
+
+	msg = dbus_message_new_method_call(w->srv, w->path,
+			HEART_RATE_WATCHER_INTERFACE, "MeasurementReceived");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH , &path);
+
+	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);
+
+	if (m->has_energy)
+		dict_append_entry(&dict, "Energy", DBUS_TYPE_UINT16,
+								&m->energy);
+
+	if (m->has_contact)
+		dict_append_entry(&dict, "Contact", DBUS_TYPE_BOOLEAN,
+								&m->contact);
+
+	if (m->num_interval > 0)
+		dict_append_array(&dict, "Interval", DBUS_TYPE_UINT16,
+						&m->interval, m->num_interval);
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	dbus_message_set_no_reply(msg, TRUE);
+	g_dbus_send_message(btd_get_dbus_connection(), msg);
+}
+
+static void process_measurement(struct heartrate *hr, const uint8_t *pdu,
+								uint16_t len)
+{
+	struct measurement m;
+	uint8_t flags;
+
+	flags = *pdu;
+
+	pdu++;
+	len--;
+
+	memset(&m, 0, sizeof(m));
+
+	if (flags & HR_VALUE_FORMAT) {
+		if (len < 2) {
+			error("Heart Rate Measurement field missing");
+			return;
+		}
+
+		m.value = att_get_u16(pdu);
+		pdu += 2;
+		len -= 2;
+	} else {
+		if (len < 1) {
+			error("Heart Rate Measurement field missing");
+			return;
+		}
+
+		m.value = *pdu;
+		pdu++;
+		len--;
+	}
+
+	if (flags & ENERGY_EXP_STATUS) {
+		if (len < 2) {
+			error("Energy Expended field missing");
+			return;
+		}
+
+		m.has_energy = TRUE;
+		m.energy = att_get_u16(pdu);
+		pdu += 2;
+		len -= 2;
+	}
+
+	if (flags & RR_INTERVAL) {
+		int i;
+
+		if (len == 0 || (len % 2 != 0)) {
+			error("RR-Interval field malformed");
+			return;
+		}
+
+		m.num_interval = len / 2;
+		m.interval = g_new(uint16_t, m.num_interval);
+
+		for (i = 0; i < m.num_interval; pdu += 2, i++)
+			m.interval[i] = att_get_u16(pdu);
+	}
+
+	if (flags & SENSOR_CONTACT_SUPPORT) {
+		m.has_contact = TRUE;
+		m.contact = !!(flags & SENSOR_CONTACT_DETECTED);
+	}
+
+	/* Notify all registered watchers */
+	m.hr = hr;
+	g_slist_foreach(hr->hradapter->watchers, update_watcher, &m);
+
+	g_free(m.interval);
+}
+
+static void notify_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+	uint16_t handle;
+
+	/* should be at least opcode (1b) + handle (2b) */
+	if (len < 3) {
+		error("Invalid PDU received");
+		return;
+	}
+
+	handle = att_get_u16(pdu + 1);
+	if (handle != hr->measurement_val_handle) {
+		error("Unexpected handle: 0x%04x", handle);
+		return;
+	}
+
+	process_measurement(hr, pdu + 3, len - 3);
+}
+
 static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 {
 	struct heartrate *hr = user_data;
@@ -365,6 +522,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);
+
 	gatt_discover_char(hr->attrib, hr->svc_range->start, hr->svc_range->end,
 						NULL, discover_char_cb, hr);
 }
@@ -375,6 +535,11 @@ static void attio_disconnected_cb(gpointer user_data)
 
 	DBG("");
 
+	if (hr->attionotid > 0) {
+		g_attrib_unregister(hr->attrib, hr->attionotid);
+		hr->attionotid = 0;
+	}
+
 	g_attrib_unref(hr->attrib);
 	hr->attrib = NULL;
 }
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v8 08/13] heartrate: Add support to enable notifications
From: Andrzej Kaczmarek @ 2012-09-25 14:27 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1348583267-16816-1-git-send-email-andrzej.kaczmarek@tieto.com>

This patch adds support to enable notifications for Heart Rate Measurement
characteristic value. Notifications are enabled automatically when at
least one watcher is registered and disabled otherwise.
---
 profiles/heartrate/heartrate.c | 67 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index b07a343..dda030b 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -207,6 +207,17 @@ static void read_sensor_location_cb(guint8 status, const guint8 *pdu,
 	hr->location = value;
 }
 
+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 discover_ccc_cb(guint8 status, const guint8 *pdu,
 						guint16 len, gpointer user_data)
 {
@@ -237,7 +248,20 @@ static void discover_ccc_cb(guint8 status, const guint8 *pdu,
 		uuid = att_get_u16(value + 2);
 
 		if (uuid == GATT_CLIENT_CHARAC_CFG_UUID) {
+			uint8_t value[2];
+			char *msg;
+
 			hr->measurement_ccc_handle = handle;
+
+			if (g_slist_length(hr->hradapter->watchers) == 0)
+				break;
+
+			att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value);
+			msg = g_strdup("Enable measurement");
+
+			gatt_write_char(hr->attrib, handle, value,
+					sizeof(value), char_write_cb, msg);
+
 			break;
 		}
 	}
@@ -299,6 +323,40 @@ static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data)
 	}
 }
 
+static void enable_measurement(gpointer data, gpointer user_data)
+{
+	struct heartrate *hr = data;
+	uint16_t handle = hr->measurement_ccc_handle;
+	uint8_t value[2];
+	char *msg;
+
+	if (hr->attrib == NULL || !handle)
+		return;
+
+	att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value);
+	msg = g_strdup("Enable measurement");
+
+	gatt_write_char(hr->attrib, handle, value, sizeof(value),
+							char_write_cb, msg);
+}
+
+static void disable_measurement(gpointer data, gpointer user_data)
+{
+	struct heartrate *hr = data;
+	uint16_t handle = hr->measurement_ccc_handle;
+	uint8_t value[2];
+	char *msg;
+
+	if (hr->attrib == NULL || !handle)
+		return;
+
+	att_put_u16(0x0000, value);
+	msg = g_strdup("Disable measurement");
+
+	gatt_write_char(hr->attrib, handle, value, sizeof(value),
+							char_write_cb, msg);
+}
+
 static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 {
 	struct heartrate *hr = user_data;
@@ -330,6 +388,9 @@ static void watcher_exit_cb(DBusConnection *conn, void *user_data)
 
 	hradapter->watchers = g_slist_remove(hradapter->watchers, watcher);
 	g_dbus_remove_watch(conn, watcher->id);
+
+	if (g_slist_length(hradapter->watchers) == 0)
+		g_slist_foreach(hradapter->devices, disable_measurement, 0);
 }
 
 static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
@@ -355,6 +416,9 @@ static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
 	watcher->srv = g_strdup(sender);
 	watcher->path = g_strdup(path);
 
+	if (g_slist_length(hradapter->watchers) == 0)
+		g_slist_foreach(hradapter->devices, enable_measurement, 0);
+
 	hradapter->watchers = g_slist_prepend(hradapter->watchers, watcher);
 
 	DBG("heartrate watcher [%s] registered", path);
@@ -381,6 +445,9 @@ static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
 	hradapter->watchers = g_slist_remove(hradapter->watchers, watcher);
 	g_dbus_remove_watch(conn, watcher->id);
 
+	if (g_slist_length(hradapter->watchers) == 0)
+		g_slist_foreach(hradapter->devices, disable_measurement, 0);
+
 	DBG("heartrate watcher [%s] unregistered", path);
 
 	return dbus_message_new_method_return(msg);
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v8 07/13] heartrate: Add HeartRateManager interface
From: Andrzej Kaczmarek @ 2012-09-25 14:27 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1348583267-16816-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 | 154 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 153 insertions(+), 1 deletion(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 2547f9b..b07a343 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 "att.h"
 #include "gatt.h"
@@ -38,9 +41,12 @@
 #include "log.h"
 #include "heartrate.h"
 
+#define HEART_RATE_MANAGER_INTERFACE	"org.bluez.HeartRateManager"
+
 struct heartrate_adapter {
 	struct btd_adapter	*adapter;
 	GSList			*devices;
+	GSList			*watchers;
 };
 
 struct heartrate {
@@ -59,6 +65,13 @@ struct heartrate {
 	uint8_t				location;
 };
 
+struct watcher {
+	struct heartrate_adapter	*hradapter;
+	guint				id;
+	char				*srv;
+	char				*path;
+};
+
 static GSList *heartrate_adapters = NULL;
 
 static gint cmp_adapter(gconstpointer a, gconstpointer b)
@@ -83,6 +96,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)
 {
@@ -94,6 +120,34 @@ find_heartrate_adapter(struct btd_adapter *adapter)
 	return l->data;
 }
 
+static void destroy_watcher(gpointer user_data)
+{
+	struct watcher *watcher = user_data;
+
+	g_free(watcher->path);
+	g_free(watcher->srv);
+	g_free(watcher);
+}
+
+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 void destroy_heartrate(gpointer user_data)
 {
 	struct heartrate *hr = user_data;
@@ -109,10 +163,19 @@ static void destroy_heartrate(gpointer user_data)
 	g_free(hr);
 }
 
+static void remove_watcher(gpointer user_data)
+{
+	struct watcher *watcher = user_data;
+
+	g_dbus_remove_watch(btd_get_dbus_connection(), watcher->id);
+}
+
 static void destroy_heartrate_adapter(gpointer user_data)
 {
 	struct heartrate_adapter *hradapter = user_data;
 
+	g_slist_free_full(hradapter->watchers, remove_watcher);
+
 	g_free(hradapter);
 }
 
@@ -258,6 +321,81 @@ static void attio_disconnected_cb(gpointer user_data)
 	hr->attrib = NULL;
 }
 
+static void watcher_exit_cb(DBusConnection *conn, void *user_data)
+{
+	struct watcher *watcher = user_data;
+	struct heartrate_adapter *hradapter = watcher->hradapter;
+
+	DBG("heartrate watcher [%s] disconnected", watcher->path);
+
+	hradapter->watchers = g_slist_remove(hradapter->watchers, watcher);
+	g_dbus_remove_watch(conn, watcher->id);
+}
+
+static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct heartrate_adapter *hradapter = data;
+	struct watcher *watcher;
+	const char *sender = dbus_message_get_sender(msg);
+	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(hradapter->watchers, sender, path);
+	if (watcher != NULL)
+		return btd_error_already_exists(msg);
+
+	watcher = g_new0(struct watcher, 1);
+	watcher->hradapter = hradapter;
+	watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit_cb,
+						watcher, destroy_watcher);
+	watcher->srv = g_strdup(sender);
+	watcher->path = g_strdup(path);
+
+	hradapter->watchers = g_slist_prepend(hradapter->watchers, watcher);
+
+	DBG("heartrate watcher [%s] registered", path);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct heartrate_adapter *hradapter = data;
+	struct watcher *watcher;
+	const char *sender = dbus_message_get_sender(msg);
+	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(hradapter->watchers, sender, path);
+	if (watcher == NULL)
+		return btd_error_does_not_exist(msg);
+
+	hradapter->watchers = g_slist_remove(hradapter->watchers, watcher);
+	g_dbus_remove_watch(conn, watcher->id);
+
+	DBG("heartrate watcher [%s] unregistered", path);
+
+	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) },
+	{ }
+};
+
 int heartrate_adapter_register(struct btd_adapter *adapter)
 {
 	struct heartrate_adapter *hradapter;
@@ -267,6 +405,18 @@ int heartrate_adapter_register(struct btd_adapter *adapter)
 
 	heartrate_adapters = g_slist_prepend(heartrate_adapters, hradapter);
 
+	if (!g_dbus_register_interface(btd_get_dbus_connection(),
+						adapter_get_path(adapter),
+						HEART_RATE_MANAGER_INTERFACE,
+						heartrate_manager_methods,
+						NULL, NULL, hradapter,
+						destroy_heartrate_adapter)) {
+		error("D-Bus failed to register %s interface",
+						HEART_RATE_MANAGER_INTERFACE);
+		destroy_heartrate_adapter(hradapter);
+		return -EIO;
+	}
+
 	return 0;
 }
 
@@ -280,7 +430,9 @@ void heartrate_adapter_unregister(struct btd_adapter *adapter)
 
 	heartrate_adapters = g_slist_remove(heartrate_adapters, hradapter);
 
-	destroy_heartrate_adapter(hradapter);
+	g_dbus_unregister_interface(btd_get_dbus_connection(),
+					adapter_get_path(hradapter->adapter),
+					HEART_RATE_MANAGER_INTERFACE);
 }
 
 int heartrate_device_register(struct btd_device *device,
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v8 06/13] heartrate: Read Body Sensor Location characteristics
From: Andrzej Kaczmarek @ 2012-09-25 14:27 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1348583267-16816-1-git-send-email-andrzej.kaczmarek@tieto.com>

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

This patch adds support to read and store Body Sensor Location
characteristic value.
---
 profiles/heartrate/heartrate.c | 35 ++++++++++++++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index d3d6d43..2547f9b 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -54,6 +54,9 @@ struct heartrate {
 	uint16_t			measurement_val_handle;
 	uint16_t			measurement_ccc_handle;
 	uint16_t			hrcp_val_handle;
+
+	gboolean			has_location;
+	uint8_t				location;
 };
 
 static GSList *heartrate_adapters = NULL;
@@ -113,6 +116,34 @@ static void destroy_heartrate_adapter(gpointer user_data)
 	g_free(hradapter);
 }
 
+static void read_sensor_location_cb(guint8 status, const guint8 *pdu,
+						guint16 len, gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+	uint8_t value;
+	ssize_t vlen;
+
+	if (status != 0) {
+		error("Body Sensor Location 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 != sizeof(value)) {
+		error("Invalid length for Body Sensor Location");
+		return;
+	}
+
+	hr->has_location = TRUE;
+	hr->location = value;
+}
+
 static void discover_ccc_cb(guint8 status, const guint8 *pdu,
 						guint16 len, gpointer user_data)
 {
@@ -194,7 +225,9 @@ static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data)
 			discover_measurement_ccc(hr, c, c_next);
 		} else if (g_strcmp0(c->uuid, BODY_SENSOR_LOCATION_UUID) == 0) {
 			DBG("Body Sensor Location supported");
-			/* TODO: read characterictic value */
+
+			gatt_read_char(hr->attrib, c->value_handle, 0,
+						read_sensor_location_cb, hr);
 		} else if (g_strcmp0(c->uuid,
 					HEART_RATE_CONTROL_POINT_UUID) == 0) {
 			DBG("Heart Rate Control Point supported");
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v8 05/13] heartrate: Discover Heart Rate Measurement CCC
From: Andrzej Kaczmarek @ 2012-09-25 14:27 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1348583267-16816-1-git-send-email-andrzej.kaczmarek@tieto.com>

This patch adds support to discover CCC descriptor for Heart Rate
Measurement characteristic.
---
 profiles/heartrate/heartrate.c | 66 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 65 insertions(+), 1 deletion(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index a6733d3..d3d6d43 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -52,6 +52,7 @@ struct heartrate {
 	struct att_range		*svc_range;	/* primary svc range */
 
 	uint16_t			measurement_val_handle;
+	uint16_t			measurement_ccc_handle;
 	uint16_t			hrcp_val_handle;
 };
 
@@ -112,6 +113,65 @@ static void destroy_heartrate_adapter(gpointer user_data)
 	g_free(hradapter);
 }
 
+static void discover_ccc_cb(guint8 status, const guint8 *pdu,
+						guint16 len, gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+	struct att_data_list *list;
+	uint8_t format;
+	int i;
+
+	if (status != 0) {
+		error("Discover Heart Rate Measurement descriptors failed: %s",
+							att_ecode2str(status));
+		return;
+	}
+
+	list = dec_find_info_resp(pdu, len, &format);
+	if (list == NULL)
+		return;
+
+	if (format != ATT_FIND_INFO_RESP_FMT_16BIT)
+		goto done;
+
+	for (i = 0; i < list->num; i++) {
+		uint8_t *value;
+		uint16_t handle, uuid;
+
+		value = list->data[i];
+		handle = att_get_u16(value);
+		uuid = att_get_u16(value + 2);
+
+		if (uuid == GATT_CLIENT_CHARAC_CFG_UUID) {
+			hr->measurement_ccc_handle = handle;
+			break;
+		}
+	}
+
+done:
+	att_data_list_free(list);
+}
+
+static void discover_measurement_ccc(struct heartrate *hr,
+				struct gatt_char *c, struct gatt_char *c_next)
+{
+	uint16_t start, end;
+
+	start = c->value_handle + 1;
+
+	if (c_next != NULL) {
+		if (start == c_next->handle)
+			return;
+		end = c_next->handle - 1;
+	} else if (c->value_handle != hr->svc_range->end) {
+		end = hr->svc_range->end;
+	} else {
+		return;
+	}
+
+	gatt_find_info(hr->attrib, start, end, discover_ccc_cb, hr);
+}
+
 static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data)
 {
 	struct heartrate *hr = user_data;
@@ -126,8 +186,12 @@ static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data)
 		struct gatt_char *c = chars->data;
 
 		if (g_strcmp0(c->uuid, HEART_RATE_MEASUREMENT_UUID) == 0) {
+			struct gatt_char *c_next =
+				(chars->next ? chars->next->data : NULL);
+
 			hr->measurement_val_handle = c->value_handle;
-			/* TODO: discover CCC handle */
+
+			discover_measurement_ccc(hr, c, c_next);
 		} else if (g_strcmp0(c->uuid, BODY_SENSOR_LOCATION_UUID) == 0) {
 			DBG("Body Sensor Location supported");
 			/* TODO: read characterictic value */
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v8 04/13] heartrate: Discover HRS characteristics
From: Andrzej Kaczmarek @ 2012-09-25 14:27 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1348583267-16816-1-git-send-email-andrzej.kaczmarek@tieto.com>

This patch adds support to discover known Heart Rate Service
characteristics.
---
 lib/uuid.h                     |  3 +++
 profiles/heartrate/heartrate.c | 43 +++++++++++++++++++++++++++++++++++++++++-
 profiles/heartrate/heartrate.h |  3 ++-
 profiles/heartrate/manager.c   | 19 ++++++++++++++++++-
 4 files changed, 65 insertions(+), 3 deletions(-)

diff --git a/lib/uuid.h b/lib/uuid.h
index 3488e66..9da1b54 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -64,6 +64,9 @@ 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 BODY_SENSOR_LOCATION_UUID	"00002a38-0000-1000-8000-00805f9b34fb"
+#define HEART_RATE_CONTROL_POINT_UUID	"00002a39-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 e057180..a6733d3 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -48,6 +48,11 @@ struct heartrate {
 	struct heartrate_adapter	*hradapter;
 	GAttrib				*attrib;
 	guint				attioid;
+
+	struct att_range		*svc_range;	/* primary svc range */
+
+	uint16_t			measurement_val_handle;
+	uint16_t			hrcp_val_handle;
 };
 
 static GSList *heartrate_adapters = NULL;
@@ -96,6 +101,7 @@ static void destroy_heartrate(gpointer user_data)
 		g_attrib_unref(hr->attrib);
 
 	btd_device_unref(hr->dev);
+	g_free(hr->svc_range);
 	g_free(hr);
 }
 
@@ -106,6 +112,33 @@ static void destroy_heartrate_adapter(gpointer user_data)
 	g_free(hradapter);
 }
 
+static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+
+	if (status) {
+		error("Discover HRS characteristics failed: %s",
+							att_ecode2str(status));
+		return;
+	}
+
+	for (; chars; chars = chars->next) {
+		struct gatt_char *c = chars->data;
+
+		if (g_strcmp0(c->uuid, HEART_RATE_MEASUREMENT_UUID) == 0) {
+			hr->measurement_val_handle = c->value_handle;
+			/* TODO: discover CCC handle */
+		} else if (g_strcmp0(c->uuid, BODY_SENSOR_LOCATION_UUID) == 0) {
+			DBG("Body Sensor Location supported");
+			/* TODO: read characterictic value */
+		} else if (g_strcmp0(c->uuid,
+					HEART_RATE_CONTROL_POINT_UUID) == 0) {
+			DBG("Heart Rate Control Point supported");
+			hr->hrcp_val_handle = c->value_handle;
+		}
+	}
+}
+
 static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 {
 	struct heartrate *hr = user_data;
@@ -113,6 +146,9 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 	DBG("");
 
 	hr->attrib = g_attrib_ref(attrib);
+
+	gatt_discover_char(hr->attrib, hr->svc_range->start, hr->svc_range->end,
+						NULL, discover_char_cb, hr);
 }
 
 static void attio_disconnected_cb(gpointer user_data)
@@ -150,7 +186,8 @@ void heartrate_adapter_unregister(struct btd_adapter *adapter)
 	destroy_heartrate_adapter(hradapter);
 }
 
-int heartrate_device_register(struct btd_device *device)
+int heartrate_device_register(struct btd_device *device,
+						struct gatt_primary *prim)
 {
 	struct btd_adapter *adapter;
 	struct heartrate_adapter *hradapter;
@@ -167,6 +204,10 @@ int heartrate_device_register(struct btd_device *device)
 	hr->dev = btd_device_ref(device);
 	hr->hradapter = hradapter;
 
+	hr->svc_range = g_new0(struct att_range, 1);
+	hr->svc_range->start = prim->range.start;
+	hr->svc_range->end = prim->range.end;
+
 	hradapter->devices = g_slist_prepend(hradapter->devices, hr);
 
 	hr->attioid = btd_device_add_attio_callback(device, attio_connected_cb,
diff --git a/profiles/heartrate/heartrate.h b/profiles/heartrate/heartrate.h
index 486f5b3..064939d 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 *prim);
 void heartrate_device_unregister(struct btd_device *device);
diff --git a/profiles/heartrate/manager.c b/profiles/heartrate/manager.c
index 3e668f3..19b18a8 100644
--- a/profiles/heartrate/manager.c
+++ b/profiles/heartrate/manager.c
@@ -34,6 +34,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_profile *p,
 						struct btd_adapter *adapter)
 {
@@ -49,7 +57,16 @@ static void heartrate_adapter_remove(struct btd_profile *p,
 static int heartrate_device_probe(struct btd_profile *p,
 				struct btd_device *device, GSList *uuids)
 {
-	return heartrate_device_register(device);
+	GSList *primaries;
+	GSList *l;
+
+	primaries = btd_device_get_primaries(device);
+
+	l = g_slist_find_custom(primaries, HEART_RATE_UUID, primary_uuid_cmp);
+	if (l == NULL)
+		return -EINVAL;
+
+	return heartrate_device_register(device, l->data);
 }
 
 static void heartrate_device_remove(struct btd_profile *p,
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v8 03/13] heartrate: Add attio callbacks
From: Andrzej Kaczmarek @ 2012-09-25 14:27 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1348583267-16816-1-git-send-email-andrzej.kaczmarek@tieto.com>

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

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 87bc309..e057180 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -31,6 +31,11 @@
 
 #include "adapter.h"
 #include "device.h"
+#include "gattrib.h"
+#include "att.h"
+#include "gatt.h"
+#include "attio.h"
+#include "log.h"
 #include "heartrate.h"
 
 struct heartrate_adapter {
@@ -41,6 +46,8 @@ struct heartrate_adapter {
 struct heartrate {
 	struct btd_device		*dev;
 	struct heartrate_adapter	*hradapter;
+	GAttrib				*attrib;
+	guint				attioid;
 };
 
 static GSList *heartrate_adapters = NULL;
@@ -82,6 +89,12 @@ static void destroy_heartrate(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);
 }
@@ -93,6 +106,25 @@ static void destroy_heartrate_adapter(gpointer user_data)
 	g_free(hradapter);
 }
 
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+
+	DBG("");
+
+	hr->attrib = g_attrib_ref(attrib);
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+
+	DBG("");
+
+	g_attrib_unref(hr->attrib);
+	hr->attrib = NULL;
+}
+
 int heartrate_adapter_register(struct btd_adapter *adapter)
 {
 	struct heartrate_adapter *hradapter;
@@ -137,6 +169,9 @@ int heartrate_device_register(struct btd_device *device)
 
 	hradapter->devices = g_slist_prepend(hradapter->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 v8 02/13] heartrate: Add initial HRP client support
From: Andrzej Kaczmarek @ 2012-09-25 14:27 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1348583267-16816-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.
Profile driver is registered to keep track of adapters and devices.
---
 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   |  80 ++++++++++++++++++++
 profiles/heartrate/manager.h   |  24 ++++++
 7 files changed, 356 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 372111a..808a81f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -211,7 +211,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 \
@@ -240,7 +240,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..87bc309
--- /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	*hradapter;
+};
+
+static GSList *heartrate_adapters = NULL;
+
+static gint cmp_adapter(gconstpointer a, gconstpointer b)
+{
+	const struct heartrate_adapter *hradapter = a;
+	const struct btd_adapter *adapter = b;
+
+	if (adapter == hradapter->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(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 *hradapter = user_data;
+
+	g_free(hradapter);
+}
+
+int heartrate_adapter_register(struct btd_adapter *adapter)
+{
+	struct heartrate_adapter *hradapter;
+
+	hradapter = g_new0(struct heartrate_adapter, 1);
+	hradapter->adapter = adapter;
+
+	heartrate_adapters = g_slist_prepend(heartrate_adapters, hradapter);
+
+	return 0;
+}
+
+void heartrate_adapter_unregister(struct btd_adapter *adapter)
+{
+	struct heartrate_adapter *hradapter;
+
+	hradapter = find_heartrate_adapter(adapter);
+	if (hradapter == NULL)
+		return;
+
+	heartrate_adapters = g_slist_remove(heartrate_adapters, hradapter);
+
+	destroy_heartrate_adapter(hradapter);
+}
+
+int heartrate_device_register(struct btd_device *device)
+{
+	struct btd_adapter *adapter;
+	struct heartrate_adapter *hradapter;
+	struct heartrate *hr;
+
+	adapter = device_get_adapter(device);
+
+	hradapter = find_heartrate_adapter(adapter);
+
+	if (hradapter == NULL)
+		return -1;
+
+	hr = g_new0(struct heartrate, 1);
+	hr->dev = btd_device_ref(device);
+	hr->hradapter = hradapter;
+
+	hradapter->devices = g_slist_prepend(hradapter->devices, hr);
+
+	return 0;
+}
+
+void heartrate_device_unregister(struct btd_device *device)
+{
+	struct btd_adapter *adapter;
+	struct heartrate_adapter *hradapter;
+	struct heartrate *hr;
+	GSList *l;
+
+	adapter = device_get_adapter(device);
+
+	hradapter = find_heartrate_adapter(adapter);
+	if (hradapter == NULL)
+		return;
+
+	l = g_slist_find_custom(hradapter->devices, device, cmp_device);
+	if (l == NULL)
+		return;
+
+	hr = l->data;
+
+	hradapter->devices = g_slist_remove(hradapter->devices, hr);
+
+	destroy_heartrate(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..3e668f3
--- /dev/null
+++ b/profiles/heartrate/manager.c
@@ -0,0 +1,80 @@
+/*
+ *
+ *  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 "profile.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+#include "heartrate.h"
+#include "manager.h"
+
+static int heartrate_adapter_probe(struct btd_profile *p,
+						struct btd_adapter *adapter)
+{
+	return heartrate_adapter_register(adapter);
+}
+
+static void heartrate_adapter_remove(struct btd_profile *p,
+						struct btd_adapter *adapter)
+{
+	heartrate_adapter_unregister(adapter);
+}
+
+static int heartrate_device_probe(struct btd_profile *p,
+				struct btd_device *device, GSList *uuids)
+{
+	return heartrate_device_register(device);
+}
+
+static void heartrate_device_remove(struct btd_profile *p,
+						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 v8 01/13] Heart Rate Profile (HRP) client API
From: Andrzej Kaczmarek @ 2012-09-25 14:27 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1348583267-16816-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..1fa9d0b
--- /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 v8 00/13] Heart Rate Profile plugin
From: Andrzej Kaczmarek @ 2012-09-25 14:27 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

Hi,

Changes since v7:
- rebased to latest upstream master (btd_profile changes)


Andrzej Kaczmarek (6):
  heartrate: Add attio callbacks
  heartrate: Discover HRS characteristics
  heartrate: Discover Heart Rate Measurement CCC
  heartrate: Add support to enable notifications
  heartrate: Process measurement notifications
  heartrate: Add support to reset Energy Expended

Rafal Garbat (6):
  heartrate: Add initial HRP client support
  heartrate: Read Body Sensor Location characteristics
  heartrate: Add HeartRateManager interface
  heartrate: Add GetProperties method
  heartrate: Add HeartRateWatcher interface to default policy
  heartrate: Add test script

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

 Makefile.am                    |   9 +-
 Makefile.tools                 |   3 +-
 doc/heartrate-api.txt          |  84 +++++
 lib/uuid.h                     |   5 +
 profiles/heartrate/heartrate.c | 826 +++++++++++++++++++++++++++++++++++++++++
 profiles/heartrate/heartrate.h |  27 ++
 profiles/heartrate/main.c      |  52 +++
 profiles/heartrate/manager.c   |  97 +++++
 profiles/heartrate/manager.h   |  24 ++
 src/bluetooth.conf             |   1 +
 test/test-heartrate            | 103 +++++
 11 files changed, 1228 insertions(+), 3 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

* Re: [PATCH BlueZ] audio: Fix attempting to create a device on driver .remove
From: Johan Hedberg @ 2012-09-25 12:58 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <1348570499-7442-1-git-send-email-luiz.dentz@gmail.com>

Hi Luiz,

On Tue, Sep 25, 2012, Luiz Augusto von Dentz wrote:
> audio_remove calls get_audio_dev which may attempt to create the device
> if it doesn't exist.
> ---
>  audio/manager.c | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)

Applied. Thanks.

Johan

^ permalink raw reply

* Re: [RFCv1 03/20] Bluetooth: Add L2CAP create channel request handling
From: Andrei Emeltchenko @ 2012-09-25 11:39 UTC (permalink / raw)
  To: Mat Martineau; +Cc: linux-bluetooth, gustavo, sunnyk
In-Reply-To: <1347387691-5285-4-git-send-email-mathewm@codeaurora.org>

Hi Mat,

On Tue, Sep 11, 2012 at 11:21:14AM -0700, Mat Martineau wrote:
> The L2CAP create channel request is very similar to an L2CAP connect
> request, but it has an additional parameter for the controller ID.  If
> the controller id is 0, the channel is set up on the BR/EDR controller
> (just like a connect request).  Using a valid high speed controller ID
> will cause the channel to be initially created on that high speed
> controller.  While the L2CAP data will be initially routed over the
> AMP controller, the L2CAP fixed signaling channel only uses BR/EDR.
> 
> When a create channel request is received for a high speed controller,
> a pending response is always sent first.  After the high speed
> physical and logical links are complete a success response will be
> sent.
> 
> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
> ---
>  net/bluetooth/l2cap_core.c | 70 +++++++++++++++++++++++++++++++++++-----------
>  1 file changed, 54 insertions(+), 16 deletions(-)
> 
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index 166382c..17e02d9 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -3362,8 +3362,9 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd
>  	return 0;
>  }
>  
> -static void __l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
> -			    u8 *data, u8 rsp_code, u8 amp_id)
> +static struct l2cap_chan *__l2cap_connect(struct l2cap_conn *conn,
> +					  struct l2cap_cmd_hdr *cmd,
> +					  u8 *data, u8 rsp_code, u8 amp_id)
>  {
>  	struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
>  	struct l2cap_conn_rsp rsp;
> @@ -3390,7 +3391,7 @@ static void __l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
>  
>  	/* Check if the ACL is secure enough (if not SDP) */
>  	if (psm != __constant_cpu_to_le16(L2CAP_PSM_SDP) &&
> -				!hci_conn_check_link_mode(conn->hcon)) {
> +	    !hci_conn_check_link_mode(conn->hcon)) {
>  		conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
>  		result = L2CAP_CR_SEC_BLOCK;
>  		goto response;
> @@ -3414,6 +3415,7 @@ static void __l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
>  	bacpy(&bt_sk(sk)->dst, conn->dst);
>  	chan->psm  = psm;
>  	chan->dcid = scid;
> +	chan->local_amp_id = amp_id;
>  
>  	bt_accept_enqueue(parent, sk);
>  
> @@ -3433,8 +3435,16 @@ static void __l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
>  				status = L2CAP_CS_AUTHOR_PEND;
>  				parent->sk_data_ready(parent, 0);
>  			} else {
> -				__l2cap_state_change(chan, BT_CONFIG);
> -				result = L2CAP_CR_SUCCESS;
> +				/* Force pending result for AMP controllers.
> +				 * The connection will succeed after the
> +				 * physical link is up. */
> +				if (amp_id) {
> +					__l2cap_state_change(chan, BT_CONNECT2);
> +					result = L2CAP_CR_PEND;
> +				} else {
> +					__l2cap_state_change(chan, BT_CONFIG);
> +					result = L2CAP_CR_SUCCESS;
> +				}
>  				status = L2CAP_CS_NO_INFO;
>  			}
>  		} else {
> @@ -3480,6 +3490,8 @@ sendresp:
>  					l2cap_build_conf_req(chan, buf), buf);
>  		chan->num_conf_req++;
>  	}
> +
> +	return chan;
>  }
>  
>  static int l2cap_connect_req(struct l2cap_conn *conn,
> @@ -3970,12 +3982,12 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
>  	return 0;
>  }
>  
> -static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
> -					struct l2cap_cmd_hdr *cmd, u16 cmd_len,
> -					void *data)
> +static int l2cap_create_channel_req(struct l2cap_conn *conn,
> +				    struct l2cap_cmd_hdr *cmd, u16 cmd_len,
> +				    void *data)
>  {
>  	struct l2cap_create_chan_req *req = data;
> -	struct l2cap_create_chan_rsp rsp;
> +	struct l2cap_chan *chan;
>  	u16 psm, scid;
>  
>  	if (cmd_len != sizeof(*req))
> @@ -3989,14 +4001,40 @@ static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
>  
>  	BT_DBG("psm 0x%2.2x, scid 0x%4.4x, amp_id %d", psm, scid, req->amp_id);
>  
> -	/* Placeholder: Always reject */
> -	rsp.dcid = 0;
> -	rsp.scid = cpu_to_le16(scid);
> -	rsp.result = __constant_cpu_to_le16(L2CAP_CR_NO_MEM);
> -	rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
> +	if (req->amp_id) {
> +		struct hci_dev *hdev;
>  
> -	l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
> -		       sizeof(rsp), &rsp);
> +		/* Validate AMP controller id */
> +		hdev = hci_dev_get(req->amp_id);
> +		if (!hdev || hdev->dev_type != HCI_AMP ||
> +		    !test_bit(HCI_UP, &hdev->flags)) {
> +			struct l2cap_create_chan_rsp rsp;
> +
> +			rsp.dcid = 0;
> +			rsp.scid = cpu_to_le16(scid);
> +			rsp.result = L2CAP_CR_BAD_AMP;
> +			rsp.status = L2CAP_CS_NO_INFO;

Please consider this:

-                       rsp.result = L2CAP_CR_BAD_AMP;
-                       rsp.status = L2CAP_CS_NO_INFO;
+                       rsp.result = __constant_cpu_to_le16(L2CAP_CR_BAD_AMP);
+                       rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);


Best regards 
Andrei Emeltchenko 


^ permalink raw reply

* Re: [RFC, PATCH] hid-ps3remote: handle multiple keypresses for joypad buttons
From: Antonio Ospite @ 2012-09-25 11:21 UTC (permalink / raw)
  To: David Dillow
  Cc: linux-bluetooth, David Herrmann, Luiz Augusto von Dentz,
	Bastien Nocera, linux-input, jkosina
In-Reply-To: <1348539215.15050.6.camel@obelisk.thedillows.org>

On Mon, 24 Sep 2012 22:13:35 -0400
David Dillow <dave@thedillows.org> wrote:

> On Mon, 2012-09-24 at 09:56 -0400, David Dillow wrote:
> > On Mon, 2012-09-24 at 13:25 +0200, Antonio Ospite wrote:
> > > In order to make this work I have to put joypad buttons only in one of
> > > the key maps, I don't know if that is compatible with the Harmony
> > > adapter.
> > 
> > I suspect it is, but I'll try to test later tonight. Feel free to merge
> > my patch and yours and push it upstream under your name/copyright; I'm
> > not attached to it.
> 
> Yep, this works with the Harmony.
>

Good.

I will send a v3 then, with you as the main author (the From: field) and
with myself added in the MODULE_AUTHOR section, this looks like the best
way to me as you are the initial author. I'd like you to take a final
look at that one tho, and maybe do an actual test too.

I will add the note about the "setup" procedure too.

> I think the logic you are using may result in some combinations being
> missed -- say Triangle + Play -- but I'm not sure how much it matters.

Yes, when pressing something like Triangle+Play the Play pressure is
completely ignored as a 0xff is reported in the 5th byte, but it's the
hardware which behaves that way, the driver is just very adherent to
what the hardware provides.

> I
> can rework the first version (building a custom report based on the
> funky rules of coding) in the next few days, or you can push your
> version if you'd like. Or perhaps a middle way, that erases the buttons
> reported in the bitmap from the byte array, but otherwise keeps track of
> the last press in that area to avoid weirdness when the user presses a
> button combo that cannot be reported due to the HW limitations.
>

I'd say we ignore this fact and not try to be too smart here, the
hardware has the limitation so we can blame someone else.
Does that make sense to you?

Thanks,
   Antonio

-- 
Antonio Ospite
http://ao2.it

A: Because it messes up the order in which people normally read text.
   See http://en.wikipedia.org/wiki/Posting_style
Q: Why is top-posting such a bad thing?

^ permalink raw reply

* Re: [PATCH v0] audio: Fix crash if gateway closed before reply
From: Luiz Augusto von Dentz @ 2012-09-25 11:04 UTC (permalink / raw)
  To: Mikel Astiz; +Cc: linux-bluetooth, Mikel Astiz
In-Reply-To: <1348565429-3045-1-git-send-email-mikel.astiz.oss@gmail.com>

Hi Mikel,

On Tue, Sep 25, 2012 at 12:30 PM, Mikel Astiz <mikel.astiz.oss@gmail.com> wrote:
> From: Mikel Astiz <mikel.astiz@bmw-carit.de>
>
> The audio gateway can be closed (dev->gateway == NULL) before the reply
> from the agent has been received, resulting in the following crash as
> reproduced while removing (unpairing) a device:
>
> bluetoothd[2219]: src/mgmt.c:mgmt_unpair_device() index 0 addr 38:16:D1:C5:D1:A2
> bluetoothd[2219]: audio/gateway.c:path_unregister() Unregistered interface org.bluez.HandsfreeGateway on path /org/bluez/2219/hci0/dev_38_16_D1_C5_D1_A2
> bluetoothd[2219]: audio/media.c:gateway_state_changed()
> bluetoothd[2219]: audio/media.c:gateway_state_changed() Clear endpoint 0x555555820640
> bluetoothd[2219]: audio/source.c:path_unregister() Unregistered interface org.bluez.AudioSource on path /org/bluez/2219/hci0/dev_38_16_D1_C5_D1_A2
> bluetoothd[2219]: src/device.c:btd_device_unref() 0x555555833e70: ref=1
> bluetoothd[2219]: src/adapter.c:adapter_get_device() 38:16:D1:C5:D1:A2
> bluetoothd[2219]: src/adapter.c:adapter_create_device() 38:16:D1:C5:D1:A2
> bluetoothd[2219]: src/device.c:device_create() Creating device /org/bluez/2219/hci0/dev_38_16_D1_C5_D1_A2
> bluetoothd[2219]: src/device.c:device_free() 0x55555581f9c0
> bluetoothd[2219]: Unable to get btd_device object for 38:16:D1:C5:D1:A2
> bluetoothd[2219]: src/device.c:btd_device_unref() 0x555555833e70: ref=0
> bluetoothd[2219]: src/device.c:device_free() 0x555555833e70
> bluetoothd[2219]: src/mgmt.c:mgmt_event() cond 1
> bluetoothd[2219]: src/mgmt.c:mgmt_event() Received 16 bytes from management socket
> bluetoothd[2219]: src/mgmt.c:mgmt_cmd_complete()
> bluetoothd[2219]: src/mgmt.c:mgmt_cmd_complete() unpair_device complete
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x000055555556fa26 in newconnection_reply (call=<optimized out>, data=0x555555824dd0) at audio/gateway.c:285
> 285             if (!dev->gateway->rfcomm) {
> ---
>  audio/gateway.c |    5 +++++
>  1 files changed, 5 insertions(+), 0 deletions(-)
>
> diff --git a/audio/gateway.c b/audio/gateway.c
> index 45b25a1..6990573 100644
> --- a/audio/gateway.c
> +++ b/audio/gateway.c
> @@ -282,6 +282,11 @@ static void newconnection_reply(DBusPendingCall *call, void *data)
>         DBusMessage *reply = dbus_pending_call_steal_reply(call);
>         DBusError derr;
>
> +       if (gw == NULL) {
> +               DBG("Gateway closed before agent reply");
> +               goto done;
> +       }
> +
>         if (!dev->gateway->rfcomm) {
>                 DBG("RFCOMM disconnected from server before agent reply");
>                 goto done;
> --
> 1.7.7.6

We should probably cancel the pending request so newconnection_reply
would not be called in this condition.


-- 
Luiz Augusto von Dentz

^ permalink raw reply

* [PATCH BlueZ] audio: Fix attempting to create a device on driver .remove
From: Luiz Augusto von Dentz @ 2012-09-25 10:54 UTC (permalink / raw)
  To: linux-bluetooth

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

audio_remove calls get_audio_dev which may attempt to create the device
if it doesn't exist.
---
 audio/manager.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/audio/manager.c b/audio/manager.c
index fbfe00f..6d7ac55 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -668,9 +668,12 @@ static struct audio_device *get_audio_dev(struct btd_device *device)
 static void audio_remove(struct btd_device *device)
 {
 	struct audio_device *dev;
+	const char *path;
 
-	dev = get_audio_dev(device);
-	if (!dev)
+	path = device_get_path(device);
+
+	dev = manager_find_device(path, NULL, NULL, NULL, FALSE);
+	if (dev == NULL)
 		return;
 
 	devices = g_slist_remove(devices, dev);
-- 
1.7.11.4


^ permalink raw reply related

* Re: [PATCH v1 3/4] adapter: Queue parallel authorization requests
From: Luiz Augusto von Dentz @ 2012-09-25 10:07 UTC (permalink / raw)
  To: Mikel Astiz; +Cc: linux-bluetooth, Mikel Astiz
In-Reply-To: <1348501338-29639-4-git-send-email-mikel.astiz.oss@gmail.com>

Hi Mikel,

On Mon, Sep 24, 2012 at 6:42 PM, Mikel Astiz <mikel.astiz.oss@gmail.com> wrote:

> +       g_queue_foreach(adapter->auths, (GFunc) g_free, NULL);
> +       g_queue_free(adapter->auths);

Above is probably a candidate to replace with g_queue_free_full

>  int btd_cancel_authorization(int auth_id)
>  {
> -       struct btd_adapter *adapter;
> -       struct agent *agent;
> -       int err;
> -
> -       adapter = find_authorization(auth_id);
> -       if (adapter == NULL)
> -               return -EPERM;
> -
> -       if (adapter->auth_idle_id) {
> -               g_source_remove(adapter->auth_idle_id);
> -               adapter->auth_idle_id = 0;
> -               g_free(adapter->auth);
> -               adapter->auth = NULL;
> -               return 0;
> -       }
> -
> -       /*
> -        * FIXME: Cancel fails if authorization is requested to adapter's
> -        * agent and in the meanwhile CreatePairedDevice is called.
> -        */
> +       struct service_auth *auth;
>
> -       agent = device_get_agent(adapter->auth->device);
> -       if (!agent)
> +       auth = find_authorization(auth_id);
> +       if (auth == NULL)
>                 return -EPERM;
>
> -       err = agent_cancel(agent);
> +       g_queue_remove(auth->adapter->auths, auth);
>
> -       if (err == 0) {
> -               g_free(adapter->auth);
> -               adapter->auth = NULL;
> -       }
> +       service_auth_cancel(auth);
>
> -       return err;
> +       return 0;
>  }

You can probably call id instead of auth_id, besides we normally use
uint/guint for handlers like this.

-- 
Luiz Augusto von Dentz

^ permalink raw reply

* Re: [PATCH hcidump] amp: Decode Read Data Block Size HCI cmd
From: Andrei Emeltchenko @ 2012-09-25 10:03 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1346331979-3837-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

ping

On Thu, Aug 30, 2012 at 04:06:19PM +0300, Andrei Emeltchenko wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> 
> Decode Read Data Block Size HCI command and command status.
> 
>  < HCI Command: Read Data Block Size (0x04|0x000a) plen 0
>  > HCI Event: Command Complete (0x0e) plen 10
>     Read Data Block Size (0x04|0x000a) ncmd 1
>     status 0x00
>     Max ACL 1492 Block len 1492 Num blocks 4
> ---
>  lib/hci.h    |    8 ++++++++
>  parser/hci.c |   24 +++++++++++++++++++++++-
>  2 files changed, 31 insertions(+), 1 deletion(-)
> 
> diff --git a/lib/hci.h b/lib/hci.h
> index 3dbb221..d068a2f 100644
> --- a/lib/hci.h
> +++ b/lib/hci.h
> @@ -1316,6 +1316,14 @@ typedef struct {
>  } __attribute__ ((packed)) read_bd_addr_rp;
>  #define READ_BD_ADDR_RP_SIZE 7
>  
> +#define OCF_READ_DATA_BLOCK_SIZE	0x000A
> +typedef struct {
> +	uint8_t		status;
> +	uint16_t	max_acl_len;
> +	uint16_t	data_block_len;
> +	uint16_t	num_blocks;
> +} __attribute__ ((packed)) read_data_block_size_rp;
> +
>  /* Status params */
>  #define OGF_STATUS_PARAM	0x05
>  
> diff --git a/parser/hci.c b/parser/hci.c
> index 115cf1e..38794bd 100644
> --- a/parser/hci.c
> +++ b/parser/hci.c
> @@ -338,7 +338,7 @@ static char *cmd_hostctl_str[CMD_HOSTCTL_NUM + 1] = {
>  	"Write LE Host Supported",
>  };
>  
> -#define CMD_INFO_NUM 9
> +#define CMD_INFO_NUM 10
>  static char *cmd_info_str[CMD_INFO_NUM + 1] = {
>  	"Unknown",
>  	"Read Local Version Information",
> @@ -350,6 +350,7 @@ static char *cmd_info_str[CMD_INFO_NUM + 1] = {
>  	"Read Country Code",
>  	"Unknown",
>  	"Read BD ADDR",
> +	"Read Data Block Size",
>  };
>  
>  #define CMD_STATUS_NUM 11
> @@ -2041,6 +2042,24 @@ static inline void bdaddr_response_dump(int level, struct frame *frm)
>  	raw_dump(level, frm);
>  }
>  
> +static inline void read_data_block_size_dump(int level, struct frame *frm)
> +{
> +	read_data_block_size_rp *rp = frm->ptr;
> +
> +	p_indent(level, frm);
> +	printf("status 0x%2.2x\n", rp->status);
> +
> +	if (rp->status > 0) {
> +		p_indent(level, frm);
> +		printf("Error: %s\n", status2str(rp->status));
> +	} else {
> +		p_indent(level, frm);
> +		printf("Max ACL %d Block len %d Num blocks %d\n",
> +			btohs(rp->max_acl_len), btohs(rp->data_block_len),
> +							btohs(rp->num_blocks));
> +	}
> +}
> +
>  static inline void generic_response_dump(int level, struct frame *frm)
>  {
>  	uint8_t status = get_u8(frm);
> @@ -2886,6 +2905,9 @@ static inline void cmd_complete_dump(int level, struct frame *frm)
>  		case OCF_READ_BD_ADDR:
>  			bdaddr_response_dump(level, frm);
>  			return;
> +		case OCF_READ_DATA_BLOCK_SIZE:
> +			read_data_block_size_dump(level, frm);
> +			return;
>  		}
>  		break;
>  
> -- 
> 1.7.9.5
> 
> --
> 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

^ permalink raw reply

* Re: [PATCH hcidump] amp: Decode Num Completed Data Blocks
From: Andrei Emeltchenko @ 2012-09-25 10:02 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1346398640-8423-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

ping

On Fri, Aug 31, 2012 at 10:37:20AM +0300, Andrei Emeltchenko wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> 
> Adds decoding Number Of Completed Data Blocks Event
> 
> > HCI Event: Number Of Completed Data Blocks (0x48) plen 9
>     Total num blocks 4 Num handles 1
>       Handle 0x0001: Num complt pkts 1 Num complt blks 1
> ---
>  lib/hci.h    |   10 ++++++++++
>  parser/hci.c |   22 ++++++++++++++++++++++
>  2 files changed, 32 insertions(+)
> 
> diff --git a/lib/hci.h b/lib/hci.h
> index d068a2f..7eacca5 100644
> --- a/lib/hci.h
> +++ b/lib/hci.h
> @@ -2197,6 +2197,16 @@ typedef struct {
>  #define EVT_FLOW_SPEC_MODIFY_COMPLETE_SIZE 3
>  
>  #define EVT_NUMBER_COMPLETED_BLOCKS		0x48
> +typedef struct {
> +	uint16_t		handle;
> +	uint16_t		num_cmplt_pkts;
> +	uint16_t		num_cmplt_blks;
> +} __attribute__ ((packed)) cmplt_handle;
> +typedef struct {
> +	uint16_t		total_num_blocks;
> +	uint8_t			num_handles;
> +	cmplt_handle		handles[0];
> +}  __attribute__ ((packed)) evt_num_completed_blocks;
>  
>  #define EVT_AMP_STATUS_CHANGE			0x4D
>  typedef struct {
> diff --git a/parser/hci.c b/parser/hci.c
> index 38794bd..19cd419 100644
> --- a/parser/hci.c
> +++ b/parser/hci.c
> @@ -3743,6 +3743,25 @@ static inline void flow_spec_modify_dump(int level, struct frame *frm)
>  	}
>  }
>  
> +static inline void num_completed_blocks_dump(int level, struct frame *frm)
> +{
> +	evt_num_completed_blocks *evt = frm->ptr;
> +	int i;
> +
> +	p_indent(level, frm);
> +	printf("Total num blocks %d Num handles %d\n",
> +			btohs(evt->total_num_blocks), evt->num_handles);
> +
> +	for (i = 0; i < evt->num_handles; i++) {
> +		cmplt_handle *h = &evt->handles[i];
> +
> +		p_indent(level + 1, frm);
> +		printf("Handle 0x%4.4x: Num complt pkts %d Num complt blks %d\n",
> +				btohs(h->handle), btohs(h->num_cmplt_pkts),
> +				btohs(h->num_cmplt_blks));
> +	}
> +}
> +
>  static inline void event_dump(int level, struct frame *frm)
>  {
>  	hci_event_hdr *hdr = frm->ptr;
> @@ -3969,6 +3988,9 @@ static inline void event_dump(int level, struct frame *frm)
>  	case EVT_FLOW_SPEC_MODIFY_COMPLETE:
>  		flow_spec_modify_dump(level + 1, frm);
>  		break;
> +	case EVT_NUMBER_COMPLETED_BLOCKS:
> +		num_completed_blocks_dump(level + 1, frm);
> +		break;
>  	default:
>  		raw_dump(level, frm);
>  		break;
> -- 
> 1.7.9.5
> 
> --
> 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

^ permalink raw reply


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