From: Mikel Astiz <[email protected]>
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
Hi Gustavo,
On Thu, Jun 6, 2013 at 10:29 AM, Gustavo Padovan <[email protected]> wrote:
> Hi Mikel,
>
> * Mikel Astiz <[email protected]> [2013-06-06 10:21:37 +0200]:
>
>> 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 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
Hi Mikel,
* Mikel Astiz <[email protected]> [2013-06-06 10:21:37 +0200]:
> 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 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
From: Mikel Astiz <[email protected]>
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
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 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
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 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
From: Mikel Astiz <[email protected]>
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
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
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
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
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
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 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
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
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
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
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 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