2014-03-27 13:21:10

by Claudio Takahasi

[permalink] [raw]
Subject: [PATCH BlueZ v0 0/5] Add GATT Characteristic Flags

This patchset adds GattCharacteristic1 "Flags" property.

Extended properties are not supported yet.

Alvaro Silva (1):
test: Add permissions for Alert Level of gatt-service

Claudio Takahasi (4):
gatt: Add parsing GattCharacteristic1 Flags
gatt: Set read and write callbacks based on Flags
gatt: Make Characteristic Flags optional
doc: Remove Core SPEC page number from gatt-api.txt

doc/gatt-api.txt | 13 ++++----
src/gatt-dbus.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++---
tools/gatt-service.c | 43 ++++++++++++++++++++----
3 files changed, 131 insertions(+), 18 deletions(-)

--
1.8.3.1



2014-03-28 12:25:18

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH BlueZ v0 0/5] Add GATT Characteristic Flags

Hi Claudio,

On Thu, Mar 27, 2014, Claudio Takahasi wrote:
> This patchset adds GattCharacteristic1 "Flags" property.
>
> Extended properties are not supported yet.
>
> Alvaro Silva (1):
> test: Add permissions for Alert Level of gatt-service
>
> Claudio Takahasi (4):
> gatt: Add parsing GattCharacteristic1 Flags
> gatt: Set read and write callbacks based on Flags
> gatt: Make Characteristic Flags optional
> doc: Remove Core SPEC page number from gatt-api.txt
>
> doc/gatt-api.txt | 13 ++++----
> src/gatt-dbus.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++---
> tools/gatt-service.c | 43 ++++++++++++++++++++----
> 3 files changed, 131 insertions(+), 18 deletions(-)

All patches have been applied. Thanks.

Johan

2014-03-27 13:35:44

by Claudio Takahasi

[permalink] [raw]
Subject: [PATCH BlueZ v1 5/5] doc: Remove Core SPEC page number from gatt-api.txt

Remove Core SPEC page number from the API document to avoid wrong
page reference when the SPEC changes.
---
Changes from v0 to v1: Fixing typo.

doc/gatt-api.txt | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/doc/gatt-api.txt b/doc/gatt-api.txt
index 0f6b084..95603fc 100644
--- a/doc/gatt-api.txt
+++ b/doc/gatt-api.txt
@@ -65,13 +65,12 @@ Properties string UUID [read-only]
array{string} Flags [read-only, optional]

Defines how the characteristic value can be used. See
- Core spec page 1898, "Table 3.5: Characteristic
- Properties bit field" and page 1900, "Table 3.8:
- Characteristic Extended Properties bit field". Allowed
- values: "broadcast", "read", "write-without-response",
- "write", "notify", "indicate",
- "authenticated-signed-writes", "reliable-write", and
- "writable-auxiliaries".
+ Core spec "Table 3.5: Characteristic Properties bit
+ field", and "Table 3.8: Characteristic Extended
+ Properties bit field". Allowed values: "broadcast",
+ "read", "write-without-response", "write", "notify",
+ "indicate", "authenticated-signed-writes",
+ "reliable-write", and "writable-auxiliaries".


Characteristic Descriptors hierarchy
--
1.8.3.1


2014-03-27 13:21:14

by Claudio Takahasi

[permalink] [raw]
Subject: [PATCH BlueZ v0 4/5] test: Add permissions for Alert Level of gatt-service

From: Alvaro Silva <[email protected]>

This patch adds properties to Alert Level characteristic of the
Immediate Alert Service. IAS specification defines Write Without
Response as mandatory.
---
tools/gatt-service.c | 43 +++++++++++++++++++++++++++++++++++++------
1 file changed, 37 insertions(+), 6 deletions(-)

diff --git a/tools/gatt-service.c b/tools/gatt-service.c
index 624b835..e319163 100644
--- a/tools/gatt-service.c
+++ b/tools/gatt-service.c
@@ -54,8 +54,18 @@ struct characteristic {
char *path;
uint8_t *value;
int vlen;
+ const char **props;
};

+/*
+ * Alert Level support Write Without Response only. Supported
+ * properties are defined at doc/gatt-api.txt. See "Flags"
+ * property of the GattCharacteristic1.
+ */
+static const char const *ias_alert_level_props[] = {
+ "write-without-response",
+ NULL };
+
static gboolean chr_get_uuid(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *user_data)
{
@@ -85,6 +95,25 @@ static gboolean chr_get_value(const GDBusPropertyTable *property,
return TRUE;
}

+static gboolean chr_get_props(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct characteristic *chr = data;
+ DBusMessageIter array;
+ int i;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array);
+
+ for (i = 0; chr->props[i]; i++)
+ dbus_message_iter_append_basic(&array,
+ DBUS_TYPE_STRING, &chr->props[i]);
+
+ dbus_message_iter_close_container(iter, &array);
+
+ return TRUE;
+}
+
static void chr_set_value(const GDBusPropertyTable *property,
DBusMessageIter *iter,
GDBusPendingPropertySet id, void *user_data)
@@ -119,6 +148,7 @@ static void chr_set_value(const GDBusPropertyTable *property,
static const GDBusPropertyTable chr_properties[] = {
{ "UUID", "s", chr_get_uuid },
{ "Value", "ay", chr_get_value, chr_set_value, NULL },
+ { "Flags", "as", chr_get_props, NULL, NULL },
{ }
};

@@ -173,6 +203,7 @@ static void chr_iface_destroy(gpointer user_data)

static gboolean register_characteristic(DBusConnection *conn, const char *uuid,
const uint8_t *value, int vlen,
+ const char **props,
const char *service_path)
{
struct characteristic *chr;
@@ -188,6 +219,7 @@ static gboolean register_characteristic(DBusConnection *conn, const char *uuid,
chr->value = g_memdup(value, vlen);
chr->vlen = vlen;
chr->path = path;
+ chr->props = props;

if (!g_dbus_register_interface(conn, path, GATT_CHR_IFACE,
NULL, NULL, chr_properties,
@@ -225,12 +257,11 @@ static void create_services()
if (!service_path)
return;

- /* Add Alert Level Characteristic to Immediate Alert Service
- * According to the IAS SPEC, reading <<Alert level>> is not allowed.
- * "Value" is readable for testing purpose only.
- */
- if (!register_characteristic(connection, ALERT_LEVEL_CHR_UUID, &level,
- sizeof(level), service_path)) {
+ /* Add Alert Level Characteristic to Immediate Alert Service */
+ if (!register_characteristic(connection, ALERT_LEVEL_CHR_UUID,
+ &level, sizeof(level),
+ ias_alert_level_props,
+ service_path)) {
printf("Couldn't register Alert Level characteristic (IAS)\n");
g_dbus_unregister_interface(connection, service_path,
GATT_SERVICE_IFACE);
--
1.8.3.1


2014-03-27 13:21:12

by Claudio Takahasi

[permalink] [raw]
Subject: [PATCH BlueZ v0 2/5] gatt: Set read and write callbacks based on Flags

This patch checks the characteristic property bitmask before setting
read and write callbacks. This approach avoids additional GDBusProxy
calls and later verifications if the characteristic doesn't support
read or write procedures.
---
src/gatt-dbus.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index 4eaf562..fbcbcfe 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -364,6 +364,8 @@ static int register_external_characteristics(GSList *proxies)
bt_uuid_t uuid;
struct btd_attribute *attr;
GDBusProxy *proxy = list->data;
+ btd_attr_write_t write_cb;
+ btd_attr_read_t read_cb;
uint8_t propmask = 0;

if (!g_dbus_proxy_get_property(proxy, "UUID", &iter))
@@ -384,8 +386,18 @@ static int register_external_characteristics(GSList *proxies)
if (!propmask)
return -EINVAL;

- attr = btd_gatt_add_char(&uuid, propmask, proxy_read_cb,
- proxy_write_cb);
+ if (propmask & GATT_CHR_PROP_READ)
+ read_cb = proxy_read_cb;
+ else
+ read_cb = NULL;
+
+ if (propmask & (GATT_CHR_PROP_WRITE |
+ GATT_CHR_PROP_WRITE_WITHOUT_RESP))
+ write_cb = proxy_write_cb;
+ else
+ write_cb = NULL;
+
+ attr = btd_gatt_add_char(&uuid, propmask, read_cb, write_cb);
if (!attr)
return -EINVAL;

--
1.8.3.1


2014-03-27 13:21:15

by Claudio Takahasi

[permalink] [raw]
Subject: [PATCH BlueZ v0 5/5] doc: Remove Core SPEC page number from gatt-api.txt

Remove Core SPEC page number from the API document to avoid wrong
page reference when the SPEC changes.
---
doc/gatt-api.txt | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/doc/gatt-api.txt b/doc/gatt-api.txt
index 0f6b084..6c70679 100644
--- a/doc/gatt-api.txt
+++ b/doc/gatt-api.txt
@@ -65,13 +65,12 @@ Properties string UUID [read-only]
array{string} Flags [read-only, optional]

Defines how the characteristic value can be used. See
- Core spec page 1898, "Table 3.5: Characteristic
- Properties bit field" and page 1900, "Table 3.8:
- Characteristic Extended Properties bit field". Allowed
- values: "broadcast", "read", "write-without-response",
- "write", "notify", "indicate",
- "authenticated-signed-writes", "reliable-write", and
- "writable-auxiliaries".
+ Core spec page "Table 3.5: Characteristic Properties
+ bit field", and "Table 3.8: Characteristic Extended
+ Properties bit field". Allowed values: "broadcast",
+ "read", "write-without-response", "write", "notify",
+ "indicate", "authenticated-signed-writes",
+ "reliable-write", and "writable-auxiliaries".


Characteristic Descriptors hierarchy
--
1.8.3.1


2014-03-27 13:21:13

by Claudio Takahasi

[permalink] [raw]
Subject: [PATCH BlueZ v0 3/5] gatt: Make Characteristic Flags optional

"Flags" is an optional property. Default value is allow read and
write procedures. If it is not informed the upper-layer should
manage security requirements returning errors using "-errno"
format in the operation result callback.
---
src/gatt-dbus.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index fbcbcfe..881e214 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -368,6 +368,7 @@ static int register_external_characteristics(GSList *proxies)
btd_attr_read_t read_cb;
uint8_t propmask = 0;

+ /* Mandatory property */
if (!g_dbus_proxy_get_property(proxy, "UUID", &iter))
return -EINVAL;

@@ -379,10 +380,17 @@ static int register_external_characteristics(GSList *proxies)
if (bt_string_to_uuid(&uuid, str) < 0)
return -EINVAL;

- if (!g_dbus_proxy_get_property(proxy, "Flags", &iter))
- return -EINVAL;
-
- propmask = flags_get_bitmask(&iter);
+ /*
+ * Optional property. If is not informed, read and write
+ * procedures will be allowed. Upper-layer should handle
+ * characteristic requirements.
+ */
+ if (g_dbus_proxy_get_property(proxy, "Flags", &iter))
+ propmask = flags_get_bitmask(&iter);
+ else
+ propmask = GATT_CHR_PROP_WRITE_WITHOUT_RESP
+ | GATT_CHR_PROP_WRITE
+ | GATT_CHR_PROP_READ;
if (!propmask)
return -EINVAL;

--
1.8.3.1


2014-03-27 13:21:11

by Claudio Takahasi

[permalink] [raw]
Subject: [PATCH BlueZ v0 1/5] gatt: Add parsing GattCharacteristic1 Flags

When fetching the external application characteristics, "Flags" field
representing the characteristic supported properties should be properly
translated to a bitmask value required to create the characteristic
declarations. Ref Core SPEC page 2183, Table 3.5: Characteristic
Properties bit field.
---
src/gatt-dbus.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 69 insertions(+), 6 deletions(-)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index 95d1243..4eaf562 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -39,6 +39,9 @@
#include "log.h"

#include "error.h"
+#include "attrib/gattrib.h"
+#include "attrib/att.h"
+#include "attrib/gatt.h"
#include "gatt.h"
#include "gatt-dbus.h"

@@ -104,6 +107,64 @@ static int proxy_path_cmp(gconstpointer a, gconstpointer b)
return g_strcmp0(path1, path2);
}

+static uint8_t flags_string2int(const char *proper)
+{
+ uint8_t value;
+
+ /* Regular Properties: See core spec 4.1 page 2183 */
+ if (!strcmp("broadcast", proper))
+ value = GATT_CHR_PROP_BROADCAST;
+ else if (!strcmp("read", proper))
+ value = GATT_CHR_PROP_READ;
+ else if (!strcmp("write-without-response", proper))
+ value = GATT_CHR_PROP_WRITE_WITHOUT_RESP;
+ else if (!strcmp("write", proper))
+ value = GATT_CHR_PROP_WRITE;
+ else if (!strcmp("notify", proper))
+ value = GATT_CHR_PROP_NOTIFY;
+ else if (!strcmp("indicate", proper))
+ value = GATT_CHR_PROP_INDICATE;
+ else if (!strcmp("authenticated-signed-writes", proper))
+ value = GATT_CHR_PROP_AUTH;
+ else
+ value = 0;
+
+ /* TODO: Extended properties. Ref core spec 4.1 page 2185 */
+
+ return value;
+}
+
+static uint8_t flags_get_bitmask(DBusMessageIter *iter)
+{
+ DBusMessageIter istr;
+ uint8_t propmask = 0, prop;
+ const char *str;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+ goto fail;
+
+ dbus_message_iter_recurse(iter, &istr);
+
+ do {
+ if (dbus_message_iter_get_arg_type(&istr) != DBUS_TYPE_STRING)
+ goto fail;
+
+ dbus_message_iter_get_basic(&istr, &str);
+ prop = flags_string2int(str);
+ if (!prop)
+ goto fail;
+
+ propmask |= prop;
+ } while (dbus_message_iter_next(&istr));
+
+ return propmask;
+
+fail:
+ error("Characteristic Flags: Invalid argument!");
+
+ return 0;
+}
+
static void proxy_added(GDBusProxy *proxy, void *user_data)
{
struct external_app *eapp = user_data;
@@ -303,6 +364,7 @@ static int register_external_characteristics(GSList *proxies)
bt_uuid_t uuid;
struct btd_attribute *attr;
GDBusProxy *proxy = list->data;
+ uint8_t propmask = 0;

if (!g_dbus_proxy_get_property(proxy, "UUID", &iter))
return -EINVAL;
@@ -315,13 +377,14 @@ static int register_external_characteristics(GSList *proxies)
if (bt_string_to_uuid(&uuid, str) < 0)
return -EINVAL;

- /*
- * TODO: Missing Flags/property
- * Add properties according to Core SPEC 4.1 page 2183.
- * Reference table 3.5: Characteristic Properties bit field.
- */
+ if (!g_dbus_proxy_get_property(proxy, "Flags", &iter))
+ return -EINVAL;
+
+ propmask = flags_get_bitmask(&iter);
+ if (!propmask)
+ return -EINVAL;

- attr = btd_gatt_add_char(&uuid, 0x00, proxy_read_cb,
+ attr = btd_gatt_add_char(&uuid, propmask, proxy_read_cb,
proxy_write_cb);
if (!attr)
return -EINVAL;
--
1.8.3.1