linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC BlueZ v1 00/13] Add experimental org.bluez.Service1
@ 2013-06-06  8:21 Mikel Astiz
  2013-06-06  8:21 ` [RFC BlueZ v1 01/13] test: Remove obsolete test script Mikel Astiz
                   ` (12 more replies)
  0 siblings, 13 replies; 16+ messages in thread
From: Mikel Astiz @ 2013-06-06  8:21 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz

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

Resending this patchset which is basically the same as v0 with the following minor changes:
- Doc errata fixed as pointed out by Scott.
- test-service script extended to print the device alias along with the BT address.

>From original cover-letter:

Beyond the desktop use-cases, some users (e.g. GENIVI) are interested in having profile-specific information and control interfaces exposed in D-Bus. Such APIs did exist in BlueZ 4 but were dropped for BlueZ 5 in favor of simpler API simplicity. This service-specific interfaces had a fairly low priority for BlueZ 5 and therefore the discussion was postponed.

This patchset proposes org.bluez.Service1 as an attempt to cover these needs. As compared to the former Device.ConnectProfile()/DisconnectProfile(), the approach has the following advantages:
- Multiple instances of the same UUID can be exposed.
- The state of each service can be exposed, without hackish lists like Device.ConnectedProfiles.
- It's ObjectManager-centric.
- The design should scale better if new properties are required in the future (supported features, service handle, etc.)

Mikel Astiz (13):
  test: Remove obsolete test script
  test: Add UUID alias table to bluezutils.py
  test: Support human-friendly UUIDs in test-device
  test: Show human-friendly UUIDs in list-devices
  dbus: Add new org.bluez.Service1
  dbus: Add Device property to org.bluez.Service1
  dbus: Add UUID property to org.bluez.Service1
  dbus: Add state property to org.bluez.Service1
  dbus: Add Connect/Disconnect to org.bluez.Service1
  doc: Add API documentation for org.bluez.Service1
  dbus: Deprecate old profile-connecting API
  test: Add test-service script
  test: Add --uuid to test-service

 Makefile.am         |   2 +-
 Makefile.tools      |   2 +-
 doc/device-api.txt  |   4 +-
 doc/service-api.txt |  52 ++++++++++++++
 src/device.c        |  14 ++--
 src/service.c       | 197 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/service.h       |   2 +-
 test/bluezutils.py  |  84 ++++++++++++++++++++++
 test/list-devices   |   6 +-
 test/simple-service | 128 ----------------------------------
 test/test-device    |   4 +-
 test/test-service   | 175 ++++++++++++++++++++++++++++++++++++++++++++++
 12 files changed, 529 insertions(+), 141 deletions(-)
 create mode 100644 doc/service-api.txt
 delete mode 100755 test/simple-service
 create mode 100755 test/test-service

-- 
1.8.1.4


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [RFC BlueZ v1 01/13] test: Remove obsolete test script
  2013-06-06  8:21 [RFC BlueZ v1 00/13] Add experimental org.bluez.Service1 Mikel Astiz
@ 2013-06-06  8:21 ` Mikel Astiz
  2013-06-06  8:21 ` [RFC BlueZ v1 02/13] test: Add UUID alias table to bluezutils.py Mikel Astiz
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Mikel Astiz @ 2013-06-06  8:21 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz

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

The interface was removed some time ago making the test script useless,
so just remove it from the codebase.
---
 Makefile.tools      |   2 +-
 test/simple-service | 128 ----------------------------------------------------
 2 files changed, 1 insertion(+), 129 deletions(-)
 delete mode 100755 test/simple-service

diff --git a/Makefile.tools b/Makefile.tools
index acd403e..b48b02f 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -240,7 +240,7 @@ test_scripts += test/sap_client.py test/bluezutils.py \
 		test/dbusdef.py test/monitor-bluetooth test/list-devices \
 		test/test-discovery test/test-manager test/test-adapter \
 		test/test-device test/simple-agent \
-		test/simple-service test/simple-endpoint test/test-sap-server \
+		test/simple-endpoint test/test-sap-server \
 		test/test-proximity test/test-network \
 		test/test-thermometer test/test-profile test/test-health \
 		test/test-health-sink test/service-record.dtd \
diff --git a/test/simple-service b/test/simple-service
deleted file mode 100755
index 02d7648..0000000
--- a/test/simple-service
+++ /dev/null
@@ -1,128 +0,0 @@
-#!/usr/bin/python
-
-from __future__ import absolute_import, print_function, unicode_literals
-
-import sys
-import time
-import dbus
-import bluezutils
-
-xml = ' \
-<?xml version="1.0" encoding="UTF-8" ?> 	\
-<record>					\
-  <attribute id="0x0001">			\
-    <sequence>					\
-      <uuid value="0x1101"/>			\
-    </sequence>					\
-  </attribute>					\
-						\
-  <attribute id="0x0002">			\
-     <uint32 value="0"/>			\
-  </attribute>					\
-						\
-  <attribute id="0x0003">			\
-    <uuid value="00001101-0000-1000-8000-00805f9b34fb"/> \
-  </attribute>					\
-						\
-  <attribute id="0x0004">			\
-    <sequence>					\
-      <sequence>				\
-        <uuid value="0x0100"/>			\
-      </sequence>				\
-      <sequence>				\
-        <uuid value="0x0003"/>			\
-        <uint8 value="23"/>			\
-      </sequence>				\
-    </sequence>					\
-  </attribute>					\
-						\
-  <attribute id="0x0005">			\
-    <sequence>					\
-      <uuid value="0x1002"/>			\
-    </sequence>					\
-  </attribute>					\
-						\
-  <attribute id="0x0006">			\
-    <sequence>					\
-      <uint16 value="0x656e"/>			\
-      <uint16 value="0x006a"/>			\
-      <uint16 value="0x0100"/>			\
-    </sequence>					\
-  </attribute>					\
-						\
-  <attribute id="0x0007">			\
-     <uint32 value="0"/>			\
-  </attribute>					\
-						\
-  <attribute id="0x0008">			\
-     <uint8 value="0xff"/>			\
-  </attribute>					\
-						\
-  <attribute id="0x0009">			\
-    <sequence>					\
-      <sequence>				\
-        <uuid value="0x1101"/>			\
-        <uint16 value="0x0100"/>		\
-      </sequence>				\
-    </sequence>					\
-  </attribute>					\
-						\
-  <attribute id="0x000a">			\
-    <url value="http://www.bluez.org/"/>	\
-  </attribute>					\
-						\
-  <attribute id="0x000b">			\
-    <url value="http://www.bluez.org/"/>	\
-  </attribute>					\
-						\
-  <attribute id="0x000c">			\
-    <url value="http://www.bluez.org/"/>	\
-  </attribute>					\
-						\
-  <attribute id="0x0100">			\
-    <text value="Serial Port"/>			\
-  </attribute>					\
-						\
-  <attribute id="0x0101">			\
-    <text value="Serial Port Service"/>		\
-  </attribute>					\
-						\
-  <attribute id="0x0102">			\
-     <text value="BlueZ"/>			\
-  </attribute>					\
-						\
-  <attribute id="0x0200">			\
-    <sequence>					\
-      <uint16 value="0x0100"/>			\
-    </sequence>					\
-  </attribute>					\
-						\
-  <attribute id="0x0201">			\
-     <uint32 value="0"/>			\
-  </attribute>					\
-</record>					\
-'
-
-bus = dbus.SystemBus()
-
-if len(sys.argv) > 1:
-	path = bluezutils.find_adapter(sys.argv[1]).object_path
-else:
-	path = bluezutils.find_adapter().object_path
-
-service = dbus.Interface(bus.get_object("org.bluez", path),
-						"org.bluez.Service")
-
-handle = service.AddRecord(xml)
-
-print("Service record with handle 0x%04x added" % (handle))
-
-print("Press CTRL-C to remove service record")
-
-try:
-	time.sleep(1000)
-	print("Terminating session")
-except:
-	pass
-
-service.RemoveRecord(dbus.UInt32(handle))
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC BlueZ v1 02/13] test: Add UUID alias table to bluezutils.py
  2013-06-06  8:21 [RFC BlueZ v1 00/13] Add experimental org.bluez.Service1 Mikel Astiz
  2013-06-06  8:21 ` [RFC BlueZ v1 01/13] test: Remove obsolete test script Mikel Astiz
@ 2013-06-06  8:21 ` Mikel Astiz
  2013-06-06  8:21 ` [RFC BlueZ v1 03/13] test: Support human-friendly UUIDs in test-device Mikel Astiz
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Mikel Astiz @ 2013-06-06  8:21 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz

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

Add a helper function to parse human-friendly strings that can be
translated into UUID strings. The input string can be one of the
following types:
	- Full UUID: e.g. "00001108-0000-1000-8000-00805f9b34fb"
	- Short UUID: e.g. "00001108"
	- Alias: e.g. HSP_HS_UUID
	- Short alias: e.g. HSP_HS
---
 test/bluezutils.py | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)

diff --git a/test/bluezutils.py b/test/bluezutils.py
index de08cbd..6fc55cb 100644
--- a/test/bluezutils.py
+++ b/test/bluezutils.py
@@ -3,6 +3,64 @@ import dbus
 SERVICE_NAME = "org.bluez"
 ADAPTER_INTERFACE = SERVICE_NAME + ".Adapter1"
 DEVICE_INTERFACE = SERVICE_NAME + ".Device1"
+UUID_ALIAS_TABLE = {
+	"GENERIC_AUDIO_UUID": "00001203-0000-1000-8000-00805f9b34fb",
+	"HSP_HS_UUID": "00001108-0000-1000-8000-00805f9b34fb",
+	"HSP_AG_UUID": "00001112-0000-1000-8000-00805f9b34fb",
+	"HFP_HS_UUID": "0000111e-0000-1000-8000-00805f9b34fb",
+	"HFP_AG_UUID": "0000111f-0000-1000-8000-00805f9b34fb",
+	"ADVANCED_AUDIO_UUID": "0000110d-0000-1000-8000-00805f9b34fb",
+	"A2DP_SOURCE_UUID": "0000110a-0000-1000-8000-00805f9b34fb",
+	"A2DP_SINK_UUID": "0000110b-0000-1000-8000-00805f9b34fb",
+	"AVRCP_REMOTE_UUID": "0000110e-0000-1000-8000-00805f9b34fb",
+	"AVRCP_TARGET_UUID": "0000110c-0000-1000-8000-00805f9b34fb",
+	"PANU_UUID": "00001115-0000-1000-8000-00805f9b34fb",
+	"NAP_UUID": "00001116-0000-1000-8000-00805f9b34fb",
+	"GN_UUID": "00001117-0000-1000-8000-00805f9b34fb",
+	"BNEP_SVC_UUID": "0000000f-0000-1000-8000-00805f9b34fb",
+	"PNPID_UUID": "00002a50-0000-1000-8000-00805f9b34fb",
+	"DEVICE_INFORMATION_UUID": "0000180a-0000-1000-8000-00805f9b34fb",
+	"GATT_UUID": "00001801-0000-1000-8000-00805f9b34fb",
+	"IMMEDIATE_ALERT_UUID": "00001802-0000-1000-8000-00805f9b34fb",
+	"LINK_LOSS_UUID": "00001803-0000-1000-8000-00805f9b34fb",
+	"TX_POWER_UUID": "00001804-0000-1000-8000-00805f9b34fb",
+	"SAP_UUID": "0000112D-0000-1000-8000-00805f9b34fb",
+	"HEART_RATE_UUID": "0000180d-0000-1000-8000-00805f9b34fb",
+	"HEART_RATE_MEASUREMENT_UUID": "00002a37-0000-1000-8000-00805f9b34fb",
+	"BODY_SENSOR_LOCATION_UUID": "00002a38-0000-1000-8000-00805f9b34fb",
+	"HEART_RATE_CONTROL_POINT_UUID": "00002a39-0000-1000-8000-00805f9b34fb",
+	"HEALTH_THERMOMETER_UUID": "00001809-0000-1000-8000-00805f9b34fb",
+	"TEMPERATURE_MEASUREMENT_UUID": "00002a1c-0000-1000-8000-00805f9b34fb",
+	"TEMPERATURE_TYPE_UUID": "00002a1d-0000-1000-8000-00805f9b34fb",
+	"INTERMEDIATE_TEMPERATURE_UUID": "00002a1e-0000-1000-8000-00805f9b34fb",
+	"MEASUREMENT_INTERVAL_UUID": "00002a21-0000-1000-8000-00805f9b34fb",
+	"CYCLING_SC_UUID": "00001816-0000-1000-8000-00805f9b34fb",
+	"CSC_MEASUREMENT_UUID": "00002a5b-0000-1000-8000-00805f9b34fb",
+	"CSC_FEATURE_UUID": "00002a5c-0000-1000-8000-00805f9b34fb",
+	"SENSOR_LOCATION_UUID": "00002a5d-0000-1000-8000-00805f9b34fb",
+	"SC_CONTROL_POINT_UUID": "00002a55-0000-1000-8000-00805f9b34fb",
+	"RFCOMM_UUID_STR": "00000003-0000-1000-8000-00805f9b34fb",
+	"HDP_UUID": "00001400-0000-1000-8000-00805f9b34fb",
+	"HDP_SOURCE_UUID": "00001401-0000-1000-8000-00805f9b34fb",
+	"HDP_SINK_UUID": "00001402-0000-1000-8000-00805f9b34fb",
+	"HSP_HS_UUID": "00001108-0000-1000-8000-00805f9b34fb",
+	"HID_UUID": "00001124-0000-1000-8000-00805f9b34fb",
+	"DUN_GW_UUID": "00001103-0000-1000-8000-00805f9b34fb",
+	"GAP_UUID": "00001800-0000-1000-8000-00805f9b34fb",
+	"PNP_UUID": "00001200-0000-1000-8000-00805f9b34fb",
+	"SPP_UUID": "00001101-0000-1000-8000-00805f9b34fb",
+	"OBEX_SYNC_UUID": "00001104-0000-1000-8000-00805f9b34fb",
+	"OBEX_OPP_UUID": "00001105-0000-1000-8000-00805f9b34fb",
+	"OBEX_FTP_UUID": "00001106-0000-1000-8000-00805f9b34fb",
+	"OBEX_PCE_UUID": "0000112e-0000-1000-8000-00805f9b34fb",
+	"OBEX_PSE_UUID": "0000112f-0000-1000-8000-00805f9b34fb",
+	"OBEX_PBAP_UUID": "00001130-0000-1000-8000-00805f9b34fb",
+	"OBEX_MAS_UUID": "00001132-0000-1000-8000-00805f9b34fb",
+	"OBEX_MNS_UUID": "00001133-0000-1000-8000-00805f9b34fb",
+	"OBEX_MAP_UUID": "00001134-0000-1000-8000-00805f9b34fb"
+}
+
+INV_UUID_ALIAS_TABLE = { v:k for k, v in UUID_ALIAS_TABLE.items() }
 
 def get_managed_objects():
 	bus = dbus.SystemBus()
@@ -45,3 +103,29 @@ def find_device_in_objects(objects, device_address, adapter_pattern=None):
 			return dbus.Interface(obj, DEVICE_INTERFACE)
 
 	raise Exception("Bluetooth device not found")
+
+def parse_uuid(s):
+	hex_digits = "0123456789abcdef"
+	uuid_digits = hex_digits + "-"
+	suffix = "-0000-1000-8000-00805f9b34fb"
+	short_len = 8
+	long_len = short_len + len(suffix)
+	us = s.upper()
+	ls = s.lower()
+
+	uuid = UUID_ALIAS_TABLE.get(us)
+	if uuid is None:
+		uuid = UUID_ALIAS_TABLE.get(us + "_UUID")
+	if not(uuid is None):
+		return uuid
+
+	if len(ls) == short_len and all((c in hex_digits) for c in ls):
+		return ls + suffix
+	elif len(ls) == long_len and all((c in uuid_digits) for c in ls):
+		return ls
+
+	raise Exception("Invalid profile UUID")
+
+def get_uuid_alias(uuid):
+	ul = uuid.lower()
+	return INV_UUID_ALIAS_TABLE.get(ul)
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC BlueZ v1 03/13] test: Support human-friendly UUIDs in test-device
  2013-06-06  8:21 [RFC BlueZ v1 00/13] Add experimental org.bluez.Service1 Mikel Astiz
  2013-06-06  8:21 ` [RFC BlueZ v1 01/13] test: Remove obsolete test script Mikel Astiz
  2013-06-06  8:21 ` [RFC BlueZ v1 02/13] test: Add UUID alias table to bluezutils.py Mikel Astiz
@ 2013-06-06  8:21 ` Mikel Astiz
  2013-06-06  8:21 ` [RFC BlueZ v1 04/13] test: Show human-friendly UUIDs in list-devices Mikel Astiz
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Mikel Astiz @ 2013-06-06  8:21 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz

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

Make use of the newly introduced helper function in bluezutils.py to
parse the command line UUID argument for "connect" and "disconnect"
operations.
---
 test/test-device | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/test/test-device b/test/test-device
index 3d7b852..b5f8f96 100755
--- a/test/test-device
+++ b/test/test-device
@@ -99,7 +99,7 @@ if (args[0] == "connect"):
 	else:
 		device = bluezutils.find_device(args[1], options.dev_id)
 		if (len(args) > 2):
-			device.ConnectProfile(args[2])
+			device.ConnectProfile(bluezutils.parse_uuid(args[2]))
 		else:
 			device.Connect()
 	sys.exit(0)
@@ -110,7 +110,7 @@ if (args[0] == "disconnect"):
 	else:
 		device = bluezutils.find_device(args[1], options.dev_id)
 		if (len(args) > 2):
-			device.DisconnectProfile(args[2])
+			device.DisconnectProfile(bluezutils.parse_uuid(args[2]))
 		else:
 			device.Disconnect()
 	sys.exit(0)
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC BlueZ v1 04/13] test: Show human-friendly UUIDs in list-devices
  2013-06-06  8:21 [RFC BlueZ v1 00/13] Add experimental org.bluez.Service1 Mikel Astiz
                   ` (2 preceding siblings ...)
  2013-06-06  8:21 ` [RFC BlueZ v1 03/13] test: Support human-friendly UUIDs in test-device Mikel Astiz
@ 2013-06-06  8:21 ` Mikel Astiz
  2013-06-06  8:21 ` [RFC BlueZ v1 05/13] dbus: Add new org.bluez.Service1 Mikel Astiz
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Mikel Astiz @ 2013-06-06  8:21 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz

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

Instead of showing the hexadecimal UUID, convert it to a human-friendly
alias as defined in the internal translation table in bluezutils.py.
---
 test/list-devices | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/test/list-devices b/test/list-devices
index 0aac217..57f9ba1 100755
--- a/test/list-devices
+++ b/test/list-devices
@@ -3,6 +3,7 @@
 from __future__ import absolute_import, print_function, unicode_literals
 
 import dbus
+import bluezutils
 
 bus = dbus.SystemBus()
 
@@ -19,7 +20,10 @@ def extract_objects(object_list):
 def extract_uuids(uuid_list):
 	list = ""
 	for uuid in uuid_list:
-		if (uuid.endswith("-0000-1000-8000-00805f9b34fb")):
+		alias = bluezutils.get_uuid_alias(uuid)
+		if alias:
+			val = alias
+		elif (uuid.endswith("-0000-1000-8000-00805f9b34fb")):
 			if (uuid.startswith("0000")):
 				val = "0x" + uuid[4:8]
 			else:
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC BlueZ v1 05/13] dbus: Add new org.bluez.Service1
  2013-06-06  8:21 [RFC BlueZ v1 00/13] Add experimental org.bluez.Service1 Mikel Astiz
                   ` (3 preceding siblings ...)
  2013-06-06  8:21 ` [RFC BlueZ v1 04/13] test: Show human-friendly UUIDs in list-devices Mikel Astiz
@ 2013-06-06  8:21 ` Mikel Astiz
  2013-06-06  8:29   ` Gustavo Padovan
  2013-06-06  8:21 ` [RFC BlueZ v1 06/13] dbus: Add Device property to org.bluez.Service1 Mikel Astiz
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 16+ messages in thread
From: Mikel Astiz @ 2013-06-06  8:21 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz

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

Add a D-Bus interface to represent a service that is supported by a
device.
---
 src/device.c  |  8 ++++++--
 src/service.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/service.h |  2 +-
 3 files changed, 60 insertions(+), 4 deletions(-)

diff --git a/src/device.c b/src/device.c
index 57bfc86..c03db12 100644
--- a/src/device.c
+++ b/src/device.c
@@ -177,6 +177,7 @@ struct btd_device {
 	GSList		*uuids;
 	GSList		*primaries;		/* List of primary services */
 	GSList		*services;		/* List of btd_service */
+	unsigned int	service_id;
 	GSList		*pending;		/* Pending services */
 	GSList		*watches;		/* List of disconnect_data */
 	gboolean	temporary;
@@ -2132,6 +2133,7 @@ static struct btd_device *device_new(struct btd_adapter *adapter,
 
 	str2ba(address, &device->bdaddr);
 	device->adapter = adapter;
+	device->service_id = 1;
 
 	return btd_device_ref(device);
 }
@@ -2477,11 +2479,12 @@ static void dev_probe(struct btd_profile *p, void *user_data)
 
 	service = service_create(d->dev, p);
 
-	if (service_probe(service) < 0) {
+	if (service_probe(service, d->dev->service_id) < 0) {
 		btd_service_unref(service);
 		return;
 	}
 
+	d->dev->service_id++;
 	d->dev->services = g_slist_append(d->dev->services, service);
 }
 
@@ -2499,11 +2502,12 @@ void device_probe_profile(gpointer a, gpointer b)
 
 	service = service_create(device, profile);
 
-	if (service_probe(service) < 0) {
+	if (service_probe(service, device->service_id) < 0) {
 		btd_service_unref(service);
 		return;
 	}
 
+	device->service_id++;
 	device->services = g_slist_append(device->services, service);
 
 	if (!profile->auto_connect || !device->general_connect)
diff --git a/src/service.c b/src/service.c
index aef9502..7b9e271 100644
--- a/src/service.c
+++ b/src/service.c
@@ -38,6 +38,7 @@
 #include <bluetooth/bluetooth.h>
 
 #include <glib.h>
+#include <gdbus/gdbus.h>
 
 #include "log.h"
 
@@ -45,6 +46,10 @@
 #include "device.h"
 #include "profile.h"
 #include "service.h"
+#include "dbus-common.h"
+#include "error.h"
+
+#define SERVICE_INTERFACE "org.bluez.Service1"
 
 struct btd_service {
 	int			ref;
@@ -53,6 +58,9 @@ struct btd_service {
 	void			*user_data;
 	btd_service_state_t	state;
 	int			err;
+	char			*path;
+	DBusMessage             *connect_msg;
+	DBusMessage             *disconnect_msg;
 };
 
 struct service_state_callback {
@@ -63,6 +71,9 @@ struct service_state_callback {
 
 static GSList *state_callbacks = NULL;
 
+static int service_register(struct btd_service *service, unsigned int id);
+static void service_unregister(struct btd_service *service);
+
 static const char *state2str(btd_service_state_t state)
 {
 	switch (state) {
@@ -149,7 +160,7 @@ struct btd_service *service_create(struct btd_device *device,
 	return service;
 }
 
-int service_probe(struct btd_service *service)
+int service_probe(struct btd_service *service, unsigned int id)
 {
 	char addr[18];
 	int err;
@@ -159,6 +170,7 @@ int service_probe(struct btd_service *service)
 	err = service->profile->device_probe(service);
 	if (err == 0) {
 		change_state(service, BTD_SERVICE_STATE_DISCONNECTED, 0);
+		service_register(service, id); /* Ignore errors */
 		return 0;
 	}
 
@@ -170,10 +182,12 @@ int service_probe(struct btd_service *service)
 
 void service_shutdown(struct btd_service *service)
 {
+	service_unregister(service);
 	change_state(service, BTD_SERVICE_STATE_UNAVAILABLE, 0);
 	service->profile->device_remove(service);
 	service->device = NULL;
 	service->profile = NULL;
+	service_unregister(service);
 }
 
 int btd_service_connect(struct btd_service *service)
@@ -333,3 +347,41 @@ void btd_service_disconnecting_complete(struct btd_service *service, int err)
 	else /* If disconnect fails, we assume it remains connected */
 		change_state(service, BTD_SERVICE_STATE_CONNECTED, err);
 }
+
+static int service_register(struct btd_service *service, unsigned int id)
+{
+	DBusConnection *dbus_conn = btd_get_dbus_connection();
+	char *path;
+
+	path = g_strdup_printf("%s/service%u", device_get_path(service->device),
+									id);
+	g_strdelimit(path, "-", '_');
+
+	if (g_dbus_register_interface(dbus_conn,
+					path, SERVICE_INTERFACE,
+					NULL, NULL, NULL, service,
+					NULL) == FALSE) {
+		g_free(path);
+		error("Unable to register service interface for %s",
+								service->path);
+		return -EIO;
+	}
+
+	service->path = path;
+
+	return 0;
+}
+
+static void service_unregister(struct btd_service *service)
+{
+	DBusConnection *dbus_conn = btd_get_dbus_connection();
+
+	if (service->path == NULL)
+		return;
+
+	g_dbus_unregister_interface(dbus_conn, service->path,
+							SERVICE_INTERFACE);
+
+	g_free(service->path);
+	service->path = NULL;
+}
diff --git a/src/service.h b/src/service.h
index 6ee8f17..e709f34 100644
--- a/src/service.h
+++ b/src/service.h
@@ -45,7 +45,7 @@ void btd_service_unref(struct btd_service *service);
 struct btd_service *service_create(struct btd_device *device,
 						struct btd_profile *profile);
 
-int service_probe(struct btd_service *service);
+int service_probe(struct btd_service *service, unsigned int id);
 void service_shutdown(struct btd_service *service);
 
 /* Connection control API */
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC BlueZ v1 06/13] dbus: Add Device property to org.bluez.Service1
  2013-06-06  8:21 [RFC BlueZ v1 00/13] Add experimental org.bluez.Service1 Mikel Astiz
                   ` (4 preceding siblings ...)
  2013-06-06  8:21 ` [RFC BlueZ v1 05/13] dbus: Add new org.bluez.Service1 Mikel Astiz
@ 2013-06-06  8:21 ` Mikel Astiz
  2013-06-06  8:21 ` [RFC BlueZ v1 07/13] dbus: Add UUID " Mikel Astiz
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Mikel Astiz @ 2013-06-06  8:21 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz

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

Expose in D-Bus the object path of the device which the service belongs
to.
---
 src/service.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/src/service.c b/src/service.c
index 7b9e271..b5b0a8e 100644
--- a/src/service.c
+++ b/src/service.c
@@ -348,6 +348,22 @@ void btd_service_disconnecting_complete(struct btd_service *service, int err)
 		change_state(service, BTD_SERVICE_STATE_CONNECTED, err);
 }
 
+static gboolean service_get_device(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct btd_service *service = data;
+	const char *path = device_get_path(service->device);
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+
+	return TRUE;
+}
+
+static const GDBusPropertyTable service_properties[] = {
+	{ "Device", "o", service_get_device },
+	{ }
+};
+
 static int service_register(struct btd_service *service, unsigned int id)
 {
 	DBusConnection *dbus_conn = btd_get_dbus_connection();
@@ -359,7 +375,7 @@ static int service_register(struct btd_service *service, unsigned int id)
 
 	if (g_dbus_register_interface(dbus_conn,
 					path, SERVICE_INTERFACE,
-					NULL, NULL, NULL, service,
+					NULL, NULL, service_properties, service,
 					NULL) == FALSE) {
 		g_free(path);
 		error("Unable to register service interface for %s",
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC BlueZ v1 07/13] dbus: Add UUID property to org.bluez.Service1
  2013-06-06  8:21 [RFC BlueZ v1 00/13] Add experimental org.bluez.Service1 Mikel Astiz
                   ` (5 preceding siblings ...)
  2013-06-06  8:21 ` [RFC BlueZ v1 06/13] dbus: Add Device property to org.bluez.Service1 Mikel Astiz
@ 2013-06-06  8:21 ` Mikel Astiz
  2013-06-06  8:21 ` [RFC BlueZ v1 08/13] dbus: Add state " Mikel Astiz
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Mikel Astiz @ 2013-06-06  8:21 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz

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

Expose in D-Bus the remote UUID corresponding to each service instance.
---
 src/service.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/service.c b/src/service.c
index b5b0a8e..9487c1a 100644
--- a/src/service.c
+++ b/src/service.c
@@ -359,8 +359,20 @@ static gboolean service_get_device(const GDBusPropertyTable *property,
 	return TRUE;
 }
 
+static gboolean service_get_uuid(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct btd_service *service = data;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
+						&service->profile->remote_uuid);
+
+	return TRUE;
+}
+
 static const GDBusPropertyTable service_properties[] = {
 	{ "Device", "o", service_get_device },
+	{ "UUID", "s", service_get_uuid },
 	{ }
 };
 
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC BlueZ v1 08/13] dbus: Add state property to org.bluez.Service1
  2013-06-06  8:21 [RFC BlueZ v1 00/13] Add experimental org.bluez.Service1 Mikel Astiz
                   ` (6 preceding siblings ...)
  2013-06-06  8:21 ` [RFC BlueZ v1 07/13] dbus: Add UUID " Mikel Astiz
@ 2013-06-06  8:21 ` Mikel Astiz
  2013-06-06  8:21 ` [RFC BlueZ v1 09/13] dbus: Add Connect/Disconnect " Mikel Astiz
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Mikel Astiz @ 2013-06-06  8:21 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz

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

Add a property representing the current state of the service, which
currently uses a simplified subset of the internal state.
---
 src/service.c | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/src/service.c b/src/service.c
index 9487c1a..fed8460 100644
--- a/src/service.c
+++ b/src/service.c
@@ -92,10 +92,27 @@ static const char *state2str(btd_service_state_t state)
 	return NULL;
 }
 
+static const char *state2dbus(btd_service_state_t state)
+{
+	switch (state) {
+	case BTD_SERVICE_STATE_UNAVAILABLE:
+		return NULL;
+	case BTD_SERVICE_STATE_DISCONNECTED:
+	case BTD_SERVICE_STATE_CONNECTING:
+	case BTD_SERVICE_STATE_DISCONNECTING:
+		return "disconnected";
+	case BTD_SERVICE_STATE_CONNECTED:
+		return "connected";
+	}
+
+	return NULL;
+}
+
 static void change_state(struct btd_service *service, btd_service_state_t state,
 									int err)
 {
 	btd_service_state_t old = service->state;
+	DBusConnection *dbus_conn = btd_get_dbus_connection();
 	char addr[18];
 	GSList *l;
 
@@ -113,6 +130,11 @@ static void change_state(struct btd_service *service, btd_service_state_t state,
 					addr, service->profile->name,
 					state2str(old), state2str(state), err);
 
+	if (state != BTD_SERVICE_STATE_UNAVAILABLE &&
+					state2dbus(old) != state2dbus(state))
+		g_dbus_emit_property_changed(dbus_conn, service->path,
+						SERVICE_INTERFACE, "State");
+
 	for (l = state_callbacks; l != NULL; l = g_slist_next(l)) {
 		struct service_state_callback *cb = l->data;
 
@@ -370,9 +392,23 @@ static gboolean service_get_uuid(const GDBusPropertyTable *property,
 	return TRUE;
 }
 
+static gboolean service_get_state(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct btd_service *service = data;
+	const char *str;
+
+	str = state2dbus(service->state);
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
+
+	return TRUE;
+}
+
 static const GDBusPropertyTable service_properties[] = {
 	{ "Device", "o", service_get_device },
 	{ "UUID", "s", service_get_uuid },
+	{ "State", "s", service_get_state },
 	{ }
 };
 
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC BlueZ v1 09/13] dbus: Add Connect/Disconnect to org.bluez.Service1
  2013-06-06  8:21 [RFC BlueZ v1 00/13] Add experimental org.bluez.Service1 Mikel Astiz
                   ` (7 preceding siblings ...)
  2013-06-06  8:21 ` [RFC BlueZ v1 08/13] dbus: Add state " Mikel Astiz
@ 2013-06-06  8:21 ` Mikel Astiz
  2013-06-06  8:21 ` [RFC BlueZ v1 10/13] doc: Add API documentation for org.bluez.Service1 Mikel Astiz
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Mikel Astiz @ 2013-06-06  8:21 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz

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

Add the control methods to connect or disconnect a specific remote
service, in a similar way that org.bluez.Device1.ConnectProfile()/
.DisconnectProfile() do.
---
 src/service.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 80 insertions(+), 1 deletion(-)

diff --git a/src/service.c b/src/service.c
index fed8460..0aa8cc4 100644
--- a/src/service.c
+++ b/src/service.c
@@ -108,6 +108,26 @@ static const char *state2dbus(btd_service_state_t state)
 	return NULL;
 }
 
+static void send_dbus_reply(DBusMessage **p, bool state_ok, int err)
+{
+	DBusMessage *msg = *p;
+	DBusMessage *reply;
+
+	if (msg == NULL)
+		return;
+
+	if (state_ok)
+		reply = dbus_message_new_method_return(msg);
+	else if (err < 0)
+		reply = btd_error_failed(msg, strerror(-err));
+	else /* For some reason, the error was not set */
+		reply = btd_error_failed(msg, strerror(EIO));
+
+	g_dbus_send_message(btd_get_dbus_connection(), reply);
+	dbus_message_unref(msg);
+	*p = NULL;
+}
+
 static void change_state(struct btd_service *service, btd_service_state_t state,
 									int err)
 {
@@ -140,6 +160,12 @@ static void change_state(struct btd_service *service, btd_service_state_t state,
 
 		cb->cb(service, old, state, cb->user_data);
 	}
+
+	send_dbus_reply(&service->connect_msg,
+				state == BTD_SERVICE_STATE_CONNECTED, err);
+
+	send_dbus_reply(&service->disconnect_msg,
+				state == BTD_SERVICE_STATE_DISCONNECTED, err);
 }
 
 struct btd_service *btd_service_ref(struct btd_service *service)
@@ -392,6 +418,52 @@ static gboolean service_get_uuid(const GDBusPropertyTable *property,
 	return TRUE;
 }
 
+static DBusMessage *service_connect(DBusConnection *conn, DBusMessage *msg,
+								void *user_data)
+{
+	struct btd_service *service = user_data;
+	int err;
+
+	if (service->state != BTD_SERVICE_STATE_DISCONNECTED)
+		return btd_error_already_connected(msg);
+
+	if (service->connect_msg != NULL || service->disconnect_msg)
+		return btd_error_busy(msg);
+
+	err = btd_service_connect(service);
+	if (err == -ENOTSUP)
+		return btd_error_not_supported(msg);
+	else if (err < 0)
+		return btd_error_failed(msg, strerror(-err));
+
+	service->connect_msg = dbus_message_ref(msg);
+
+	return NULL;
+}
+
+static DBusMessage *service_disconnect(DBusConnection *conn, DBusMessage *msg,
+								void *user_data)
+{
+	struct btd_service *service = user_data;
+	int err;
+
+	if (service->state == BTD_SERVICE_STATE_DISCONNECTED)
+		return btd_error_not_connected(msg);
+
+	if (service->disconnect_msg != NULL)
+		return btd_error_busy(msg);
+
+	err = btd_service_disconnect(service);
+	if (err == -ENOTSUP)
+		return btd_error_not_supported(msg);
+	else if (err < 0)
+		return btd_error_failed(msg, strerror(-err));
+
+	service->disconnect_msg = dbus_message_ref(msg);
+
+	return NULL;
+}
+
 static gboolean service_get_state(const GDBusPropertyTable *property,
 					DBusMessageIter *iter, void *data)
 {
@@ -405,6 +477,12 @@ static gboolean service_get_state(const GDBusPropertyTable *property,
 	return TRUE;
 }
 
+static const GDBusMethodTable service_methods[] = {
+	{ GDBUS_ASYNC_METHOD("Connect", NULL, NULL, service_connect) },
+	{ GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, service_disconnect) },
+	{ }
+};
+
 static const GDBusPropertyTable service_properties[] = {
 	{ "Device", "o", service_get_device },
 	{ "UUID", "s", service_get_uuid },
@@ -423,7 +501,8 @@ static int service_register(struct btd_service *service, unsigned int id)
 
 	if (g_dbus_register_interface(dbus_conn,
 					path, SERVICE_INTERFACE,
-					NULL, NULL, service_properties, service,
+					service_methods, NULL,
+					service_properties, service,
 					NULL) == FALSE) {
 		g_free(path);
 		error("Unable to register service interface for %s",
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC BlueZ v1 10/13] doc: Add API documentation for org.bluez.Service1
  2013-06-06  8:21 [RFC BlueZ v1 00/13] Add experimental org.bluez.Service1 Mikel Astiz
                   ` (8 preceding siblings ...)
  2013-06-06  8:21 ` [RFC BlueZ v1 09/13] dbus: Add Connect/Disconnect " Mikel Astiz
@ 2013-06-06  8:21 ` Mikel Astiz
  2013-06-06  8:21 ` [RFC BlueZ v1 11/13] dbus: Deprecate old profile-connecting API Mikel Astiz
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 16+ messages in thread
From: Mikel Astiz @ 2013-06-06  8:21 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz

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

Update the documentation to reflect the newly adopted D-Bus API.
---
 Makefile.am         |  2 +-
 doc/service-api.txt | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+), 1 deletion(-)
 create mode 100644 doc/service-api.txt

diff --git a/Makefile.am b/Makefile.am
index 9d570fb..abab329 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -199,7 +199,7 @@ EXTRA_DIST += doc/assigned-numbers.txt doc/supported-features.txt
 
 EXTRA_DIST += doc/mgmt-api.txt \
 		doc/adapter-api.txt doc/device-api.txt \
-		doc/agent-api.txt doc/profile-api.txt \
+		doc/agent-api.txt doc/profile-api.txt doc/service-api.txt \
 		doc/network-api.txt doc/media-api.txt \
 		doc/health-api.txt doc/sap-api.txt
 
diff --git a/doc/service-api.txt b/doc/service-api.txt
new file mode 100644
index 0000000..72b2369
--- /dev/null
+++ b/doc/service-api.txt
@@ -0,0 +1,52 @@
+BlueZ D-Bus Service API description
+***********************************
+
+Copyright (C) 2012-2013  BMW Car IT GmbH. All rights reserved.
+
+
+Service hierarchy
+=================
+
+Service		unique name
+Interface	org.bluez.Service1 [Experimental]
+Object path	[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/
+								serviceZZZ
+
+Methods		void Connect()
+
+			This method connects a specific service of this
+			device.
+
+			Possible errors: org.bluez.Error.AgentNotAvailable
+					 org.bluez.Error.AlreadyConnected
+					 org.bluez.Error.Canceled
+					 org.bluez.Error.Failed
+					 org.bluez.Error.InProgress
+
+		void Disconnect()
+
+			This method disconnects a specific service of this
+			device.
+
+			There is no connection tracking for a service, so
+			as long as the service is registered this will always
+			succeed.
+
+			Possible errors: org.bluez.Error.Failed
+					 org.bluez.Error.InProgress
+					 org.bluez.Error.NotConnected
+
+Properties	object Device [readonly]
+
+			The object path of the device the service belongs to.
+
+		string State [readonly]
+
+			Indicates the state of the connection.  Possible
+			values are:
+				"disconnected"
+				"connected"
+
+		string UUID [readonly]
+
+			128-bit UUID that representing the remote service.
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC BlueZ v1 11/13] dbus: Deprecate old profile-connecting API
  2013-06-06  8:21 [RFC BlueZ v1 00/13] Add experimental org.bluez.Service1 Mikel Astiz
                   ` (9 preceding siblings ...)
  2013-06-06  8:21 ` [RFC BlueZ v1 10/13] doc: Add API documentation for org.bluez.Service1 Mikel Astiz
@ 2013-06-06  8:21 ` Mikel Astiz
  2013-06-06  8:21 ` [RFC BlueZ v1 12/13] test: Add test-service script Mikel Astiz
  2013-06-06  8:21 ` [RFC BlueZ v1 13/13] test: Add --uuid to test-service Mikel Astiz
  12 siblings, 0 replies; 16+ messages in thread
From: Mikel Astiz @ 2013-06-06  8:21 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz

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

The new org.bluez.Service1 interface deprecates the old UUID-specific
connect/disconnect methods in org.bluez.Device1.
---
 doc/device-api.txt | 4 ++--
 src/device.c       | 6 ++++--
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/doc/device-api.txt b/doc/device-api.txt
index 6201780..5329054 100644
--- a/doc/device-api.txt
+++ b/doc/device-api.txt
@@ -40,7 +40,7 @@ Methods		void Connect()
 
 			Possible errors: org.bluez.Error.NotConnected
 
-		void ConnectProfile(string uuid)
+		void ConnectProfile(string uuid) [Deprecated]
 
 			This method connects a specific profile of this
 			device. The UUID provided is the remote service
@@ -50,7 +50,7 @@ Methods		void Connect()
 					 org.bluez.Error.AlreadyConnected
 					 org.bluez.Error.ConnectFailed
 
-		void DisconnectProfile(string uuid)
+		void DisconnectProfile(string uuid) [Deprecated]
 
 			This method disconnects a specific profile of
 			this device. The profile needs to be registered
diff --git a/src/device.c b/src/device.c
index c03db12..fed1966 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1725,9 +1725,11 @@ static DBusMessage *cancel_pairing(DBusConnection *conn, DBusMessage *msg,
 static const GDBusMethodTable device_methods[] = {
 	{ GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, disconnect) },
 	{ GDBUS_ASYNC_METHOD("Connect", NULL, NULL, dev_connect) },
-	{ GDBUS_ASYNC_METHOD("ConnectProfile", GDBUS_ARGS({ "UUID", "s" }),
+	{ GDBUS_DEPRECATED_ASYNC_METHOD("ConnectProfile",
+						GDBUS_ARGS({ "UUID", "s" }),
 						NULL, connect_profile) },
-	{ GDBUS_ASYNC_METHOD("DisconnectProfile", GDBUS_ARGS({ "UUID", "s" }),
+	{ GDBUS_DEPRECATED_ASYNC_METHOD("DisconnectProfile",
+						GDBUS_ARGS({ "UUID", "s" }),
 						NULL, disconnect_profile) },
 	{ GDBUS_ASYNC_METHOD("Pair", NULL, NULL, pair_device) },
 	{ GDBUS_METHOD("CancelPairing", NULL, NULL, cancel_pairing) },
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC BlueZ v1 12/13] test: Add test-service script
  2013-06-06  8:21 [RFC BlueZ v1 00/13] Add experimental org.bluez.Service1 Mikel Astiz
                   ` (10 preceding siblings ...)
  2013-06-06  8:21 ` [RFC BlueZ v1 11/13] dbus: Deprecate old profile-connecting API Mikel Astiz
@ 2013-06-06  8:21 ` Mikel Astiz
  2013-06-06  8:21 ` [RFC BlueZ v1 13/13] test: Add --uuid to test-service Mikel Astiz
  12 siblings, 0 replies; 16+ messages in thread
From: Mikel Astiz @ 2013-06-06  8:21 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz

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

This simple script can be used to control the org.bluez.Service1 API.
---
 test/test-service | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 157 insertions(+)
 create mode 100755 test/test-service

diff --git a/test/test-service b/test/test-service
new file mode 100755
index 0000000..48426f9
--- /dev/null
+++ b/test/test-service
@@ -0,0 +1,157 @@
+#!/usr/bin/python
+
+# Copyright (C) 2012-2013  BMW Car IT GmbH.
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+from gi.repository import GObject
+
+import sys
+import dbus
+import dbus.mainloop.glib
+from optparse import OptionParser, make_option
+import bluezutils
+
+BUS_NAME = 'org.bluez'
+SERVICE_INTERFACE = 'org.bluez.Service1'
+
+dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+bus = dbus.SystemBus()
+mainloop = GObject.MainLoop()
+
+option_list = [
+		make_option("-i", "--adapter", action="store",
+				type="string", dest="adap_id"),
+		]
+
+description="Test script to operate on org.bluez.Service1 interfaces"
+usage = "usage: %prog [options] <command> [<args>]"
+epilog="""
+Commands:
+	list [<address>]
+	connect <address> <service-path-suffix>
+	disconnect <address> <service-path-suffix>
+
+"""
+
+OptionParser.format_epilog = lambda self, formatter: self.epilog
+parser = OptionParser(
+	usage=usage,
+	description = description,
+	epilog = epilog,
+	option_list=option_list)
+
+(options, args) = parser.parse_args()
+
+if len(args) < 1:
+	parser.print_help()
+	sys.exit(1)
+
+if args[0] == "list":
+	if len(args) > 2:
+		parser.print_help()
+		sys.exit(1)
+
+	adapter = bluezutils.find_adapter(options.adap_id)
+	adapter_path = adapter.object_path
+
+	om = dbus.Interface(bus.get_object("org.bluez", "/"),
+					"org.freedesktop.DBus.ObjectManager")
+	objects = om.GetManagedObjects()
+
+	all_services = (str(path) for path, interfaces in objects.iteritems()
+			if SERVICE_INTERFACE in interfaces.keys())
+	all_services = list(all_services)
+
+	for path, interfaces in objects.iteritems():
+		if "org.bluez.Device1" not in interfaces:
+			continue
+
+		properties = interfaces["org.bluez.Device1"]
+		if properties["Adapter"] != adapter_path:
+			continue
+
+		alias = properties["Alias"]
+		address = properties["Address"]
+		if len(args) >= 2 and args[1] != address:
+			continue
+
+		print("[ %s ('%s') ]" % (address, alias))
+
+		for service_path in all_services:
+			service = objects[service_path]
+			properties = service[SERVICE_INTERFACE]
+
+			if properties["Device"] != path:
+				continue
+
+			print("    [ " + service_path + " ]")
+
+			for key in properties.keys():
+				value = properties[key]
+				extra = ""
+				if key == "Device":
+					continue
+				elif key == "UUID":
+					alias = bluezutils.get_uuid_alias(value)
+					if alias:
+						extra = " (%s)" % alias
+				print("        %s = %s%s" % (key, value, extra))
+
+		print("")
+
+	sys.exit(0)
+
+def service_do(func):
+	if len(args) < 3:
+		parser.print_help()
+		sys.exit(1)
+
+	objects = bluezutils.get_managed_objects()
+	adapter = bluezutils.find_adapter_in_objects(objects, options.adap_id)
+	device = bluezutils.find_device_in_objects(objects, args[1],
+								options.adap_id)
+	path_suffix = args[2]
+	found = False
+	for path, ifaces in objects.iteritems():
+		service = ifaces.get(SERVICE_INTERFACE)
+		if service is None:
+			continue
+		if device.object_path != service["Device"]:
+			continue
+		if not(path.endswith(path_suffix)):
+			continue
+		try:
+			found = True
+			service = bus.get_object(BUS_NAME, path)
+			iface = dbus.Interface(service, SERVICE_INTERFACE)
+			func(path, iface)
+		except dbus.exceptions.DBusException as e:
+			print(e)
+			print()
+
+	if not(found):
+		raise Exception("Service not found")
+
+if args[0] == "connect":
+	def connect(path, iface):
+		print("Connecting service %s..." % path)
+		iface.Connect()
+		print("Done.")
+		print()
+
+	service_do(connect)
+	sys.exit(0)
+
+if args[0] == "disconnect":
+	def disconnect(path, iface):
+		print("Disconnecting service %s..." % path)
+		iface.Disconnect()
+		print("Done.")
+		print()
+
+	service_do(disconnect)
+	sys.exit(0)
+
+parser.print_help()
+sys.exit(1)
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC BlueZ v1 13/13] test: Add --uuid to test-service
  2013-06-06  8:21 [RFC BlueZ v1 00/13] Add experimental org.bluez.Service1 Mikel Astiz
                   ` (11 preceding siblings ...)
  2013-06-06  8:21 ` [RFC BlueZ v1 12/13] test: Add test-service script Mikel Astiz
@ 2013-06-06  8:21 ` Mikel Astiz
  12 siblings, 0 replies; 16+ messages in thread
From: Mikel Astiz @ 2013-06-06  8:21 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz

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

Extend the test script with an optional filter to let the user operate
on services matching a given UUID.
---
 test/test-service | 34 ++++++++++++++++++++++++++--------
 1 file changed, 26 insertions(+), 8 deletions(-)

diff --git a/test/test-service b/test/test-service
index 48426f9..f8dee66 100755
--- a/test/test-service
+++ b/test/test-service
@@ -22,6 +22,8 @@ mainloop = GObject.MainLoop()
 option_list = [
 		make_option("-i", "--adapter", action="store",
 				type="string", dest="adap_id"),
+		make_option("-u", "--uuid", action="store",
+				type="string", dest="uuid"),
 		]
 
 description="Test script to operate on org.bluez.Service1 interfaces"
@@ -29,8 +31,8 @@ usage = "usage: %prog [options] <command> [<args>]"
 epilog="""
 Commands:
 	list [<address>]
-	connect <address> <service-path-suffix>
-	disconnect <address> <service-path-suffix>
+	connect [<address> [<service-path-suffix>]]
+	disconnect [<address> [<service-path-suffix>]]
 
 """
 
@@ -47,6 +49,10 @@ if len(args) < 1:
 	parser.print_help()
 	sys.exit(1)
 
+uuid = None
+if options.uuid:
+	uuid = bluezutils.parse_uuid(options.uuid)
+
 if args[0] == "list":
 	if len(args) > 2:
 		parser.print_help()
@@ -84,6 +90,10 @@ if args[0] == "list":
 
 			if properties["Device"] != path:
 				continue
+			elif uuid:
+				if properties["UUID"] != uuid:
+					continue
+				del(properties["UUID"])
 
 			print("    [ " + service_path + " ]")
 
@@ -103,23 +113,31 @@ if args[0] == "list":
 	sys.exit(0)
 
 def service_do(func):
-	if len(args) < 3:
-		parser.print_help()
+	if len(args) < 3 and not(uuid):
+		print("ERROR: Either service suffix or UUID must be specified")
 		sys.exit(1)
 
 	objects = bluezutils.get_managed_objects()
 	adapter = bluezutils.find_adapter_in_objects(objects, options.adap_id)
-	device = bluezutils.find_device_in_objects(objects, args[1],
+
+	device = None
+	if len(args) >= 2:
+		device = bluezutils.find_device_in_objects(objects, args[1],
 								options.adap_id)
-	path_suffix = args[2]
+	path_suffix = None
+	if len(args) >= 3:
+		path_suffix = args[2]
+
 	found = False
 	for path, ifaces in objects.iteritems():
 		service = ifaces.get(SERVICE_INTERFACE)
 		if service is None:
 			continue
-		if device.object_path != service["Device"]:
+		if device and device.object_path != service["Device"]:
+			continue
+		if uuid and uuid != service["UUID"]:
 			continue
-		if not(path.endswith(path_suffix)):
+		if path_suffix and not(path.endswith(path_suffix)):
 			continue
 		try:
 			found = True
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [RFC BlueZ v1 05/13] dbus: Add new org.bluez.Service1
  2013-06-06  8:21 ` [RFC BlueZ v1 05/13] dbus: Add new org.bluez.Service1 Mikel Astiz
@ 2013-06-06  8:29   ` Gustavo Padovan
  2013-06-06  9:26     ` Mikel Astiz
  0 siblings, 1 reply; 16+ messages in thread
From: Gustavo Padovan @ 2013-06-06  8:29 UTC (permalink / raw)
  To: Mikel Astiz; +Cc: linux-bluetooth, Mikel Astiz

Hi Mikel,

* Mikel Astiz <mikel.astiz.oss@gmail.com> [2013-06-06 10:21:37 +0200]:

> From: Mikel Astiz <mikel.astiz@bmw-carit.de>
> 
> Add a D-Bus interface to represent a service that is supported by a
> device.
> ---
>  src/device.c  |  8 ++++++--
>  src/service.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  src/service.h |  2 +-
>  3 files changed, 60 insertions(+), 4 deletions(-)
> 
> diff --git a/src/device.c b/src/device.c
> index 57bfc86..c03db12 100644
> --- a/src/device.c
> +++ b/src/device.c
> @@ -177,6 +177,7 @@ struct btd_device {
>  	GSList		*uuids;
>  	GSList		*primaries;		/* List of primary services */
>  	GSList		*services;		/* List of btd_service */
> +	unsigned int	service_id;
>  	GSList		*pending;		/* Pending services */
>  	GSList		*watches;		/* List of disconnect_data */
>  	gboolean	temporary;
> @@ -2132,6 +2133,7 @@ static struct btd_device *device_new(struct btd_adapter *adapter,
>  
>  	str2ba(address, &device->bdaddr);
>  	device->adapter = adapter;
> +	device->service_id = 1;
>  
>  	return btd_device_ref(device);
>  }
> @@ -2477,11 +2479,12 @@ static void dev_probe(struct btd_profile *p, void *user_data)
>  
>  	service = service_create(d->dev, p);
>  
> -	if (service_probe(service) < 0) {
> +	if (service_probe(service, d->dev->service_id) < 0) {
>  		btd_service_unref(service);
>  		return;
>  	}
>  
> +	d->dev->service_id++;
>  	d->dev->services = g_slist_append(d->dev->services, service);
>  }
>  
> @@ -2499,11 +2502,12 @@ void device_probe_profile(gpointer a, gpointer b)
>  
>  	service = service_create(device, profile);
>  
> -	if (service_probe(service) < 0) {
> +	if (service_probe(service, device->service_id) < 0) {
>  		btd_service_unref(service);
>  		return;
>  	}
>  
> +	device->service_id++;
>  	device->services = g_slist_append(device->services, service);
>  
>  	if (!profile->auto_connect || !device->general_connect)
> diff --git a/src/service.c b/src/service.c
> index aef9502..7b9e271 100644
> --- a/src/service.c
> +++ b/src/service.c
> @@ -38,6 +38,7 @@
>  #include <bluetooth/bluetooth.h>
>  
>  #include <glib.h>
> +#include <gdbus/gdbus.h>
>  
>  #include "log.h"
>  
> @@ -45,6 +46,10 @@
>  #include "device.h"
>  #include "profile.h"
>  #include "service.h"
> +#include "dbus-common.h"
> +#include "error.h"
> +
> +#define SERVICE_INTERFACE "org.bluez.Service1"
>  
>  struct btd_service {
>  	int			ref;
> @@ -53,6 +58,9 @@ struct btd_service {
>  	void			*user_data;
>  	btd_service_state_t	state;
>  	int			err;
> +	char			*path;
> +	DBusMessage             *connect_msg;
> +	DBusMessage             *disconnect_msg;
>  };
>  
>  struct service_state_callback {
> @@ -63,6 +71,9 @@ struct service_state_callback {
>  
>  static GSList *state_callbacks = NULL;
>  
> +static int service_register(struct btd_service *service, unsigned int id);
> +static void service_unregister(struct btd_service *service);
> +
>  static const char *state2str(btd_service_state_t state)
>  {
>  	switch (state) {
> @@ -149,7 +160,7 @@ struct btd_service *service_create(struct btd_device *device,
>  	return service;
>  }
>  
> -int service_probe(struct btd_service *service)
> +int service_probe(struct btd_service *service, unsigned int id)
>  {
>  	char addr[18];
>  	int err;
> @@ -159,6 +170,7 @@ int service_probe(struct btd_service *service)
>  	err = service->profile->device_probe(service);
>  	if (err == 0) {
>  		change_state(service, BTD_SERVICE_STATE_DISCONNECTED, 0);
> +		service_register(service, id); /* Ignore errors */
>  		return 0;
>  	}
>  
> @@ -170,10 +182,12 @@ int service_probe(struct btd_service *service)
>  
>  void service_shutdown(struct btd_service *service)
>  {
> +	service_unregister(service);
>  	change_state(service, BTD_SERVICE_STATE_UNAVAILABLE, 0);
>  	service->profile->device_remove(service);
>  	service->device = NULL;
>  	service->profile = NULL;
> +	service_unregister(service);

Didn't get why you are calling service_unregister twice here.

	Gustavo

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC BlueZ v1 05/13] dbus: Add new org.bluez.Service1
  2013-06-06  8:29   ` Gustavo Padovan
@ 2013-06-06  9:26     ` Mikel Astiz
  0 siblings, 0 replies; 16+ messages in thread
From: Mikel Astiz @ 2013-06-06  9:26 UTC (permalink / raw)
  To: Gustavo Padovan, linux-bluetooth, Mikel Astiz

Hi Gustavo,

On Thu, Jun 6, 2013 at 10:29 AM, Gustavo Padovan <gustavo@padovan.org> wrote:
> Hi Mikel,
>
> * Mikel Astiz <mikel.astiz.oss@gmail.com> [2013-06-06 10:21:37 +0200]:
>
>> From: Mikel Astiz <mikel.astiz@bmw-carit.de>
>>
>> Add a D-Bus interface to represent a service that is supported by a
>> device.
>> ---
>>  src/device.c  |  8 ++++++--
>>  src/service.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>  src/service.h |  2 +-
>>  3 files changed, 60 insertions(+), 4 deletions(-)
>>
>> diff --git a/src/device.c b/src/device.c
>> index 57bfc86..c03db12 100644
>> --- a/src/device.c
>> +++ b/src/device.c
>> @@ -177,6 +177,7 @@ struct btd_device {
>>       GSList          *uuids;
>>       GSList          *primaries;             /* List of primary services */
>>       GSList          *services;              /* List of btd_service */
>> +     unsigned int    service_id;
>>       GSList          *pending;               /* Pending services */
>>       GSList          *watches;               /* List of disconnect_data */
>>       gboolean        temporary;
>> @@ -2132,6 +2133,7 @@ static struct btd_device *device_new(struct btd_adapter *adapter,
>>
>>       str2ba(address, &device->bdaddr);
>>       device->adapter = adapter;
>> +     device->service_id = 1;
>>
>>       return btd_device_ref(device);
>>  }
>> @@ -2477,11 +2479,12 @@ static void dev_probe(struct btd_profile *p, void *user_data)
>>
>>       service = service_create(d->dev, p);
>>
>> -     if (service_probe(service) < 0) {
>> +     if (service_probe(service, d->dev->service_id) < 0) {
>>               btd_service_unref(service);
>>               return;
>>       }
>>
>> +     d->dev->service_id++;
>>       d->dev->services = g_slist_append(d->dev->services, service);
>>  }
>>
>> @@ -2499,11 +2502,12 @@ void device_probe_profile(gpointer a, gpointer b)
>>
>>       service = service_create(device, profile);
>>
>> -     if (service_probe(service) < 0) {
>> +     if (service_probe(service, device->service_id) < 0) {
>>               btd_service_unref(service);
>>               return;
>>       }
>>
>> +     device->service_id++;
>>       device->services = g_slist_append(device->services, service);
>>
>>       if (!profile->auto_connect || !device->general_connect)
>> diff --git a/src/service.c b/src/service.c
>> index aef9502..7b9e271 100644
>> --- a/src/service.c
>> +++ b/src/service.c
>> @@ -38,6 +38,7 @@
>>  #include <bluetooth/bluetooth.h>
>>
>>  #include <glib.h>
>> +#include <gdbus/gdbus.h>
>>
>>  #include "log.h"
>>
>> @@ -45,6 +46,10 @@
>>  #include "device.h"
>>  #include "profile.h"
>>  #include "service.h"
>> +#include "dbus-common.h"
>> +#include "error.h"
>> +
>> +#define SERVICE_INTERFACE "org.bluez.Service1"
>>
>>  struct btd_service {
>>       int                     ref;
>> @@ -53,6 +58,9 @@ struct btd_service {
>>       void                    *user_data;
>>       btd_service_state_t     state;
>>       int                     err;
>> +     char                    *path;
>> +     DBusMessage             *connect_msg;
>> +     DBusMessage             *disconnect_msg;
>>  };
>>
>>  struct service_state_callback {
>> @@ -63,6 +71,9 @@ struct service_state_callback {
>>
>>  static GSList *state_callbacks = NULL;
>>
>> +static int service_register(struct btd_service *service, unsigned int id);
>> +static void service_unregister(struct btd_service *service);
>> +
>>  static const char *state2str(btd_service_state_t state)
>>  {
>>       switch (state) {
>> @@ -149,7 +160,7 @@ struct btd_service *service_create(struct btd_device *device,
>>       return service;
>>  }
>>
>> -int service_probe(struct btd_service *service)
>> +int service_probe(struct btd_service *service, unsigned int id)
>>  {
>>       char addr[18];
>>       int err;
>> @@ -159,6 +170,7 @@ int service_probe(struct btd_service *service)
>>       err = service->profile->device_probe(service);
>>       if (err == 0) {
>>               change_state(service, BTD_SERVICE_STATE_DISCONNECTED, 0);
>> +             service_register(service, id); /* Ignore errors */
>>               return 0;
>>       }
>>
>> @@ -170,10 +182,12 @@ int service_probe(struct btd_service *service)
>>
>>  void service_shutdown(struct btd_service *service)
>>  {
>> +     service_unregister(service);
>>       change_state(service, BTD_SERVICE_STATE_UNAVAILABLE, 0);
>>       service->profile->device_remove(service);
>>       service->device = NULL;
>>       service->profile = NULL;
>> +     service_unregister(service);
>
> Didn't get why you are calling service_unregister twice here.

My mistake, the second call is useless (it's actually being ignored)
and should be removed from the patch.

Cheers,
Mikel

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2013-06-06  9:26 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-06-06  8:21 [RFC BlueZ v1 00/13] Add experimental org.bluez.Service1 Mikel Astiz
2013-06-06  8:21 ` [RFC BlueZ v1 01/13] test: Remove obsolete test script Mikel Astiz
2013-06-06  8:21 ` [RFC BlueZ v1 02/13] test: Add UUID alias table to bluezutils.py Mikel Astiz
2013-06-06  8:21 ` [RFC BlueZ v1 03/13] test: Support human-friendly UUIDs in test-device Mikel Astiz
2013-06-06  8:21 ` [RFC BlueZ v1 04/13] test: Show human-friendly UUIDs in list-devices Mikel Astiz
2013-06-06  8:21 ` [RFC BlueZ v1 05/13] dbus: Add new org.bluez.Service1 Mikel Astiz
2013-06-06  8:29   ` Gustavo Padovan
2013-06-06  9:26     ` Mikel Astiz
2013-06-06  8:21 ` [RFC BlueZ v1 06/13] dbus: Add Device property to org.bluez.Service1 Mikel Astiz
2013-06-06  8:21 ` [RFC BlueZ v1 07/13] dbus: Add UUID " Mikel Astiz
2013-06-06  8:21 ` [RFC BlueZ v1 08/13] dbus: Add state " Mikel Astiz
2013-06-06  8:21 ` [RFC BlueZ v1 09/13] dbus: Add Connect/Disconnect " Mikel Astiz
2013-06-06  8:21 ` [RFC BlueZ v1 10/13] doc: Add API documentation for org.bluez.Service1 Mikel Astiz
2013-06-06  8:21 ` [RFC BlueZ v1 11/13] dbus: Deprecate old profile-connecting API Mikel Astiz
2013-06-06  8:21 ` [RFC BlueZ v1 12/13] test: Add test-service script Mikel Astiz
2013-06-06  8:21 ` [RFC BlueZ v1 13/13] test: Add --uuid to test-service Mikel Astiz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).