Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH BlueZ v1 1/9] gdbus: Add g_dbus_client_set_ready_watch()
From: Claudio Takahasi @ 2014-03-06 13:44 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1394113467-24331-1-git-send-email-claudio.takahasi@openbossa.org>

This patch adds a new gdbus helper to notify the clients that
GetManagedObjects reply was received and the last proxy has been
informed previously by the proxy_added callback.
---
 gdbus/client.c | 17 +++++++++++++++++
 gdbus/gdbus.h  |  4 +++-
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/gdbus/client.c b/gdbus/client.c
index be8cc29..5193b6c 100644
--- a/gdbus/client.c
+++ b/gdbus/client.c
@@ -56,6 +56,8 @@ struct GDBusClient {
 	void *signal_data;
 	GDBusProxyFunction proxy_added;
 	GDBusProxyFunction proxy_removed;
+	GDBusClientFunction ready;
+	void *ready_data;
 	GDBusPropertyFunction property_changed;
 	void *user_data;
 	GList *proxy_list;
@@ -982,6 +984,9 @@ static void parse_managed_objects(GDBusClient *client, DBusMessage *msg)
 
 		dbus_message_iter_next(&dict);
 	}
+
+	if (client->ready)
+		client->ready(client, client->ready_data);
 }
 
 static void get_managed_objects_reply(DBusPendingCall *call, void *user_data)
@@ -1243,6 +1248,18 @@ gboolean g_dbus_client_set_signal_watch(GDBusClient *client,
 	return TRUE;
 }
 
+gboolean g_dbus_client_set_ready_watch(GDBusClient *client,
+				GDBusClientFunction ready, void *user_data)
+{
+	if (client == NULL)
+		return FALSE;
+
+	client->ready = ready;
+	client->ready_data = user_data;
+
+	return TRUE;
+}
+
 gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client,
 					GDBusProxyFunction proxy_added,
 					GDBusProxyFunction proxy_removed,
diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h
index 9542109..8ada200 100644
--- a/gdbus/gdbus.h
+++ b/gdbus/gdbus.h
@@ -337,6 +337,7 @@ gboolean g_dbus_proxy_method_call(GDBusProxy *proxy, const char *method,
 				GDBusReturnFunction function, void *user_data,
 				GDBusDestroyFunction destroy);
 
+typedef void (* GDBusClientFunction) (GDBusClient *client, void *user_data);
 typedef void (* GDBusProxyFunction) (GDBusProxy *proxy, void *user_data);
 typedef void (* GDBusPropertyFunction) (GDBusProxy *proxy, const char *name,
 					DBusMessageIter *iter, void *user_data);
@@ -359,7 +360,8 @@ gboolean g_dbus_client_set_disconnect_watch(GDBusClient *client,
 				GDBusWatchFunction function, void *user_data);
 gboolean g_dbus_client_set_signal_watch(GDBusClient *client,
 				GDBusMessageFunction function, void *user_data);
-
+gboolean g_dbus_client_set_ready_watch(GDBusClient *client,
+				GDBusClientFunction ready, void *user_data);
 gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client,
 					GDBusProxyFunction proxy_added,
 					GDBusProxyFunction proxy_removed,
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 2/9] gatt: Add proxy added handler
From: Claudio Takahasi @ 2014-03-06 13:44 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1394113467-24331-1-git-send-email-claudio.takahasi@openbossa.org>

This patch creates a list of GATT objects sorting the entries based on
the object path to allow inserting the attributes following hierarchical
association.
---
 src/gatt-dbus.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index fd614f9..f8486f3 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -42,11 +42,15 @@
 #include "gatt-dbus.h"
 
 #define GATT_MGR_IFACE			"org.bluez.GattManager1"
+#define GATT_SERVICE_IFACE		"org.bluez.GattService1"
+#define GATT_CHR_IFACE			"org.bluez.GattCharacteristic1"
+#define GATT_DESCRIPTOR_IFACE		"org.bluez.GattDescriptor1"
 
 struct external_app {
 	char *owner;
 	char *path;
 	GDBusClient *client;
+	GSList *proxies;
 	unsigned int watch;
 };
 
@@ -75,6 +79,43 @@ static void external_app_watch_destroy(gpointer user_data)
 	g_free(eapp);
 }
 
+static int proxy_path_cmp(gconstpointer a, gconstpointer b)
+{
+	GDBusProxy *proxy1 = (GDBusProxy *) a;
+	GDBusProxy *proxy2 = (GDBusProxy *) b;
+	const char *path1 = g_dbus_proxy_get_path(proxy1);
+	const char *path2 = g_dbus_proxy_get_path(proxy2);
+
+	return g_strcmp0(path1, path2);
+}
+
+static void proxy_added(GDBusProxy *proxy, void *user_data)
+{
+	struct external_app *eapp = user_data;
+	const char *interface, *path;
+
+	interface = g_dbus_proxy_get_interface(proxy);
+	path = g_dbus_proxy_get_path(proxy);
+
+	if (!g_str_has_prefix(path, eapp->path))
+		return;
+
+	if (g_strcmp0(interface, GATT_CHR_IFACE) != 0 &&
+			g_strcmp0(interface, GATT_SERVICE_IFACE) != 0 &&
+			g_strcmp0(interface, GATT_DESCRIPTOR_IFACE) != 0)
+		return;
+
+	DBG("path %s iface %s", path, interface);
+
+	/*
+	 * Object path follows a hierarchical organization. Add the
+	 * proxies sorted by path helps the logic to register the
+	 * object path later.
+	 */
+	eapp->proxies = g_slist_insert_sorted(eapp->proxies, proxy,
+							proxy_path_cmp);
+}
+
 static struct external_app *new_external_app(DBusConnection *conn,
 					const char *sender, const char *path)
 {
@@ -99,6 +140,9 @@ static struct external_app *new_external_app(DBusConnection *conn,
 	eapp->client = client;
 	eapp->path = g_strdup(path);
 
+	g_dbus_client_set_proxy_handlers(client, proxy_added, NULL, NULL,
+								eapp);
+
 	return eapp;
 }
 
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 3/9] gatt: Add proxy removed handler
From: Claudio Takahasi @ 2014-03-06 13:44 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1394113467-24331-1-git-send-email-claudio.takahasi@openbossa.org>

---
 src/gatt-dbus.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index f8486f3..28d7f78 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -116,6 +116,19 @@ static void proxy_added(GDBusProxy *proxy, void *user_data)
 							proxy_path_cmp);
 }
 
+static void proxy_removed(GDBusProxy *proxy, void *user_data)
+{
+	struct external_app *eapp = user_data;
+	const char *interface, *path;
+
+	interface = g_dbus_proxy_get_interface(proxy);
+	path = g_dbus_proxy_get_path(proxy);
+
+	DBG("path %s iface %s", path, interface);
+
+	eapp->proxies = g_slist_remove(eapp->proxies, proxy);
+}
+
 static struct external_app *new_external_app(DBusConnection *conn,
 					const char *sender, const char *path)
 {
@@ -140,8 +153,8 @@ static struct external_app *new_external_app(DBusConnection *conn,
 	eapp->client = client;
 	eapp->path = g_strdup(path);
 
-	g_dbus_client_set_proxy_handlers(client, proxy_added, NULL, NULL,
-								eapp);
+	g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
+								NULL, eapp);
 
 	return eapp;
 }
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 4/9] gatt: Add GATT service to the local database
From: Claudio Takahasi @ 2014-03-06 13:44 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1394113467-24331-1-git-send-email-claudio.takahasi@openbossa.org>

This patch creates GATT service attribute based on its GDBusProxy
object, and inserts the declaration to the local database.
---
 src/gatt-dbus.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index 28d7f78..d62e2cf 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -39,6 +39,7 @@
 #include "log.h"
 
 #include "error.h"
+#include "gatt.h"
 #include "gatt-dbus.h"
 
 #define GATT_MGR_IFACE			"org.bluez.GattManager1"
@@ -129,6 +130,56 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
 	eapp->proxies = g_slist_remove(eapp->proxies, proxy);
 }
 
+static int register_external_service(const struct external_app *eapp,
+							GDBusProxy *proxy)
+{
+	DBusMessageIter iter;
+	const char *str, *path, *iface;
+	bt_uuid_t uuid;
+
+	path = g_dbus_proxy_get_path(proxy);
+	iface = g_dbus_proxy_get_interface(proxy);
+	if (g_strcmp0(eapp->path, path) != 0 ||
+			g_strcmp0(iface, GATT_SERVICE_IFACE) != 0)
+		return -EINVAL;
+
+	if (!g_dbus_proxy_get_property(proxy, "UUID", &iter))
+		return -EINVAL;
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+		return -EINVAL;
+
+	dbus_message_iter_get_basic(&iter, &str);
+
+	if (bt_string_to_uuid(&uuid, str) < 0)
+		return -EINVAL;
+
+	if (btd_gatt_add_service(&uuid) == NULL)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void client_ready(GDBusClient *client, void *user_data)
+{
+	struct external_app *eapp = user_data;
+	GDBusProxy *proxy;
+
+	if (eapp->proxies == NULL)
+		goto fail;
+
+	proxy = eapp->proxies->data;
+	if (register_external_service(eapp, proxy) < 0)
+		goto fail;
+
+	DBG("Added GATT service %s", eapp->path);
+
+	return;
+
+fail:
+	error("Could not register external service: %s", eapp->path);
+}
+
 static struct external_app *new_external_app(DBusConnection *conn,
 					const char *sender, const char *path)
 {
@@ -156,6 +207,8 @@ static struct external_app *new_external_app(DBusConnection *conn,
 	g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
 								NULL, eapp);
 
+	g_dbus_client_set_ready_watch(client, client_ready, eapp);
+
 	return eapp;
 }
 
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 5/9] gatt: Make RegisterService() async
From: Claudio Takahasi @ 2014-03-06 13:44 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1394113467-24331-1-git-send-email-claudio.takahasi@openbossa.org>

GDBusProxy objects consistency should be checked, and attributes
declaration inserted in the local GATT database before replying
the caller.
---
 src/gatt-dbus.c | 27 ++++++++++++++++++++++-----
 1 file changed, 22 insertions(+), 5 deletions(-)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index d62e2cf..3fbff87 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -50,6 +50,7 @@
 struct external_app {
 	char *owner;
 	char *path;
+	DBusMessage *reg;
 	GDBusClient *client;
 	GSList *proxies;
 	unsigned int watch;
@@ -74,6 +75,8 @@ static void external_app_watch_destroy(gpointer user_data)
 	external_apps = g_slist_remove(external_apps, eapp);
 
 	g_dbus_client_unref(eapp->client);
+	if (eapp->reg)
+		dbus_message_unref(eapp->reg);
 
 	g_free(eapp->owner);
 	g_free(eapp->path);
@@ -164,6 +167,8 @@ static void client_ready(GDBusClient *client, void *user_data)
 {
 	struct external_app *eapp = user_data;
 	GDBusProxy *proxy;
+	DBusConnection *conn = btd_get_dbus_connection();
+	DBusMessage *reply;
 
 	if (eapp->proxies == NULL)
 		goto fail;
@@ -174,17 +179,28 @@ static void client_ready(GDBusClient *client, void *user_data)
 
 	DBG("Added GATT service %s", eapp->path);
 
-	return;
+	reply = dbus_message_new_method_return(eapp->reg);
+	goto reply;
 
 fail:
 	error("Could not register external service: %s", eapp->path);
+
+	reply = btd_error_invalid_args(eapp->reg);
+	/* TODO: missing eapp cleanup */
+
+reply:
+	dbus_message_unref(eapp->reg);
+	eapp->reg = NULL;
+
+	g_dbus_send_message(conn, reply);
 }
 
 static struct external_app *new_external_app(DBusConnection *conn,
-					const char *sender, const char *path)
+					DBusMessage *msg, const char *path)
 {
 	struct external_app *eapp;
 	GDBusClient *client;
+	const char *sender = dbus_message_get_sender(msg);
 
 	client = g_dbus_client_new(conn, sender, "/");
 	if (client == NULL)
@@ -201,6 +217,7 @@ static struct external_app *new_external_app(DBusConnection *conn,
 	}
 
 	eapp->owner = g_strdup(sender);
+	eapp->reg = dbus_message_ref(msg);
 	eapp->client = client;
 	eapp->path = g_strdup(path);
 
@@ -230,7 +247,7 @@ static DBusMessage *register_service(DBusConnection *conn,
 	if (g_slist_find_custom(external_apps, path, external_app_path_cmp))
 		return btd_error_already_exists(msg);
 
-	eapp = new_external_app(conn, dbus_message_get_sender(msg), path);
+	eapp = new_external_app(conn, msg, path);
 	if (eapp == NULL)
 		return btd_error_failed(msg, "Not enough resources");
 
@@ -238,7 +255,7 @@ static DBusMessage *register_service(DBusConnection *conn,
 
 	DBG("New app %p: %s", eapp, path);
 
-	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+	return NULL;
 }
 
 static DBusMessage *unregister_service(DBusConnection *conn,
@@ -248,7 +265,7 @@ static DBusMessage *unregister_service(DBusConnection *conn,
 }
 
 static const GDBusMethodTable methods[] = {
-	{ GDBUS_EXPERIMENTAL_METHOD("RegisterService",
+	{ GDBUS_EXPERIMENTAL_ASYNC_METHOD("RegisterService",
 				GDBUS_ARGS({ "service", "o"},
 						{ "options", "a{sv}"}),
 				NULL, register_service) },
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 6/9] test: Add external service GATT skeleton
From: Claudio Takahasi @ 2014-03-06 13:44 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1394113467-24331-1-git-send-email-claudio.takahasi@openbossa.org>

This patch adds the initial code for an external GATT service example.
It implements the API defined at doc/gatt-api.txt
---
 .gitignore          |   1 +
 Makefile.tools      |   5 +++
 test/gatt-service.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 127 insertions(+)
 create mode 100644 test/gatt-service.c

diff --git a/.gitignore b/.gitignore
index 47ba9b8..f323080 100644
--- a/.gitignore
+++ b/.gitignore
@@ -76,6 +76,7 @@ test/sap_client.pyc
 test/bluezutils.pyc
 unit/test-ringbuf
 unit/test-queue
+test/gatt-service
 unit/test-eir
 unit/test-uuid
 unit/test-crc
diff --git a/Makefile.tools b/Makefile.tools
index 31e1093..c589199 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -393,3 +393,8 @@ test_scripts += test/sap_client.py test/bluezutils.py \
 		test/test-heartrate test/test-alert test/test-hfp \
 		test/test-cyclingspeed test/opp-client test/ftp-client \
 		test/pbap-client test/map-client
+
+noinst_PROGRAMS += test/gatt-service
+
+test_gatt_service_SOURCES = test/gatt-service.c
+test_gatt_service_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ gdbus/libgdbus-internal.la
diff --git a/test/gatt-service.c b/test/gatt-service.c
new file mode 100644
index 0000000..18ab7da
--- /dev/null
+++ b/test/gatt-service.c
@@ -0,0 +1,121 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2014  Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus/gdbus.h>
+
+#define GATT_SERVICE_IFACE		"org.bluez.GattService1"
+
+/* Immediate Alert Service UUID */
+#define IAS_UUID			"00001802-0000-1000-8000-00805f9b34fb"
+
+static GMainLoop *main_loop;
+static GSList *services;
+
+static gboolean service_get_uuid(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *user_data)
+{
+	const char *uuid = user_data;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);
+
+	return TRUE;
+}
+
+static gboolean service_get_includes(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *user_data)
+{
+	return TRUE;
+}
+
+static gboolean service_exist_includes(const GDBusPropertyTable *property,
+							void *user_data)
+{
+	return FALSE;
+}
+
+static const GDBusPropertyTable service_properties[] = {
+	{ "UUID", "s", service_get_uuid },
+	{ "Includes", "ao", service_get_includes, NULL,
+					service_exist_includes },
+	{ }
+};
+
+static char *register_service(DBusConnection *conn, const char *uuid)
+{
+	static int id = 1;
+	char *path;
+
+	path = g_strdup_printf("/service%d", id++);
+	if (g_dbus_register_interface(conn, path, GATT_SERVICE_IFACE,
+				NULL, NULL, service_properties,
+				g_strdup(uuid), g_free) == FALSE) {
+		printf("Couldn't register service interface\n");
+		g_free(path);
+		return NULL;
+	}
+
+	return path;
+}
+
+static void create_services(DBusConnection *conn)
+{
+	char *service_path;
+
+	service_path = register_service(conn, IAS_UUID);
+
+	services = g_slist_prepend(services, service_path);
+
+	printf("Registered service: %s\n", service_path);
+}
+
+int main(int argc, char *argv[])
+{
+	DBusConnection *dbus_conn;
+
+	dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
+
+	main_loop = g_main_loop_new(NULL, FALSE);
+
+	g_dbus_attach_object_manager(dbus_conn);
+
+	printf("gatt-service unique name: %s\n",
+				dbus_bus_get_unique_name(dbus_conn));
+
+	create_services(dbus_conn);
+
+	g_main_loop_run(main_loop);
+
+	g_slist_free_full(services, g_free);
+	dbus_connection_unref(dbus_conn);
+
+	return 0;
+}
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 7/9] test: Add signal handling for gatt-service
From: Claudio Takahasi @ 2014-03-06 13:44 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1394113467-24331-1-git-send-email-claudio.takahasi@openbossa.org>

This patch implements signal handling to run cleanup tasks before
exiting.
---
 test/gatt-service.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/test/gatt-service.c b/test/gatt-service.c
index 18ab7da..ecb5cc3 100644
--- a/test/gatt-service.c
+++ b/test/gatt-service.c
@@ -27,6 +27,9 @@
 
 #include <errno.h>
 #include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <sys/signalfd.h>
 
 #include <glib.h>
 #include <dbus/dbus.h>
@@ -97,9 +100,83 @@ static void create_services(DBusConnection *conn)
 	printf("Registered service: %s\n", service_path);
 }
 
+static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
+							gpointer user_data)
+{
+	static bool __terminated = false;
+	struct signalfd_siginfo si;
+	ssize_t result;
+	int fd;
+
+	if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
+		return FALSE;
+
+	fd = g_io_channel_unix_get_fd(channel);
+
+	result = read(fd, &si, sizeof(si));
+	if (result != sizeof(si))
+		return FALSE;
+
+	switch (si.ssi_signo) {
+	case SIGINT:
+	case SIGTERM:
+		if (!__terminated) {
+			printf("Terminating\n");
+			g_main_loop_quit(main_loop);
+		}
+
+		__terminated = true;
+		break;
+	}
+
+	return TRUE;
+}
+
+static guint setup_signalfd(void)
+{
+	GIOChannel *channel;
+	guint source;
+	sigset_t mask;
+	int fd;
+
+	sigemptyset(&mask);
+	sigaddset(&mask, SIGINT);
+	sigaddset(&mask, SIGTERM);
+
+	if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
+		perror("Failed to set signal mask");
+		return 0;
+	}
+
+	fd = signalfd(-1, &mask, 0);
+	if (fd < 0) {
+		perror("Failed to create signal descriptor");
+		return 0;
+	}
+
+	channel = g_io_channel_unix_new(fd);
+
+	g_io_channel_set_close_on_unref(channel, TRUE);
+	g_io_channel_set_encoding(channel, NULL, NULL);
+	g_io_channel_set_buffered(channel, FALSE);
+
+	source = g_io_add_watch(channel,
+				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+				signal_handler, NULL);
+
+	g_io_channel_unref(channel);
+
+	return source;
+}
+
 int main(int argc, char *argv[])
 {
 	DBusConnection *dbus_conn;
+	guint signal;
+
+	signal = setup_signalfd();
+	if (signal == 0)
+		return -errno;
 
 	dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
 
@@ -114,6 +191,8 @@ int main(int argc, char *argv[])
 
 	g_main_loop_run(main_loop);
 
+	g_source_remove(signal);
+
 	g_slist_free_full(services, g_free);
 	dbus_connection_unref(dbus_conn);
 
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 8/9] test: Add registering external service
From: Claudio Takahasi @ 2014-03-06 13:44 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1394113467-24331-1-git-send-email-claudio.takahasi@openbossa.org>

This patch extends gatt-service to call RegisterService() when org.bluez
service gets connected to the system bus.
---
 test/gatt-service.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/test/gatt-service.c b/test/gatt-service.c
index ecb5cc3..f8ae7cc 100644
--- a/test/gatt-service.c
+++ b/test/gatt-service.c
@@ -35,6 +35,7 @@
 #include <dbus/dbus.h>
 #include <gdbus/gdbus.h>
 
+#define GATT_MGR_IFACE			"org.bluez.GattManager1"
 #define GATT_SERVICE_IFACE		"org.bluez.GattService1"
 
 /* Immediate Alert Service UUID */
@@ -100,6 +101,65 @@ static void create_services(DBusConnection *conn)
 	printf("Registered service: %s\n", service_path);
 }
 
+static void register_external_service_reply(DBusPendingCall *call,
+							void *user_data)
+{
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusError derr;
+
+	dbus_error_init(&derr);
+	dbus_set_error_from_message(&derr, reply);
+
+	if (dbus_error_is_set(&derr))
+		printf("RegisterService: %s\n", derr.message);
+	else
+		printf("RegisterService: OK\n");
+
+	dbus_message_unref(reply);
+	dbus_error_free(&derr);
+}
+
+static void register_external_service(gpointer a, gpointer b)
+{
+	DBusConnection *conn = b;
+	const char *path = a;
+	DBusMessage *msg;
+	DBusPendingCall *call;
+	DBusMessageIter iter, dict;
+
+	msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
+					GATT_MGR_IFACE, "RegisterService");
+	if (msg == NULL) {
+		printf("Couldn't allocate D-Bus message\n");
+		return;
+	}
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &dict);
+
+	/* TODO: Add options dictionary */
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	if (g_dbus_send_message_with_reply(conn, msg, &call, -1) == FALSE) {
+		dbus_message_unref(msg);
+		return;
+	}
+
+	dbus_pending_call_set_notify(call, register_external_service_reply,
+								NULL, NULL);
+
+	dbus_pending_call_unref(call);
+}
+
+static void connect_handler(DBusConnection *conn, void *user_data)
+{
+	g_slist_foreach(services, register_external_service, conn);
+}
+
 static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
 							gpointer user_data)
 {
@@ -171,6 +231,7 @@ static guint setup_signalfd(void)
 
 int main(int argc, char *argv[])
 {
+	GDBusClient *client;
 	DBusConnection *dbus_conn;
 	guint signal;
 
@@ -189,8 +250,14 @@ int main(int argc, char *argv[])
 
 	create_services(dbus_conn);
 
+	client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
+
+	g_dbus_client_set_connect_watch(client, connect_handler, NULL);
+
 	g_main_loop_run(main_loop);
 
+	g_dbus_client_unref(client);
+
 	g_source_remove(signal);
 
 	g_slist_free_full(services, g_free);
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 9/9] bluetooth.conf: Add ObjectManager interface
From: Claudio Takahasi @ 2014-03-06 13:44 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1394113467-24331-1-git-send-email-claudio.takahasi@openbossa.org>

---
 src/bluetooth.conf | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/bluetooth.conf b/src/bluetooth.conf
index 0495200..ad8891a 100644
--- a/src/bluetooth.conf
+++ b/src/bluetooth.conf
@@ -18,6 +18,7 @@
     <allow send_interface="org.bluez.Profile1"/>
     <allow send_interface="org.bluez.HeartRateWatcher1"/>
     <allow send_interface="org.bluez.CyclingSpeedWatcher1"/>
+    <allow send_interface="org.freedesktop.DBus.ObjectManager"/>
   </policy>
 
   <policy at_console="true">
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH v2 1/4] android/avrcp: Add remote features notification
From: Luiz Augusto von Dentz @ 2014-03-06 13:45 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
v2: Keep uint16_t as type of device features.

 android/avrcp.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/android/avrcp.c b/android/avrcp.c
index cb46dcc..d5eb31d 100644
--- a/android/avrcp.c
+++ b/android/avrcp.c
@@ -43,6 +43,7 @@
 #include "ipc.h"
 #include "bluetooth.h"
 #include "avrcp.h"
+#include "utils.h"
 
 #define L2CAP_PSM_AVCTP 0x17
 
@@ -699,6 +700,7 @@ static const struct avrcp_control_handler control_handlers[] = {
 static int avrcp_device_add_session(struct avrcp_device *dev, int fd,
 						uint16_t imtu, uint16_t omtu)
 {
+	struct hal_ev_avrcp_remote_features ev;
 	char address[18];
 
 	dev->session = avrcp_new(fd, imtu, omtu, dev->version);
@@ -717,6 +719,21 @@ static int avrcp_device_add_session(struct avrcp_device *dev, int fd,
 	/* FIXME: get the real name of the device */
 	avrcp_init_uinput(dev->session, "bluetooth", address);
 
+	bdaddr2android(&dev->dst, ev.bdaddr);
+	ev.features = HAL_AVRCP_FEATURE_NONE;
+
+	DBG("version 0x%02x", dev->version);
+
+	if (dev->version < 0x0103)
+		goto done;
+
+	ev.features |= HAL_AVRCP_FEATURE_METADATA;
+
+done:
+	ipc_send_notif(hal_ipc, HAL_SERVICE_ID_AVRCP,
+					HAL_EV_AVRCP_REMOTE_FEATURES,
+					sizeof(ev), &ev);
+
 	return 0;
 }
 
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH v2 2/4] android/client: Add AVRCP remote_features_cb support
From: Luiz Augusto von Dentz @ 2014-03-06 13:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1394113527-4398-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 android/client/if-rc.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/android/client/if-rc.c b/android/client/if-rc.c
index 55fdf1d..60c3247 100644
--- a/android/client/if-rc.c
+++ b/android/client/if-rc.c
@@ -46,6 +46,15 @@ SINTMAP(btrc_media_attr_t, -1, "(unknown)")
 	DELEMENT(BTRC_MEDIA_ATTR_PLAYING_TIME),
 ENDMAP
 
+static char last_addr[MAX_ADDR_STR_LEN];
+
+static void remote_features_cb(bt_bdaddr_t *bd_addr,
+					btrc_remote_features_t features)
+{
+	haltest_info("%s: remote_bd_addr=%s features=%u\n", __func__,
+				bt_bdaddr_t2str(bd_addr, last_addr), features);
+}
+
 static void get_play_status_cb(void)
 {
 	haltest_info("%s\n", __func__);
@@ -73,6 +82,7 @@ static void volume_change_cb(uint8_t volume, uint8_t ctype)
 
 static btrc_callbacks_t rc_cbacks = {
 	.size = sizeof(rc_cbacks),
+	.remote_features_cb = remote_features_cb,
 	.get_play_status_cb = get_play_status_cb,
 	.get_element_attr_cb = get_element_attr_cb,
 	.register_notification_cb = register_notification_cb,
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH v2 3/4] android/arvrcp: Fix not parsing SDP record correctly
From: Luiz Augusto von Dentz @ 2014-03-06 13:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1394113527-4398-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 android/avrcp.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/android/avrcp.c b/android/avrcp.c
index d5eb31d..911b1df 100644
--- a/android/avrcp.c
+++ b/android/avrcp.c
@@ -25,6 +25,7 @@
 #include <config.h>
 #endif
 
+#include <stdlib.h>
 #include <stdbool.h>
 #include <errno.h>
 #include <glib.h>
@@ -817,15 +818,22 @@ static void search_cb(sdp_list_t *recs, int err, gpointer data)
 
 	for (list = recs; list; list = list->next) {
 		sdp_record_t *rec = list->data;
-		sdp_data_t *data;
+		sdp_list_t *l;
+		sdp_profile_desc_t *desc;
+		int features;
 
-		data = sdp_data_get(rec, SDP_ATTR_VERSION);
-		if (data)
-			dev->version = data->val.uint16;
+		if (sdp_get_profile_descs(rec, &l) < 0)
+			continue;
 
-		data = sdp_data_get(rec, SDP_ATTR_SUPPORTED_FEATURES);
-		if (data)
-			dev->features = data->val.uint16;
+		desc = l->data;
+		dev->version = desc->version;
+
+		if (sdp_get_int_attr(rec, SDP_ATTR_SUPPORTED_FEATURES,
+							&features) == 0)
+			dev->features = features;
+
+		sdp_list_free(l, free);
+		break;
 	}
 
 	if (dev->io) {
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH v2 4/4] android/avrcp: Fix warnings when freeing avrcp_device struct
From: Luiz Augusto von Dentz @ 2014-03-06 13:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1394113527-4398-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

If the device does not yet have queue due to not have a session it cause
the following warnings when avrcp_device_free is called:
(bluetoothd:1102): GLib-CRITICAL **: g_queue_foreach: assertion 'queue != NULL' failed
(bluetoothd:1102): GLib-CRITICAL **: g_queue_free: assertion 'queue != NULL' failed
---
 android/avrcp.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/android/avrcp.c b/android/avrcp.c
index 911b1df..1d211ad 100644
--- a/android/avrcp.c
+++ b/android/avrcp.c
@@ -442,8 +442,10 @@ static void avrcp_device_free(void *data)
 {
 	struct avrcp_device *dev = data;
 
-	g_queue_foreach(dev->queue, (GFunc) g_free, NULL);
-	g_queue_free(dev->queue);
+	if (dev->queue) {
+		g_queue_foreach(dev->queue, (GFunc) g_free, NULL);
+		g_queue_free(dev->queue);
+	}
 
 	if (dev->session)
 		avrcp_shutdown(dev->session);
-- 
1.8.5.3


^ permalink raw reply related

* Re: [PATCH BlueZ v1 1/9] gdbus: Add g_dbus_client_set_ready_watch()
From: Luiz Augusto von Dentz @ 2014-03-06 13:56 UTC (permalink / raw)
  To: Claudio Takahasi; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1394113467-24331-2-git-send-email-claudio.takahasi@openbossa.org>

Hi Claudio,

On Thu, Mar 6, 2014 at 3:44 PM, Claudio Takahasi
<claudio.takahasi@openbossa.org> wrote:
> This patch adds a new gdbus helper to notify the clients that
> GetManagedObjects reply was received and the last proxy has been
> informed previously by the proxy_added callback.
> ---
>  gdbus/client.c | 17 +++++++++++++++++
>  gdbus/gdbus.h  |  4 +++-
>  2 files changed, 20 insertions(+), 1 deletion(-)
>
> diff --git a/gdbus/client.c b/gdbus/client.c
> index be8cc29..5193b6c 100644
> --- a/gdbus/client.c
> +++ b/gdbus/client.c
> @@ -56,6 +56,8 @@ struct GDBusClient {
>         void *signal_data;
>         GDBusProxyFunction proxy_added;
>         GDBusProxyFunction proxy_removed;
> +       GDBusClientFunction ready;
> +       void *ready_data;
>         GDBusPropertyFunction property_changed;
>         void *user_data;
>         GList *proxy_list;
> @@ -982,6 +984,9 @@ static void parse_managed_objects(GDBusClient *client, DBusMessage *msg)
>
>                 dbus_message_iter_next(&dict);
>         }
> +
> +       if (client->ready)
> +               client->ready(client, client->ready_data);
>  }
>
>  static void get_managed_objects_reply(DBusPendingCall *call, void *user_data)
> @@ -1243,6 +1248,18 @@ gboolean g_dbus_client_set_signal_watch(GDBusClient *client,
>         return TRUE;
>  }
>
> +gboolean g_dbus_client_set_ready_watch(GDBusClient *client,
> +                               GDBusClientFunction ready, void *user_data)
> +{
> +       if (client == NULL)
> +               return FALSE;
> +
> +       client->ready = ready;
> +       client->ready_data = user_data;
> +
> +       return TRUE;
> +}
> +
>  gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client,
>                                         GDBusProxyFunction proxy_added,
>                                         GDBusProxyFunction proxy_removed,
> diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h
> index 9542109..8ada200 100644
> --- a/gdbus/gdbus.h
> +++ b/gdbus/gdbus.h
> @@ -337,6 +337,7 @@ gboolean g_dbus_proxy_method_call(GDBusProxy *proxy, const char *method,
>                                 GDBusReturnFunction function, void *user_data,
>                                 GDBusDestroyFunction destroy);
>
> +typedef void (* GDBusClientFunction) (GDBusClient *client, void *user_data);
>  typedef void (* GDBusProxyFunction) (GDBusProxy *proxy, void *user_data);
>  typedef void (* GDBusPropertyFunction) (GDBusProxy *proxy, const char *name,
>                                         DBusMessageIter *iter, void *user_data);
> @@ -359,7 +360,8 @@ gboolean g_dbus_client_set_disconnect_watch(GDBusClient *client,
>                                 GDBusWatchFunction function, void *user_data);
>  gboolean g_dbus_client_set_signal_watch(GDBusClient *client,
>                                 GDBusMessageFunction function, void *user_data);
> -
> +gboolean g_dbus_client_set_ready_watch(GDBusClient *client,
> +                               GDBusClientFunction ready, void *user_data);
>  gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client,
>                                         GDBusProxyFunction proxy_added,
>                                         GDBusProxyFunction proxy_removed,
> --
> 1.8.3.1

It should be relatively simple to add a unit for it, doesn't need to
be in the same patch-set since I don't want to slow down the set just
because of the lack of it.


-- 
Luiz Augusto von Dentz

^ permalink raw reply

* [PATCH 1/7] unit/avrcp: Add /TP/MDI/BV-01-C test
From: Andrei Emeltchenko @ 2014-03-06 14:42 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Test verifies Get play status.
---
 unit/test-avrcp.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 8682e63..46ddde9 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -459,6 +459,23 @@ static ssize_t avrcp_handle_set_player_value(struct avrcp *session,
 	return 1;
 }
 
+static ssize_t avrcp_handle_get_play_status(struct avrcp *session,
+						uint8_t transaction,
+						uint16_t params_len,
+						uint8_t *params,
+						void *user_data)
+{
+	DBG("");
+
+	if (params_len)
+		return -EINVAL;
+
+	avrcp_get_play_status_rsp(session, transaction, 0xaaaaaaaa, 0xbbbbbbbb,
+									0x00);
+
+	return -EAGAIN;
+}
+
 static const struct avrcp_control_handler control_handlers[] = {
 		{ AVRCP_GET_CAPABILITIES,
 					AVC_CTYPE_STATUS, AVC_CTYPE_STABLE,
@@ -481,6 +498,9 @@ static const struct avrcp_control_handler control_handlers[] = {
 		{ AVRCP_SET_PLAYER_VALUE,
 					AVC_CTYPE_CONTROL, AVC_CTYPE_STABLE,
 					avrcp_handle_set_player_value },
+		{ AVRCP_GET_PLAY_STATUS,
+					AVC_CTYPE_STATUS, AVC_CTYPE_STABLE,
+					avrcp_handle_get_play_status },
 		{ },
 };
 
@@ -782,5 +802,16 @@ int main(int argc, char *argv[])
 				0x00, 0x19, 0x58, AVRCP_GET_PLAY_STATUS,
 				0x00, 0x00, 0x00));
 
+	/* Get play status - TG */
+	define_test("/TP/MDI/BV-02-C", test_server,
+			raw_pdu(0x00, 0x11, 0x0e, 0x01, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_GET_PLAY_STATUS,
+				0x00, 0x00, 0x00),
+			raw_pdu(0x02, 0x11, 0x0e, 0x0c, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_GET_PLAY_STATUS,
+				0x00, 0x00, 0x09, 0xaa, 0xaa, 0xaa,
+				0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0x00));
+
+
 	return g_test_run();
 }
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH 2/7] android/avrcp: Add avrcp_get_element_attributes() function
From: Andrei Emeltchenko @ 2014-03-06 14:43 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1394116985-28247-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

---
 android/avrcp-lib.c | 13 +++++++++++++
 android/avrcp-lib.h |  2 ++
 2 files changed, 15 insertions(+)

diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index cd39071..fbaa48d 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -403,6 +403,19 @@ int avrcp_get_play_status(struct avrcp *session, avctp_rsp_cb func,
 				user_data);
 }
 
+int avrcp_get_element_attributes(struct avrcp *session, avctp_rsp_cb func,
+								void *user_data)
+{
+	uint8_t buf[9];
+
+	/* This returns all attributes */
+	memset(buf, 0, sizeof(buf));
+
+	return avrcp_send_req(session, AVC_CTYPE_STATUS, AVC_SUBUNIT_PANEL,
+				AVRCP_GET_ELEMENT_ATTRIBUTES, buf, sizeof(buf),
+				func, user_data);
+}
+
 int avrcp_get_play_status_rsp(struct avrcp *session, uint8_t transaction,
 				uint32_t position, uint32_t duration,
 				uint8_t status)
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index ba1d84a..5e90ea1 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -145,6 +145,8 @@ int avrcp_get_current_player_value(struct avrcp *session, uint8_t *attrs,
 					void *user_data);
 int avrcp_get_play_status(struct avrcp *session, avctp_rsp_cb func,
 							void *user_data);
+int avrcp_get_element_attributes(struct avrcp *session, avctp_rsp_cb func,
+							void *user_data);
 
 int avrcp_get_play_status_rsp(struct avrcp *session, uint8_t transaction,
 				uint32_t position, uint32_t duration,
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH 3/7] unit/avrcp: Add /TP/MDI/BV-03-C test
From: Andrei Emeltchenko @ 2014-03-06 14:43 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1394116985-28247-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Test verifies that Get element attributes issued correctly.
---
 unit/test-avrcp.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 46ddde9..d50b1ad 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -553,6 +553,9 @@ static void test_client(gconstpointer data)
 	if (g_str_equal(context->data->test_name, "/TP/MDI/BV-01-C"))
 		avrcp_get_play_status(context->session, NULL, NULL);
 
+	if (g_str_equal(context->data->test_name, "/TP/MDI/BV-03-C"))
+		avrcp_get_element_attributes(context->session, NULL, NULL);
+
 	execute_context(context);
 }
 
@@ -812,6 +815,12 @@ int main(int argc, char *argv[])
 				0x00, 0x00, 0x09, 0xaa, 0xaa, 0xaa,
 				0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0x00));
 
+	/* Get element attributes - CT */
+	define_test("/TP/MDI/BV-03-C", test_client,
+			raw_pdu(0x00, 0x11, 0x0e, 0x01, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_GET_ELEMENT_ATTRIBUTES,
+				0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
 
 	return g_test_run();
 }
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH 4/7] unit/avrcp: Add /TP/MDI/BV-04-C test
From: Andrei Emeltchenko @ 2014-03-06 14:43 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1394116985-28247-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Test verifies Get element attributes responded by Target.
---
 unit/test-avrcp.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index d50b1ad..45ac798 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -476,6 +476,22 @@ static ssize_t avrcp_handle_get_play_status(struct avrcp *session,
 	return -EAGAIN;
 }
 
+static ssize_t avrcp_handle_get_element_attrs(struct avrcp *session,
+						uint8_t transaction,
+						uint16_t params_len,
+						uint8_t *params,
+						void *user_data)
+{
+	DBG("");
+
+	if (params_len < 9)
+		return -EINVAL;
+
+	avrcp_get_element_attrs_rsp(session, transaction, NULL, 0);
+
+	return -EAGAIN;
+}
+
 static const struct avrcp_control_handler control_handlers[] = {
 		{ AVRCP_GET_CAPABILITIES,
 					AVC_CTYPE_STATUS, AVC_CTYPE_STABLE,
@@ -501,6 +517,9 @@ static const struct avrcp_control_handler control_handlers[] = {
 		{ AVRCP_GET_PLAY_STATUS,
 					AVC_CTYPE_STATUS, AVC_CTYPE_STABLE,
 					avrcp_handle_get_play_status },
+		{  AVRCP_GET_ELEMENT_ATTRIBUTES,
+					AVC_CTYPE_STATUS, AVC_CTYPE_STABLE,
+					avrcp_handle_get_element_attrs },
 		{ },
 };
 
@@ -822,5 +841,14 @@ int main(int argc, char *argv[])
 				0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
 				0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
 
+	/* Get element attributes - TG */
+	define_test("/TP/MDI/BV-04-C", test_server,
+			raw_pdu(0x00, 0x11, 0x0e, 0x01, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_GET_ELEMENT_ATTRIBUTES,
+				0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
+			raw_pdu(0x02, 0x11, 0x0e, 0x0c, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_GET_ELEMENT_ATTRIBUTES,
+				0x00, 0x00, 0x00));
 	return g_test_run();
 }
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH 5/7] unit/avrcp: Add /TP/MDI/BV-05-C test
From: Andrei Emeltchenko @ 2014-03-06 14:43 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1394116985-28247-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Test verifies that Target responds to Get element attributes cmd.
---
 unit/test-avrcp.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 45ac798..2df3d6c 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -482,11 +482,14 @@ static ssize_t avrcp_handle_get_element_attrs(struct avrcp *session,
 						uint8_t *params,
 						void *user_data)
 {
-	DBG("");
+	DBG("params_len %d params[8] %d", params_len, params[8]);
 
 	if (params_len < 9)
 		return -EINVAL;
 
+	if (params_len != 9 + params[8] * 4)
+		return -EINVAL;
+
 	avrcp_get_element_attrs_rsp(session, transaction, NULL, 0);
 
 	return -EAGAIN;
@@ -850,5 +853,17 @@ int main(int argc, char *argv[])
 			raw_pdu(0x02, 0x11, 0x0e, 0x0c, 0x48, 0x00,
 				0x00, 0x19, 0x58, AVRCP_GET_ELEMENT_ATTRIBUTES,
 				0x00, 0x00, 0x00));
+
+	/* Get element attributes - TG */
+	define_test("/TP/MDI/BV-05-C", test_server,
+			raw_pdu(0x00, 0x11, 0x0e, 0x01, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_GET_ELEMENT_ATTRIBUTES,
+				0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+				0x00, 0x00, 0x00, 0x01),
+			raw_pdu(0x02, 0x11, 0x0e, 0x0c, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_GET_ELEMENT_ATTRIBUTES,
+				0x00, 0x00, 0x00));
+
 	return g_test_run();
 }
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH 6/7] android/avrcp: Add avrcp_register_notification() function
From: Andrei Emeltchenko @ 2014-03-06 14:43 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1394116985-28247-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

---
 android/avrcp-lib.c | 14 ++++++++++++++
 android/avrcp-lib.h |  6 ++++++
 2 files changed, 20 insertions(+)

diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index fbaa48d..1663218 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -416,6 +416,20 @@ int avrcp_get_element_attributes(struct avrcp *session, avctp_rsp_cb func,
 				func, user_data);
 }
 
+int avrcp_register_notification(struct avrcp *session, uint8_t event,
+				uint32_t interval, avctp_rsp_cb func,
+				void *user_data)
+{
+	uint8_t pdu[AVRCP_REGISTER_NOTIFICATION_PARAM_LENGTH];
+
+	pdu[0] = event;
+	bt_put_be32(interval, &pdu[1]);
+
+	return avrcp_send_req(session, AVC_CTYPE_NOTIFY, AVC_SUBUNIT_PANEL,
+				AVRCP_REGISTER_NOTIFICATION, pdu, sizeof(pdu),
+				func, user_data);
+}
+
 int avrcp_get_play_status_rsp(struct avrcp *session, uint8_t transaction,
 				uint32_t position, uint32_t duration,
 				uint8_t status)
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index 5e90ea1..b0a1025 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -86,6 +86,9 @@
 /* Company IDs for vendor dependent commands */
 #define IEEEID_BTSIG		0x001958
 
+/* Parameters legths */
+#define AVRCP_REGISTER_NOTIFICATION_PARAM_LENGTH	5
+
 struct avrcp;
 
 struct avrcp_control_handler {
@@ -147,6 +150,9 @@ int avrcp_get_play_status(struct avrcp *session, avctp_rsp_cb func,
 							void *user_data);
 int avrcp_get_element_attributes(struct avrcp *session, avctp_rsp_cb func,
 							void *user_data);
+int avrcp_register_notification(struct avrcp *session, uint8_t event,
+				uint32_t interval, avctp_rsp_cb func,
+				void *user_data);
 
 int avrcp_get_play_status_rsp(struct avrcp *session, uint8_t transaction,
 				uint32_t position, uint32_t duration,
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH 7/7] unit/avrcp: Add /TP/NFY/BV-01-C test
From: Andrei Emeltchenko @ 2014-03-06 14:43 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1394116985-28247-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Test verifies that Register notification command is issued by
Controller.
---
 unit/test-avrcp.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 2df3d6c..baff66d 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -578,6 +578,11 @@ static void test_client(gconstpointer data)
 	if (g_str_equal(context->data->test_name, "/TP/MDI/BV-03-C"))
 		avrcp_get_element_attributes(context->session, NULL, NULL);
 
+	if (g_str_equal(context->data->test_name, "/TP/NFY/BV-01-C"))
+		avrcp_register_notification(context->session,
+						AVRCP_EVENT_STATUS_CHANGED, 0,
+						NULL, NULL);
+
 	execute_context(context);
 }
 
@@ -865,5 +870,14 @@ int main(int argc, char *argv[])
 				0x00, 0x19, 0x58, AVRCP_GET_ELEMENT_ATTRIBUTES,
 				0x00, 0x00, 0x00));
 
+	/* Notification Commands */
+
+	/* Register notification - CT */
+	define_test("/TP/NFY/BV-01-C", test_client,
+			raw_pdu(0x00, 0x11, 0x0e, 0x03, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_REGISTER_NOTIFICATION,
+				0x00, 0x00, 0x05, AVRCP_EVENT_STATUS_CHANGED,
+				0x00, 0x00, 0x00, 0x00));
+
 	return g_test_run();
 }
-- 
1.8.3.2


^ permalink raw reply related

* Re: [PATCH BlueZ v1 0/9] GATT API: Add Register Services Async
From: Johan Hedberg @ 2014-03-06 14:54 UTC (permalink / raw)
  To: Claudio Takahasi; +Cc: linux-bluetooth
In-Reply-To: <1394113467-24331-1-git-send-email-claudio.takahasi@openbossa.org>

Hi Claudio,

On Thu, Mar 06, 2014, Claudio Takahasi wrote:
> This patchset is an extension of "[PATCH BlueZ v7 00/11] GATT API:
> External Services". It adds the following features:
>   * new gdbus helper to allow notifying the clients when
>     GetManagedObjects() reply is received and all proxies reported to
>     upper-layer.
>   * reply for RegisterService() after validating fetched objects
>   * adds the service declaration to the local GATT database
> 
> * Changes from v0 to v1:
>   - renames g_dbus_client_set_proxies_ready_watch() to
>     g_dbus_client_set_ready_watch()
> 
> Claudio Takahasi (9):
>   gdbus: Add g_dbus_client_set_ready_watch()
>   gatt: Add proxy added handler
>   gatt: Add proxy removed handler
>   gatt: Add GATT service to the local database
>   gatt: Make RegisterService() async
>   test: Add external service GATT skeleton
>   test: Add signal handling for gatt-service
>   test: Add registering external service
>   bluetooth.conf: Add ObjectManager interface
> 
>  .gitignore          |   1 +
>  Makefile.tools      |   5 +
>  gdbus/client.c      |  17 ++++
>  gdbus/gdbus.h       |   4 +-
>  src/bluetooth.conf  |   1 +
>  src/gatt-dbus.c     | 135 +++++++++++++++++++++++++-
>  test/gatt-service.c | 267 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  7 files changed, 425 insertions(+), 5 deletions(-)
>  create mode 100644 test/gatt-service.c

All patches in the set have been applied. Thanks.

Johan

^ permalink raw reply

* Re: [PATCH v2 1/4] android/avrcp: Add remote features notification
From: Luiz Augusto von Dentz @ 2014-03-06 15:38 UTC (permalink / raw)
  To: linux-bluetooth@vger.kernel.org
In-Reply-To: <1394113527-4398-1-git-send-email-luiz.dentz@gmail.com>

Hi,

On Thu, Mar 6, 2014 at 3:45 PM, Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> ---
> v2: Keep uint16_t as type of device features.
>
>  android/avrcp.c | 17 +++++++++++++++++
>  1 file changed, 17 insertions(+)
>
> diff --git a/android/avrcp.c b/android/avrcp.c
> index cb46dcc..d5eb31d 100644
> --- a/android/avrcp.c
> +++ b/android/avrcp.c
> @@ -43,6 +43,7 @@
>  #include "ipc.h"
>  #include "bluetooth.h"
>  #include "avrcp.h"
> +#include "utils.h"
>
>  #define L2CAP_PSM_AVCTP 0x17
>
> @@ -699,6 +700,7 @@ static const struct avrcp_control_handler control_handlers[] = {
>  static int avrcp_device_add_session(struct avrcp_device *dev, int fd,
>                                                 uint16_t imtu, uint16_t omtu)
>  {
> +       struct hal_ev_avrcp_remote_features ev;
>         char address[18];
>
>         dev->session = avrcp_new(fd, imtu, omtu, dev->version);
> @@ -717,6 +719,21 @@ static int avrcp_device_add_session(struct avrcp_device *dev, int fd,
>         /* FIXME: get the real name of the device */
>         avrcp_init_uinput(dev->session, "bluetooth", address);
>
> +       bdaddr2android(&dev->dst, ev.bdaddr);
> +       ev.features = HAL_AVRCP_FEATURE_NONE;
> +
> +       DBG("version 0x%02x", dev->version);
> +
> +       if (dev->version < 0x0103)
> +               goto done;
> +
> +       ev.features |= HAL_AVRCP_FEATURE_METADATA;
> +
> +done:
> +       ipc_send_notif(hal_ipc, HAL_SERVICE_ID_AVRCP,
> +                                       HAL_EV_AVRCP_REMOTE_FEATURES,
> +                                       sizeof(ev), &ev);
> +
>         return 0;
>  }
>
> --
> 1.8.5.3

Pushed.


-- 
Luiz Augusto von Dentz

^ permalink raw reply

* Re: [PATCH 01/10] unit/avrcp: Refactor check attributes code
From: Luiz Augusto von Dentz @ 2014-03-06 15:45 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1394029952-3319-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

Hi Andrei,

On Wed, Mar 5, 2014 at 4:32 PM, Andrei Emeltchenko
<Andrei.Emeltchenko.news@gmail.com> wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> Make check_attributes() function which would handle attributes check.
> ---
>  unit/test-avrcp.c | 24 ++++++++++++++++--------
>  1 file changed, 16 insertions(+), 8 deletions(-)
>
> diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
> index 803dd6b..7ce2801 100644
> --- a/unit/test-avrcp.c
> +++ b/unit/test-avrcp.c
> @@ -288,6 +288,20 @@ static const struct avrcp_passthrough_handler passthrough_handlers[] = {
>                 { },
>  };
>
> +static bool check_attributes(const uint8_t *params)
> +{
> +       int i;
> +
> +       for (i = 1; i <= params[0]; i++) {
> +               DBG("params[%d] = 0x%02x", i, params[i]);
> +               if (params[i] > AVRCP_ATTRIBUTE_LAST ||
> +                   params[i] == AVRCP_ATTRIBUTE_ILEGAL)
> +                       return false;
> +       }
> +
> +       return true;
> +}
> +
>  static ssize_t avrcp_handle_get_capabilities(struct avrcp *session,
>                                                 uint8_t transaction,
>                                                 uint16_t params_len,
> @@ -326,16 +340,10 @@ static ssize_t avrcp_handle_get_player_attr_text(struct avrcp *session,
>                                                 uint8_t *params,
>                                                 void *user_data)
>  {
> -       int i;
> -
>         DBG("params[0] %d params_len %d", params[0], params_len);
>
> -       for (i = 1; i <= params[0]; i++) {
> -               DBG("params[%d] = 0x%02x", i, params[i]);
> -               if (params[i] > AVRCP_ATTRIBUTE_LAST ||
> -                       params[i] == AVRCP_ATTRIBUTE_ILEGAL)
> -                       return -EINVAL;
> -       }
> +       if (!check_attributes(params))
> +               return -EINVAL;
>
>         params[0] = 0;
>
> --
> 1.8.3.2

Pushed after some code style fixes, please do not mix spaces and tabs.
Also the tests are starting to get logic outside of just testing the
handler but the actual PDU handling so perhaps we need to think if the
API of avrcp-lib.h is really a proper one or we should do create a
different one as it is done for passthrough where the callback are not
actually pure PDU handlers.


-- 
Luiz Augusto von Dentz

^ permalink raw reply

* Re: Background scanning and white list usage
From: Andre Guedes @ 2014-03-06 21:15 UTC (permalink / raw)
  To: Marcel Holtmann, Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <B2E73B9C-3787-4B4B-802B-0C76302BF8F9@holtmann.org>

Hi Johan/Marcel,

On 02/28/2014 03:51 AM, Marcel Holtmann wrote:
> Hi Johan,
>
>>> The complicated part comes into play when we have devices with
>>> LE Privacy enabled and when they are using resolvable private
>>> addresses. Meaning when our IRK list is populated with identity
>>> addresses and their IRKs. The only way to make this work with the
>>> current available controller features is if we program the RPA
>>> into the white list. Since that RPA is going to change over time,
>>> we need to stop scanning with the white list filter every now and
>>> then, scan for all devices and resolve the RPA. If we see a new
>>> RPA for a know IRK, we have to replace the old RPA in the white
>>> list with the new RPA. And then we go back to scanning with the
>>> white list filter policy.
>>>
>>> Now the important question is what are good enough intervals to
>>> make this work smoothly. Devices using LE Privacy will take a hit
>>> in their re-connection time, but that is what we have to trade in
>>> for compared to waking up the host for every single advertising
>>> packet.
>>>
>>> My initial idea is to scan 5 minutes using the white list, then
>>> scan 10 seconds without the white list, then back to 5 minutes
>>> using the white list and so on.
>>>
>>> The default value for the PRA lifetime according to the
>>> specification is 15 minutes. I timed recent iOS devices which
>>> seem to be using 9 minutes intervals. So we have to play a little
>>> bit with this and see what are good values.
>>>
>>> Maybe 3 minutes white list scan and 5 seconds without white list
>>> is better. Things to try out.
>>
>> I don't think this is a good idea at all. With LE starting
>> advertising is typically seen as the initiating action of
>> connection creation (unlike with BR/EDR where HCI_Create_Connection
>> is the initiating action). Typically peripherals mean "connect to
>> me now!" when they start connectable advertising.
>>
>> Let's stay you switch on your peripheral device, or it comes into
>> range you haven't used it for some time (hours or even days). If
>> it's using RPAs it's pretty much guaranteed to have a different one
>> than what we know of and even if we're using 3 minutes white list
>> scanning the user is on average going to have to wait for 1.5
>> minutes for the device to get connected which is not acceptable
>> behavior (the extreme example would be if this is a keyboard or a
>> mouse which you start using for the first time in the morning -
>> moving the mouse or pressing a key on the keyboard should certainly
>> get you a connection in less than 1 second).
>
> HID devices would suffer the most here. Fully agree here.
>
> However since neither Microsoft Windows nor OS X can deal with RPAs
> at the moment, I do not think we are entering a dangerous zone here
> from an interoperability point of view. Actually Windows 8.1 is not
> able to connect to any random address for that matter.
>
> My point is that we certainly not make it worse.

HoG is not the only problem. I'm afraid delaying re-connection 3-5
minutes we might become others profiles impractical (e.g. Fob keeps
beeping even if it is beside the cellphone).

>> I fully understand the desire to use the white list as it's a very
>> nice power saving feature, but I don't think we can win here as
>> long as we don't have a way to have the controller do the resolving
>> for us.
>>
>> One thing we could potentially try to do (but which I doubt is
>> really worth it in the end) is to track the age of resolved RPAs.
>> If we have an RPA which was resolved say less than 5 minutes ago we
>> consider it appropriate to place into the white list. Otherwise we
>> skip using the white list.
>
> I was thinking about this as well. Over time we could learn the age
> of a RPA and thus schedule the scanning without white list times most
> efficient. Frankly, I want to get the white list usage going first.
> As long as you only have public or static addresses, it is the way to
> go. And then we optimize it when we have to deal with RPAs.

I agree with Johan about this aging approach, I seems not worthy. 
Honestly, I don't see how we would properly deal with white list and LE 
Privacy issue by now.

> We can not close our eyes to iOS devices using RPAs and I am not
> willing to take the power hit of getting flooded with advertising
> reports.

To fix this other issue (advertising flooding), filtering duplicates is 
just fine.

The problem with enabling filter duplicates in background scan happens 
in the following scenario:
   * Background scan is running.
   * A device disconnects and starts advertising.
   * Before host gets the disconnect event, the advertising is reported
     to host. Since there is no pending LE connection at that time,
     nothing happens.
   * Host gets the disconnection event and adds a pending connection.
   * No advertising is reported (since controller is filtering) and the
     connection is never established.

To address this scenario, all we have to do is: always restart 
background scan when a new LE pending connection is added. This way, we 
unsure that we don't miss the advertising report.

If you guys agree with this approach I can write the patches.

Regards,

Andre

^ 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