2013-05-06 08:43:17

by Mikel Astiz

[permalink] [raw]
Subject: [RFC BlueZ v0 00/13] Add experimental org.bluez.Service1

From: Mikel Astiz <[email protected]>

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 | 54 ++++++++++++++
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 | 174 ++++++++++++++++++++++++++++++++++++++++++++++
12 files changed, 530 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



2013-05-28 09:45:21

by Mikel Astiz

[permalink] [raw]
Subject: Re: [RFC BlueZ v0 00/13] Add experimental org.bluez.Service1

Hi,

On Wed, May 15, 2013 at 10:56 AM, Mikel Astiz <[email protected]> wrote:
> Hi,
>
> On Mon, May 6, 2013 at 11:19 AM, Luiz Augusto von Dentz
> <[email protected]> wrote:
>> Hi Mikel,
>>
>> On Mon, May 6, 2013 at 11:43 AM, Mikel Astiz <[email protected]> wrote:
>>> From: Mikel Astiz <[email protected]>
>>>
>>> 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 | 54 ++++++++++++++
>>> 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 | 174 ++++++++++++++++++++++++++++++++++++++++++++++
>>> 12 files changed, 530 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
>>
>> This is probably the way forward, but currently there have been some
>> instability after service was introduced, so before we move on to this
>> set I would like that we make sure those crashes are fixed.
>>
>> --
>> Luiz Augusto von Dentz
>
> Now that the main issues seem to be fixed and 5.5 is out, ping.
>
> Cheers,
> Mikel

Ping.

There's a pending minor doc fix as pointed out by Scott but I'd rather
have more feedback before submitting v1.

Cheers,
Mikel

2013-05-17 09:20:27

by Mikel Astiz

[permalink] [raw]
Subject: Re: [RFC BlueZ v0 10/13] doc: Add API documentation for org.bluez.Service1

Hi Scott,

On Thu, May 16, 2013 at 7:10 PM, Scott James Remnant <[email protected]> wrote:
> On Wed, May 15, 2013 at 11:22 PM, Mikel Astiz <[email protected]> wrote:
>> Hi Scott,
>>
>> On Wed, May 15, 2013 at 6:38 PM, Scott James Remnant <[email protected]> wrote:
>>> On Mon, May 6, 2013 at 1:43 AM, Mikel Astiz <[email protected]> wrote:
>>>
>>>> diff --git a/doc/service-api.txt b/doc/service-api.txt
>>>> new file mode 100644
>>>> index 0000000..ef611d6
>>>> --- /dev/null
>>>> +++ b/doc/service-api.txt
>>>> @@ -0,0 +1,54 @@
>>>> +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 freely definable
>>>> +
>>>> +Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/
>>>> + serviceZZZ
>>>> +
>>>
>>> This says the Object path is both freely definable and fixed, which is it? :)
>>
>> The later is the correct one, thanks for pointing it out.
>>
>
> What's the interaction between this and org.bluez.Profile1 ?

There'no direct relation between these two interfaces.

org.bluez.Profile1 is some kind of agent which can be used by a
external component (e.g. oFono) to implement a profile. I argued in
the past that the name is misleading but without success.

>
> Do you need an exported org.bluez.Profile1 object with a matching UUID
> of serviceZZZ to be able to connect? I would assume so, since that's
> what would receive the file descriptor.

No, they are independent mechanisms. For example A2DP is implemented
inside bluetoothd and has therefore no associated org.bluez.Profile1
interface, but the service gets exposed nevertheless in a
org.bluez.Service1 and can thus be connected.

Cheers,
Mikel

2013-05-16 17:10:22

by Scott James Remnant

[permalink] [raw]
Subject: Re: [RFC BlueZ v0 10/13] doc: Add API documentation for org.bluez.Service1

On Wed, May 15, 2013 at 11:22 PM, Mikel Astiz <[email protected]> wrote:
> Hi Scott,
>
> On Wed, May 15, 2013 at 6:38 PM, Scott James Remnant <[email protected]> wrote:
>> On Mon, May 6, 2013 at 1:43 AM, Mikel Astiz <[email protected]> wrote:
>>
>>> diff --git a/doc/service-api.txt b/doc/service-api.txt
>>> new file mode 100644
>>> index 0000000..ef611d6
>>> --- /dev/null
>>> +++ b/doc/service-api.txt
>>> @@ -0,0 +1,54 @@
>>> +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 freely definable
>>> +
>>> +Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/
>>> + serviceZZZ
>>> +
>>
>> This says the Object path is both freely definable and fixed, which is it? :)
>
> The later is the correct one, thanks for pointing it out.
>

What's the interaction between this and org.bluez.Profile1 ?

Do you need an exported org.bluez.Profile1 object with a matching UUID
of serviceZZZ to be able to connect? I would assume so, since that's
what would receive the file descriptor.

Scott
--
Scott James Remnant | Chrome OS Systems | [email protected] | Google

2013-05-16 06:22:26

by Mikel Astiz

[permalink] [raw]
Subject: Re: [RFC BlueZ v0 10/13] doc: Add API documentation for org.bluez.Service1

Hi Scott,

On Wed, May 15, 2013 at 6:38 PM, Scott James Remnant <[email protected]> wrote:
> On Mon, May 6, 2013 at 1:43 AM, Mikel Astiz <[email protected]> wrote:
>
>> diff --git a/doc/service-api.txt b/doc/service-api.txt
>> new file mode 100644
>> index 0000000..ef611d6
>> --- /dev/null
>> +++ b/doc/service-api.txt
>> @@ -0,0 +1,54 @@
>> +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 freely definable
>> +
>> +Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/
>> + serviceZZZ
>> +
>
> This says the Object path is both freely definable and fixed, which is it? :)

The later is the correct one, thanks for pointing it out.

Cheers,
Mikel

2013-05-15 16:38:31

by Scott James Remnant

[permalink] [raw]
Subject: Re: [RFC BlueZ v0 10/13] doc: Add API documentation for org.bluez.Service1

On Mon, May 6, 2013 at 1:43 AM, Mikel Astiz <[email protected]> wrote:

> diff --git a/doc/service-api.txt b/doc/service-api.txt
> new file mode 100644
> index 0000000..ef611d6
> --- /dev/null
> +++ b/doc/service-api.txt
> @@ -0,0 +1,54 @@
> +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 freely definable
> +
> +Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/
> + serviceZZZ
> +

This says the Object path is both freely definable and fixed, which is it? :)

Scott
--
Scott James Remnant | Chrome OS Systems | [email protected] | Google

2013-05-15 08:56:06

by Mikel Astiz

[permalink] [raw]
Subject: Re: [RFC BlueZ v0 00/13] Add experimental org.bluez.Service1

Hi,

On Mon, May 6, 2013 at 11:19 AM, Luiz Augusto von Dentz
<[email protected]> wrote:
> Hi Mikel,
>
> On Mon, May 6, 2013 at 11:43 AM, Mikel Astiz <[email protected]> wrote:
>> From: Mikel Astiz <[email protected]>
>>
>> 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 | 54 ++++++++++++++
>> 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 | 174 ++++++++++++++++++++++++++++++++++++++++++++++
>> 12 files changed, 530 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
>
> This is probably the way forward, but currently there have been some
> instability after service was introduced, so before we move on to this
> set I would like that we make sure those crashes are fixed.
>
> --
> Luiz Augusto von Dentz

Now that the main issues seem to be fixed and 5.5 is out, ping.

Cheers,
Mikel

2013-05-07 07:49:20

by Mikel Astiz

[permalink] [raw]
Subject: Re: [RFC BlueZ v0 08/13] dbus: Add state property to org.bluez.Service1

Hi Luiz,

On Mon, May 6, 2013 at 12:00 PM, Luiz Augusto von Dentz
<[email protected]> wrote:
> Hi Mikel,
>
> On Mon, May 6, 2013 at 11:43 AM, Mikel Astiz <[email protected]> wrote:
>> +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);
>
> The code about would break if state2dbus returns NULL for
> BTD_SERVICE_STATE_UNAVAILABLE, perhaps if service is unavailable it
> should not have an object path representing it?

That's exactly the case. The service is exposed in D-Bus only while
it's *not* unavailable, i.e. it's probed and usable.

The code already implements this behavior but if it's not clear enough
we could make it more explicit by adding assertions here and there.

Cheers,
Mikel

2013-05-06 10:00:42

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [RFC BlueZ v0 08/13] dbus: Add state property to org.bluez.Service1

Hi Mikel,

On Mon, May 6, 2013 at 11:43 AM, Mikel Astiz <[email protected]> wrote:
> +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);

The code about would break if state2dbus returns NULL for
BTD_SERVICE_STATE_UNAVAILABLE, perhaps if service is unavailable it
should not have an object path representing it?

2013-05-06 09:19:37

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [RFC BlueZ v0 00/13] Add experimental org.bluez.Service1

Hi Mikel,

On Mon, May 6, 2013 at 11:43 AM, Mikel Astiz <[email protected]> wrote:
> From: Mikel Astiz <[email protected]>
>
> 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 | 54 ++++++++++++++
> 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 | 174 ++++++++++++++++++++++++++++++++++++++++++++++
> 12 files changed, 530 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

This is probably the way forward, but currently there have been some
instability after service was introduced, so before we move on to this
set I would like that we make sure those crashes are fixed.

--
Luiz Augusto von Dentz

2013-05-06 08:43:30

by Mikel Astiz

[permalink] [raw]
Subject: [RFC BlueZ v0 13/13] test: Add --uuid to test-service

From: Mikel Astiz <[email protected]>

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 7143891..2342d50 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()
@@ -83,6 +89,10 @@ if args[0] == "list":

if properties["Device"] != path:
continue
+ elif uuid:
+ if properties["UUID"] != uuid:
+ continue
+ del(properties["UUID"])

print(" [ " + service_path + " ]")

@@ -102,23 +112,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


2013-05-06 08:43:29

by Mikel Astiz

[permalink] [raw]
Subject: [RFC BlueZ v0 12/13] test: Add test-service script

From: Mikel Astiz <[email protected]>

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

diff --git a/test/test-service b/test/test-service
new file mode 100755
index 0000000..7143891
--- /dev/null
+++ b/test/test-service
@@ -0,0 +1,156 @@
+#!/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
+
+ address = properties["Address"]
+ if len(args) >= 2 and args[1] != address:
+ continue
+
+ print("[ %s ]" % address)
+
+ 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


2013-05-06 08:43:28

by Mikel Astiz

[permalink] [raw]
Subject: [RFC BlueZ v0 11/13] dbus: Deprecate old profile-connecting API

From: Mikel Astiz <[email protected]>

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 187f2bf..1e294ad 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 41e0e15..720a476 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1667,9 +1667,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


2013-05-06 08:43:27

by Mikel Astiz

[permalink] [raw]
Subject: [RFC BlueZ v0 10/13] doc: Add API documentation for org.bluez.Service1

From: Mikel Astiz <[email protected]>

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

diff --git a/Makefile.am b/Makefile.am
index da87a21..9cd10b9 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..ef611d6
--- /dev/null
+++ b/doc/service-api.txt
@@ -0,0 +1,54 @@
+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 freely definable
+
+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


2013-05-06 08:43:26

by Mikel Astiz

[permalink] [raw]
Subject: [RFC BlueZ v0 09/13] dbus: Add Connect/Disconnect to org.bluez.Service1

From: Mikel Astiz <[email protected]>

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


2013-05-06 08:43:25

by Mikel Astiz

[permalink] [raw]
Subject: [RFC BlueZ v0 08/13] dbus: Add state property to org.bluez.Service1

From: Mikel Astiz <[email protected]>

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


2013-05-06 08:43:24

by Mikel Astiz

[permalink] [raw]
Subject: [RFC BlueZ v0 07/13] dbus: Add UUID property to org.bluez.Service1

From: Mikel Astiz <[email protected]>

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


2013-05-06 08:43:23

by Mikel Astiz

[permalink] [raw]
Subject: [RFC BlueZ v0 06/13] dbus: Add Device property to org.bluez.Service1

From: Mikel Astiz <[email protected]>

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


2013-05-06 08:43:22

by Mikel Astiz

[permalink] [raw]
Subject: [RFC BlueZ v0 05/13] dbus: Add new org.bluez.Service1

From: Mikel Astiz <[email protected]>

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 ff4c553..41e0e15 100644
--- a/src/device.c
+++ b/src/device.c
@@ -171,6 +171,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;
@@ -2074,6 +2075,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);
}
@@ -2414,11 +2416,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);
}

@@ -2436,11 +2439,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


2013-05-06 08:43:21

by Mikel Astiz

[permalink] [raw]
Subject: [RFC BlueZ v0 04/13] test: Show human-friendly UUIDs in list-devices

From: Mikel Astiz <[email protected]>

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


2013-05-06 08:43:20

by Mikel Astiz

[permalink] [raw]
Subject: [RFC BlueZ v0 03/13] test: Support human-friendly UUIDs in test-device

From: Mikel Astiz <[email protected]>

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


2013-05-06 08:43:19

by Mikel Astiz

[permalink] [raw]
Subject: [RFC BlueZ v0 02/13] test: Add UUID alias table to bluezutils.py

From: Mikel Astiz <[email protected]>

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


2013-05-06 08:43:18

by Mikel Astiz

[permalink] [raw]
Subject: [RFC BlueZ v0 01/13] test: Remove obsolete test script

From: Mikel Astiz <[email protected]>

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 0de0a0d..98a6da8 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -229,7 +229,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