2011-03-14 21:19:40

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v2 1/5] Rename the Discover method to DiscoverCharacteristics

---
attrib/client.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/attrib/client.c b/attrib/client.c
index 17157cd..f0b0b14 100644
--- a/attrib/client.c
+++ b/attrib/client.c
@@ -983,7 +983,7 @@ static DBusMessage *prim_get_properties(DBusConnection *conn, DBusMessage *msg,
}

static GDBusMethodTable prim_methods[] = {
- { "Discover", "", "", discover_char },
+ { "DiscoverCharacteristics", "", "", discover_char },
{ "RegisterCharacteristicsWatcher", "o", "",
register_watcher },
{ "UnregisterCharacteristicsWatcher", "o", "",
--
1.7.4.1



2011-03-15 08:54:01

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH v2 1/5] Rename the Discover method to DiscoverCharacteristics

Hi Vinicius,

On Mon, Mar 14, 2011, Vinicius Costa Gomes wrote:
> ---
> attrib/client.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)

All five patches have been pushed upstream. Thanks.

Johan

2011-03-14 21:19:44

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v2 5/5] Update the test-attrib test script

Now it is more similar to the other test-* scripts. And allows to
exercise more of the API.
---
test/test-attrib | 212 +++++++++++++++++++++++++-----------------------------
1 files changed, 98 insertions(+), 114 deletions(-)

diff --git a/test/test-attrib b/test/test-attrib
index dc3f804..b9e83c5 100755
--- a/test/test-attrib
+++ b/test/test-attrib
@@ -6,119 +6,103 @@ from optparse import OptionParser, OptionValueError
from binascii import hexlify, unhexlify

import gobject
+
+import sys
import dbus
-import dbus.service
import dbus.mainloop.glib
-
-def handle_set_property(option, opt_str, value, parser):
- """Handle --set-property parameter."""
-
- char_path = parser.values.char_path
- if not char_path:
- raise OptionValueError, "%s requires --char-path" % opt_str
- if len(value.split("=")) != 2:
- raise OptionValueError, "%s must have format \"property=value\"" % opt_str
- if not getattr(parser.values, option.dest, None):
- setattr(parser.values, option.dest, {})
- props = getattr(parser.values, option.dest)
- if not props.get(char_path):
- props[char_path] = []
- props[char_path].append(value.split("="))
-
-def command_parse():
- """Parse command line options."""
-
- usage = """
- Usage: %s [options]""" % sys.argv[0]
- parser = OptionParser(usage=usage)
- parser.add_option("-i", "--adapter", action="store", type="string",
- help="Specify local adapter interface")
- parser.add_option("--listen", action="store_true",
- help="Listen for notifications and indications (requires policy changes)")
- parser.add_option("--char-path", action="store", type="string",
- help="D-Bus path for specific characteristic")
- parser.add_option("--set-property", action="callback", type="string",
- metavar="NAME=VALUE", callback=handle_set_property,
- help="Set property for characteristic")
- return parser.parse_args()
-
-def dbus_type_to_str(d):
- """Convert a D-Bus array to a hexdump."""
-
- if isinstance(d, dbus.Array):
- return hexlify("".join([str(x) for x in d]))
- else:
- return str(d)
-
-def hexdump_to_dbus(data):
- """Convert an hexadecimal dump to D-Bus array."""
-
- d = [dbus.Byte(ord(i)) for i in unhexlify(data)]
- return dbus.Array(d, signature=dbus.Signature('y'), variant_level=1)
-
-class Watcher(dbus.service.Object):
- @dbus.service.method("org.bluez.Watcher", in_signature="oay", out_signature="")
- def ValueChanged(self, char, newvalue):
- print "Watcher: new value for %s: %s" % (char, dbus_type_to_str(newvalue))
-
-def handle_characteristics(char):
- char.Discover()
- for c in char.GetProperties()["Characteristics"]:
- char = dbus.Interface(bus.get_object("org.bluez", c),
- "org.bluez.Characteristic")
-
- if options.char_path and c != options.char_path:
- continue
-
- if not options.set_property:
- ret = "Characteristic: %s\nProperties:\n" % c
- for (k, v) in char.GetProperties().iteritems():
- ret += "\t%s: %s\n" % (k, dbus_type_to_str(v))
- print ret
- elif options.set_property.get(path, None):
- for (k, v) in options.set_property[path]:
- char2 = dbus.Interface(bus.get_object("org.bluez",
- path), "org.bluez.Characteristic")
- if k == "Value":
- char2.SetProperty(k, hexdump_to_dbus(v))
- else:
- char2.SetProperty(k, v)
-
-def handle_services(device):
- for s in device.GetProperties()["Services"]:
- char = dbus.Interface(bus.get_object("org.bluez", s),
- "org.bluez.Characteristic")
- if options.listen:
- char.RegisterCharacteristicsWatcher(watcher_path)
- else:
- handle_characteristics(char)
-
-if __name__ == "__main__":
- (options, args) = command_parse()
-
- dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
- bus = dbus.SystemBus()
- manager = dbus.Interface(bus.get_object("org.bluez", "/"),
- "org.bluez.Manager")
-
- if options.adapter:
- path = manager.FindAdapter(options.adapter)
- else:
- path = manager.DefaultAdapter()
-
- adapter = dbus.Interface(bus.get_object("org.bluez", path),
- "org.bluez.Adapter")
-
- if options.listen:
- watcher_path = "/test/watcher"
- watcher = Watcher(bus, watcher_path)
-
- for d in adapter.GetProperties()["Devices"]:
- device = dbus.Interface(bus.get_object("org.bluez", d),
- "org.bluez.Device")
- handle_services(device)
-
- if options.listen:
- print "Waiting for incoming notifications/indications..."
- mainloop = gobject.MainLoop()
- mainloop.run()
+from optparse import OptionParser, make_option
+
+dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+bus = dbus.SystemBus()
+mainloop = gobject.MainLoop()
+
+manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
+
+option_list = [
+ make_option("-i", "--device", action="store",
+ type="string", dest="dev_id"),
+ ]
+parser = OptionParser(option_list=option_list)
+
+(options, args) = parser.parse_args()
+
+if options.dev_id:
+ adapter_path = manager.FindAdapter(options.dev_id)
+else:
+ adapter_path = manager.DefaultAdapter()
+
+adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+ "org.bluez.Adapter")
+
+if (len(args) < 1):
+ print "Usage: %s <command>" % (sys.argv[0])
+ print ""
+ print " list"
+ print " services <address>"
+ print " discover <service path>"
+ print " chars <service path>"
+ sys.exit(1)
+
+if (args[0] == "list"):
+ for path in adapter.ListDevices():
+ device = dbus.Interface(bus.get_object("org.bluez", path),
+ "org.bluez.Device")
+ devprop = device.GetProperties()
+ print "[ %s ]" % devprop["Address"]
+ for path in devprop["Services"]:
+
+ service = dbus.Interface(bus.get_object("org.bluez", path),
+ "org.bluez.Characteristic")
+ srvprop = service.GetProperties()
+ print " * %s" % (path)
+ print " UUID: %s" % srvprop["UUID"]
+ print " Chars: ",
+ for char in srvprop["Characteristics"]:
+ print "%s " % char,
+ print
+ print
+ print
+ sys.exit(0)
+
+if (args[0] == "services"):
+ if (len(args) < 2):
+ print "Need address parameter"
+ else:
+ path = adapter.FindDevice(args[1])
+ device = dbus.Interface(bus.get_object("org.bluez", path),
+ "org.bluez.Device")
+ properties = device.GetProperties()
+ for path in properties["Services"]:
+ print path
+ sys.exit(0)
+
+if (args[0] == "discover"):
+ if (len(args) < 2):
+ print "Need service path parameter"
+ else:
+ service = dbus.Interface(bus.get_object("org.bluez", args[1]),
+ "org.bluez.Characteristic")
+ for path in service.DiscoverCharacteristics():
+ print path
+ sys.exit(0)
+
+if (args[0] == "chars"):
+ if (len(args) < 2):
+ print "Need service path parameter"
+ else:
+ service = dbus.Interface(bus.get_object("org.bluez", args[1]),
+ "org.bluez.Characteristic")
+ srvprop = service.GetProperties()
+ for path in srvprop["Characteristics"]:
+ print "[ %s ]" % (path)
+ char = dbus.Interface(bus.get_object("org.bluez", path),
+ "org.bluez.Characteristic")
+ charprop = char.GetProperties()
+ print " Name: %s" % charprop["Name"]
+ print " UUID: %s" % charprop["UUID"]
+ print
+ print
+ sys.exit(0)
+
+print "Unknown command"
+sys.exit(1)
--
1.7.4.1


2011-03-14 21:19:43

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v2 4/5] Add DiscoverCharacteristics method to the Attribute API

---
doc/attribute-api.txt | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/doc/attribute-api.txt b/doc/attribute-api.txt
index 23808e6..f2778f3 100644
--- a/doc/attribute-api.txt
+++ b/doc/attribute-api.txt
@@ -50,6 +50,14 @@ Methods dict GetProperties()
Returns all properties for the interface. See the
Properties section for the available properties.

+ array{object} DiscoverCharacteristics()
+
+ Discover all characteristics that belongs in this service.
+ When it returns all the characteristics paths will be
+ already registered. It will return the characteristics paths
+ as soon as they are discovered. After that it will try to
+ read all values.
+
RegisterCharacteristicsWatcher(object agent)

Register a watcher to monitor characteristic changes.
--
1.7.4.1


2011-03-14 21:19:42

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v2 3/5] Fix not returning an error when DiscoverCharacteristics() fails

When the connection fails an error should be returned to inform
the user.

This adds a field to store the DBusMessage that caused the error,
so we can send the correct reply.
---
attrib/client.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/attrib/client.c b/attrib/client.c
index 14fd911..aa22a79 100644
--- a/attrib/client.c
+++ b/attrib/client.c
@@ -59,6 +59,7 @@ struct gatt_service {
char *path;
GSList *primary;
GAttrib *attrib;
+ DBusMessage *msg;
int psm;
gboolean listen;
};
@@ -335,6 +336,12 @@ static void connect_cb(GIOChannel *chan, GError *gerr, gpointer user_data)
struct gatt_service *gatt = user_data;

if (gerr) {
+ if (gatt->msg) {
+ DBusMessage *reply = btd_error_failed(gatt->msg,
+ gerr->message);
+ g_dbus_send_message(connection, reply);
+ }
+
error("%s", gerr->message);
goto fail;
}
--
1.7.4.1


2011-03-14 21:19:41

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v2 2/5] Fix the behaviour of the DiscoverCharacteristics method

The previous behaviour could lead to some problems, as it returned
as soon as possible. To avoid problems we return just after as the
characteristics are discovered, and to save a few round trips we
return the path of all characteristics that belong to this service.

After this method return it will try to read the characteristics
values.
---
attrib/client.c | 32 ++++++++++++++++++++++++++++----
1 files changed, 28 insertions(+), 4 deletions(-)

diff --git a/attrib/client.c b/attrib/client.c
index f0b0b14..14fd911 100644
--- a/attrib/client.c
+++ b/attrib/client.c
@@ -96,6 +96,7 @@ struct characteristic {
struct query_data {
struct primary *prim;
struct characteristic *chr;
+ DBusMessage *msg;
uint16_t handle;
};

@@ -863,6 +864,8 @@ static void update_all_chars(gpointer data, gpointer user_data)
static void char_discovered_cb(GSList *characteristics, guint8 status,
gpointer user_data)
{
+ DBusMessage *reply;
+ DBusMessageIter iter, array_iter;
struct query_data *current = user_data;
struct primary *prim = current->prim;
struct att_primary *att = prim->att;
@@ -871,8 +874,10 @@ static void char_discovered_cb(GSList *characteristics, guint8 status,
GSList *l;

if (status != 0) {
- DBG("Discover all characteristics failed: %s",
- att_ecode2str(status));
+ const char *str = att_ecode2str(status);
+
+ DBG("Discover all characteristics failed: %s", str);
+ reply = btd_error_failed(current->msg, str);
goto fail;
}

@@ -909,9 +914,26 @@ static void char_discovered_cb(GSList *characteristics, guint8 status,
store_characteristics(gatt, prim);
register_characteristics(prim);

+ reply = dbus_message_new_method_return(current->msg);
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter);
+
+ for (l = prim->chars; l; l = l->next) {
+ struct characteristic *chr = l->data;
+
+ dbus_message_iter_append_basic(&array_iter,
+ DBUS_TYPE_OBJECT_PATH, &chr->path);
+ }
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
g_slist_foreach(prim->chars, update_all_chars, prim);

fail:
+ g_dbus_send_message(connection, reply);
g_attrib_unref(gatt->attrib);
g_free(current);
}
@@ -933,11 +955,12 @@ static DBusMessage *discover_char(DBusConnection *conn, DBusMessage *msg,

qchr = g_new0(struct query_data, 1);
qchr->prim = prim;
+ qchr->msg = dbus_message_ref(msg);

gatt_discover_char(gatt->attrib, att->start, att->end,
char_discovered_cb, qchr);

- return dbus_message_new_method_return(msg);
+ return NULL;
}

static DBusMessage *prim_get_properties(DBusConnection *conn, DBusMessage *msg,
@@ -983,7 +1006,8 @@ static DBusMessage *prim_get_properties(DBusConnection *conn, DBusMessage *msg,
}

static GDBusMethodTable prim_methods[] = {
- { "DiscoverCharacteristics", "", "", discover_char },
+ { "DiscoverCharacteristics", "", "ao", discover_char,
+ G_DBUS_METHOD_FLAG_ASYNC },
{ "RegisterCharacteristicsWatcher", "o", "",
register_watcher },
{ "UnregisterCharacteristicsWatcher", "o", "",
--
1.7.4.1