2011-02-23 13:49:39

by Elvis Pfutzenreuter

[permalink] [raw]
Subject: [PATCH 1/2 v3] Add generic descriptor support to Attribute API document

This patch proposes extensions to Attribute API, giving access to all
characteristic descriptors (beyond 'Description' and 'Format').

Client Characteristic Configuration automatic update upon Watcher
registering will be handled by another patch series.
---
doc/attribute-api.txt | 30 ++++++++++++++++++++++++++++++
1 files changed, 30 insertions(+), 0 deletions(-)

diff --git a/doc/attribute-api.txt b/doc/attribute-api.txt
index 23808e6..bb7cbfa 100644
--- a/doc/attribute-api.txt
+++ b/doc/attribute-api.txt
@@ -104,6 +104,7 @@ Methods dict GetProperties()

Possible Errors: org.bluez.Error.InvalidArguments

+
Properties string UUID [readonly]

UUID128 of this characteristic.
@@ -143,6 +144,35 @@ Properties string UUID [readonly]
Friendly representation of the Characteristic Value
based on the format attribute.

+ dict Descriptors [readwrite]
+
+ Dict of descriptors for this characteristic.
+
+ This dict contains only the descriptors not already
+ covered by other properties (v.g. Description, Format).
+
+ Each descriptor is mapped to an unique object path,
+ which is the dict key.
+
+ Each dict value is, in turn, a dict with at least
+ the following keys:
+
+ {
+ "UUID": string. Descriptor UUID, always present
+ "Value": array of bytes. Raw descriptor value,
+ present only when/if descriptor value
+ has been fetched.
+ }
+
+ When updating a descriptor value using SetProperty(),
+ only one descriptor at a time may be updated in order
+ to guarantee unambiguous error reporting. In other
+ words, when calling SetProperty('Descriptors', dict),
+ dict must have exactly one entry.
+
+ Descriptor's UUID may not be updated. If present, it is
+ ignored by SetProperty().
+

Characteristic Watcher hierarchy
===============================
--
1.7.1



2011-02-24 20:46:16

by Anderson Lizardo

[permalink] [raw]
Subject: Re: [PATCH 1/2 v3] Add generic descriptor support to Attribute API document

Hi Elvis,

On Thu, Feb 24, 2011 at 4:34 PM, Elvis Pf?tzenreuter <[email protected]> wrote:
>> With all those restrictions for writing, do you think it makes sense
>> to allow writing to the "Descriptors" property? Can you mention
>> situations where you might want applications to modify descriptors?
>
> Apart from CCC (which we plan to deal with in another series), no :(
>
> But GATT has this feature, so a general API should IMHO have it, since some
> future GATT-based profile may well use it.
>
> Actually, there is just one restriction for writing: one descriptor at a time,
> and I propose this just because of difficulties in error reporting (if e.g.
> 2 out of 5 descriptors could not be updated due to lack of permissions, yet
> just 1 error can be reported back).

As we discussed on IRC, let's wait for stabilization and clarification
or our D-Bus API for GATT services and characteristics, then we can
introduce a descriptor access API upstream.

Anyway, your patch is useful for whoever wants direct access to descriptors :)

Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

2011-02-24 19:34:26

by Elvis Pfutzenreuter

[permalink] [raw]
Subject: Re: [PATCH 1/2 v3] Add generic descriptor support to Attribute API document


On 24 Feb 2011, at 15:29 , Anderson Lizardo wrote:

> Hi Elvis,
>
> On Wed, Feb 23, 2011 at 10:49 AM, Elvis Pf?tzenreuter <[email protected]> wrote:
>> This patch proposes extensions to Attribute API, giving access to all
>> characteristic descriptors (beyond 'Description' and 'Format').
>>
>> Client Characteristic Configuration automatic update upon Watcher
>> registering will be handled by another patch series.
>> ---
>> doc/attribute-api.txt | 30 ++++++++++++++++++++++++++++++
>> 1 files changed, 30 insertions(+), 0 deletions(-)
>>
>> diff --git a/doc/attribute-api.txt b/doc/attribute-api.txt
>> index 23808e6..bb7cbfa 100644
>> --- a/doc/attribute-api.txt
>> +++ b/doc/attribute-api.txt
>> @@ -104,6 +104,7 @@ Methods dict GetProperties()
>>
>> Possible Errors: org.bluez.Error.InvalidArguments
>>
>> +
>> Properties string UUID [readonly]
>>
>> UUID128 of this characteristic.
>> @@ -143,6 +144,35 @@ Properties string UUID [readonly]
>> Friendly representation of the Characteristic Value
>> based on the format attribute.
>>
>> + dict Descriptors [readwrite]
>> +
>> + Dict of descriptors for this characteristic.
>> +
>> + This dict contains only the descriptors not already
>> + covered by other properties (v.g. Description, Format).
>> +
>> + Each descriptor is mapped to an unique object path,
>> + which is the dict key.
>> +
>> + Each dict value is, in turn, a dict with at least
>> + the following keys:
>> +
>> + {
>> + "UUID": string. Descriptor UUID, always present
>> + "Value": array of bytes. Raw descriptor value,
>> + present only when/if descriptor value
>> + has been fetched.
>> + }
>> +
>> + When updating a descriptor value using SetProperty(),
>> + only one descriptor at a time may be updated in order
>> + to guarantee unambiguous error reporting. In other
>> + words, when calling SetProperty('Descriptors', dict),
>> + dict must have exactly one entry.
>> +
>> + Descriptor's UUID may not be updated. If present, it is
>> + ignored by SetProperty().
>
> With all those restrictions for writing, do you think it makes sense
> to allow writing to the "Descriptors" property? Can you mention
> situations where you might want applications to modify descriptors?

Apart from CCC (which we plan to deal with in another series), no :(

But GATT has this feature, so a general API should IMHO have it, since some
future GATT-based profile may well use it.

Actually, there is just one restriction for writing: one descriptor at a time,
and I propose this just because of difficulties in error reporting (if e.g.
2 out of 5 descriptors could not be updated due to lack of permissions, yet
just 1 error can be reported back).

2011-02-24 18:29:22

by Anderson Lizardo

[permalink] [raw]
Subject: Re: [PATCH 1/2 v3] Add generic descriptor support to Attribute API document

Hi Elvis,

On Wed, Feb 23, 2011 at 10:49 AM, Elvis Pf?tzenreuter <[email protected]> wrote:
> This patch proposes extensions to Attribute API, giving access to all
> characteristic descriptors (beyond 'Description' and 'Format').
>
> Client Characteristic Configuration automatic update upon Watcher
> registering will be handled by another patch series.
> ---
> ?doc/attribute-api.txt | ? 30 ++++++++++++++++++++++++++++++
> ?1 files changed, 30 insertions(+), 0 deletions(-)
>
> diff --git a/doc/attribute-api.txt b/doc/attribute-api.txt
> index 23808e6..bb7cbfa 100644
> --- a/doc/attribute-api.txt
> +++ b/doc/attribute-api.txt
> @@ -104,6 +104,7 @@ Methods ? ? ? ? ? ? dict GetProperties()
>
> ? ? ? ? ? ? ? ? ? ? ? ?Possible Errors: org.bluez.Error.InvalidArguments
>
> +
> ?Properties ? ? string UUID [readonly]
>
> ? ? ? ? ? ? ? ? ? ? ? ?UUID128 of this characteristic.
> @@ -143,6 +144,35 @@ Properties ? ? ? ? string UUID [readonly]
> ? ? ? ? ? ? ? ? ? ? ? ?Friendly representation of the Characteristic Value
> ? ? ? ? ? ? ? ? ? ? ? ?based on the format attribute.
>
> + ? ? ? ? ? ? ? dict Descriptors [readwrite]
> +
> + ? ? ? ? ? ? ? ? ? ? ? Dict of descriptors for this characteristic.
> +
> + ? ? ? ? ? ? ? ? ? ? ? This dict contains only the descriptors not already
> + ? ? ? ? ? ? ? ? ? ? ? covered by other properties (v.g. Description, Format).
> +
> + ? ? ? ? ? ? ? ? ? ? ? Each descriptor is mapped to an unique object path,
> + ? ? ? ? ? ? ? ? ? ? ? which is the dict key.
> +
> + ? ? ? ? ? ? ? ? ? ? ? Each dict value is, in turn, a dict with at least
> + ? ? ? ? ? ? ? ? ? ? ? the following keys:
> +
> + ? ? ? ? ? ? ? ? ? ? ? {
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "UUID": string. Descriptor UUID, always present
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "Value": array of bytes. Raw descriptor value,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?present only when/if descriptor value
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?has been fetched.
> + ? ? ? ? ? ? ? ? ? ? ? }
> +
> + ? ? ? ? ? ? ? ? ? ? ? When updating a descriptor value using SetProperty(),
> + ? ? ? ? ? ? ? ? ? ? ? only one descriptor at a time may be updated in order
> + ? ? ? ? ? ? ? ? ? ? ? to guarantee unambiguous error reporting. In other
> + ? ? ? ? ? ? ? ? ? ? ? words, when calling SetProperty('Descriptors', dict),
> + ? ? ? ? ? ? ? ? ? ? ? dict must have exactly one entry.
> +
> + ? ? ? ? ? ? ? ? ? ? ? Descriptor's UUID may not be updated. If present, it is
> + ? ? ? ? ? ? ? ? ? ? ? ignored by SetProperty().

With all those restrictions for writing, do you think it makes sense
to allow writing to the "Descriptors" property? Can you mention
situations where you might want applications to modify descriptors?

Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

2011-02-23 13:49:40

by Elvis Pfutzenreuter

[permalink] [raw]
Subject: [PATCH 2/2 v3] Implement generic descriptor access to Attribute API

This patch implements the proposed API changes.

Client Characteristic Configuration automatic update upon Watcher
registering will be handled by another series.
---
attrib/client.c | 367 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 356 insertions(+), 11 deletions(-)

diff --git a/attrib/client.c b/attrib/client.c
index 0f9ba3e..711813b 100644
--- a/attrib/client.c
+++ b/attrib/client.c
@@ -79,6 +79,15 @@ struct primary {
GSList *watchers;
};

+struct descriptor {
+ char *path;
+ uint16_t handle;
+ uuid_t uuid;
+ char type[MAX_LEN_UUID_STR + 1];
+ uint8_t *value;
+ size_t vlen;
+};
+
struct characteristic {
struct primary *prim;
char *path;
@@ -91,12 +100,14 @@ struct characteristic {
struct format *format;
uint8_t *value;
size_t vlen;
+ GSList *descriptors;
};

struct query_data {
struct primary *prim;
struct characteristic *chr;
uint16_t handle;
+ struct descriptor *descr;
};

struct watcher {
@@ -110,10 +121,22 @@ static GSList *gatt_services = NULL;

static DBusConnection *connection;

+static void descriptor_free(void *user_data)
+{
+ struct descriptor *descr = user_data;
+
+ g_free(descr->path);
+ g_free(descr->value);
+
+ g_free(descr);
+}
+
static void characteristic_free(void *user_data)
{
struct characteristic *chr = user_data;

+ g_slist_foreach(chr->descriptors, (GFunc) descriptor_free, NULL);
+
g_free(chr->path);
g_free(chr->desc);
g_free(chr->format);
@@ -188,11 +211,90 @@ static int watcher_cmp(gconstpointer a, gconstpointer b)
return g_strcmp0(watcher->path, match->path);
}

+static void add_descriptor_dict(DBusMessageIter *entry,
+ struct descriptor *descr)
+{
+ DBusMessageIter descr_dict_var;
+ DBusMessageIter descr_dict;
+ const char *uuid;
+ const uint8_t *value;
+ size_t vlen;
+
+ value = descr->value;
+ vlen = descr->vlen;
+ uuid = descr->type;
+
+ dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+ &descr_dict_var);
+
+ dbus_message_iter_open_container(&descr_dict_var, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+ &descr_dict);
+
+ dict_append_entry(&descr_dict, "UUID", DBUS_TYPE_STRING, &uuid);
+
+ if (value)
+ dict_append_array(&descr_dict, "Value", DBUS_TYPE_BYTE,
+ &value, vlen);
+
+ dbus_message_iter_close_container(&descr_dict_var, &descr_dict);
+ dbus_message_iter_close_container(entry, &descr_dict_var);
+}
+
+static void add_descriptors_dict(DBusMessageIter *outer_entry,
+ struct characteristic *chr)
+{
+ DBusMessageIter descrs_dict_var;
+ DBusMessageIter descrs_dict;
+ GSList *l;
+
+ dbus_message_iter_open_container(outer_entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+ &descrs_dict_var);
+
+ dbus_message_iter_open_container(&descrs_dict_var, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+ &descrs_dict);
+
+ for (l = chr->descriptors; l; l = l->next) {
+ struct descriptor *descr = l->data;
+ const char *key;
+ DBusMessageIter entry;
+
+ key = descr->path;
+
+ dbus_message_iter_open_container(&descrs_dict,
+ DBUS_TYPE_DICT_ENTRY, NULL, &entry);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+ add_descriptor_dict(&entry, descr);
+
+ dbus_message_iter_close_container(&descrs_dict, &entry);
+ }
+
+ dbus_message_iter_close_container(&descrs_dict_var, &descrs_dict);
+ dbus_message_iter_close_container(outer_entry, &descrs_dict_var);
+}
+
static void append_char_dict(DBusMessageIter *iter, struct characteristic *chr)
{
DBusMessageIter dict;
+ DBusMessageIter entry;
const char *name = "";
char *uuid;
+ const char *key;

dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
@@ -214,6 +316,19 @@ static void append_char_dict(DBusMessageIter *iter, struct characteristic *chr)
dict_append_array(&dict, "Value", DBUS_TYPE_BYTE, &chr->value,
chr->vlen);

+ /* Descriptors entry */
+
+ dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+
+ key = "Descriptors";
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+ add_descriptors_dict(&entry, chr);
+
+ dbus_message_iter_close_container(&dict, &entry);
+
/* FIXME: Missing Format, Value and Representation */

dbus_message_iter_close_container(iter, &dict);
@@ -245,6 +360,19 @@ static int characteristic_set_value(struct characteristic *chr,
return 0;
}

+static int descriptor_set_value(struct descriptor *descr,
+ const uint8_t *value, size_t vlen)
+{
+ descr->value = g_try_realloc(descr->value, vlen);
+ if (descr->value == NULL)
+ return -ENOMEM;
+
+ memcpy(descr->value, value, vlen);
+ descr->vlen = vlen;
+
+ return 0;
+}
+
static void update_watchers(gpointer data, gpointer user_data)
{
struct watcher *w = data;
@@ -483,6 +611,172 @@ static DBusMessage *set_value(DBusConnection *conn, DBusMessage *msg,
return dbus_message_new_method_return(msg);
}

+static int descriptor_path_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct descriptor *descr = a;
+ const char *path = b;
+
+ return strcmp(descr->path, path);
+}
+
+static struct descriptor *find_descriptor_by_path(struct characteristic *chr,
+ const char *path)
+{
+ GSList *ldescr;
+
+ ldescr = g_slist_find_custom(chr->descriptors, path,
+ descriptor_path_cmp);
+
+ if (ldescr)
+ return ldescr->data;
+
+ return NULL;
+}
+
+static int descriptor_handle_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct descriptor *descr = a;
+ uint16_t handle = GPOINTER_TO_UINT(b);
+
+ return descr->handle - handle;
+}
+
+static struct descriptor *find_descriptor_by_handle(struct characteristic *chr,
+ guint handle)
+{
+ GSList *ldescr;
+
+ ldescr = g_slist_find_custom(chr->descriptors, GUINT_TO_POINTER(handle),
+ descriptor_handle_cmp);
+
+ if (ldescr)
+ return ldescr->data;
+
+ return NULL;
+}
+
+static DBusMessage *set_descriptor(DBusConnection *conn, DBusMessage *msg,
+ struct characteristic *chr, const char *path,
+ uint8_t *value, int len)
+{
+ struct gatt_service *gatt = chr->prim->gatt;
+ GError *gerr = NULL;
+ struct descriptor *descr;
+
+ descr = find_descriptor_by_path(chr, path);
+
+ if (!descr)
+ return btd_error_invalid_args(msg);
+
+ if (l2cap_connect(gatt, &gerr, FALSE) < 0) {
+ DBusMessage *reply = btd_error_failed(msg, gerr->message);
+ g_error_free(gerr);
+ return reply;
+ }
+
+ gatt_write_cmd(gatt->attrib, descr->handle, value, len, NULL, NULL);
+
+ descriptor_set_value(descr, value, len);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *set_descriptor_front(DBusConnection *conn,
+ DBusMessage *msg, DBusMessageIter *iter,
+ struct characteristic *chr)
+{
+ DBusMessageIter dict, entry;
+ DBusMessageIter descr_iter, descr_dict, descr_entry, sub;
+ int ctype;
+ const char *descriptor_path;
+ const char *key;
+ uint8_t *value;
+ int len;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+ return btd_error_invalid_args(msg);
+
+ dbus_message_iter_recurse(iter, &dict);
+
+ if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY)
+ return btd_error_invalid_args(msg);
+
+ /* Unpack descriptor entry */
+
+ dbus_message_iter_recurse(&dict, &entry);
+ ctype = dbus_message_iter_get_arg_type(&entry);
+
+ if (ctype != DBUS_TYPE_OBJECT_PATH && ctype != DBUS_TYPE_STRING)
+ return btd_error_invalid_args(msg);
+
+ /* Got descriptor path */
+
+ dbus_message_iter_get_basic(&entry, &descriptor_path);
+
+ dbus_message_iter_next(&entry);
+
+ /* Get descriptor dict */
+
+ if (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_VARIANT)
+ dbus_message_iter_recurse(&entry, &descr_iter);
+ else
+ descr_iter = entry;
+
+ if (dbus_message_iter_get_arg_type(&descr_iter) != DBUS_TYPE_ARRAY)
+ return btd_error_invalid_args(msg);
+
+ /* Unpack descriptor dict */
+
+ dbus_message_iter_recurse(&descr_iter, &descr_dict);
+
+ while ((ctype = dbus_message_iter_get_arg_type(&descr_dict)) !=
+ DBUS_TYPE_INVALID) {
+ if (ctype != DBUS_TYPE_DICT_ENTRY)
+ return btd_error_invalid_args(msg);
+
+ /* Interpret descriptor dict's entry */
+
+ dbus_message_iter_recurse(&descr_dict, &descr_entry);
+
+ ctype = dbus_message_iter_get_arg_type(&descr_entry);
+ if (ctype != DBUS_TYPE_STRING)
+ return btd_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&descr_entry, &key);
+
+ if (!g_str_equal(key, "Value")) {
+ dbus_message_iter_next(&descr_dict);
+ continue;
+ }
+
+ /* Key is Value, get array of bytes */
+
+ dbus_message_iter_next(&descr_entry);
+
+ ctype = dbus_message_iter_get_arg_type(&descr_entry);
+ if (ctype != DBUS_TYPE_ARRAY)
+ return btd_error_invalid_args(msg);
+
+ ctype = dbus_message_iter_get_element_type(&descr_entry);
+ if (ctype != DBUS_TYPE_BYTE)
+ return btd_error_invalid_args(msg);
+
+ dbus_message_iter_recurse(&descr_entry, &sub);
+ dbus_message_iter_get_fixed_array(&sub, &value, &len);
+
+ dbus_message_iter_next(&descr_dict);
+ }
+
+ /* Just one descriptor entry per SetProperty() call */
+
+ dbus_message_iter_next(&dict);
+
+ if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID)
+ return btd_error_invalid_args(msg);
+
+ return set_descriptor(conn, msg, chr, descriptor_path, value, len);
+}
+
static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
void *data)
{
@@ -525,6 +819,8 @@ static DBusMessage *set_property(DBusConnection *conn,

if (g_str_equal("Value", property))
return set_value(conn, msg, &sub, chr);
+ else if (g_str_equal("Descriptors", property))
+ return set_descriptor_front(conn, msg, &sub, chr);

return btd_error_invalid_args(msg);
}
@@ -737,6 +1033,26 @@ done:
g_free(current);
}

+static void update_descriptor(guint8 status, const guint8 *pdu, guint16 len,
+ gpointer user_data)
+{
+ struct query_data *current = user_data;
+ struct gatt_service *gatt = current->prim->gatt;
+ struct descriptor *descr = current->descr;
+
+ if (status != 0)
+ goto done;
+
+ if (len < 2)
+ goto done;
+
+ descriptor_set_value(descr, pdu + 1, len - 1);
+
+done:
+ g_attrib_unref(gatt->attrib);
+ g_free(current);
+}
+
static void update_char_value(guint8 status, const guint8 *pdu,
guint16 len, gpointer user_data)
{
@@ -762,6 +1078,31 @@ static void update_char_value(guint8 status, const guint8 *pdu,
g_free(current);
}

+static struct descriptor *char_add_descriptor(struct characteristic *chr,
+ uint16_t handle, uuid_t uuid)
+{
+ struct descriptor *descr;
+
+ descr = find_descriptor_by_handle(chr, handle);
+
+ if (!descr) {
+ descr = g_new0(struct descriptor, 1);
+ descr->path = g_strdup_printf("%s/descriptor%04x",
+ chr->path, handle);
+ descr->handle = handle;
+ chr->descriptors = g_slist_append(chr->descriptors, descr);
+ }
+
+ if (sdp_uuid_cmp(&uuid, &descr->uuid) != 0) {
+ char *uuidstr = bt_uuid2string(&uuid);
+ strcpy(descr->type, uuidstr);
+ g_free(uuidstr);
+ descr->uuid = uuid;
+ }
+
+ return descr;
+}
+
static int uuid_desc16_cmp(uuid_t *uuid, guint16 desc)
{
uuid_t u16;
@@ -783,7 +1124,7 @@ static void descriptor_cb(guint8 status, const guint8 *pdu, guint16 plen,
if (status != 0)
goto done;

- DBG("Find Information Response received");
+ DBG("Discover Descriptors Response received");

list = dec_find_info_resp(pdu, plen, &format);
if (list == NULL)
@@ -797,15 +1138,14 @@ static void descriptor_cb(guint8 status, const guint8 *pdu, guint16 plen,

handle = att_get_u16(info);

- if (format == 0x01) {
+ if (format == 0x01)
sdp_uuid16_create(&uuid, att_get_u16(&info[2]));
- } else {
- /* Currently, only "user description" and "presentation
- * format" descriptors are used, and both have 16-bit
- * UUIDs. Therefore there is no need to support format
- * 0x02 yet. */
+ else if (format == 0x02)
+ // FIXME use att_get_u128
+ sdp_uuid128_create(&uuid, &info[2]);
+ else
continue;
- }
+
qfmt = g_new0(struct query_data, 1);
qfmt->prim = current->prim;
qfmt->chr = current->chr;
@@ -819,8 +1159,13 @@ static void descriptor_cb(guint8 status, const guint8 *pdu, guint16 plen,
gatt->attrib = g_attrib_ref(gatt->attrib);
gatt_read_char(gatt->attrib, handle,
update_char_format, qfmt);
- } else
- g_free(qfmt);
+ } else {
+ qfmt->descr = char_add_descriptor(current->chr, handle,
+ uuid);
+ gatt->attrib = g_attrib_ref(gatt->attrib);
+ gatt_read_char(gatt->attrib, handle, update_descriptor,
+ qfmt);
+ }
}

att_data_list_free(list);
@@ -888,7 +1233,7 @@ static void char_discovered_cb(GSList *characteristics, guint8 status,
strncpy(chr->type, current_chr->uuid, sizeof(chr->type));

if (previous_end)
- *previous_end = current_chr->handle;
+ *previous_end = current_chr->handle - 1;

previous_end = &chr->end;

--
1.7.1