Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH 05/15] GATT server: parse primary/secondary services
From: Anderson Lizardo @ 2011-03-17  1:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1300323639-13296-1-git-send-email-anderson.lizardo@openbossa.org>

---
 plugins/gatt-profile.c |   76 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 75 insertions(+), 1 deletions(-)

diff --git a/plugins/gatt-profile.c b/plugins/gatt-profile.c
index 694769c..c0b2a50 100644
--- a/plugins/gatt-profile.c
+++ b/plugins/gatt-profile.c
@@ -29,6 +29,7 @@
 #include <errno.h>
 
 #include <gdbus.h>
+#include <bluetooth/uuid.h>
 
 #include "plugin.h"
 #include "adapter.h"
@@ -40,12 +41,72 @@
 static DBusConnection *connection = NULL;
 static const char *any_path = NULL;
 
+struct gatt_service {
+	gboolean primary;
+	bt_uuid_t uuid;
+	gchar *id;
+	GSList *chars;
+	GSList *includes;
+};
+
+static void parse_service(const gchar **attribute_names,
+					const gchar **attribute_values,
+					gboolean primary, GSList **services)
+{
+	struct gatt_service *svc;
+	const gchar *uuid, *id;
+	int i;
+
+	for (i = 0, uuid = NULL, id = NULL; attribute_names[i]; i++) {
+		if (g_strcmp0(attribute_names[i], "uuid") == 0)
+			uuid = attribute_values[i];
+		else if (g_strcmp0(attribute_names[i], "id") == 0)
+			id = attribute_values[i];
+		else
+			error("Invalid XML attribute: %s", attribute_names[i]);
+	}
+
+	if (uuid == NULL) {
+		error("Missing UUID for service");
+		return;
+	}
+
+	if (!primary && (id == NULL || id[0] == '\0')) {
+		error("Missing ID for secondary service");
+		return;
+	}
+
+	svc = g_new0(struct gatt_service, 1);
+	svc->primary = primary;
+
+	if (bt_string_to_uuid(&svc->uuid, uuid) < 0) {
+		error("Invalid UUID: %s", uuid);
+		g_free(svc);
+		return;
+	}
+
+	svc->id = g_strdup(id);
+
+	DBG("New %s service with UUID %s", primary ? "primary" : "secondary",
+									uuid);
+
+	*services = g_slist_prepend(*services, svc);
+}
+
 static void element_start(GMarkupParseContext *ctx, const gchar *element_name,
 		const gchar **attribute_names, const gchar **attribute_values,
 		gpointer user_data, GError **err)
 {
+	GSList **services = user_data;
+
 	if (g_strcmp0(element_name, "gatt-profile") == 0)
 		return;
+	else if (g_strcmp0(element_name, "primary-service") == 0)
+		parse_service(attribute_names, attribute_values, TRUE,
+								services);
+	else if (g_strcmp0(element_name, "secondary-service") == 0)
+		parse_service(attribute_names, attribute_values, FALSE,
+								services);
 	else
 		error("Invalid XML tag: %s", element_name);
 }
@@ -56,19 +117,32 @@ static void element_end(GMarkupParseContext *ctx, const gchar *element_name,
 	/* TODO: verify tag balance */
 }
 
+static void free_services(gpointer data, gpointer user_data)
+{
+	struct gatt_service *svc = data;
+
+	/* TODO: free characteristics, includes and descriptors */
+
+	g_free(svc);
+}
+
 static int add_xml_profile(DBusConnection *conn, const char *profile)
 {
 	GMarkupParser parser = { element_start, element_end, NULL, NULL, NULL };
 	GMarkupParseContext *ctx;
+	GSList *services = NULL;
 	int ret = 0;
 
-	ctx = g_markup_parse_context_new(&parser, 0, NULL, NULL);
+	ctx = g_markup_parse_context_new(&parser, 0, &services, NULL);
 	if (!g_markup_parse_context_parse(ctx, profile, strlen(profile),
 									NULL)) {
 		error("Parsing of GATT profile XML failed");
 		ret = -EINVAL;
 	}
 
+	g_slist_foreach(services, free_services, NULL);
+	g_slist_free(services);
+
 	g_markup_parse_context_free(ctx);
 
 	return ret;
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 06/15] GATT server: parse and resolve service includes
From: Anderson Lizardo @ 2011-03-17  1:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1300323639-13296-1-git-send-email-anderson.lizardo@openbossa.org>

"Resolving" service includes consists of replacing pointers to the ID
strings with actual struct gatt_service pointers, after all services
have been parsed.
---
 plugins/gatt-profile.c |   73 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 70 insertions(+), 3 deletions(-)

diff --git a/plugins/gatt-profile.c b/plugins/gatt-profile.c
index c0b2a50..b746449 100644
--- a/plugins/gatt-profile.c
+++ b/plugins/gatt-profile.c
@@ -93,6 +93,28 @@ static void parse_service(const gchar **attribute_names,
 	*services = g_slist_prepend(*services, svc);
 }
 
+static void parse_include(const gchar **attribute_names,
+						const gchar **attribute_values,
+						struct gatt_service *cur_svc)
+{
+	const gchar *id;
+	int i;
+
+	for (i = 0, id = NULL; attribute_names[i]; i++) {
+		if (g_strcmp0(attribute_names[i], "id") == 0)
+			id = attribute_values[i];
+		else
+			error("Invalid XML attribute: %s", attribute_names[i]);
+	}
+
+	if (id == NULL || id[0] == '\0') {
+		error("\"id\" attribute required");
+		return;
+	}
+
+	cur_svc->includes = g_slist_append(cur_svc->includes, g_strdup(id));
+}
+
 static void element_start(GMarkupParseContext *ctx, const gchar *element_name,
 		const gchar **attribute_names, const gchar **attribute_values,
 		gpointer user_data, GError **err)
@@ -107,8 +129,18 @@ static void element_start(GMarkupParseContext *ctx, const gchar *element_name,
 	else if (g_strcmp0(element_name, "secondary-service") == 0)
 		parse_service(attribute_names, attribute_values, FALSE,
 								services);
-	else
-		error("Invalid XML tag: %s", element_name);
+	else {
+		struct gatt_service *cur_svc = g_slist_nth_data(*services, 0);
+
+		if (cur_svc == NULL)
+			error("XML tag \"%s\" must be inside a service",
+								element_name);
+		else if (g_strcmp0(element_name, "include") == 0)
+			parse_include(attribute_names, attribute_values,
+								cur_svc);
+		else
+			error("Invalid XML tag: %s", element_name);
+	}
 }
 
 static void element_end(GMarkupParseContext *ctx, const gchar *element_name,
@@ -117,11 +149,45 @@ static void element_end(GMarkupParseContext *ctx, const gchar *element_name,
 	/* TODO: verify tag balance */
 }
 
+static gint find_id(gconstpointer a, gconstpointer b)
+{
+	const struct gatt_service *svc = a;
+	const gchar *id = b;
+
+	return g_strcmp0(svc->id, id);
+}
+
+static void resolve_includes(gpointer data, gpointer user_data)
+{
+	struct gatt_service *svc = data;
+	GSList *services = user_data;
+	GSList *l, *includes = NULL;
+
+	/* TODO: check for circular references */
+
+	for (l = svc->includes; l; l = l->next) {
+		gchar *id = l->data;
+		GSList *l2;
+
+		l2 = g_slist_find_custom(services, id, find_id);
+		if (l2)
+			includes = g_slist_append(includes, l2->data);
+		else
+			error("Could not find service with ID %s", id);
+
+		g_free(id);
+	}
+
+	g_slist_free(svc->includes);
+	svc->includes = includes;
+}
+
 static void free_services(gpointer data, gpointer user_data)
 {
 	struct gatt_service *svc = data;
 
-	/* TODO: free characteristics, includes and descriptors */
+	g_free(svc->id);
+	g_slist_free(svc->includes);
 
 	g_free(svc);
 }
@@ -140,6 +206,7 @@ static int add_xml_profile(DBusConnection *conn, const char *profile)
 		ret = -EINVAL;
 	}
 
+	g_slist_foreach(services, resolve_includes, services);
 	g_slist_foreach(services, free_services, NULL);
 	g_slist_free(services);
 
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 07/15] GATT server: parse characteristics
From: Anderson Lizardo @ 2011-03-17  1:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1300323639-13296-1-git-send-email-anderson.lizardo@openbossa.org>

---
 plugins/gatt-profile.c |  208 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 208 insertions(+), 0 deletions(-)

diff --git a/plugins/gatt-profile.c b/plugins/gatt-profile.c
index b746449..728c2ab 100644
--- a/plugins/gatt-profile.c
+++ b/plugins/gatt-profile.c
@@ -26,6 +26,7 @@
 #include <config.h>
 #endif
 
+#include <stdlib.h>
 #include <errno.h>
 
 #include <gdbus.h>
@@ -35,12 +36,36 @@
 #include "adapter.h"
 #include "error.h"
 #include "log.h"
+#include "att.h"
 
 #define GATT_PROFILE_INTERFACE "org.bluez.GattProfile"
 
 static DBusConnection *connection = NULL;
 static const char *any_path = NULL;
 
+struct gatt_descriptor {
+	uint16_t type;
+	union {
+		uint16_t ext_props;
+		uint16_t client_cfg;
+		uint16_t server_cfg;
+		gchar *description;
+		struct {
+			uint8_t format;
+			int8_t exponent;
+			uint16_t unit;
+			uint8_t namespace;
+			uint16_t description;
+		} presentation;
+	} data;
+};
+
+struct gatt_characteristic {
+	uint8_t props;
+	bt_uuid_t value_uuid;
+	GSList *descriptors;
+};
+
 struct gatt_service {
 	gboolean primary;
 	bt_uuid_t uuid;
@@ -93,6 +118,159 @@ static void parse_service(const gchar **attribute_names,
 	*services = g_slist_prepend(*services, svc);
 }
 
+static int string2uint16(uint16_t *dst, const char *src)
+{
+	int length = strlen(src);
+	char *endptr = NULL;
+
+	if (length != 4 && length != 6)
+		return -EINVAL;
+
+	*dst = strtoul(src, &endptr, 16);
+	if (endptr == NULL || *endptr != '\0')
+		return -EINVAL;
+
+	return 0;
+}
+
+static void parse_characteristic(const gchar **attribute_names,
+						const gchar **attribute_values,
+						struct gatt_service *cur_svc)
+{
+	struct gatt_characteristic *chr;
+	const gchar *uuid = NULL, *props = NULL;
+	uint16_t u16 = 0x00;
+	bt_uuid_t value_uuid;
+	int i;
+
+	for (i = 0; attribute_names[i]; i++) {
+		if (g_strcmp0(attribute_names[i], "uuid") == 0)
+			uuid = attribute_values[i];
+		else if (g_strcmp0(attribute_names[i], "properties") == 0)
+			props = attribute_values[i];
+		else
+			error("Invalid XML attribute: %s", attribute_names[i]);
+	}
+
+	if (uuid == NULL) {
+		error("Missing UUID for characteristic");
+		return;
+	}
+
+	if (bt_string_to_uuid(&value_uuid, uuid) < 0) {
+		error("Invalid UUID: %s", uuid);
+		return;
+	}
+
+	if (props != NULL && (string2uint16(&u16, props) < 0 || u16 > 0xff)) {
+		error("Invalid properties: %s", props);
+		return;
+	}
+
+	chr = g_new0(struct gatt_characteristic, 1);
+	chr->props = u16;
+	memcpy(&chr->value_uuid, &value_uuid, sizeof(chr->value_uuid));
+
+	DBG("New characteristic with UUID %s, properties 0x%02x", uuid,
+								chr->props);
+
+	cur_svc->chars = g_slist_prepend(cur_svc->chars, chr);
+}
+
+static void parse_descriptor(const gchar **attribute_names,
+				const gchar **attribute_values, uint16_t type,
+				struct gatt_service *cur_svc)
+{
+	struct gatt_characteristic *cur_chr;
+	struct gatt_descriptor dsc;
+	const gchar *fmt = NULL, *exp = NULL, *unit = NULL, *ns = NULL;
+	const gchar *desc = NULL, *value = NULL;
+	int i;
+
+	for (i = 0; attribute_names[i]; i++) {
+		if (g_strcmp0(attribute_names[i], "format") == 0)
+			fmt = attribute_values[i];
+		else if (g_strcmp0(attribute_names[i], "exponent") == 0)
+			exp = attribute_values[i];
+		else if (g_strcmp0(attribute_names[i], "unit") == 0)
+			unit = attribute_values[i];
+		else if (g_strcmp0(attribute_names[i], "namespace") == 0)
+			ns = attribute_values[i];
+		else if (g_strcmp0(attribute_names[i], "description") == 0)
+			desc = attribute_values[i];
+		else if (g_strcmp0(attribute_names[i], "value") == 0)
+			value = attribute_values[i];
+		else
+			error("Invalid XML attribute: %s", attribute_names[i]);
+	}
+
+	if (type == GATT_CHARAC_FMT_UUID && (!fmt || !unit || !ns || !desc)) {
+		error("Missing fields for presentation format");
+		return;
+	}
+
+	if (type == GATT_CHARAC_USER_DESC_UUID && value == NULL) {
+		error("Missing characteristic user description value");
+		return;
+	}
+
+	dsc.type = type;
+
+	if (type == GATT_CHARAC_USER_DESC_UUID)
+		dsc.data.description = g_strdup(value);
+	else if (type == GATT_CHARAC_FMT_UUID) {
+		uint16_t u16;
+
+		if (string2uint16(&u16, fmt) < 0 || u16 > UCHAR_MAX) {
+			error("Invalid format: %s", fmt);
+			return;
+		} else
+			dsc.data.presentation.format = u16;
+
+		/* Exponent is a signed decimal value and is optional for some
+		 * formats. */
+		if (exp) {
+			char *endptr = NULL;
+			long val = strtol(exp, &endptr, 10);
+
+			if (endptr == NULL || *endptr != '\0' ||
+					val < SCHAR_MIN || val > SCHAR_MAX) {
+				error("Invalid exponent: %s", exp);
+				return;
+			} else
+				dsc.data.presentation.exponent = val;
+		} else
+			dsc.data.presentation.exponent = 0;
+
+		if (string2uint16(&u16, unit) < 0) {
+			error("Invalid unit: %s", unit);
+			return;
+		} else
+			dsc.data.presentation.unit = u16;
+
+		if (string2uint16(&u16, ns) < 0 || u16 > UCHAR_MAX) {
+			error("Invalid namespace: %s", ns);
+			return;
+		} else
+			dsc.data.presentation.namespace = u16;
+
+		if (string2uint16(&u16, desc) < 0) {
+			error("Invalid description: %s", desc);
+			return;
+		} else
+			dsc.data.presentation.description = u16;
+	}
+
+	DBG("New %s descriptor",
+		type == GATT_CHARAC_USER_DESC_UUID ? "user description" :
+		type == GATT_CHARAC_FMT_UUID ? "presentation format" :
+		"unknown");
+
+	cur_chr = cur_svc->chars->data;
+	cur_chr->descriptors = g_slist_prepend(cur_chr->descriptors,
+						g_memdup(&dsc, sizeof(dsc)));
+}
+
 static void parse_include(const gchar **attribute_names,
 						const gchar **attribute_values,
 						struct gatt_service *cur_svc)
@@ -135,6 +313,16 @@ static void element_start(GMarkupParseContext *ctx, const gchar *element_name,
 		if (cur_svc == NULL)
 			error("XML tag \"%s\" must be inside a service",
 								element_name);
+		else if (g_strcmp0(element_name, "characteristic") == 0)
+			parse_characteristic(attribute_names, attribute_values,
+								cur_svc);
+		else if (g_strcmp0(element_name, "presentation") == 0)
+			parse_descriptor(attribute_names, attribute_values,
+						GATT_CHARAC_FMT_UUID, cur_svc);
+		else if (g_strcmp0(element_name, "user-description") == 0)
+			parse_descriptor(attribute_names, attribute_values,
+						GATT_CHARAC_USER_DESC_UUID,
+						cur_svc);
 		else if (g_strcmp0(element_name, "include") == 0)
 			parse_include(attribute_names, attribute_values,
 								cur_svc);
@@ -185,6 +373,26 @@ static void resolve_includes(gpointer data, gpointer user_data)
 static void free_services(gpointer data, gpointer user_data)
 {
 	struct gatt_service *svc = data;
+	GSList *cl;
+
+	for (cl = svc->chars; cl; cl = cl->next) {
+		struct gatt_characteristic *chr = cl->data;
+		GSList *dl;
+
+		for (dl = chr->descriptors; dl; dl = dl->next) {
+			struct gatt_descriptor *dsc = dl->data;
+
+			if (dsc->type == GATT_CHARAC_USER_DESC_UUID)
+				g_free(dsc->data.description);
+
+			g_free(dsc);
+		}
+
+		g_slist_free(chr->descriptors);
+		g_free(chr);
+	}
+
+	g_slist_free(svc->chars);
 
 	g_free(svc->id);
 	g_slist_free(svc->includes);
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 08/15] GATT server: parse characteristic value
From: Anderson Lizardo @ 2011-03-17  1:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1300323639-13296-1-git-send-email-anderson.lizardo@openbossa.org>

---
 attrib/att.h           |    1 +
 plugins/gatt-profile.c |   39 +++++++++++++++++++++++++++++++++++++--
 2 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/attrib/att.h b/attrib/att.h
index 7a83bfa..4d176dd 100644
--- a/attrib/att.h
+++ b/attrib/att.h
@@ -109,6 +109,7 @@
 #define ATT_MAX_MTU				256
 #define ATT_DEFAULT_L2CAP_MTU			48
 #define ATT_DEFAULT_LE_MTU			23
+#define ATT_MAX_VALUE_LEN			512
 
 /* Requirements for read/write operations */
 enum {
diff --git a/plugins/gatt-profile.c b/plugins/gatt-profile.c
index 728c2ab..b0256ba 100644
--- a/plugins/gatt-profile.c
+++ b/plugins/gatt-profile.c
@@ -62,6 +62,8 @@ struct gatt_descriptor {
 
 struct gatt_characteristic {
 	uint8_t props;
+	uint8_t *value;
+	size_t vlen;
 	bt_uuid_t value_uuid;
 	GSList *descriptors;
 };
@@ -138,16 +140,20 @@ static void parse_characteristic(const gchar **attribute_names,
 						struct gatt_service *cur_svc)
 {
 	struct gatt_characteristic *chr;
-	const gchar *uuid = NULL, *props = NULL;
+	const gchar *uuid = NULL, *props = NULL, *value = NULL;
+	uint8_t atval[ATT_MAX_VALUE_LEN];
 	uint16_t u16 = 0x00;
 	bt_uuid_t value_uuid;
-	int i;
+	unsigned int i;
+	size_t vlen;
 
 	for (i = 0; attribute_names[i]; i++) {
 		if (g_strcmp0(attribute_names[i], "uuid") == 0)
 			uuid = attribute_values[i];
 		else if (g_strcmp0(attribute_names[i], "properties") == 0)
 			props = attribute_values[i];
+		else if (g_strcmp0(attribute_names[i], "value") == 0)
+			value = attribute_values[i];
 		else
 			error("Invalid XML attribute: %s", attribute_names[i]);
 	}
@@ -167,8 +173,36 @@ static void parse_characteristic(const gchar **attribute_names,
 		return;
 	}
 
+	if (value == NULL) {
+		error("Missing value for characteristic");
+		return;
+	}
+
+	vlen = strlen(value);
+
+	if (vlen == 0 || vlen % 2 != 0) {
+		error("Characteristic value must be even and not empty");
+		return;
+	}
+
+	if (vlen > ATT_MAX_VALUE_LEN * 2) {
+		error("Characteristic value too long (%zu bytes, maximum is %d"
+				" bytes)", vlen, ATT_MAX_VALUE_LEN * 2);
+		return;
+	}
+
+	for (i = 0; i < vlen / 2; i++) {
+		if (sscanf(value + (i * 2), "%02hhX", &atval[i]) != 1) {
+			error("Characteristic value contains invalid "
+								"character");
+			return;
+		}
+	}
+
 	chr = g_new0(struct gatt_characteristic, 1);
 	chr->props = u16;
+	chr->vlen = vlen / 2;
+	chr->value = g_memdup(atval, chr->vlen);
 	memcpy(&chr->value_uuid, &value_uuid, sizeof(chr->value_uuid));
 
 	DBG("New characteristic with UUID %s, properties 0x%02x", uuid,
@@ -389,6 +423,7 @@ static void free_services(gpointer data, gpointer user_data)
 		}
 
 		g_slist_free(chr->descriptors);
+		g_free(chr->value);
 		g_free(chr);
 	}
 
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 09/15] GATT server: add test/test-gatt-profile example
From: Anderson Lizardo @ 2011-03-17  1:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1300323639-13296-1-git-send-email-anderson.lizardo@openbossa.org>

This script registers an example GATT profile, replacing the old
built-in example server (attrib/example.c).
---
 test/test-gatt-profile |   80 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 80 insertions(+), 0 deletions(-)
 create mode 100755 test/test-gatt-profile

diff --git a/test/test-gatt-profile b/test/test-gatt-profile
new file mode 100755
index 0000000..7234cd1
--- /dev/null
+++ b/test/test-gatt-profile
@@ -0,0 +1,80 @@
+#!/usr/bin/python
+import dbus
+import dbus.mainloop.glib
+import gobject
+
+profile = """
+<?xml version="1.0" encoding="UTF-8" ?>
+<gatt-profile>
+
+<!-- Battery state service -->
+<primary-service uuid="0xA002">
+<characteristic properties="0x12" uuid="0xA003" value="04"/>
+</primary-service>
+
+<!-- Thermometer service -->
+<primary-service uuid="0xA004">
+<include id="manufacturer1"/>
+<include id="vendor-specific"/>
+
+<characteristic properties="0x02" uuid="0xA006" value="8A02">
+<presentation format="0x0E" exponent="-2" unit="0x272F" namespace="0x01" description="0xA008"/>
+<user-description value="Outside Temperature"/>
+</characteristic>
+
+<characteristic properties="0x02" uuid="0xA009" value="27">
+<presentation format="0x04" exponent="0" unit="0x27AD" namespace="0x01" description="0xA008"/>
+<user-description value="Outside Relative Humidity"/>
+</characteristic>
+</primary-service>
+
+<!-- Manufacturer1 service -->
+<secondary-service id="manufacturer1" uuid="0xA005">
+<characteristic properties="0x02" uuid="0xA00C" value="41434D452054656D70657261747572652053656E736F7200"/>
+<characteristic properties="0x02" uuid="0xA00D" value="3233373439352D333238322D4100"/>
+</secondary-service>
+
+<!-- Manufacturer2 service -->
+<secondary-service id="manufacturer2" uuid="0xA005">
+<characteristic properties="0x02" uuid="0xA00C" value="41434D45205765696768696E67205363616C657300"/>
+<characteristic properties="0x02" uuid="0xA00D" value="31313236372D3233323741303032333900"/>
+</secondary-service>
+
+<!-- Vendor specific service -->
+<secondary-service id="vendor-specific" uuid="0xA00E">
+<characteristic properties="0x02" uuid="0xA00F" value="56656E646F72"/>
+</secondary-service>
+
+<!-- Weight service -->
+<primary-service uuid="4f0ac096-35d4-4911-9631-dea8dc74eefe">
+<include id="manufacturer2"/>
+
+<characteristic properties="0x02" uuid="8088f218-902c-450b-b6c4-62891e8c25e9" value="82550000">
+<presentation format="0x08" exponent="-3" unit="0x2702" namespace="0x01" description="0xA011"/>
+<user-description value="Rucksack Weight"/>
+</characteristic>
+</primary-service>
+
+<!-- for aggregates (not supported yet):
+<presentation id="p1" .../>
+<presentation id="p2" .../>
+<aggregate>
+<presentation id="p1"/>
+<presentation id="p2"/>
+</aggregate>
+-->
+
+</gatt-profile>
+"""
+
+dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+bus = dbus.SystemBus()
+manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
+adapter_path = manager.DefaultAdapter()
+
+gatt_profile = dbus.Interface(bus.get_object("org.bluez", adapter_path), "org.bluez.GattProfile")
+gatt_profile.AddProfile(profile)
+
+mainloop = gobject.MainLoop()
+mainloop.run()
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 10/15] Add attrib_db_find_avail() function to attribute server
From: Anderson Lizardo @ 2011-03-17  1:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1300323639-13296-1-git-send-email-anderson.lizardo@openbossa.org>

This new function searches for a range of at least "nitems" available
(unused) attribute handles. It then returns either zero (if no available
range was found) or the start handle of the available range.
---
 src/attrib-server.c |   28 ++++++++++++++++++++++++++++
 src/attrib-server.h |    1 +
 2 files changed, 29 insertions(+), 0 deletions(-)

diff --git a/src/attrib-server.c b/src/attrib-server.c
index 74a1c8d..67165f8 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -1209,6 +1209,34 @@ void attrib_free_sdp(uint32_t sdp_handle)
 	remove_record_from_server(sdp_handle);
 }
 
+uint16_t attrib_db_find_avail(uint16_t nitems)
+{
+	uint16_t handle;
+	GSList *l;
+
+	g_assert(nitems > 0);
+
+	for (l = database, handle = 0; l; l = l->next) {
+		struct attribute *a = l->data;
+
+		if (handle && (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 ||
+				bt_uuid_cmp(&a->uuid, &snd_uuid) == 0) &&
+				a->handle - handle >= nitems)
+			/* Note: the range above excludes the current handle */
+			return handle;
+
+		if (a->handle == 0xffff)
+			return 0;
+
+		handle = a->handle + 1;
+	}
+
+	if (0xffff - handle + 1 >= nitems)
+		return handle;
+
+	return 0;
+}
+
 struct attribute *attrib_db_add(uint16_t handle, bt_uuid_t *uuid, int read_reqs,
 				int write_reqs, const uint8_t *value, int len)
 {
diff --git a/src/attrib-server.h b/src/attrib-server.h
index 38a1f05..83484fc 100644
--- a/src/attrib-server.h
+++ b/src/attrib-server.h
@@ -25,6 +25,7 @@
 int attrib_server_init(void);
 void attrib_server_exit(void);
 
+uint16_t attrib_db_find_avail(uint16_t nitems);
 struct attribute *attrib_db_add(uint16_t handle, bt_uuid_t *uuid, int read_reqs,
 				int write_reqs, const uint8_t *value, int len);
 int attrib_db_update(uint16_t handle, bt_uuid_t *uuid, const uint8_t *value,
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 11/15] GATT server: add service registration
From: Anderson Lizardo @ 2011-03-17  1:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1300323639-13296-1-git-send-email-anderson.lizardo@openbossa.org>

---
 plugins/gatt-profile.c |   63 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 63 insertions(+), 0 deletions(-)

diff --git a/plugins/gatt-profile.c b/plugins/gatt-profile.c
index b0256ba..f61bdb4 100644
--- a/plugins/gatt-profile.c
+++ b/plugins/gatt-profile.c
@@ -37,6 +37,7 @@
 #include "error.h"
 #include "log.h"
 #include "att.h"
+#include "attrib-server.h"
 
 #define GATT_PROFILE_INTERFACE "org.bluez.GattProfile"
 
@@ -74,6 +75,7 @@ struct gatt_service {
 	gchar *id;
 	GSList *chars;
 	GSList *includes;
+	GSList *attrs;
 };
 
 static void parse_service(const gchar **attribute_names,
@@ -404,6 +406,66 @@ static void resolve_includes(gpointer data, gpointer user_data)
 	svc->includes = includes;
 }
 
+static uint16_t service_size(struct gatt_service *svc)
+{
+	GSList *cl;
+	uint16_t size;
+
+	/* A service contains at minimum one declaration attribute, plus one
+	 * attribute for each service include. */
+	size = 1 + g_slist_length(svc->includes);
+
+	for (cl = svc->chars; cl; cl = cl->next) {
+		struct gatt_characteristic *c = cl->data;
+
+		/* A characteristic contains at least two attributes (for
+		 * declaration and value), plus one attribute for each
+		 * descriptor. */
+		size += 2 + g_slist_length(c->descriptors);
+	}
+
+	return size;
+}
+
+static void register_services(gpointer data, gpointer user_data)
+{
+	struct gatt_service *svc = data;
+	struct attribute *a;
+	uint16_t handle, size;
+	bt_uuid_t uuid;
+	char uuidstr[MAX_LEN_UUID_STR];
+	uint8_t atval[ATT_MAX_VALUE_LEN];
+	int atlen;
+
+	size = service_size(svc);
+	handle = attrib_db_find_avail(size);
+	if (handle == 0) {
+		error("Not enough space on attribute database");
+		return;
+	}
+
+	bt_uuid_to_string(&svc->uuid, uuidstr, MAX_LEN_UUID_STR);
+	DBG("service: primary=%s, uuid=%s, id=%s, handle=0x%04x, size=%u",
+				svc->primary ? "TRUE" : "FALSE", uuidstr,
+				svc->id ? svc->id : "", handle, size);
+
+	if (svc->primary)
+		bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+	else
+		bt_uuid16_create(&uuid, GATT_SND_SVC_UUID);
+
+	att_put_uuid(svc->uuid, atval);
+	if (svc->uuid.type == BT_UUID16)
+		atlen = 2;
+	else
+		atlen = 16;
+
+	a = attrib_db_add(handle++, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval,
+									atlen);
+	g_assert(a != NULL);
+	svc->attrs = g_slist_append(svc->attrs, a);
+}
+
 static void free_services(gpointer data, gpointer user_data)
 {
 	struct gatt_service *svc = data;
@@ -450,6 +512,7 @@ static int add_xml_profile(DBusConnection *conn, const char *profile)
 	}
 
 	g_slist_foreach(services, resolve_includes, services);
+	g_slist_foreach(services, register_services, NULL);
 	g_slist_foreach(services, free_services, NULL);
 	g_slist_free(services);
 
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 12/15] GATT server: add service includes registration
From: Anderson Lizardo @ 2011-03-17  1:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1300323639-13296-1-git-send-email-anderson.lizardo@openbossa.org>

Service includes may appear in any other services (before or after the
include declaration), therefore its attribute is initially added to the
database with empty data, which is filled after all services have been
registered (and thus have allocated handles).
---
 plugins/gatt-profile.c |   57 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 57 insertions(+), 0 deletions(-)

diff --git a/plugins/gatt-profile.c b/plugins/gatt-profile.c
index f61bdb4..83006fb 100644
--- a/plugins/gatt-profile.c
+++ b/plugins/gatt-profile.c
@@ -434,6 +434,7 @@ static void register_services(gpointer data, gpointer user_data)
 	uint16_t handle, size;
 	bt_uuid_t uuid;
 	char uuidstr[MAX_LEN_UUID_STR];
+	GSList *l;
 	uint8_t atval[ATT_MAX_VALUE_LEN];
 	int atlen;
 
@@ -464,6 +465,18 @@ static void register_services(gpointer data, gpointer user_data)
 									atlen);
 	g_assert(a != NULL);
 	svc->attrs = g_slist_append(svc->attrs, a);
+
+	bt_uuid16_create(&uuid, GATT_INCLUDE_UUID);
+
+	for (l = svc->includes; l; l = l->next) {
+		memset(atval, 0, 6);
+		a = attrib_db_add(handle++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+								atval, 6);
+		g_assert(a != NULL);
+		svc->attrs = g_slist_append(svc->attrs, a);
+
+		DBG("include: handle=0x%04x", a->handle);
+	}
 }
 
 static void free_services(gpointer data, gpointer user_data)
@@ -497,6 +510,49 @@ static void free_services(gpointer data, gpointer user_data)
 	g_free(svc);
 }
 
+static void update_includes(gpointer data, gpointer user_data)
+{
+	struct gatt_service *svc = data;
+	GSList *al, *il;
+	bt_uuid_t uuid;
+
+	bt_uuid16_create(&uuid, GATT_INCLUDE_UUID);
+
+	il = svc->includes;
+	if (il == NULL)
+		return;
+
+	for (al = svc->attrs; al; al = al->next) {
+		struct attribute *a = al->data;
+		struct attribute *start, *end;
+		struct gatt_service *inc_svc;
+		uint8_t atval[20];
+
+		if (bt_uuid_cmp(&a->uuid, &uuid) != 0)
+			continue;
+
+		inc_svc = il->data;
+		start = inc_svc->attrs->data;
+		end = g_slist_last(inc_svc->attrs)->data;
+
+		att_put_u16(start->handle, &atval[0]);
+		att_put_u16(end->handle, &atval[2]);
+
+		att_put_uuid(start->uuid, &atval[4]);
+		if (start->uuid.type == BT_UUID16)
+			attrib_db_update(a->handle, NULL, atval, 6, &a);
+		else
+			/* According to spec, the include declaration shall
+			 * only contain the service UUID if it is 16-bit.
+			 * Otherwise, omitting the UUID the length is
+			 * 4 bytes. */
+			attrib_db_update(a->handle, NULL, atval, 4, &a);
+		al->data = a;
+
+		il = il->next;
+	}
+}
+
 static int add_xml_profile(DBusConnection *conn, const char *profile)
 {
 	GMarkupParser parser = { element_start, element_end, NULL, NULL, NULL };
@@ -513,6 +569,7 @@ static int add_xml_profile(DBusConnection *conn, const char *profile)
 
 	g_slist_foreach(services, resolve_includes, services);
 	g_slist_foreach(services, register_services, NULL);
+	g_slist_foreach(services, update_includes, NULL);
 	g_slist_foreach(services, free_services, NULL);
 	g_slist_free(services);
 
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 13/15] GATT server: add characteristic registration
From: Anderson Lizardo @ 2011-03-17  1:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1300323639-13296-1-git-send-email-anderson.lizardo@openbossa.org>

---
 plugins/gatt-profile.c |   45 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 45 insertions(+), 0 deletions(-)

diff --git a/plugins/gatt-profile.c b/plugins/gatt-profile.c
index 83006fb..4cf0164 100644
--- a/plugins/gatt-profile.c
+++ b/plugins/gatt-profile.c
@@ -427,6 +427,49 @@ static uint16_t service_size(struct gatt_service *svc)
 	return size;
 }
 
+static void register_characteristics(gpointer data, gpointer user_data)
+{
+	struct gatt_characteristic *chr = data;
+	GSList **attrs = user_data, *l;
+	struct attribute *a;
+	uint16_t handle;
+	bt_uuid_t uuid;
+	char uuidstr[MAX_LEN_UUID_STR];
+	uint8_t atval[ATT_MAX_VALUE_LEN];
+	int atlen;
+
+	bt_uuid_to_string(&chr->value_uuid, uuidstr, MAX_LEN_UUID_STR);
+	DBG("characteristic: props=0x%02x, value_uuid=%s", chr->props, uuidstr);
+
+	bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
+
+	l = g_slist_last(*attrs);
+	g_assert(l != NULL);
+
+	a = l->data;
+	handle = a->handle + 1;
+
+	atval[0] = chr->props;
+	att_put_u16(handle + 1, &atval[1]);
+	att_put_uuid(chr->value_uuid, &atval[3]);
+	if (chr->value_uuid.type == BT_UUID16)
+		atlen = 2;
+	else
+		atlen = 16;
+
+	/* Characteristic declaration attribute */
+	a = attrib_db_add(handle++, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval,
+								atlen + 3);
+	g_assert(a != NULL);
+	*attrs = g_slist_append(*attrs, a);
+
+	/* Characteristic value attribute */
+	a = attrib_db_add(handle, &chr->value_uuid, ATT_NONE,
+				ATT_NOT_PERMITTED, chr->value, chr->vlen);
+	g_assert(a != NULL);
+	*attrs = g_slist_append(*attrs, a);
+}
+
 static void register_services(gpointer data, gpointer user_data)
 {
 	struct gatt_service *svc = data;
@@ -477,6 +520,8 @@ static void register_services(gpointer data, gpointer user_data)
 
 		DBG("include: handle=0x%04x", a->handle);
 	}
+
+	g_slist_foreach(svc->chars, register_characteristics, &svc->attrs);
 }
 
 static void free_services(gpointer data, gpointer user_data)
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 14/15] GATT server: add characteristic descriptor registration
From: Anderson Lizardo @ 2011-03-17  1:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1300323639-13296-1-git-send-email-anderson.lizardo@openbossa.org>

---
 plugins/gatt-profile.c |   41 +++++++++++++++++++++++++++++++++++++++++
 1 files changed, 41 insertions(+), 0 deletions(-)

diff --git a/plugins/gatt-profile.c b/plugins/gatt-profile.c
index 4cf0164..521befe 100644
--- a/plugins/gatt-profile.c
+++ b/plugins/gatt-profile.c
@@ -427,6 +427,45 @@ static uint16_t service_size(struct gatt_service *svc)
 	return size;
 }
 
+static void register_descriptors(gpointer data, gpointer user_data)
+{
+	struct gatt_descriptor *desc = data;
+	GSList **attrs = user_data, *l;
+	struct attribute *a;
+	uint8_t atval[ATT_MAX_VALUE_LEN];
+	uint16_t handle;
+	bt_uuid_t uuid;
+
+	DBG("descriptor: type=0x%04x", desc->type);
+
+	l = g_slist_last(*attrs);
+	g_assert(l != NULL);
+
+	a = l->data;
+	handle = a->handle + 1;
+
+	bt_uuid16_create(&uuid, desc->type);
+	if (desc->type == GATT_CHARAC_USER_DESC_UUID)
+		a = attrib_db_add(handle, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+					(uint8_t *) desc->data.description,
+					strlen(desc->data.description));
+	else if (desc->type == GATT_CHARAC_FMT_UUID) {
+		atval[0] = desc->data.presentation.format;
+		atval[1] = desc->data.presentation.exponent;
+		att_put_u16(desc->data.presentation.unit, &atval[2]);
+		atval[4] = desc->data.presentation.namespace;
+		att_put_u16(desc->data.presentation.description, &atval[5]);
+		a = attrib_db_add(handle, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+								atval, 7);
+	} else {
+		error("Unsupported descriptor type: 0x%04x", desc->type);
+		return;
+	}
+
+	g_assert(a != NULL);
+	*attrs = g_slist_append(*attrs, a);
+}
+
 static void register_characteristics(gpointer data, gpointer user_data)
 {
 	struct gatt_characteristic *chr = data;
@@ -468,6 +507,8 @@ static void register_characteristics(gpointer data, gpointer user_data)
 				ATT_NOT_PERMITTED, chr->value, chr->vlen);
 	g_assert(a != NULL);
 	*attrs = g_slist_append(*attrs, a);
+
+	g_slist_foreach(chr->descriptors, register_descriptors, attrs);
 }
 
 static void register_services(gpointer data, gpointer user_data)
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 15/15] GATT server: add disconnect watch
From: Anderson Lizardo @ 2011-03-17  1:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1300323639-13296-1-git-send-email-anderson.lizardo@openbossa.org>

The disconnect watch is used to delete attributes added by a client. The
added attributes are only useful while the D-Bus client which added them
is alive, otherwise read/write callbacks, notifications and indications
will not work.
---
 plugins/gatt-profile.c |   64 +++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 58 insertions(+), 6 deletions(-)

diff --git a/plugins/gatt-profile.c b/plugins/gatt-profile.c
index 521befe..600efa1 100644
--- a/plugins/gatt-profile.c
+++ b/plugins/gatt-profile.c
@@ -44,6 +44,11 @@
 static DBusConnection *connection = NULL;
 static const char *any_path = NULL;
 
+struct client_data {
+	GSList *attrs; /* All attributes registered by this client */
+	guint listener_id;
+};
+
 struct gatt_descriptor {
 	uint16_t type;
 	union {
@@ -568,6 +573,7 @@ static void register_services(gpointer data, gpointer user_data)
 static void free_services(gpointer data, gpointer user_data)
 {
 	struct gatt_service *svc = data;
+	GSList **attrs = user_data;
 	GSList *cl;
 
 	for (cl = svc->chars; cl; cl = cl->next) {
@@ -593,6 +599,9 @@ static void free_services(gpointer data, gpointer user_data)
 	g_free(svc->id);
 	g_slist_free(svc->includes);
 
+	if (attrs)
+		*attrs = g_slist_concat(*attrs, svc->attrs);
+
 	g_free(svc);
 }
 
@@ -639,7 +648,8 @@ static void update_includes(gpointer data, gpointer user_data)
 	}
 }
 
-static int add_xml_profile(DBusConnection *conn, const char *profile)
+static int add_xml_profile(DBusConnection *conn, const char *profile,
+								GSList **attrs)
 {
 	GMarkupParser parser = { element_start, element_end, NULL, NULL, NULL };
 	GMarkupParseContext *ctx;
@@ -656,7 +666,7 @@ static int add_xml_profile(DBusConnection *conn, const char *profile)
 	g_slist_foreach(services, resolve_includes, services);
 	g_slist_foreach(services, register_services, NULL);
 	g_slist_foreach(services, update_includes, NULL);
-	g_slist_foreach(services, free_services, NULL);
+	g_slist_foreach(services, free_services, attrs);
 	g_slist_free(services);
 
 	g_markup_parse_context_free(ctx);
@@ -664,23 +674,59 @@ static int add_xml_profile(DBusConnection *conn, const char *profile)
 	return ret;
 }
 
+static void exit_callback(DBusConnection *conn, void *user_data)
+{
+	struct client_data *client = user_data;
+	GSList *l;
+
+	DBG("client=%p", client);
+
+	for (l = client->attrs; l; l = l->next) {
+		struct attribute *a = l->data;
+
+		attrib_db_del(a->handle);
+	}
+
+	g_slist_free(client->attrs);
+	client->attrs = NULL;
+}
+
 static DBusMessage *add_profile(DBusConnection *conn, DBusMessage *msg,
 								void *user_data)
 {
-	const char *profile;
+	struct client_data *client = user_data;
+	const char *sender, *profile;
 	int err;
 
 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &profile,
 							DBUS_TYPE_INVALID))
 		return NULL;
 
-	err = add_xml_profile(conn, profile);
+	err = add_xml_profile(conn, profile, &client->attrs);
 	if (err < 0)
 		return btd_error_failed(msg, strerror(-err));
 
+	sender = dbus_message_get_sender(msg);
+	client->listener_id = g_dbus_add_disconnect_watch(conn, sender,
+					exit_callback, client, NULL);
+
+	DBG("listener_id %d", client->listener_id);
+
 	return dbus_message_new_method_return(msg);
 }
 
+static void destroy_interface(void *user_data)
+{
+	struct client_data *client = user_data;
+
+	DBG("client=%p", client);
+
+	g_dbus_remove_watch(connection, client->listener_id);
+	exit_callback(connection, client);
+
+	g_free(client);
+}
+
 static GDBusMethodTable gatt_profile_methods[] = {
 	{ "AddProfile", "s", "", add_profile },
 	{ }
@@ -688,13 +734,19 @@ static GDBusMethodTable gatt_profile_methods[] = {
 
 static int register_interface(const char *path, struct btd_adapter *adapter)
 {
+	struct client_data *client;
+
 	DBG("path %s", path);
 
+	client = g_new0(struct client_data, 1);
+
 	if (!g_dbus_register_interface(connection, path, GATT_PROFILE_INTERFACE,
-					gatt_profile_methods, NULL, NULL, NULL,
-					NULL)) {
+					gatt_profile_methods, NULL, NULL,
+					client, destroy_interface)) {
 		error("D-Bus failed to register %s interface",
 							GATT_PROFILE_INTERFACE);
+		g_free(client);
+
 		return -EIO;
 	}
 
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH] Update TODO regarding bt_uuid_* functions
From: Elvis Pfützenreuter @ 2011-03-17  1:36 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: epx

---
 TODO |   14 ++++----------
 1 files changed, 4 insertions(+), 10 deletions(-)

diff --git a/TODO b/TODO
index 1120ad9..3351ac9 100644
--- a/TODO
+++ b/TODO
@@ -17,18 +17,12 @@ Background
 General
 ==========
 
-- UUID128 handling: Create new functions to handle UUIDs on host order.
-  Functions should start with prefix "bt_uuid". In the first phase, attribute
-  server/client and gatttool code should be changed to use these new functions.
-  The idea is to keep the consistency for UUID-16, UUID-32 and UUID-128. SDP
-  functions store UUID-16 and UUID-32 on host order, however UUID-128 is stored
-  on network order/big endian. Attribute Protocol uses little endian, while
-  SDP uses big endian. The idea is always store the UUID values on host order
-  and use utility functions to convert to the proper byte order depending on
-  the protocol: ATT or SDP.
+- UUID handling: Use the new functions created for UUID handling in all parts
+  of BlueZ code.  Currently, the new bt_uuid_* functions are being used by
+  GATT-related code only.
 
   Priority: high
-  Complexity: C1
+  Complexity: C4
 
 - Rename glib-helper file to a more convenient name. The ideia is try to keep
   only sdp helpers functions. bt_* prefix shall be also changed.
-- 
1.7.1


^ permalink raw reply related

* Re: [PATCH] Add 'Protocol not supported' error in a2dp_add_sep
From: Dmitriy Paliy @ 2011-03-17  7:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1300276872-20149-1-git-send-email-dmitriy.paliy@nokia.com>

Hi,

On Wed, 2011-03-16 at 14:01 +0200, ext Dmitriy Paliy wrote:
> 'Protocol not supported' error code is added to registeration of A2DP
> end-points. Error response org.bluez.Error.NotSupported instead of
> org.bluez.Error.InvalidArguments is used when SEP registration fails
> due to disabled corresponding interface in audio.conf.

Seems like there were some comment about this patch that I missed. Could
anybody post a reply with them to this email?

Thanks,
Dmitriy



^ permalink raw reply

* Re: Switching between SBC and MPEG audio on headsets
From: Peter Dons Tychsen @ 2011-03-17  9:35 UTC (permalink / raw)
  To: Brian Gix
  Cc: Luiz Augusto von Dentz, Arun Raghavan, linux-bluetooth,
	Johan Hedberg
In-Reply-To: <4D814334.6080407@codeaurora.org>

Hi Brian,

On Wed, 2011-03-16 at 16:09 -0700, Brian Gix wrote:
> This is not actually true. You can have multiple media channels open 
> simultaneously (for instance one for Video and one for Audio) which
> are 
> opened with careful handshaking with the AVDTP_OPEN signaling
> command. 
> In theory, this could be two audio channels as well.  If someone wants
> a 
> Journaling channel, it would be opened without the AVDTP_OPEN
> signaling.

Yes, except protocol-wise the new channel on PSM=0x19 could also be the
start of a new A2DP signaling connection (however very unlikely). As you
mentioned, the problem with the Journaling channel can be filtered out
with correct signaling.

I totally agree with you that your solution is the most elegant. However
back when A2DP was introduced it did not seem clear to everyone how
multiple streams would work. Some thought it would work with multiple
media channels (like you suggest), and some thought it would work with
multiple signaling channels (with max 1 media channel).

Most of the implementations i have seen (for headsets), unfortunately
ended up with the last solution. This means that they will not accept a
secondary media channel. This is unfortunately basically true for all of
the most popular chipsets and SDKs.

Your suggestion is clever and follows the standard nicely (and would get
my vote for a white-paper), but i doubt it will work with many headsets
out there.

Even worse, many headsets are hardcoded (not nice) to believe that the
3rd channel is always the Journaling channel. That is of course, just
plain wrong due to the reasons you have stated.

Thanks,

/pedro




^ permalink raw reply

* RE: [PATCH v5 2/4] Add support for SAP protocol
From: Waldemar.Rymarkiewicz @ 2011-03-17  9:50 UTC (permalink / raw)
  To: hombre71; +Cc: johan.hedberg, linux-bluetooth
In-Reply-To: <AANLkTinF695CSLoSgxCn1LOiZ=jF-Z8OjAsEeY52K8GG@mail.gmail.com>

Hi Angus.H,

>A lot of code could be refactored.
>Quite a few repeatable (logically) blocks in every 
>"...._req()" and "..._rsp()" handlers.
>

Indeed, but those blocks are not equal in all cases. Thus, I prefere to split it up into seperate functions instead of having one big function with switch-case statement.
It's not like we can replace those blocks with one generic function without switch-case.  I consider this as slightly more readable. However, I'm not strongly opposed to change it one function.

Waldek

^ permalink raw reply

* Re: [PATCH] Bluetooth: Fix HCI_RESET command syncronization
From: Szymon Janc @ 2011-03-17 10:35 UTC (permalink / raw)
  To: Gustavo F. Padovan
  Cc: linux-bluetooth@vger.kernel.org, mmvinni@yahoo.com,
	justinmattock@gmail.com, edt@aei.ca
In-Reply-To: <1300301086-22653-1-git-send-email-padovan@profusion.mobi>

> We can't send new commands before a cmd_complete for the HCI_RESET commnnd

Typo: comm*a*nd

> shows up.
> 
> Reported-by: Mikko Vinni <mmvinni@yahoo.com>
> Reported-by: Justin P. Mattock <justinmattock@gmail.com>
> Reported-by: Ed Tomlinson <edt@aei.ca>
> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
> ---
>  include/net/bluetooth/hci.h |    2 ++
>  net/bluetooth/hci_core.c    |    3 +++
>  net/bluetooth/hci_event.c   |    4 +++-
>  3 files changed, 8 insertions(+), 1 deletions(-)
> 
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index ec6acf2..2c0d309 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -84,6 +84,8 @@ enum {
>  	HCI_SERVICE_CACHE,
>  	HCI_LINK_KEYS,
>  	HCI_DEBUG_KEYS,
> +
> +	HCI_RESET,
>  };
>  
>  /* HCI ioctl defines */
> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> index b372fb8..32b82e2 100644
> --- a/net/bluetooth/hci_core.c
> +++ b/net/bluetooth/hci_core.c
> @@ -534,6 +534,8 @@ int hci_dev_open(__u16 dev)
>  		set_bit(HCI_INIT, &hdev->flags);
>  		hdev->init_last_cmd = 0;
>  
> +		set_bit(HCI_RESET, &hdev->flags);

Does this work with HCI_QUIRK_NO_RESET enabled?
Shouldn't this bit be set only right before sending HCI_OP_RESET
(in hci_init_req and hci_reset_req) for doing what commit msg says?

Now it looks more like a workaround for initialization issue..

> +
>  		ret = __hci_request(hdev, hci_init_req, 0,
>  					msecs_to_jiffies(HCI_INIT_TIMEOUT));
>  
> @@ -1074,6 +1076,7 @@ static void hci_cmd_timer(unsigned long arg)
>  
>  	BT_ERR("%s command tx timeout", hdev->name);
>  	atomic_set(&hdev->cmd_cnt, 1);
> +	clear_bit(HCI_RESET, &hdev->flags);
>  	tasklet_schedule(&hdev->cmd_task);
>  }
>  
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index 3fbfa50..cebe7588 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -183,6 +183,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
>  
>  	BT_DBG("%s status 0x%x", hdev->name, status);
>  
> +	clear_bit(HCI_RESET, &hdev->flags);
> +
>  	hci_req_complete(hdev, HCI_OP_RESET, status);
>  }
>  
> @@ -1847,7 +1849,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
>  	if (ev->opcode != HCI_OP_NOP)
>  		del_timer(&hdev->cmd_timer);
>  
> -	if (ev->ncmd) {
> +	if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
>  		atomic_set(&hdev->cmd_cnt, 1);
>  		if (!skb_queue_empty(&hdev->cmd_q))
>  			tasklet_schedule(&hdev->cmd_task);

Maybe use unlikely() here?

-- 
BR
Szymon Janc

^ permalink raw reply

* [PATCH] TODO: set owner of 'Define attribute server API' task
From: Anderson Lizardo @ 2011-03-17 11:55 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo

An initial implementation was sent as RFC.
---
 TODO |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/TODO b/TODO
index 1120ad9..6932c4e 100644
--- a/TODO
+++ b/TODO
@@ -224,6 +224,7 @@ ATT/GATT
 
   Priority: Low
   Complexity: C2
+  Owner: Anderson Lizardo <anderson.lizardo@openbossa.org>
 
 Management Interface
 ====================
-- 
1.7.0.4


^ permalink raw reply related

* Re: [PATCH 2/5] Add internal buffer to GAttrib struct
From: Johan Hedberg @ 2011-03-17 12:30 UTC (permalink / raw)
  To: Bruna Moreira; +Cc: linux-bluetooth
In-Reply-To: <1300274712-3931-2-git-send-email-bruna.moreira@openbossa.org>

Hi Bruna,

On Wed, Mar 16, 2011, Bruna Moreira wrote:
> +gboolean g_attrib_set_buffer(GAttrib *attrib, int mtu)
> +{
> +	if (mtu < ATT_DEFAULT_LE_MTU)
> +		mtu = ATT_DEFAULT_LE_MTU;
> +
> +	if (mtu > ATT_MAX_MTU)
> +		mtu = ATT_MAX_MTU;
> +
> +	if (!bt_io_set(attrib->io, BT_IO_L2CAP, NULL,
> +			BT_IO_OPT_OMTU, mtu,
> +			BT_IO_OPT_INVALID))
> +		return FALSE;
> +
> +	attrib->buf = g_realloc(attrib->buf, mtu);
> +
> +	attrib->buflen = mtu;
> +
> +	return TRUE;
> +}

Wouldn't g_attrib_set_mtu make more sense for the name of this function?
Since it's named symmetrically to the _get version one would expect it
to take a buffer as an input parameter, but it's not doing that.

Johan

^ permalink raw reply

* Re: [PATCH 2/5] Add internal buffer to GAttrib struct
From: Bruna Moreira @ 2011-03-17 12:43 UTC (permalink / raw)
  To: Bruna Moreira, linux-bluetooth
In-Reply-To: <20110317123031.GA12238@jh-x301>

On 3/17/11, Johan Hedberg <johan.hedberg@gmail.com> wrote:
> Hi Bruna,
>
> On Wed, Mar 16, 2011, Bruna Moreira wrote:
>> +gboolean g_attrib_set_buffer(GAttrib *attrib, int mtu)
>> +{
>> +	if (mtu < ATT_DEFAULT_LE_MTU)
>> +		mtu = ATT_DEFAULT_LE_MTU;
>> +
>> +	if (mtu > ATT_MAX_MTU)
>> +		mtu = ATT_MAX_MTU;
>> +
>> +	if (!bt_io_set(attrib->io, BT_IO_L2CAP, NULL,
>> +			BT_IO_OPT_OMTU, mtu,
>> +			BT_IO_OPT_INVALID))
>> +		return FALSE;
>> +
>> +	attrib->buf = g_realloc(attrib->buf, mtu);
>> +
>> +	attrib->buflen = mtu;
>> +
>> +	return TRUE;
>> +}
>
> Wouldn't g_attrib_set_mtu make more sense for the name of this function?
> Since it's named symmetrically to the _get version one would expect it
> to take a buffer as an input parameter, but it's not doing that.

Agreed. I will send a new updated series.

BR,
-- 
Bruna Moreira
Instituto Nokia de Tecnologia (INdT)
Manaus - Brazil

^ permalink raw reply

* Re: [PATCH] Add 'Protocol not supported' error in a2dp_add_sep
From: Johan Hedberg @ 2011-03-17 12:44 UTC (permalink / raw)
  To: Dmitriy Paliy; +Cc: linux-bluetooth
In-Reply-To: <1300347949.2509.11.camel@dp-x301>

Hi Dmitriy,

On Thu, Mar 17, 2011, Dmitriy Paliy wrote:
> On Wed, 2011-03-16 at 14:01 +0200, ext Dmitriy Paliy wrote:
> > 'Protocol not supported' error code is added to registeration of A2DP
> > end-points. Error response org.bluez.Error.NotSupported instead of
> > org.bluez.Error.InvalidArguments is used when SEP registration fails
> > due to disabled corresponding interface in audio.conf.
> 
> Seems like there were some comment about this patch that I missed. Could
> anybody post a reply with them to this email?

The main concern raised on IRC was about the convention of returning an
integer error through a pointer parameter instead of the return value of
the function. Usually it's better to have integer errors in the return
value, but as the main purpose of this function is to create and return
and object and checking for the exact error is a secondary concern
(which isn't always needed). So I think it's kind of ok in this case and
I've therefore pushed the patch upstream. It'd be nice if we had similar
macros as the kernel has for encoding POSIX errno's into a pointer
value. Then this kind of issue wouldn't exist.

Johan

^ permalink raw reply

* Re: [PATCH] Add discover characteristics by uuid to gattool
From: Johan Hedberg @ 2011-03-17 12:47 UTC (permalink / raw)
  To: Sheldon Demario; +Cc: linux-bluetooth
In-Reply-To: <1300297246-11056-1-git-send-email-sheldon.demario@openbossa.org>

Hi Sheldon,

On Wed, Mar 16, 2011, Sheldon Demario wrote:
> +		uuid = g_try_new(bt_uuid_t, 1);
> +		if (bt_string_to_uuid(uuid, argvp[3]) < 0) {
> +			g_free(uuid);
> +			printf("Invalid UUID\n");
> +			return;
> +		}

If you're gonna use the _try version of GLib memory allocators you need
to check for the return value. However in this case I'd just use the
non-try version (since the amount of memory is small).

Johan

^ permalink raw reply

* Re: [PATCH] Add discover characteristics by uuid to gattool
From: Johan Hedberg @ 2011-03-17 12:49 UTC (permalink / raw)
  To: Sheldon Demario, linux-bluetooth
In-Reply-To: <20110317124754.GC12238@jh-x301>

Hi,

On Thu, Mar 17, 2011, Johan Hedberg wrote:
> On Wed, Mar 16, 2011, Sheldon Demario wrote:
> > +		uuid = g_try_new(bt_uuid_t, 1);
> > +		if (bt_string_to_uuid(uuid, argvp[3]) < 0) {
> > +			g_free(uuid);
> > +			printf("Invalid UUID\n");
> > +			return;
> > +		}
> 
> If you're gonna use the _try version of GLib memory allocators you need
> to check for the return value. However in this case I'd just use the
> non-try version (since the amount of memory is small).

Never mind, I just saw that you've sent an updated version which gets
rid of the memory allocation need completely (by using a stack
variable).

Johan

^ permalink raw reply

* Re: [PATCH v2] Add discover characteristics by uuid to gatttool
From: Johan Hedberg @ 2011-03-17 12:52 UTC (permalink / raw)
  To: Sheldon Demario; +Cc: linux-bluetooth
In-Reply-To: <1300312856-14034-1-git-send-email-sheldon.demario@openbossa.org>

Hi Sheldon,

On Wed, Mar 16, 2011, Sheldon Demario wrote:
> According to the spec the characteristics discover and characteristics discover
> by uuid use the same opcode and the result should be filtered by callback.
> ---
>  attrib/client.c      |    2 +-
>  attrib/gatt.c        |   16 +++++++++++-----
>  attrib/gatt.h        |    3 ++-
>  attrib/gatttool.c    |    3 ++-
>  attrib/interactive.c |   16 ++++++++++++++--
>  5 files changed, 30 insertions(+), 10 deletions(-)

Pushed upstream after manually fixing your commit message: please limit
line lengths to 74 characters.

Johan

^ permalink raw reply

* Re: [PATCH 0/5] Attribute server API fixes
From: Johan Hedberg @ 2011-03-17 12:58 UTC (permalink / raw)
  To: Anderson Lizardo; +Cc: linux-bluetooth
In-Reply-To: <1300307416-29909-1-git-send-email-anderson.lizardo@openbossa.org>

Hi Lizardo,

On Wed, Mar 16, 2011, Anderson Lizardo wrote:
> This series contains small fixes to the attribute server API. Some fixes are
> required for a RFC that I will send soon.

Thanks. All five patches have been pushed upstream.

Johan

^ permalink raw reply

* Re: [PATCH] Update TODO regarding bt_uuid_* functions
From: Johan Hedberg @ 2011-03-17 12:59 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1300325814-6247-1-git-send-email-epx@signove.com>

Hi Elvis,

On Wed, Mar 16, 2011, Elvis Pf??tzenreuter wrote:
> ---
>  TODO |   14 ++++----------
>  1 files changed, 4 insertions(+), 10 deletions(-)

Pushed upstream. Thanks.

Johan

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox