All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH BlueZ 0/9] client: Add GATT application support
@ 2017-06-28 12:54 Luiz Augusto von Dentz
  2017-06-28 12:54 ` [PATCH BlueZ 1/9] client: Allow register-application without any UUID Luiz Augusto von Dentz
                   ` (8 more replies)
  0 siblings, 9 replies; 17+ messages in thread
From: Luiz Augusto von Dentz @ 2017-06-28 12:54 UTC (permalink / raw)
  To: linux-bluetooth

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

This adds necessary commands to create GATT services which can then
be registered with bluetoothd:

[bluetooth]# register-service 00001802-0000-1000-8000-00805f9b34fb
[NEW] Primary Service
	/org/bluez/app/service0x902610
	00001802-0000-1000-8000-00805f9b34fb
	Immediate Alert
[bluetooth]# register-characteristic 00002a06-0000-1000-8000-00805f9b34fb write-without-response
[NEW] Characteristic
	/org/bluez/app/service0x902610/chrc0x91d690
	00002a06-0000-1000-8000-00805f9b34fb
	Alert Level
[/org/bluez/app/service0x902610/chrc0x91d690] Enter value:  
[bluetooth]# register-descriptor 8260c653-1a54-426b-9e36-e84c238bc669 read,write
[NEW] Descriptor
	/org/bluez/app/service0x902610/chrc0x91d690/desc0x9095a0
	8260c653-1a54-426b-9e36-e84c238bc669
	Vendor specific
[/org/bluez/app/service0x902610/chrc0x91d690/desc0x9095a0] Enter value:  
[bluetooth]# register-application
[CHG] Controller B8:8A:60:D8:17:D7 UUIDs: 00001112-0000-1000-8000-00805f9b34fb
[CHG] Controller B8:8A:60:D8:17:D7 UUIDs: 00001801-0000-1000-8000-00805f9b34fb
[CHG] Controller B8:8A:60:D8:17:D7 UUIDs: 0000110e-0000-1000-8000-00805f9b34fb
[CHG] Controller B8:8A:60:D8:17:D7 UUIDs: 0000112d-0000-1000-8000-00805f9b34fb
[CHG] Controller B8:8A:60:D8:17:D7 UUIDs: 00001800-0000-1000-8000-00805f9b34fb
[CHG] Controller B8:8A:60:D8:17:D7 UUIDs: 00001200-0000-1000-8000-00805f9b34fb
[CHG] Controller B8:8A:60:D8:17:D7 UUIDs: 0000110c-0000-1000-8000-00805f9b34fb
[CHG] Controller B8:8A:60:D8:17:D7 UUIDs: 0000110a-0000-1000-8000-00805f9b34fb
[CHG] Controller B8:8A:60:D8:17:D7 UUIDs: 0000110b-0000-1000-8000-00805f9b34fb
[CHG] Controller B8:8A:60:D8:17:D7 UUIDs: 00001802-0000-1000-8000-00805f9b34fb
Application registered


bluetoothd[7704]: src/gatt-database.c:manager_register_app() Registering application: :1.79:/
bluetoothd[7704]: src/gatt-database.c:proxy_added_cb() Object received: /org/bluez/app/service0x902610, iface: org.bluez.GattService1
bluetoothd[7704]: src/gatt-database.c:proxy_added_cb() Object received: /org/bluez/app/service0x902610/chrc0x91d690, iface: org.bluez.GattCharacteristic1
bluetoothd[7704]: src/gatt-database.c:proxy_added_cb() Object received: /org/bluez/app/service0x902610/chrc0x91d690/desc0x9095a0, iface: org.bluez.GattDescriptor1


Luiz Augusto von Dentz (9):
  client: Allow register-application without any UUID
  client: Add register-service command
  client: Add unregister-service command
  client: Add register-characteristic command
  client: Add unregister-characteristic command
  client: Add generic way to request input from user
  client: Ask user the characteristic value
  client: Add register-descriptor command
  client: Add unregister-descriptor command

 client/display.c |  58 ++++
 client/display.h |   5 +
 client/gatt.c    | 833 +++++++++++++++++++++++++++++++++++++++++++++++++++----
 client/gatt.h    |  13 +
 client/main.c    | 154 +++++++++-
 5 files changed, 1000 insertions(+), 63 deletions(-)

-- 
2.9.4


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH BlueZ 1/9] client: Allow register-application without any UUID
  2017-06-28 12:54 [PATCH BlueZ 0/9] client: Add GATT application support Luiz Augusto von Dentz
@ 2017-06-28 12:54 ` Luiz Augusto von Dentz
  2017-06-28 12:54 ` [PATCH BlueZ 2/9] client: Add register-service command Luiz Augusto von Dentz
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Luiz Augusto von Dentz @ 2017-06-28 12:54 UTC (permalink / raw)
  To: linux-bluetooth

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

This means that GattProfile1 should not be registered but there could still
be services that needs registered with bluetoothd.
---
 client/gatt.c | 24 +++++++++++++++---------
 client/main.c |  7 +------
 2 files changed, 16 insertions(+), 15 deletions(-)

diff --git a/client/gatt.c b/client/gatt.c
index 40d3f6a..8b7a9c6 100644
--- a/client/gatt.c
+++ b/client/gatt.c
@@ -726,16 +726,19 @@ void gatt_register_app(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w)
 		return;
 	}
 
-	if (g_dbus_register_interface(conn, APP_PATH,
-					PROFILE_INTERFACE, methods,
-					NULL, properties, NULL, NULL) == FALSE) {
-		rl_printf("Failed to register application object\n");
-		return;
-	}
-
 	for (i = 0; i < w->we_wordc; i++)
 		uuids = g_list_append(uuids, g_strdup(w->we_wordv[i]));
 
+	if (uuids) {
+		if (g_dbus_register_interface(conn, APP_PATH,
+						PROFILE_INTERFACE, methods,
+						NULL, properties, NULL,
+						NULL) == FALSE) {
+			rl_printf("Failed to register application object\n");
+			return;
+		}
+	}
+
 	if (g_dbus_proxy_method_call(l->data, "RegisterApplication",
 						register_app_setup,
 						register_app_reply, w,
@@ -759,11 +762,14 @@ static void unregister_app_reply(DBusMessage *message, void *user_data)
 		return;
 	}
 
+	rl_printf("Application unregistered\n");
+
+	if (!uuids)
+		return;
+
 	g_list_free_full(uuids, g_free);
 	uuids = NULL;
 
-	rl_printf("Application unregistered\n");
-
 	g_dbus_unregister_interface(conn, APP_PATH, PROFILE_INTERFACE);
 }
 
diff --git a/client/main.c b/client/main.c
index 578dde9..31d06b8 100644
--- a/client/main.c
+++ b/client/main.c
@@ -1826,11 +1826,6 @@ static void cmd_register_app(const char *arg)
 		return;
 	}
 
-	if (w.we_wordc == 0) {
-		rl_printf("Missing argument\n");
-		return;
-	}
-
 	gatt_register_app(dbus_conn, default_ctrl->proxy, &w);
 
 	wordfree(&w);
@@ -2142,7 +2137,7 @@ static const struct {
 	{ "write",        "<data=[xx xx ...]>", cmd_write,
 						"Write attribute value" },
 	{ "notify",       "<on/off>", cmd_notify, "Notify attribute value" },
-	{ "register-application", "<UUID ...>", cmd_register_app,
+	{ "register-application", "[UUID ...]", cmd_register_app,
 						"Register profile to connect" },
 	{ "unregister-application", NULL, cmd_unregister_app,
 						"Unregister profile" },
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH BlueZ 2/9] client: Add register-service command
  2017-06-28 12:54 [PATCH BlueZ 0/9] client: Add GATT application support Luiz Augusto von Dentz
  2017-06-28 12:54 ` [PATCH BlueZ 1/9] client: Allow register-application without any UUID Luiz Augusto von Dentz
@ 2017-06-28 12:54 ` Luiz Augusto von Dentz
  2017-06-30  5:50   ` ERAMOTO Masaya
  2017-06-28 12:54 ` [PATCH BlueZ 3/9] client: Add unregister-service command Luiz Augusto von Dentz
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 17+ messages in thread
From: Luiz Augusto von Dentz @ 2017-06-28 12:54 UTC (permalink / raw)
  To: linux-bluetooth

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

This adds register-service command which can be used to add GATT services
to the application:

[bluetooth]# register-service 00001820-0000-1000-8000-00805f9b34fb
[NEW] Primary Service
	/org/bluez/app/service0x92a150
	00001820-0000-1000-8000-00805f9b34fb
	Internet Protocol Support
[bluetooth]# register-application
[CHG] Controller 00:1B:DC:07:31:88 UUIDs: 00001112-0000-1000-8000-00805f9b34fb
[CHG] Controller 00:1B:DC:07:31:88 UUIDs: 00001801-0000-1000-8000-00805f9b34fb
[CHG] Controller 00:1B:DC:07:31:88 UUIDs: 0000110e-0000-1000-8000-00805f9b34fb
[CHG] Controller 00:1B:DC:07:31:88 UUIDs: 0000112d-0000-1000-8000-00805f9b34fb
[CHG] Controller 00:1B:DC:07:31:88 UUIDs: 00001800-0000-1000-8000-00805f9b34fb
[CHG] Controller 00:1B:DC:07:31:88 UUIDs: 00001820-0000-1000-8000-00805f9b34fb
[CHG] Controller 00:1B:DC:07:31:88 UUIDs: 00001200-0000-1000-8000-00805f9b34fb
[CHG] Controller 00:1B:DC:07:31:88 UUIDs: 0000110c-0000-1000-8000-00805f9b34fb
[CHG] Controller 00:1B:DC:07:31:88 UUIDs: 0000110a-0000-1000-8000-00805f9b34fb
[CHG] Controller 00:1B:DC:07:31:88 UUIDs: 0000110b-0000-1000-8000-00805f9b34fb

Note: register-application still has to be called at the end to register
with bluetoothd as everything is done with ObjectManager.
---
 client/gatt.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++---------
 client/gatt.h |   3 ++
 client/main.c |  24 ++++++++++
 3 files changed, 145 insertions(+), 22 deletions(-)

diff --git a/client/gatt.c b/client/gatt.c
index 8b7a9c6..282f07e 100644
--- a/client/gatt.c
+++ b/client/gatt.c
@@ -45,22 +45,55 @@
 
 #define APP_PATH "/org/bluez/app"
 #define PROFILE_INTERFACE "org.bluez.GattProfile1"
+#define SERVICE_INTERFACE "org.bluez.GattService1"
 
 /* String display constants */
 #define COLORED_NEW	COLOR_GREEN "NEW" COLOR_OFF
 #define COLORED_CHG	COLOR_YELLOW "CHG" COLOR_OFF
 #define COLORED_DEL	COLOR_RED "DEL" COLOR_OFF
 
+struct service {
+	DBusConnection *conn;
+	char *path;
+	char *uuid;
+	bool primary;
+};
+
+static GList *local_services;
 static GList *services;
 static GList *characteristics;
 static GList *descriptors;
 static GList *managers;
 static GList *uuids;
 
-static void print_service(GDBusProxy *proxy, const char *description)
+static void print_service(struct service *service, const char *description)
 {
+	const char *text;
+
+	text = uuidstr_to_str(service->uuid);
+	if (!text)
+		rl_printf("%s%s%s%s Service\n\t%s\n\t%s\n",
+					description ? "[" : "",
+					description ? : "",
+					description ? "] " : "",
+					service->primary ? "Primary" :
+					"Secondary",
+					service->path, service->uuid);
+	else
+		rl_printf("%s%s%s%s Service\n\t%s\n\t%s\n\t%s\n",
+					description ? "[" : "",
+					description ? : "",
+					description ? "] " : "",
+					service->primary ? "Primary" :
+					"Secondary",
+					service->path, service->uuid, text);
+}
+
+static void print_service_proxy(GDBusProxy *proxy, const char *description)
+{
+	struct service service;
 	DBusMessageIter iter;
-	const char *uuid, *text;
+	const char *uuid;
 	dbus_bool_t primary;
 
 	if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
@@ -73,30 +106,18 @@ static void print_service(GDBusProxy *proxy, const char *description)
 
 	dbus_message_iter_get_basic(&iter, &primary);
 
-	text = uuidstr_to_str(uuid);
-	if (!text)
-		rl_printf("%s%s%s%s Service\n\t%s\n\t%s\n",
-					description ? "[" : "",
-					description ? : "",
-					description ? "] " : "",
-					primary ? "Primary" : "Secondary",
-					g_dbus_proxy_get_path(proxy),
-					uuid);
-	else
-		rl_printf("%s%s%s%s Service\n\t%s\n\t%s\n\t%s\n",
-					description ? "[" : "",
-					description ? : "",
-					description ? "] " : "",
-					primary ? "Primary" : "Secondary",
-					g_dbus_proxy_get_path(proxy),
-					uuid, text);
+	service.path = (char *) g_dbus_proxy_get_path(proxy);
+	service.uuid = (char *) uuid;
+	service.primary = primary;
+
+	print_service(&service, description);
 }
 
 void gatt_add_service(GDBusProxy *proxy)
 {
 	services = g_list_append(services, proxy);
 
-	print_service(proxy, COLORED_NEW);
+	print_service_proxy(proxy, COLORED_NEW);
 }
 
 void gatt_remove_service(GDBusProxy *proxy)
@@ -109,7 +130,7 @@ void gatt_remove_service(GDBusProxy *proxy)
 
 	services = g_list_delete_link(services, l);
 
-	print_service(proxy, COLORED_DEL);
+	print_service_proxy(proxy, COLORED_DEL);
 }
 
 static void print_characteristic(GDBusProxy *proxy, const char *description)
@@ -272,7 +293,7 @@ static void list_attributes(const char *path, GList *source)
 			continue;
 
 		if (source == services) {
-			print_service(proxy, NULL);
+			print_service_proxy(proxy, NULL);
 			list_attributes(proxy_path, characteristics);
 		} else if (source == characteristics) {
 			print_characteristic(proxy, NULL);
@@ -798,3 +819,78 @@ void gatt_unregister_app(DBusConnection *conn, GDBusProxy *proxy)
 		return;
 	}
 }
+
+static void service_free(void *data)
+{
+	struct service *service = data;
+
+	g_free(service->path);
+	g_free(service->uuid);
+	g_free(service);
+}
+
+static gboolean service_get_uuid(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct service *service = data;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &service->uuid);
+
+	return TRUE;
+}
+
+static gboolean service_get_primary(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct service *service = data;
+	dbus_bool_t primary;
+
+	primary = service->primary ? TRUE : FALSE;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &primary);
+
+	return TRUE;
+}
+
+static const GDBusPropertyTable service_properties[] = {
+	{ "UUID", "s", service_get_uuid },
+	{ "Primary", "b", service_get_primary },
+	{ }
+};
+
+void gatt_register_service(DBusConnection *conn, GDBusProxy *proxy,
+								wordexp_t *w)
+{
+	struct service *service;
+	bool primary = true;
+
+	if (w->we_wordc > 1) {
+		if (!strcmp(w->we_wordv[1], "yes")) {
+			primary = true;
+		} else if (!strcmp(w->we_wordv[1], "no")) {
+			primary = false;
+		} else {
+			rl_printf("Invalid option: %s\n", w->we_wordv[0]);
+			return;
+		}
+	}
+
+	service = g_new0(struct service, 1);
+	service->conn = conn;
+	service->uuid = g_strdup(w->we_wordv[0]);
+	service->path = g_strdup_printf("%s/service%p", APP_PATH, service);
+	service->primary = primary;
+
+	if (g_dbus_register_interface(conn, service->path,
+					SERVICE_INTERFACE, NULL, NULL,
+					service_properties, service,
+					service_free) == FALSE) {
+		rl_printf("Failed to register service object\n");
+		service_free(service);
+		return;
+	}
+
+	rl_printf("Service registered at %s\n", service->path);
+
+	local_services = g_list_append(local_services, service);
+}
diff --git a/client/gatt.h b/client/gatt.h
index 4c9fd5b..7f116df 100644
--- a/client/gatt.h
+++ b/client/gatt.h
@@ -43,3 +43,6 @@ void gatt_remove_manager(GDBusProxy *proxy);
 
 void gatt_register_app(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w);
 void gatt_unregister_app(DBusConnection *conn, GDBusProxy *proxy);
+
+void gatt_register_service(DBusConnection *conn, GDBusProxy *proxy,
+								wordexp_t *w);
diff --git a/client/main.c b/client/main.c
index 31d06b8..2bcf02c 100644
--- a/client/main.c
+++ b/client/main.c
@@ -1839,6 +1839,28 @@ static void cmd_unregister_app(const char *arg)
 	gatt_unregister_app(dbus_conn, default_ctrl->proxy);
 }
 
+static void cmd_register_service(const char *arg)
+{
+	wordexp_t w;
+
+	if (check_default_ctrl() == FALSE)
+		return;
+
+	if (wordexp(arg, &w, WRDE_NOCMD)) {
+		rl_printf("Invalid argument\n");
+		return;
+	}
+
+	if (w.we_wordc == 0) {
+		rl_printf("Missing argument\n");
+		return;
+	}
+
+	gatt_register_service(dbus_conn, default_ctrl->proxy, &w);
+
+	wordfree(&w);
+}
+
 static void cmd_version(const char *arg)
 {
 	rl_printf("Version %s\n", VERSION);
@@ -2141,6 +2163,8 @@ static const struct {
 						"Register profile to connect" },
 	{ "unregister-application", NULL, cmd_unregister_app,
 						"Unregister profile" },
+	{ "register-service", "<UUID> <primary=yes/no>", cmd_register_service,
+					"Register application service" },
 	{ "version",      NULL,       cmd_version, "Display version" },
 	{ "quit",         NULL,       cmd_quit, "Quit program" },
 	{ "exit",         NULL,       cmd_quit, "Quit program" },
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH BlueZ 3/9] client: Add unregister-service command
  2017-06-28 12:54 [PATCH BlueZ 0/9] client: Add GATT application support Luiz Augusto von Dentz
  2017-06-28 12:54 ` [PATCH BlueZ 1/9] client: Allow register-application without any UUID Luiz Augusto von Dentz
  2017-06-28 12:54 ` [PATCH BlueZ 2/9] client: Add register-service command Luiz Augusto von Dentz
@ 2017-06-28 12:54 ` Luiz Augusto von Dentz
  2017-06-30  5:52   ` ERAMOTO Masaya
  2017-06-28 12:54 ` [PATCH BlueZ 4/9] client: Add register-characteristic command Luiz Augusto von Dentz
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 17+ messages in thread
From: Luiz Augusto von Dentz @ 2017-06-28 12:54 UTC (permalink / raw)
  To: linux-bluetooth

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

This adds unregister-service which can be used to unregister an
application service registered with register-service:

register-service 00001820-0000-1000-8000-00805f9b34fb
[NEW] Primary Service
	/org/bluez/app/service0x92a150
	00001820-0000-1000-8000-00805f9b34fb
	Internet Protocol Support
[bluetooth]# unregister-service /org/bluez/app/service0x92a150
[DEL] Primary Service
	/org/bluez/app/service0x92a150
	00001820-0000-1000-8000-00805f9b34fb
	Internet Protocol Support
---
 client/gatt.c | 40 +++++++++++++++++++++++++++++++++++++++-
 client/gatt.h |  2 ++
 client/main.c | 24 ++++++++++++++++++++++++
 3 files changed, 65 insertions(+), 1 deletion(-)

diff --git a/client/gatt.c b/client/gatt.c
index 282f07e..92ace0e 100644
--- a/client/gatt.c
+++ b/client/gatt.c
@@ -890,7 +890,45 @@ void gatt_register_service(DBusConnection *conn, GDBusProxy *proxy,
 		return;
 	}
 
-	rl_printf("Service registered at %s\n", service->path);
+	print_service(service, COLORED_NEW);
 
 	local_services = g_list_append(local_services, service);
 }
+
+static struct service *service_find(const char *pattern)
+{
+	GList *l;
+
+	for (l = local_services; l; l = g_list_next(l)) {
+		struct service *service = l->data;
+
+		/* match object path */
+		if (!strcmp(service->path, pattern))
+			return service;
+
+		/* match UUID */
+		if (!strcmp(service->uuid, pattern))
+			return service;
+	}
+
+	return NULL;
+}
+
+void gatt_unregister_service(DBusConnection *conn, GDBusProxy *proxy,
+								wordexp_t *w)
+{
+	struct service *service;
+
+	service = service_find(w->we_wordv[0]);
+	if (!service) {
+		rl_printf("Failed to unregister service object\n");
+		return;
+	}
+
+	local_services = g_list_remove(local_services, service);
+
+	print_service(service, COLORED_DEL);
+
+	g_dbus_unregister_interface(service->conn, service->path,
+						SERVICE_INTERFACE);
+}
diff --git a/client/gatt.h b/client/gatt.h
index 7f116df..4b9edd5 100644
--- a/client/gatt.h
+++ b/client/gatt.h
@@ -46,3 +46,5 @@ void gatt_unregister_app(DBusConnection *conn, GDBusProxy *proxy);
 
 void gatt_register_service(DBusConnection *conn, GDBusProxy *proxy,
 								wordexp_t *w);
+void gatt_unregister_service(DBusConnection *conn, GDBusProxy *proxy,
+								wordexp_t *w);
diff --git a/client/main.c b/client/main.c
index 2bcf02c..16bc125 100644
--- a/client/main.c
+++ b/client/main.c
@@ -1861,6 +1861,28 @@ static void cmd_register_service(const char *arg)
 	wordfree(&w);
 }
 
+static void cmd_unregister_service(const char *arg)
+{
+	wordexp_t w;
+
+	if (check_default_ctrl() == FALSE)
+		return;
+
+	if (wordexp(arg, &w, WRDE_NOCMD)) {
+		rl_printf("Invalid argument\n");
+		return;
+	}
+
+	if (w.we_wordc == 0) {
+		rl_printf("Missing argument\n");
+		return;
+	}
+
+	gatt_unregister_service(dbus_conn, default_ctrl->proxy, &w);
+
+	wordfree(&w);
+}
+
 static void cmd_version(const char *arg)
 {
 	rl_printf("Version %s\n", VERSION);
@@ -2165,6 +2187,8 @@ static const struct {
 						"Unregister profile" },
 	{ "register-service", "<UUID> <primary=yes/no>", cmd_register_service,
 					"Register application service" },
+	{ "unregister-service", "<UUID/object>", cmd_unregister_service,
+					"Unregister application service" },
 	{ "version",      NULL,       cmd_version, "Display version" },
 	{ "quit",         NULL,       cmd_quit, "Quit program" },
 	{ "exit",         NULL,       cmd_quit, "Quit program" },
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH BlueZ 4/9] client: Add register-characteristic command
  2017-06-28 12:54 [PATCH BlueZ 0/9] client: Add GATT application support Luiz Augusto von Dentz
                   ` (2 preceding siblings ...)
  2017-06-28 12:54 ` [PATCH BlueZ 3/9] client: Add unregister-service command Luiz Augusto von Dentz
@ 2017-06-28 12:54 ` Luiz Augusto von Dentz
  2017-06-30  6:13   ` ERAMOTO Masaya
  2017-06-28 12:54 ` [PATCH BlueZ 5/9] client: Add unregister-characteristic command Luiz Augusto von Dentz
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 17+ messages in thread
From: Luiz Augusto von Dentz @ 2017-06-28 12:54 UTC (permalink / raw)
  To: linux-bluetooth

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

This adds register-characteristic which can be used to register
characteristic to a service registered with register-service:

register-characteristic 00002a06-0000-1000-8000-00805f9b34fb write-without-response
[NEW] Characteristic
	/org/bluez/app/service0x1122150/chrc0x113fa40
	00002a06-0000-1000-8000-00805f9b34fb
	Alert Level
---
 client/gatt.c | 285 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 client/gatt.h |   2 +
 client/main.c |  25 ++++++
 3 files changed, 297 insertions(+), 15 deletions(-)

diff --git a/client/gatt.c b/client/gatt.c
index 92ace0e..2e56e0c 100644
--- a/client/gatt.c
+++ b/client/gatt.c
@@ -46,17 +46,30 @@
 #define APP_PATH "/org/bluez/app"
 #define PROFILE_INTERFACE "org.bluez.GattProfile1"
 #define SERVICE_INTERFACE "org.bluez.GattService1"
+#define CHRC_INTERFACE "org.bluez.GattCharacteristic1"
 
 /* String display constants */
 #define COLORED_NEW	COLOR_GREEN "NEW" COLOR_OFF
 #define COLORED_CHG	COLOR_YELLOW "CHG" COLOR_OFF
 #define COLORED_DEL	COLOR_RED "DEL" COLOR_OFF
 
+struct chrc {
+	struct service *service;
+	char *path;
+	char *uuid;
+	char **flags;
+	bool notifying;
+	GList *descs;
+	int value_len;
+	uint8_t *value;
+};
+
 struct service {
 	DBusConnection *conn;
 	char *path;
 	char *uuid;
 	bool primary;
+	GList *chrcs;
 };
 
 static GList *local_services;
@@ -133,34 +146,43 @@ void gatt_remove_service(GDBusProxy *proxy)
 	print_service_proxy(proxy, COLORED_DEL);
 }
 
-static void print_characteristic(GDBusProxy *proxy, const char *description)
+static void print_chrc(struct chrc *chrc, const char *description)
 {
-	DBusMessageIter iter;
-	const char *uuid, *text;
-
-	if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
-		return;
-
-	dbus_message_iter_get_basic(&iter, &uuid);
+	const char *text;
 
-	text = uuidstr_to_str(uuid);
+	text = uuidstr_to_str(chrc->uuid);
 	if (!text)
 		rl_printf("%s%s%sCharacteristic\n\t%s\n\t%s\n",
 					description ? "[" : "",
 					description ? : "",
 					description ? "] " : "",
-					g_dbus_proxy_get_path(proxy),
-					uuid);
+					chrc->path, chrc->uuid);
 	else
 		rl_printf("%s%s%sCharacteristic\n\t%s\n\t%s\n\t%s\n",
 					description ? "[" : "",
 					description ? : "",
 					description ? "] " : "",
-					g_dbus_proxy_get_path(proxy),
-					uuid, text);
+					chrc->path, chrc->uuid, text);
+}
+
+static void print_characteristic(GDBusProxy *proxy, const char *description)
+{
+	struct chrc chrc;
+	DBusMessageIter iter;
+	const char *uuid;
+
+	if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
+		return;
+
+	dbus_message_iter_get_basic(&iter, &uuid);
+
+	chrc.path = (char *) g_dbus_proxy_get_path(proxy);
+	chrc.uuid = (char *) uuid;
+
+	print_chrc(&chrc, description);
 }
 
-static gboolean characteristic_is_child(GDBusProxy *characteristic)
+static gboolean chrc_is_child(GDBusProxy *characteristic)
 {
 	GList *l;
 	DBusMessageIter iter;
@@ -185,7 +207,7 @@ static gboolean characteristic_is_child(GDBusProxy *characteristic)
 
 void gatt_add_characteristic(GDBusProxy *proxy)
 {
-	if (!characteristic_is_child(proxy))
+	if (!chrc_is_child(proxy))
 		return;
 
 	characteristics = g_list_append(characteristics, proxy);
@@ -820,10 +842,31 @@ void gatt_unregister_app(DBusConnection *conn, GDBusProxy *proxy)
 	}
 }
 
+static void chrc_free(void *data)
+{
+	struct chrc *chrc = data;
+
+	g_free(chrc->path);
+	g_free(chrc->uuid);
+	g_strfreev(chrc->flags);
+	g_free(chrc);
+}
+
+static void chrc_unregister(void *data)
+{
+	struct chrc *chrc = data;
+
+	print_chrc(chrc, COLORED_DEL);
+
+	g_dbus_unregister_interface(chrc->service->conn, chrc->path,
+						CHRC_INTERFACE);
+}
+
 static void service_free(void *data)
 {
 	struct service *service = data;
 
+	g_list_free_full(service->chrcs, chrc_unregister);
 	g_free(service->path);
 	g_free(service->uuid);
 	g_free(service);
@@ -932,3 +975,215 @@ void gatt_unregister_service(DBusConnection *conn, GDBusProxy *proxy,
 	g_dbus_unregister_interface(service->conn, service->path,
 						SERVICE_INTERFACE);
 }
+
+static gboolean chrc_get_uuid(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct chrc *chrc = data;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &chrc->uuid);
+
+	return TRUE;
+}
+
+static gboolean chrc_get_service(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct chrc *chrc = data;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
+						&chrc->service->path);
+
+	return TRUE;
+}
+
+static gboolean chrc_get_value(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct chrc *chrc = data;
+	DBusMessageIter array;
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
+
+	dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
+						&chrc->value, chrc->value_len);
+
+	dbus_message_iter_close_container(iter, &array);
+
+	return TRUE;
+}
+
+static gboolean chrc_get_notifying(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct chrc *chrc = data;
+	dbus_bool_t value;
+
+	value = chrc->notifying ? TRUE : FALSE;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+	return TRUE;
+}
+
+static gboolean chrc_get_flags(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct chrc *chrc = data;
+	int i;
+	DBusMessageIter array;
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &array);
+
+	for (i = 0; chrc->flags[i]; i++)
+		dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
+							&chrc->flags[i]);
+
+	dbus_message_iter_close_container(iter, &array);
+
+	return TRUE;
+}
+
+static const GDBusPropertyTable chrc_properties[] = {
+	{ "UUID", "s", chrc_get_uuid, NULL, NULL },
+	{ "Service", "o", chrc_get_service, NULL, NULL },
+	{ "Value", "ay", chrc_get_value, NULL, NULL },
+	{ "Notifying", "b", chrc_get_notifying, NULL, NULL },
+	{ "Flags", "as", chrc_get_flags, NULL, NULL },
+	{ }
+};
+
+static DBusMessage *read_value(DBusMessage *msg, uint8_t *value,
+						uint16_t value_len)
+{
+	DBusMessage *reply;
+	DBusMessageIter iter, array;
+
+	reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+
+	dbus_message_iter_init_append(reply, &iter);
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "y", &array);
+	dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
+						&value, value_len);
+	dbus_message_iter_close_container(&iter, &array);
+
+	return reply;
+}
+
+static DBusMessage *chrc_read_value(DBusConnection *conn, DBusMessage *msg,
+							void *user_data)
+{
+	struct chrc *chrc = user_data;
+
+	return read_value(msg, chrc->value, chrc->value_len);
+}
+
+static int parse_value_arg(DBusMessageIter *iter, uint8_t **value, int *len)
+{
+	DBusMessageIter array;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+		return -EINVAL;
+
+	dbus_message_iter_recurse(iter, &array);
+	dbus_message_iter_get_fixed_array(&array, value, len);
+
+	return 0;
+}
+
+static DBusMessage *chrc_write_value(DBusConnection *conn, DBusMessage *msg,
+							void *user_data)
+{
+	struct chrc *chrc = user_data;
+	DBusMessageIter iter;
+
+	dbus_message_iter_init(msg, &iter);
+
+	if (parse_value_arg(&iter, &chrc->value, &chrc->value_len))
+		return g_dbus_create_error(msg,
+					"org.bluez.Error.InvalidArguments",
+					NULL);
+
+	rl_printf("[" COLORED_CHG "] Attribute %s written" , chrc->path);
+
+	g_dbus_emit_property_changed(conn, chrc->path, CHRC_INTERFACE, "Value");
+
+	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *chrc_start_notify(DBusConnection *conn, DBusMessage *msg,
+							void *user_data)
+{
+	struct chrc *chrc = user_data;
+
+	if (!chrc->notifying)
+		return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+
+	chrc->notifying = true;
+	rl_printf("[" COLORED_CHG "] Attribute %s notifications enabled",
+							chrc->path);
+	g_dbus_emit_property_changed(conn, chrc->path, CHRC_INTERFACE,
+							"Notifying");
+
+	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *chrc_stop_notify(DBusConnection *conn, DBusMessage *msg,
+							void *user_data)
+{
+	struct chrc *chrc = user_data;
+
+	if (chrc->notifying)
+		return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+
+	chrc->notifying = false;
+	rl_printf("[" COLORED_CHG "] Attribute %s notifications disabled",
+							chrc->path);
+	g_dbus_emit_property_changed(conn, chrc->path, CHRC_INTERFACE,
+							"Notifying");
+
+	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static const GDBusMethodTable chrc_methods[] = {
+	{ GDBUS_ASYNC_METHOD("ReadValue", GDBUS_ARGS({ "options", "a{sv}" }),
+					GDBUS_ARGS({ "value", "ay" }),
+					chrc_read_value) },
+	{ GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" },
+						{ "options", "a{sv}" }),
+					NULL, chrc_write_value) },
+	{ GDBUS_ASYNC_METHOD("StartNotify", NULL, NULL, chrc_start_notify) },
+	{ GDBUS_METHOD("StopNotify", NULL, NULL, chrc_stop_notify) },
+	{ }
+};
+
+void gatt_register_chrc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w)
+{
+	struct service *service;
+	struct chrc *chrc;
+
+	if (!local_services) {
+		rl_printf("No service registered\n");
+		return;
+	}
+
+	service = g_list_last(local_services)->data;
+
+	chrc = g_new0(struct chrc, 1);
+	chrc->service = service;
+	chrc->uuid = g_strdup(w->we_wordv[0]);
+	chrc->path = g_strdup_printf("%s/chrc%p", service->path, chrc);
+	chrc->flags = g_strsplit(w->we_wordv[1], ",", -1);
+
+	if (g_dbus_register_interface(conn, chrc->path, CHRC_INTERFACE,
+					chrc_methods, NULL, chrc_properties,
+					chrc, chrc_free) == FALSE) {
+		rl_printf("Failed to register characteristic object\n");
+		chrc_free(chrc);
+		return;
+	}
+
+	service->chrcs = g_list_append(service->chrcs, chrc);
+
+	print_chrc(chrc, COLORED_NEW);
+}
diff --git a/client/gatt.h b/client/gatt.h
index 4b9edd5..4ecf642 100644
--- a/client/gatt.h
+++ b/client/gatt.h
@@ -48,3 +48,5 @@ void gatt_register_service(DBusConnection *conn, GDBusProxy *proxy,
 								wordexp_t *w);
 void gatt_unregister_service(DBusConnection *conn, GDBusProxy *proxy,
 								wordexp_t *w);
+
+void gatt_register_chrc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w);
diff --git a/client/main.c b/client/main.c
index 16bc125..76a731f 100644
--- a/client/main.c
+++ b/client/main.c
@@ -1883,6 +1883,28 @@ static void cmd_unregister_service(const char *arg)
 	wordfree(&w);
 }
 
+static void cmd_register_characteristic(const char *arg)
+{
+	wordexp_t w;
+
+	if (check_default_ctrl() == FALSE)
+		return;
+
+	if (wordexp(arg, &w, WRDE_NOCMD)) {
+		rl_printf("Invalid argument\n");
+		return;
+	}
+
+	if (w.we_wordc < 2) {
+		rl_printf("Missing arguments\n");
+		return;
+	}
+
+	gatt_register_chrc(dbus_conn, default_ctrl->proxy, &w);
+
+	wordfree(&w);
+}
+
 static void cmd_version(const char *arg)
 {
 	rl_printf("Version %s\n", VERSION);
@@ -2189,6 +2211,9 @@ static const struct {
 					"Register application service" },
 	{ "unregister-service", "<UUID/object>", cmd_unregister_service,
 					"Unregister application service" },
+	{ "register-characteristic", "<UUID> <Flags=read,write,notify...>",
+					cmd_register_characteristic,
+					"Register application characteristic" },
 	{ "version",      NULL,       cmd_version, "Display version" },
 	{ "quit",         NULL,       cmd_quit, "Quit program" },
 	{ "exit",         NULL,       cmd_quit, "Quit program" },
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH BlueZ 5/9] client: Add unregister-characteristic command
  2017-06-28 12:54 [PATCH BlueZ 0/9] client: Add GATT application support Luiz Augusto von Dentz
                   ` (3 preceding siblings ...)
  2017-06-28 12:54 ` [PATCH BlueZ 4/9] client: Add register-characteristic command Luiz Augusto von Dentz
@ 2017-06-28 12:54 ` Luiz Augusto von Dentz
  2017-06-30  6:46   ` ERAMOTO Masaya
  2017-06-28 12:54 ` [PATCH BlueZ 6/9] client: Add generic way to request input from user Luiz Augusto von Dentz
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 17+ messages in thread
From: Luiz Augusto von Dentz @ 2017-06-28 12:54 UTC (permalink / raw)
  To: linux-bluetooth

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

This adds unregister-characteristic which can be used to unregister
characteristics registered with register-characteristic:

unregister-characteristic /org/bluez/app/service0xc80150/chrc0xc99960
[DEL] Characteristic
	/org/bluez/app/service0xc80150/chrc0xc99960
	00002a06-0000-1000-8000-00805f9b34fb
	Alert Level
---
 client/gatt.c | 41 +++++++++++++++++++++++++++++++++++++++++
 client/gatt.h |  2 ++
 client/main.c | 25 +++++++++++++++++++++++++
 3 files changed, 68 insertions(+)

diff --git a/client/gatt.c b/client/gatt.c
index 2e56e0c..342b60f 100644
--- a/client/gatt.c
+++ b/client/gatt.c
@@ -1187,3 +1187,44 @@ void gatt_register_chrc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w)
 
 	print_chrc(chrc, COLORED_NEW);
 }
+
+static struct chrc *chrc_find(const char *pattern)
+{
+	GList *l, *lc;
+	struct service *service;
+	struct chrc *chrc;
+
+	for (l = local_services; l; l = g_list_next(l)) {
+		service = l->data;
+
+		for (lc = service->chrcs; lc; lc =  g_list_next(lc)) {
+			chrc = lc->data;
+
+			/* match object path */
+			if (!strcmp(chrc->path, pattern))
+				return chrc;
+
+			/* match UUID */
+			if (!strcmp(chrc->uuid, pattern))
+				return chrc;
+		}
+	}
+
+	return NULL;
+}
+
+void gatt_unregister_chrc(DBusConnection *conn, GDBusProxy *proxy,
+								wordexp_t *w)
+{
+	struct chrc *chrc;
+
+	chrc = chrc_find(w->we_wordv[0]);
+	if (!chrc) {
+		rl_printf("Failed to unregister characteristic object\n");
+		return;
+	}
+
+	chrc->service->chrcs = g_list_remove(chrc->service->chrcs, chrc);
+
+	chrc_unregister(chrc);
+}
diff --git a/client/gatt.h b/client/gatt.h
index 4ecf642..0acce4d 100644
--- a/client/gatt.h
+++ b/client/gatt.h
@@ -50,3 +50,5 @@ void gatt_unregister_service(DBusConnection *conn, GDBusProxy *proxy,
 								wordexp_t *w);
 
 void gatt_register_chrc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w);
+void gatt_unregister_chrc(DBusConnection *conn, GDBusProxy *proxy,
+								wordexp_t *w);
diff --git a/client/main.c b/client/main.c
index 76a731f..7eeeefa 100644
--- a/client/main.c
+++ b/client/main.c
@@ -1905,6 +1905,28 @@ static void cmd_register_characteristic(const char *arg)
 	wordfree(&w);
 }
 
+static void cmd_unregister_characteristic(const char *arg)
+{
+	wordexp_t w;
+
+	if (check_default_ctrl() == FALSE)
+		return;
+
+	if (wordexp(arg, &w, WRDE_NOCMD)) {
+		rl_printf("Invalid argument\n");
+		return;
+	}
+
+	if (w.we_wordc < 1) {
+		rl_printf("Missing arguments\n");
+		return;
+	}
+
+	gatt_unregister_chrc(dbus_conn, default_ctrl->proxy, &w);
+
+	wordfree(&w);
+}
+
 static void cmd_version(const char *arg)
 {
 	rl_printf("Version %s\n", VERSION);
@@ -2214,6 +2236,9 @@ static const struct {
 	{ "register-characteristic", "<UUID> <Flags=read,write,notify...>",
 					cmd_register_characteristic,
 					"Register application characteristic" },
+	{ "unregister-characteristic", "<UUID/object>",
+				cmd_unregister_characteristic,
+				"Unregister application characteristic" },
 	{ "version",      NULL,       cmd_version, "Display version" },
 	{ "quit",         NULL,       cmd_quit, "Quit program" },
 	{ "exit",         NULL,       cmd_quit, "Quit program" },
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH BlueZ 6/9] client: Add generic way to request input from user
  2017-06-28 12:54 [PATCH BlueZ 0/9] client: Add GATT application support Luiz Augusto von Dentz
                   ` (4 preceding siblings ...)
  2017-06-28 12:54 ` [PATCH BlueZ 5/9] client: Add unregister-characteristic command Luiz Augusto von Dentz
@ 2017-06-28 12:54 ` Luiz Augusto von Dentz
  2017-06-28 12:54 ` [PATCH BlueZ 7/9] client: Ask user the characteristic value Luiz Augusto von Dentz
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Luiz Augusto von Dentz @ 2017-06-28 12:54 UTC (permalink / raw)
  To: linux-bluetooth

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

This adds rl_prompt_input which can be used by different parts to ask
user input.
---
 client/display.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 client/display.h |  5 +++++
 client/main.c    |  3 +++
 3 files changed, 66 insertions(+)

diff --git a/client/display.c b/client/display.c
index d85b9d0..1dc4294 100644
--- a/client/display.c
+++ b/client/display.c
@@ -34,6 +34,11 @@
 
 #include "display.h"
 
+static char *saved_prompt = NULL;
+static int saved_point = 0;
+static rl_prompt_input_func saved_func = NULL;
+static void *saved_user_data = NULL;
+
 void rl_printf(const char *fmt, ...)
 {
 	va_list args;
@@ -104,3 +109,56 @@ void rl_hexdump(const unsigned char *buf, size_t len)
 		rl_printf("%s\n", str);
 	}
 }
+
+void rl_prompt_input(const char *label, const char *msg,
+				rl_prompt_input_func func, void *user_data)
+{
+	char prompt[256];
+
+	/* Normal use should not prompt for user input to the value a second
+	 * time before it releases the prompt, but we take a safe action. */
+	if (saved_prompt)
+		return;
+
+	saved_point = rl_point;
+	saved_prompt = strdup(rl_prompt);
+	saved_func = func;
+	saved_user_data = user_data;
+
+	memset(prompt, 0, sizeof(prompt));
+	snprintf(prompt, sizeof(prompt), COLOR_RED "[%s]" COLOR_OFF " %s ",
+								label, msg);
+	rl_set_prompt(prompt);
+
+	rl_replace_line("", 0);
+	rl_redisplay();
+}
+
+int rl_release_prompt(const char *input)
+{
+	rl_prompt_input_func func;
+	void *user_data;
+
+	if (!saved_prompt)
+		return -1;
+
+	/* This will cause rl_expand_prompt to re-run over the last prompt, but
+	 * our prompt doesn't expand anyway. */
+	rl_set_prompt(saved_prompt);
+	rl_replace_line("", 0);
+	rl_point = saved_point;
+	rl_redisplay();
+
+	free(saved_prompt);
+	saved_prompt = NULL;
+
+	func = saved_func;
+	user_data = saved_user_data;
+
+	saved_func = NULL;
+	saved_user_data = NULL;
+
+	func(input, user_data);
+
+	return 0;
+}
diff --git a/client/display.h b/client/display.h
index 88dbbd0..e991d19 100644
--- a/client/display.h
+++ b/client/display.h
@@ -31,3 +31,8 @@
 
 void rl_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
 void rl_hexdump(const unsigned char *buf, size_t len);
+
+typedef void (*rl_prompt_input_func) (const char *input, void *user_data);
+void rl_prompt_input(const char *label, const char *msg,
+				rl_prompt_input_func func, void *user_data);
+int rl_release_prompt(const char *input);
diff --git a/client/main.c b/client/main.c
index 7eeeefa..e5497f1 100644
--- a/client/main.c
+++ b/client/main.c
@@ -2321,6 +2321,9 @@ static void rl_handler(char *input)
 	if (agent_input(dbus_conn, input) == TRUE)
 		goto done;
 
+	if (!rl_release_prompt(input))
+		goto done;
+
 	add_history(input);
 
 	cmd = strtok_r(input, " ", &arg);
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH BlueZ 7/9] client: Ask user the characteristic value
  2017-06-28 12:54 [PATCH BlueZ 0/9] client: Add GATT application support Luiz Augusto von Dentz
                   ` (5 preceding siblings ...)
  2017-06-28 12:54 ` [PATCH BlueZ 6/9] client: Add generic way to request input from user Luiz Augusto von Dentz
@ 2017-06-28 12:54 ` Luiz Augusto von Dentz
  2017-06-28 12:54 ` [PATCH BlueZ 8/9] client: Add register-descriptor command Luiz Augusto von Dentz
  2017-06-28 12:54 ` [PATCH BlueZ 9/9] client: Add unregister-descriptor command Luiz Augusto von Dentz
  8 siblings, 0 replies; 17+ messages in thread
From: Luiz Augusto von Dentz @ 2017-06-28 12:54 UTC (permalink / raw)
  To: linux-bluetooth

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

During register-characteristic ask user to input the initial value it
should assume:

register-characteristic 00002a06-0000-1000-8000-00805f9b34fb write-without-response
[NEW] Characteristic
	/org/bluez/app/service0x1da7150/chrc0x1dc0bb0
	00002a06-0000-1000-8000-00805f9b34fb
	Alert Level
[/org/bluez/app/service0x1da7150/chrc0x1dc0bb0] Enter value: 00 00
---
 client/gatt.c | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/client/gatt.c b/client/gatt.c
index 342b60f..674795a 100644
--- a/client/gatt.c
+++ b/client/gatt.c
@@ -1157,6 +1157,40 @@ static const GDBusMethodTable chrc_methods[] = {
 	{ }
 };
 
+static void chrc_set_value(const char *input, void *user_data)
+{
+	struct chrc *chrc = user_data;
+	uint8_t value[512];
+	char *entry;
+	unsigned int i;
+
+	g_free(chrc->value);
+
+	for (i = 0; (entry = strsep((char **)&input, " \t")) != NULL; i++) {
+		long int val;
+		char *endptr = NULL;
+
+		if (*entry == '\0')
+			continue;
+
+		if (i >= G_N_ELEMENTS(value)) {
+			rl_printf("Too much data\n");
+			return;
+		}
+
+		val = strtol(entry, &endptr, 0);
+		if (!endptr || *endptr != '\0' || val > UINT8_MAX) {
+			rl_printf("Invalid value at index %d\n", i);
+			return;
+		}
+
+		value[i] = val;
+	}
+
+	chrc->value_len = i;
+	chrc->value = g_memdup(value, i);
+}
+
 void gatt_register_chrc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w)
 {
 	struct service *service;
@@ -1186,6 +1220,8 @@ void gatt_register_chrc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w)
 	service->chrcs = g_list_append(service->chrcs, chrc);
 
 	print_chrc(chrc, COLORED_NEW);
+
+	rl_prompt_input(chrc->path, "Enter value:", chrc_set_value, chrc);
 }
 
 static struct chrc *chrc_find(const char *pattern)
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH BlueZ 8/9] client: Add register-descriptor command
  2017-06-28 12:54 [PATCH BlueZ 0/9] client: Add GATT application support Luiz Augusto von Dentz
                   ` (6 preceding siblings ...)
  2017-06-28 12:54 ` [PATCH BlueZ 7/9] client: Ask user the characteristic value Luiz Augusto von Dentz
@ 2017-06-28 12:54 ` Luiz Augusto von Dentz
  2017-06-30  7:28   ` ERAMOTO Masaya
  2017-06-28 12:54 ` [PATCH BlueZ 9/9] client: Add unregister-descriptor command Luiz Augusto von Dentz
  8 siblings, 1 reply; 17+ messages in thread
From: Luiz Augusto von Dentz @ 2017-06-28 12:54 UTC (permalink / raw)
  To: linux-bluetooth

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

This adds register-descriptor which can be used to register
descriptors to a characteristic registered with register-characteristic:

register-descriptor 8260c653-1a54-426b-9e36-e84c238bc669 read,write
[NEW] Descriptor
	/org/bluez/app/service0x902610/chrc0x91d690/desc0x9095a0
	8260c653-1a54-426b-9e36-e84c238bc669
	Vendor specific
[/org/bluez/app/service0x902610/chrc0x91d690/desc0x9095a0] Enter value: 00
---
 client/gatt.c | 241 ++++++++++++++++++++++++++++++++++++++++++++++++++++------
 client/gatt.h |   2 +
 client/main.c |  25 ++++++
 3 files changed, 246 insertions(+), 22 deletions(-)

diff --git a/client/gatt.c b/client/gatt.c
index 674795a..7cfdc54 100644
--- a/client/gatt.c
+++ b/client/gatt.c
@@ -47,12 +47,22 @@
 #define PROFILE_INTERFACE "org.bluez.GattProfile1"
 #define SERVICE_INTERFACE "org.bluez.GattService1"
 #define CHRC_INTERFACE "org.bluez.GattCharacteristic1"
+#define DESC_INTERFACE "org.bluez.GattDescriptor1"
 
 /* String display constants */
 #define COLORED_NEW	COLOR_GREEN "NEW" COLOR_OFF
 #define COLORED_CHG	COLOR_YELLOW "CHG" COLOR_OFF
 #define COLORED_DEL	COLOR_RED "DEL" COLOR_OFF
 
+struct desc {
+	struct chrc *chrc;
+	char *path;
+	char *uuid;
+	char **flags;
+	int value_len;
+	uint8_t *value;
+};
+
 struct chrc {
 	struct service *service;
 	char *path;
@@ -228,31 +238,40 @@ void gatt_remove_characteristic(GDBusProxy *proxy)
 	print_characteristic(proxy, COLORED_DEL);
 }
 
-static void print_descriptor(GDBusProxy *proxy, const char *description)
+static void print_desc(struct desc *desc, const char *description)
 {
-	DBusMessageIter iter;
-	const char *uuid, *text;
-
-	if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
-		return;
-
-	dbus_message_iter_get_basic(&iter, &uuid);
+	const char *text;
 
-	text = uuidstr_to_str(uuid);
+	text = uuidstr_to_str(desc->uuid);
 	if (!text)
 		rl_printf("%s%s%sDescriptor\n\t%s\n\t%s\n",
 					description ? "[" : "",
 					description ? : "",
 					description ? "] " : "",
-					g_dbus_proxy_get_path(proxy),
-					uuid);
+					desc->path, desc->uuid);
 	else
 		rl_printf("%s%s%sDescriptor\n\t%s\n\t%s\n\t%s\n",
 					description ? "[" : "",
 					description ? : "",
 					description ? "] " : "",
-					g_dbus_proxy_get_path(proxy),
-					uuid, text);
+					desc->path, desc->uuid, text);
+}
+
+static void print_descriptor(GDBusProxy *proxy, const char *description)
+{
+	struct desc desc;
+	DBusMessageIter iter;
+	const char *uuid;
+
+	if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
+		return;
+
+	dbus_message_iter_get_basic(&iter, &uuid);
+
+	desc.path = (char *) g_dbus_proxy_get_path(proxy);
+	desc.uuid = (char *) uuid;
+
+	print_desc(&desc, description);
 }
 
 static gboolean descriptor_is_child(GDBusProxy *characteristic)
@@ -842,10 +861,31 @@ void gatt_unregister_app(DBusConnection *conn, GDBusProxy *proxy)
 	}
 }
 
+static void desc_free(void *data)
+{
+	struct desc *desc = data;
+
+	g_free(desc->path);
+	g_free(desc->uuid);
+	g_strfreev(desc->flags);
+	g_free(desc);
+}
+
+static void desc_unregister(void *data)
+{
+	struct desc *desc = data;
+
+	print_desc(desc, COLORED_DEL);
+
+	g_dbus_unregister_interface(desc->chrc->service->conn, desc->path,
+						DESC_INTERFACE);
+}
+
 static void chrc_free(void *data)
 {
 	struct chrc *chrc = data;
 
+	g_list_free_full(chrc->descs, desc_unregister);
 	g_free(chrc->path);
 	g_free(chrc->uuid);
 	g_strfreev(chrc->flags);
@@ -1157,16 +1197,13 @@ static const GDBusMethodTable chrc_methods[] = {
 	{ }
 };
 
-static void chrc_set_value(const char *input, void *user_data)
+static uint8_t *str2bytearray(char *arg, int *val_len)
 {
-	struct chrc *chrc = user_data;
 	uint8_t value[512];
 	char *entry;
 	unsigned int i;
 
-	g_free(chrc->value);
-
-	for (i = 0; (entry = strsep((char **)&input, " \t")) != NULL; i++) {
+	for (i = 0; (entry = strsep(&arg, " \t")) != NULL; i++) {
 		long int val;
 		char *endptr = NULL;
 
@@ -1175,20 +1212,30 @@ static void chrc_set_value(const char *input, void *user_data)
 
 		if (i >= G_N_ELEMENTS(value)) {
 			rl_printf("Too much data\n");
-			return;
+			return NULL;
 		}
 
 		val = strtol(entry, &endptr, 0);
 		if (!endptr || *endptr != '\0' || val > UINT8_MAX) {
 			rl_printf("Invalid value at index %d\n", i);
-			return;
+			return NULL;
 		}
 
 		value[i] = val;
 	}
 
-	chrc->value_len = i;
-	chrc->value = g_memdup(value, i);
+	*val_len = i;
+
+	return g_memdup(value, i);
+}
+
+static void chrc_set_value(const char *input, void *user_data)
+{
+	struct chrc *chrc = user_data;
+
+	g_free(chrc->value);
+
+	chrc->value = str2bytearray((char *) input, &chrc->value_len);
 }
 
 void gatt_register_chrc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w)
@@ -1264,3 +1311,153 @@ void gatt_unregister_chrc(DBusConnection *conn, GDBusProxy *proxy,
 
 	chrc_unregister(chrc);
 }
+
+static DBusMessage *desc_read_value(DBusConnection *conn, DBusMessage *msg,
+							void *user_data)
+{
+	struct desc *desc = user_data;
+
+	return read_value(msg, desc->value, desc->value_len);
+}
+
+static DBusMessage *desc_write_value(DBusConnection *conn, DBusMessage *msg,
+							void *user_data)
+{
+	struct desc *desc = user_data;
+	DBusMessageIter iter;
+
+	dbus_message_iter_init(msg, &iter);
+
+	if (parse_value_arg(&iter, &desc->value, &desc->value_len))
+		return g_dbus_create_error(msg,
+					"org.bluez.Error.InvalidArguments",
+					NULL);
+
+	rl_printf("[" COLORED_CHG "] Attribute %s written" , desc->path);
+
+	g_dbus_emit_property_changed(conn, desc->path, CHRC_INTERFACE, "Value");
+
+	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static const GDBusMethodTable desc_methods[] = {
+	{ GDBUS_ASYNC_METHOD("ReadValue", GDBUS_ARGS({ "options", "a{sv}" }),
+					GDBUS_ARGS({ "value", "ay" }),
+					desc_read_value) },
+	{ GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" },
+						{ "options", "a{sv}" }),
+					NULL, desc_write_value) },
+	{ }
+};
+
+static gboolean desc_get_uuid(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct desc *desc = data;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &desc->uuid);
+
+	return TRUE;
+}
+
+static gboolean desc_get_chrc(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct desc *desc = data;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
+						&desc->chrc->path);
+
+	return TRUE;
+}
+
+static gboolean desc_get_value(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct desc *desc = data;
+	DBusMessageIter array;
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
+
+	if (desc->value)
+		dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
+							&desc->value,
+							desc->value_len);
+
+	dbus_message_iter_close_container(iter, &array);
+
+	return TRUE;
+}
+
+static gboolean desc_get_flags(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct desc *desc = data;
+	int i;
+	DBusMessageIter array;
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &array);
+
+	for (i = 0; desc->flags[i]; i++)
+		dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
+							&desc->flags[i]);
+
+	dbus_message_iter_close_container(iter, &array);
+
+	return TRUE;
+}
+
+static const GDBusPropertyTable desc_properties[] = {
+	{ "UUID", "s", desc_get_uuid, NULL, NULL },
+	{ "Characteristic", "o", desc_get_chrc, NULL, NULL },
+	{ "Value", "ay", desc_get_value, NULL, NULL },
+	{ "Flags", "as", desc_get_flags, NULL, NULL },
+	{ }
+};
+
+static void desc_set_value(const char *input, void *user_data)
+{
+	struct desc *desc = user_data;
+
+	g_free(desc->value);
+
+	desc->value = str2bytearray((char *) input, &desc->value_len);
+}
+
+void gatt_register_desc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w)
+{
+	struct service *service;
+	struct desc *desc;
+
+	if (!local_services) {
+		rl_printf("No service registered\n");
+		return;
+	}
+
+	service = g_list_last(local_services)->data;
+
+	if (!service->chrcs) {
+		rl_printf("No characteristic registered\n");
+		return;
+	}
+
+	desc = g_new0(struct desc, 1);
+	desc->chrc = g_list_last(service->chrcs)->data;
+	desc->uuid = g_strdup(w->we_wordv[0]);
+	desc->path = g_strdup_printf("%s/desc%p", desc->chrc->path, desc);
+	desc->flags = g_strsplit(w->we_wordv[1], ",", -1);
+
+	if (g_dbus_register_interface(conn, desc->path, DESC_INTERFACE,
+					desc_methods, NULL, desc_properties,
+					desc, desc_free) == FALSE) {
+		rl_printf("Failed to register descriptor object\n");
+		desc_free(desc);
+		return;
+	}
+
+	desc->chrc->descs = g_list_append(desc->chrc->descs, desc);
+
+	print_desc(desc, COLORED_NEW);
+
+	rl_prompt_input(desc->path, "Enter value:", desc_set_value, desc);
+}
diff --git a/client/gatt.h b/client/gatt.h
index 0acce4d..4d1e63f 100644
--- a/client/gatt.h
+++ b/client/gatt.h
@@ -52,3 +52,5 @@ void gatt_unregister_service(DBusConnection *conn, GDBusProxy *proxy,
 void gatt_register_chrc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w);
 void gatt_unregister_chrc(DBusConnection *conn, GDBusProxy *proxy,
 								wordexp_t *w);
+
+void gatt_register_desc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w);
diff --git a/client/main.c b/client/main.c
index e5497f1..88dbdb3 100644
--- a/client/main.c
+++ b/client/main.c
@@ -1927,6 +1927,28 @@ static void cmd_unregister_characteristic(const char *arg)
 	wordfree(&w);
 }
 
+static void cmd_register_descriptor(const char *arg)
+{
+	wordexp_t w;
+
+	if (check_default_ctrl() == FALSE)
+		return;
+
+	if (wordexp(arg, &w, WRDE_NOCMD)) {
+		rl_printf("Invalid argument\n");
+		return;
+	}
+
+	if (w.we_wordc < 2) {
+		rl_printf("Missing arguments\n");
+		return;
+	}
+
+	gatt_register_desc(dbus_conn, default_ctrl->proxy, &w);
+
+	wordfree(&w);
+}
+
 static void cmd_version(const char *arg)
 {
 	rl_printf("Version %s\n", VERSION);
@@ -2239,6 +2261,9 @@ static const struct {
 	{ "unregister-characteristic", "<UUID/object>",
 				cmd_unregister_characteristic,
 				"Unregister application characteristic" },
+	{ "register-descriptor", "<UUID> <Flags=read,write...>",
+					cmd_register_descriptor,
+					"Register application descriptor" },
 	{ "version",      NULL,       cmd_version, "Display version" },
 	{ "quit",         NULL,       cmd_quit, "Quit program" },
 	{ "exit",         NULL,       cmd_quit, "Quit program" },
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH BlueZ 9/9] client: Add unregister-descriptor command
  2017-06-28 12:54 [PATCH BlueZ 0/9] client: Add GATT application support Luiz Augusto von Dentz
                   ` (7 preceding siblings ...)
  2017-06-28 12:54 ` [PATCH BlueZ 8/9] client: Add register-descriptor command Luiz Augusto von Dentz
@ 2017-06-28 12:54 ` Luiz Augusto von Dentz
  2017-06-30  7:30   ` ERAMOTO Masaya
  8 siblings, 1 reply; 17+ messages in thread
From: Luiz Augusto von Dentz @ 2017-06-28 12:54 UTC (permalink / raw)
  To: linux-bluetooth

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

This adds unregister-descriptor which can be used to unregister
descriptors registered with register-descriptor:

unregister-descriptor /org/bluez/app/service0xf48150/chrc0xf49a40/desc0xf4d350
[DEL] Descriptor
	/org/bluez/app/service0xf48150/chrc0xf49a40/desc0xf4d350
	8260c653-1a54-426b-9e36-e84c238bc669
	Vendor specific
---
 client/gatt.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 client/gatt.h |  2 ++
 client/main.c | 25 +++++++++++++++++++++++++
 3 files changed, 73 insertions(+)

diff --git a/client/gatt.c b/client/gatt.c
index 7cfdc54..47bf0ae 100644
--- a/client/gatt.c
+++ b/client/gatt.c
@@ -1461,3 +1461,49 @@ void gatt_register_desc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w)
 
 	rl_prompt_input(desc->path, "Enter value:", desc_set_value, desc);
 }
+
+static struct desc *desc_find(const char *pattern)
+{
+	GList *l, *lc, *ld;
+	struct service *service;
+	struct chrc *chrc;
+	struct desc *desc;
+
+	for (l = local_services; l; l = g_list_next(l)) {
+		service = l->data;
+
+		for (lc = service->chrcs; lc; lc = g_list_next(lc)) {
+			chrc = lc->data;
+
+			for (ld = chrc->descs; ld; ld = g_list_next(ld)) {
+				desc = ld->data;
+
+				/* match object path */
+				if (!strcmp(desc->path, pattern))
+					return desc;
+
+				/* match UUID */
+				if (!strcmp(desc->uuid, pattern))
+					return desc;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+void gatt_unregister_desc(DBusConnection *conn, GDBusProxy *proxy,
+								wordexp_t *w)
+{
+	struct desc *desc;
+
+	desc = desc_find(w->we_wordv[0]);
+	if (!desc) {
+		rl_printf("Failed to unregister descriptor object\n");
+		return;
+	}
+
+	desc->chrc->descs = g_list_remove(desc->chrc->descs, desc);
+
+	desc_unregister(desc);
+}
diff --git a/client/gatt.h b/client/gatt.h
index 4d1e63f..8031a46 100644
--- a/client/gatt.h
+++ b/client/gatt.h
@@ -54,3 +54,5 @@ void gatt_unregister_chrc(DBusConnection *conn, GDBusProxy *proxy,
 								wordexp_t *w);
 
 void gatt_register_desc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w);
+void gatt_unregister_desc(DBusConnection *conn, GDBusProxy *proxy,
+								wordexp_t *w);
diff --git a/client/main.c b/client/main.c
index 88dbdb3..985859c 100644
--- a/client/main.c
+++ b/client/main.c
@@ -1949,6 +1949,28 @@ static void cmd_register_descriptor(const char *arg)
 	wordfree(&w);
 }
 
+static void cmd_unregister_descriptor(const char *arg)
+{
+	wordexp_t w;
+
+	if (check_default_ctrl() == FALSE)
+		return;
+
+	if (wordexp(arg, &w, WRDE_NOCMD)) {
+		rl_printf("Invalid argument\n");
+		return;
+	}
+
+	if (w.we_wordc < 1) {
+		rl_printf("Missing arguments\n");
+		return;
+	}
+
+	gatt_unregister_desc(dbus_conn, default_ctrl->proxy, &w);
+
+	wordfree(&w);
+}
+
 static void cmd_version(const char *arg)
 {
 	rl_printf("Version %s\n", VERSION);
@@ -2264,6 +2286,9 @@ static const struct {
 	{ "register-descriptor", "<UUID> <Flags=read,write...>",
 					cmd_register_descriptor,
 					"Register application descriptor" },
+	{ "unregister-descriptor", "<UUID/object>",
+					cmd_unregister_descriptor,
+					"Unregister application descriptor" },
 	{ "version",      NULL,       cmd_version, "Display version" },
 	{ "quit",         NULL,       cmd_quit, "Quit program" },
 	{ "exit",         NULL,       cmd_quit, "Quit program" },
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH BlueZ 2/9] client: Add register-service command
  2017-06-28 12:54 ` [PATCH BlueZ 2/9] client: Add register-service command Luiz Augusto von Dentz
@ 2017-06-30  5:50   ` ERAMOTO Masaya
  2017-06-30  8:34     ` Luiz Augusto von Dentz
  0 siblings, 1 reply; 17+ messages in thread
From: ERAMOTO Masaya @ 2017-06-30  5:50 UTC (permalink / raw)
  To: Luiz Augusto von Dentz, linux-bluetooth

Hi Luiz,

On 2017年06月28日 21:54, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> This adds register-service command which can be used to add GATT services
> to the application:
> 
> [bluetooth]# register-service 00001820-0000-1000-8000-00805f9b34fb
> [NEW] Primary Service
> 	/org/bluez/app/service0x92a150
> 	00001820-0000-1000-8000-00805f9b34fb
> 	Internet Protocol Support
> [bluetooth]# register-application
> [CHG] Controller 00:1B:DC:07:31:88 UUIDs: 00001112-0000-1000-8000-00805f9b34fb
> [CHG] Controller 00:1B:DC:07:31:88 UUIDs: 00001801-0000-1000-8000-00805f9b34fb
> [CHG] Controller 00:1B:DC:07:31:88 UUIDs: 0000110e-0000-1000-8000-00805f9b34fb
> [CHG] Controller 00:1B:DC:07:31:88 UUIDs: 0000112d-0000-1000-8000-00805f9b34fb
> [CHG] Controller 00:1B:DC:07:31:88 UUIDs: 00001800-0000-1000-8000-00805f9b34fb
> [CHG] Controller 00:1B:DC:07:31:88 UUIDs: 00001820-0000-1000-8000-00805f9b34fb
> [CHG] Controller 00:1B:DC:07:31:88 UUIDs: 00001200-0000-1000-8000-00805f9b34fb
> [CHG] Controller 00:1B:DC:07:31:88 UUIDs: 0000110c-0000-1000-8000-00805f9b34fb
> [CHG] Controller 00:1B:DC:07:31:88 UUIDs: 0000110a-0000-1000-8000-00805f9b34fb
> [CHG] Controller 00:1B:DC:07:31:88 UUIDs: 0000110b-0000-1000-8000-00805f9b34fb
> 
> Note: register-application still has to be called at the end to register
> with bluetoothd as everything is done with ObjectManager.
> ---
>  client/gatt.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++---------
>  client/gatt.h |   3 ++
>  client/main.c |  24 ++++++++++
>  3 files changed, 145 insertions(+), 22 deletions(-)
> 
> diff --git a/client/gatt.c b/client/gatt.c
> index 8b7a9c6..282f07e 100644
> --- a/client/gatt.c
> +++ b/client/gatt.c
> @@ -45,22 +45,55 @@
>  
>  #define APP_PATH "/org/bluez/app"
>  #define PROFILE_INTERFACE "org.bluez.GattProfile1"
> +#define SERVICE_INTERFACE "org.bluez.GattService1"
>  
>  /* String display constants */
>  #define COLORED_NEW	COLOR_GREEN "NEW" COLOR_OFF
>  #define COLORED_CHG	COLOR_YELLOW "CHG" COLOR_OFF
>  #define COLORED_DEL	COLOR_RED "DEL" COLOR_OFF
>  
> +struct service {
> +	DBusConnection *conn;
> +	char *path;
> +	char *uuid;
> +	bool primary;
> +};
> +
> +static GList *local_services;
>  static GList *services;
>  static GList *characteristics;
>  static GList *descriptors;
>  static GList *managers;
>  static GList *uuids;
>  
> -static void print_service(GDBusProxy *proxy, const char *description)
> +static void print_service(struct service *service, const char *description)
>  {
> +	const char *text;
> +
> +	text = uuidstr_to_str(service->uuid);
> +	if (!text)
> +		rl_printf("%s%s%s%s Service\n\t%s\n\t%s\n",
> +					description ? "[" : "",
> +					description ? : "",
> +					description ? "] " : "",
> +					service->primary ? "Primary" :
> +					"Secondary",
> +					service->path, service->uuid);
> +	else
> +		rl_printf("%s%s%s%s Service\n\t%s\n\t%s\n\t%s\n",
> +					description ? "[" : "",
> +					description ? : "",
> +					description ? "] " : "",
> +					service->primary ? "Primary" :
> +					"Secondary",
> +					service->path, service->uuid, text);
> +}
> +
> +static void print_service_proxy(GDBusProxy *proxy, const char *description)
> +{
> +	struct service service;
>  	DBusMessageIter iter;
> -	const char *uuid, *text;
> +	const char *uuid;
>  	dbus_bool_t primary;
>  
>  	if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
> @@ -73,30 +106,18 @@ static void print_service(GDBusProxy *proxy, const char *description)
>  
>  	dbus_message_iter_get_basic(&iter, &primary);
>  
> -	text = uuidstr_to_str(uuid);
> -	if (!text)
> -		rl_printf("%s%s%s%s Service\n\t%s\n\t%s\n",
> -					description ? "[" : "",
> -					description ? : "",
> -					description ? "] " : "",
> -					primary ? "Primary" : "Secondary",
> -					g_dbus_proxy_get_path(proxy),
> -					uuid);
> -	else
> -		rl_printf("%s%s%s%s Service\n\t%s\n\t%s\n\t%s\n",
> -					description ? "[" : "",
> -					description ? : "",
> -					description ? "] " : "",
> -					primary ? "Primary" : "Secondary",
> -					g_dbus_proxy_get_path(proxy),
> -					uuid, text);
> +	service.path = (char *) g_dbus_proxy_get_path(proxy);
> +	service.uuid = (char *) uuid;
> +	service.primary = primary;
> +
> +	print_service(&service, description);
>  }
>  
>  void gatt_add_service(GDBusProxy *proxy)
>  {
>  	services = g_list_append(services, proxy);
>  
> -	print_service(proxy, COLORED_NEW);
> +	print_service_proxy(proxy, COLORED_NEW);
>  }
>  
>  void gatt_remove_service(GDBusProxy *proxy)
> @@ -109,7 +130,7 @@ void gatt_remove_service(GDBusProxy *proxy)
>  
>  	services = g_list_delete_link(services, l);
>  
> -	print_service(proxy, COLORED_DEL);
> +	print_service_proxy(proxy, COLORED_DEL);
>  }
>  
>  static void print_characteristic(GDBusProxy *proxy, const char *description)
> @@ -272,7 +293,7 @@ static void list_attributes(const char *path, GList *source)
>  			continue;
>  
>  		if (source == services) {
> -			print_service(proxy, NULL);
> +			print_service_proxy(proxy, NULL);
>  			list_attributes(proxy_path, characteristics);
>  		} else if (source == characteristics) {
>  			print_characteristic(proxy, NULL);
> @@ -798,3 +819,78 @@ void gatt_unregister_app(DBusConnection *conn, GDBusProxy *proxy)
>  		return;
>  	}
>  }
> +
> +static void service_free(void *data)
> +{
> +	struct service *service = data;
> +
> +	g_free(service->path);
> +	g_free(service->uuid);
> +	g_free(service);
> +}
> +
> +static gboolean service_get_uuid(const GDBusPropertyTable *property,
> +					DBusMessageIter *iter, void *data)
> +{
> +	struct service *service = data;
> +
> +	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &service->uuid);
> +
> +	return TRUE;
> +}
> +
> +static gboolean service_get_primary(const GDBusPropertyTable *property,
> +					DBusMessageIter *iter, void *data)
> +{
> +	struct service *service = data;
> +	dbus_bool_t primary;
> +
> +	primary = service->primary ? TRUE : FALSE;
> +
> +	dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &primary);
> +
> +	return TRUE;
> +}
> +
> +static const GDBusPropertyTable service_properties[] = {
> +	{ "UUID", "s", service_get_uuid },
> +	{ "Primary", "b", service_get_primary },
> +	{ }
> +};
> +
> +void gatt_register_service(DBusConnection *conn, GDBusProxy *proxy,
> +								wordexp_t *w)
> +{
> +	struct service *service;
> +	bool primary = true;
> +
> +	if (w->we_wordc > 1) {
> +		if (!strcmp(w->we_wordv[1], "yes")) {
> +			primary = true;
> +		} else if (!strcmp(w->we_wordv[1], "no")) {
> +			primary = false;
> +		} else {
> +			rl_printf("Invalid option: %s\n", w->we_wordv[0]);
> +			return;
> +		}
> +	}
> +
> +	service = g_new0(struct service, 1);
> +	service->conn = conn;
> +	service->uuid = g_strdup(w->we_wordv[0]);
> +	service->path = g_strdup_printf("%s/service%p", APP_PATH, service);
> +	service->primary = primary;
> +
> +	if (g_dbus_register_interface(conn, service->path,
> +					SERVICE_INTERFACE, NULL, NULL,
> +					service_properties, service,
> +					service_free) == FALSE) {
> +		rl_printf("Failed to register service object\n");
> +		service_free(service);
> +		return;
> +	}
> +
> +	rl_printf("Service registered at %s\n", service->path);
> +
> +	local_services = g_list_append(local_services, service);
> +}
> diff --git a/client/gatt.h b/client/gatt.h
> index 4c9fd5b..7f116df 100644
> --- a/client/gatt.h
> +++ b/client/gatt.h
> @@ -43,3 +43,6 @@ void gatt_remove_manager(GDBusProxy *proxy);
>  
>  void gatt_register_app(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w);
>  void gatt_unregister_app(DBusConnection *conn, GDBusProxy *proxy);
> +
> +void gatt_register_service(DBusConnection *conn, GDBusProxy *proxy,
> +								wordexp_t *w);
> diff --git a/client/main.c b/client/main.c
> index 31d06b8..2bcf02c 100644
> --- a/client/main.c
> +++ b/client/main.c
> @@ -1839,6 +1839,28 @@ static void cmd_unregister_app(const char *arg)
>  	gatt_unregister_app(dbus_conn, default_ctrl->proxy);
>  }
>  
> +static void cmd_register_service(const char *arg)
> +{
> +	wordexp_t w;
> +
> +	if (check_default_ctrl() == FALSE)
> +		return;
> +
> +	if (wordexp(arg, &w, WRDE_NOCMD)) {
> +		rl_printf("Invalid argument\n");
> +		return;
> +	}
> +
> +	if (w.we_wordc == 0) {
> +		rl_printf("Missing argument\n");
> +		return;

It seems that the memory of the variable w leaks.

> +	}
> +
> +	gatt_register_service(dbus_conn, default_ctrl->proxy, &w);
> +
> +	wordfree(&w);
> +}
> +
>  static void cmd_version(const char *arg)
>  {
>  	rl_printf("Version %s\n", VERSION);
> @@ -2141,6 +2163,8 @@ static const struct {
>  						"Register profile to connect" },
>  	{ "unregister-application", NULL, cmd_unregister_app,
>  						"Unregister profile" },
> +	{ "register-service", "<UUID> <primary=yes/no>", cmd_register_service,
> +					"Register application service" },

 - It seems that the second argument is optional.
 - I can not determine whether it needs string 'primary=' from the help message.

So, if you do not restrict the description length, would you change to the 
following description:

	{ "register-service", "<UUID> [yes/no]", cmd_register_service,
		"Register application service. If no, register as secondary" },

>  	{ "version",      NULL,       cmd_version, "Display version" },
>  	{ "quit",         NULL,       cmd_quit, "Quit program" },
>  	{ "exit",         NULL,       cmd_quit, "Quit program" },
> 

Regards,
Eramoto

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH BlueZ 3/9] client: Add unregister-service command
  2017-06-28 12:54 ` [PATCH BlueZ 3/9] client: Add unregister-service command Luiz Augusto von Dentz
@ 2017-06-30  5:52   ` ERAMOTO Masaya
  0 siblings, 0 replies; 17+ messages in thread
From: ERAMOTO Masaya @ 2017-06-30  5:52 UTC (permalink / raw)
  To: Luiz Augusto von Dentz, linux-bluetooth

Hi Luiz,

On 2017年06月28日 21:54, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> This adds unregister-service which can be used to unregister an
> application service registered with register-service:
> 
> register-service 00001820-0000-1000-8000-00805f9b34fb
> [NEW] Primary Service
> 	/org/bluez/app/service0x92a150
> 	00001820-0000-1000-8000-00805f9b34fb
> 	Internet Protocol Support
> [bluetooth]# unregister-service /org/bluez/app/service0x92a150
> [DEL] Primary Service
> 	/org/bluez/app/service0x92a150
> 	00001820-0000-1000-8000-00805f9b34fb
> 	Internet Protocol Support
> ---
>  client/gatt.c | 40 +++++++++++++++++++++++++++++++++++++++-
>  client/gatt.h |  2 ++
>  client/main.c | 24 ++++++++++++++++++++++++
>  3 files changed, 65 insertions(+), 1 deletion(-)
> 
> diff --git a/client/gatt.c b/client/gatt.c
> index 282f07e..92ace0e 100644
> --- a/client/gatt.c
> +++ b/client/gatt.c
> @@ -890,7 +890,45 @@ void gatt_register_service(DBusConnection *conn, GDBusProxy *proxy,
>  		return;
>  	}
>  
> -	rl_printf("Service registered at %s\n", service->path);
> +	print_service(service, COLORED_NEW);
>  
>  	local_services = g_list_append(local_services, service);
>  }
> +
> +static struct service *service_find(const char *pattern)
> +{
> +	GList *l;
> +
> +	for (l = local_services; l; l = g_list_next(l)) {
> +		struct service *service = l->data;
> +
> +		/* match object path */
> +		if (!strcmp(service->path, pattern))
> +			return service;
> +
> +		/* match UUID */
> +		if (!strcmp(service->uuid, pattern))
> +			return service;
> +	}
> +
> +	return NULL;
> +}
> +
> +void gatt_unregister_service(DBusConnection *conn, GDBusProxy *proxy,
> +								wordexp_t *w)
> +{
> +	struct service *service;
> +
> +	service = service_find(w->we_wordv[0]);
> +	if (!service) {
> +		rl_printf("Failed to unregister service object\n");
> +		return;
> +	}
> +
> +	local_services = g_list_remove(local_services, service);
> +
> +	print_service(service, COLORED_DEL);
> +
> +	g_dbus_unregister_interface(service->conn, service->path,
> +						SERVICE_INTERFACE);
> +}
> diff --git a/client/gatt.h b/client/gatt.h
> index 7f116df..4b9edd5 100644
> --- a/client/gatt.h
> +++ b/client/gatt.h
> @@ -46,3 +46,5 @@ void gatt_unregister_app(DBusConnection *conn, GDBusProxy *proxy);
>  
>  void gatt_register_service(DBusConnection *conn, GDBusProxy *proxy,
>  								wordexp_t *w);
> +void gatt_unregister_service(DBusConnection *conn, GDBusProxy *proxy,
> +								wordexp_t *w);
> diff --git a/client/main.c b/client/main.c
> index 2bcf02c..16bc125 100644
> --- a/client/main.c
> +++ b/client/main.c
> @@ -1861,6 +1861,28 @@ static void cmd_register_service(const char *arg)
>  	wordfree(&w);
>  }
>  
> +static void cmd_unregister_service(const char *arg)
> +{
> +	wordexp_t w;
> +
> +	if (check_default_ctrl() == FALSE)
> +		return;
> +
> +	if (wordexp(arg, &w, WRDE_NOCMD)) {
> +		rl_printf("Invalid argument\n");
> +		return;
> +	}
> +
> +	if (w.we_wordc == 0) {
> +		rl_printf("Missing argument\n");
> +		return;

It seem that the memory of the variable w leaks.


Regards,
Eramoto

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH BlueZ 4/9] client: Add register-characteristic command
  2017-06-28 12:54 ` [PATCH BlueZ 4/9] client: Add register-characteristic command Luiz Augusto von Dentz
@ 2017-06-30  6:13   ` ERAMOTO Masaya
  0 siblings, 0 replies; 17+ messages in thread
From: ERAMOTO Masaya @ 2017-06-30  6:13 UTC (permalink / raw)
  To: Luiz Augusto von Dentz, linux-bluetooth

Hi Luiz,

On 2017年06月28日 21:54, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> This adds register-characteristic which can be used to register
> characteristic to a service registered with register-service:
> 
> register-characteristic 00002a06-0000-1000-8000-00805f9b34fb write-without-response
> [NEW] Characteristic
> 	/org/bluez/app/service0x1122150/chrc0x113fa40
> 	00002a06-0000-1000-8000-00805f9b34fb
> 	Alert Level
> ---
>  client/gatt.c | 285 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----
>  client/gatt.h |   2 +
>  client/main.c |  25 ++++++
>  3 files changed, 297 insertions(+), 15 deletions(-)
> 
> diff --git a/client/gatt.c b/client/gatt.c
> index 92ace0e..2e56e0c 100644
> --- a/client/gatt.c
> +++ b/client/gatt.c
> @@ -46,17 +46,30 @@
>  #define APP_PATH "/org/bluez/app"
>  #define PROFILE_INTERFACE "org.bluez.GattProfile1"
>  #define SERVICE_INTERFACE "org.bluez.GattService1"
> +#define CHRC_INTERFACE "org.bluez.GattCharacteristic1"
>  
>  /* String display constants */
>  #define COLORED_NEW	COLOR_GREEN "NEW" COLOR_OFF
>  #define COLORED_CHG	COLOR_YELLOW "CHG" COLOR_OFF
>  #define COLORED_DEL	COLOR_RED "DEL" COLOR_OFF
>  
> +struct chrc {
> +	struct service *service;
> +	char *path;
> +	char *uuid;
> +	char **flags;
> +	bool notifying;
> +	GList *descs;
> +	int value_len;
> +	uint8_t *value;
> +};
> +
>  struct service {
>  	DBusConnection *conn;
>  	char *path;
>  	char *uuid;
>  	bool primary;
> +	GList *chrcs;
>  };
>  
>  static GList *local_services;
> @@ -133,34 +146,43 @@ void gatt_remove_service(GDBusProxy *proxy)
>  	print_service_proxy(proxy, COLORED_DEL);
>  }
>  
> -static void print_characteristic(GDBusProxy *proxy, const char *description)
> +static void print_chrc(struct chrc *chrc, const char *description)
>  {
> -	DBusMessageIter iter;
> -	const char *uuid, *text;
> -
> -	if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
> -		return;
> -
> -	dbus_message_iter_get_basic(&iter, &uuid);
> +	const char *text;
>  
> -	text = uuidstr_to_str(uuid);
> +	text = uuidstr_to_str(chrc->uuid);
>  	if (!text)
>  		rl_printf("%s%s%sCharacteristic\n\t%s\n\t%s\n",
>  					description ? "[" : "",
>  					description ? : "",
>  					description ? "] " : "",
> -					g_dbus_proxy_get_path(proxy),
> -					uuid);
> +					chrc->path, chrc->uuid);
>  	else
>  		rl_printf("%s%s%sCharacteristic\n\t%s\n\t%s\n\t%s\n",
>  					description ? "[" : "",
>  					description ? : "",
>  					description ? "] " : "",
> -					g_dbus_proxy_get_path(proxy),
> -					uuid, text);
> +					chrc->path, chrc->uuid, text);
> +}
> +
> +static void print_characteristic(GDBusProxy *proxy, const char *description)
> +{
> +	struct chrc chrc;
> +	DBusMessageIter iter;
> +	const char *uuid;
> +
> +	if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
> +		return;
> +
> +	dbus_message_iter_get_basic(&iter, &uuid);
> +
> +	chrc.path = (char *) g_dbus_proxy_get_path(proxy);
> +	chrc.uuid = (char *) uuid;
> +
> +	print_chrc(&chrc, description);
>  }
>  
> -static gboolean characteristic_is_child(GDBusProxy *characteristic)
> +static gboolean chrc_is_child(GDBusProxy *characteristic)
>  {
>  	GList *l;
>  	DBusMessageIter iter;
> @@ -185,7 +207,7 @@ static gboolean characteristic_is_child(GDBusProxy *characteristic)
>  
>  void gatt_add_characteristic(GDBusProxy *proxy)
>  {
> -	if (!characteristic_is_child(proxy))
> +	if (!chrc_is_child(proxy))
>  		return;
>  
>  	characteristics = g_list_append(characteristics, proxy);
> @@ -820,10 +842,31 @@ void gatt_unregister_app(DBusConnection *conn, GDBusProxy *proxy)
>  	}
>  }
>  
> +static void chrc_free(void *data)
> +{
> +	struct chrc *chrc = data;
> +
> +	g_free(chrc->path);
> +	g_free(chrc->uuid);
> +	g_strfreev(chrc->flags);
> +	g_free(chrc);
> +}
> +
> +static void chrc_unregister(void *data)
> +{
> +	struct chrc *chrc = data;
> +
> +	print_chrc(chrc, COLORED_DEL);
> +
> +	g_dbus_unregister_interface(chrc->service->conn, chrc->path,
> +						CHRC_INTERFACE);
> +}
> +
>  static void service_free(void *data)
>  {
>  	struct service *service = data;
>  
> +	g_list_free_full(service->chrcs, chrc_unregister);
>  	g_free(service->path);
>  	g_free(service->uuid);
>  	g_free(service);
> @@ -932,3 +975,215 @@ void gatt_unregister_service(DBusConnection *conn, GDBusProxy *proxy,
>  	g_dbus_unregister_interface(service->conn, service->path,
>  						SERVICE_INTERFACE);
>  }
> +
> +static gboolean chrc_get_uuid(const GDBusPropertyTable *property,
> +					DBusMessageIter *iter, void *data)
> +{
> +	struct chrc *chrc = data;
> +
> +	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &chrc->uuid);
> +
> +	return TRUE;
> +}
> +
> +static gboolean chrc_get_service(const GDBusPropertyTable *property,
> +					DBusMessageIter *iter, void *data)
> +{
> +	struct chrc *chrc = data;
> +
> +	dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
> +						&chrc->service->path);
> +
> +	return TRUE;
> +}
> +
> +static gboolean chrc_get_value(const GDBusPropertyTable *property,
> +					DBusMessageIter *iter, void *data)
> +{
> +	struct chrc *chrc = data;
> +	DBusMessageIter array;
> +
> +	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
> +
> +	dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
> +						&chrc->value, chrc->value_len);
> +
> +	dbus_message_iter_close_container(iter, &array);
> +
> +	return TRUE;
> +}
> +
> +static gboolean chrc_get_notifying(const GDBusPropertyTable *property,
> +					DBusMessageIter *iter, void *data)
> +{
> +	struct chrc *chrc = data;
> +	dbus_bool_t value;
> +
> +	value = chrc->notifying ? TRUE : FALSE;
> +
> +	dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
> +
> +	return TRUE;
> +}
> +
> +static gboolean chrc_get_flags(const GDBusPropertyTable *property,
> +					DBusMessageIter *iter, void *data)
> +{
> +	struct chrc *chrc = data;
> +	int i;
> +	DBusMessageIter array;
> +
> +	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &array);
> +
> +	for (i = 0; chrc->flags[i]; i++)
> +		dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
> +							&chrc->flags[i]);
> +
> +	dbus_message_iter_close_container(iter, &array);
> +
> +	return TRUE;
> +}
> +
> +static const GDBusPropertyTable chrc_properties[] = {
> +	{ "UUID", "s", chrc_get_uuid, NULL, NULL },
> +	{ "Service", "o", chrc_get_service, NULL, NULL },
> +	{ "Value", "ay", chrc_get_value, NULL, NULL },
> +	{ "Notifying", "b", chrc_get_notifying, NULL, NULL },
> +	{ "Flags", "as", chrc_get_flags, NULL, NULL },
> +	{ }
> +};
> +
> +static DBusMessage *read_value(DBusMessage *msg, uint8_t *value,
> +						uint16_t value_len)
> +{
> +	DBusMessage *reply;
> +	DBusMessageIter iter, array;
> +
> +	reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
> +
> +	dbus_message_iter_init_append(reply, &iter);
> +	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "y", &array);
> +	dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
> +						&value, value_len);
> +	dbus_message_iter_close_container(&iter, &array);
> +
> +	return reply;
> +}
> +
> +static DBusMessage *chrc_read_value(DBusConnection *conn, DBusMessage *msg,
> +							void *user_data)
> +{
> +	struct chrc *chrc = user_data;
> +
> +	return read_value(msg, chrc->value, chrc->value_len);
> +}
> +
> +static int parse_value_arg(DBusMessageIter *iter, uint8_t **value, int *len)
> +{
> +	DBusMessageIter array;
> +
> +	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
> +		return -EINVAL;
> +
> +	dbus_message_iter_recurse(iter, &array);
> +	dbus_message_iter_get_fixed_array(&array, value, len);
> +
> +	return 0;
> +}
> +
> +static DBusMessage *chrc_write_value(DBusConnection *conn, DBusMessage *msg,
> +							void *user_data)
> +{
> +	struct chrc *chrc = user_data;
> +	DBusMessageIter iter;
> +
> +	dbus_message_iter_init(msg, &iter);
> +
> +	if (parse_value_arg(&iter, &chrc->value, &chrc->value_len))
> +		return g_dbus_create_error(msg,
> +					"org.bluez.Error.InvalidArguments",
> +					NULL);
> +
> +	rl_printf("[" COLORED_CHG "] Attribute %s written" , chrc->path);
> +
> +	g_dbus_emit_property_changed(conn, chrc->path, CHRC_INTERFACE, "Value");
> +
> +	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
> +}
> +
> +static DBusMessage *chrc_start_notify(DBusConnection *conn, DBusMessage *msg,
> +							void *user_data)
> +{
> +	struct chrc *chrc = user_data;
> +
> +	if (!chrc->notifying)
> +		return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
> +
> +	chrc->notifying = true;
> +	rl_printf("[" COLORED_CHG "] Attribute %s notifications enabled",
> +							chrc->path);
> +	g_dbus_emit_property_changed(conn, chrc->path, CHRC_INTERFACE,
> +							"Notifying");
> +
> +	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
> +}
> +
> +static DBusMessage *chrc_stop_notify(DBusConnection *conn, DBusMessage *msg,
> +							void *user_data)
> +{
> +	struct chrc *chrc = user_data;
> +
> +	if (chrc->notifying)
> +		return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
> +
> +	chrc->notifying = false;
> +	rl_printf("[" COLORED_CHG "] Attribute %s notifications disabled",
> +							chrc->path);
> +	g_dbus_emit_property_changed(conn, chrc->path, CHRC_INTERFACE,
> +							"Notifying");
> +
> +	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
> +}
> +
> +static const GDBusMethodTable chrc_methods[] = {
> +	{ GDBUS_ASYNC_METHOD("ReadValue", GDBUS_ARGS({ "options", "a{sv}" }),
> +					GDBUS_ARGS({ "value", "ay" }),
> +					chrc_read_value) },
> +	{ GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" },
> +						{ "options", "a{sv}" }),
> +					NULL, chrc_write_value) },
> +	{ GDBUS_ASYNC_METHOD("StartNotify", NULL, NULL, chrc_start_notify) },
> +	{ GDBUS_METHOD("StopNotify", NULL, NULL, chrc_stop_notify) },
> +	{ }
> +};
> +
> +void gatt_register_chrc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w)
> +{
> +	struct service *service;
> +	struct chrc *chrc;
> +
> +	if (!local_services) {
> +		rl_printf("No service registered\n");
> +		return;
> +	}
> +
> +	service = g_list_last(local_services)->data;
> +
> +	chrc = g_new0(struct chrc, 1);
> +	chrc->service = service;
> +	chrc->uuid = g_strdup(w->we_wordv[0]);
> +	chrc->path = g_strdup_printf("%s/chrc%p", service->path, chrc);
> +	chrc->flags = g_strsplit(w->we_wordv[1], ",", -1);
> +
> +	if (g_dbus_register_interface(conn, chrc->path, CHRC_INTERFACE,
> +					chrc_methods, NULL, chrc_properties,
> +					chrc, chrc_free) == FALSE) {
> +		rl_printf("Failed to register characteristic object\n");
> +		chrc_free(chrc);
> +		return;
> +	}
> +
> +	service->chrcs = g_list_append(service->chrcs, chrc);
> +
> +	print_chrc(chrc, COLORED_NEW);
> +}
> diff --git a/client/gatt.h b/client/gatt.h
> index 4b9edd5..4ecf642 100644
> --- a/client/gatt.h
> +++ b/client/gatt.h
> @@ -48,3 +48,5 @@ void gatt_register_service(DBusConnection *conn, GDBusProxy *proxy,
>  								wordexp_t *w);
>  void gatt_unregister_service(DBusConnection *conn, GDBusProxy *proxy,
>  								wordexp_t *w);
> +
> +void gatt_register_chrc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w);
> diff --git a/client/main.c b/client/main.c
> index 16bc125..76a731f 100644
> --- a/client/main.c
> +++ b/client/main.c
> @@ -1883,6 +1883,28 @@ static void cmd_unregister_service(const char *arg)
>  	wordfree(&w);
>  }
>  
> +static void cmd_register_characteristic(const char *arg)
> +{
> +	wordexp_t w;
> +
> +	if (check_default_ctrl() == FALSE)
> +		return;
> +
> +	if (wordexp(arg, &w, WRDE_NOCMD)) {
> +		rl_printf("Invalid argument\n");
> +		return;
> +	}
> +
> +	if (w.we_wordc < 2) {
> +		rl_printf("Missing arguments\n");
> +		return;

It seems that the memory of the variable w leaks.

> +	}
> +
> +	gatt_register_chrc(dbus_conn, default_ctrl->proxy, &w);
> +
> +	wordfree(&w);
> +}
> +
>  static void cmd_version(const char *arg)
>  {
>  	rl_printf("Version %s\n", VERSION);
> @@ -2189,6 +2211,9 @@ static const struct {
>  					"Register application service" },
>  	{ "unregister-service", "<UUID/object>", cmd_unregister_service,
>  					"Unregister application service" },
> +	{ "register-characteristic", "<UUID> <Flags=read,write,notify...>",
> +					cmd_register_characteristic,
> +					"Register application characteristic" },

I can not determine whether the second argument needs string 'Flags=' from
the help message. So, would you delete it below:

	{ "register-characteristic", "<UUID> <read,write,notify...>",

>  	{ "version",      NULL,       cmd_version, "Display version" },
>  	{ "quit",         NULL,       cmd_quit, "Quit program" },
>  	{ "exit",         NULL,       cmd_quit, "Quit program" },
> 

Regards,
Eramoto

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH BlueZ 5/9] client: Add unregister-characteristic command
  2017-06-28 12:54 ` [PATCH BlueZ 5/9] client: Add unregister-characteristic command Luiz Augusto von Dentz
@ 2017-06-30  6:46   ` ERAMOTO Masaya
  0 siblings, 0 replies; 17+ messages in thread
From: ERAMOTO Masaya @ 2017-06-30  6:46 UTC (permalink / raw)
  To: Luiz Augusto von Dentz, linux-bluetooth

Hi Luiz,

On 2017年06月28日 21:54, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> This adds unregister-characteristic which can be used to unregister
> characteristics registered with register-characteristic:
> 
> unregister-characteristic /org/bluez/app/service0xc80150/chrc0xc99960
> [DEL] Characteristic
> 	/org/bluez/app/service0xc80150/chrc0xc99960
> 	00002a06-0000-1000-8000-00805f9b34fb
> 	Alert Level
> ---
>  client/gatt.c | 41 +++++++++++++++++++++++++++++++++++++++++
>  client/gatt.h |  2 ++
>  client/main.c | 25 +++++++++++++++++++++++++
>  3 files changed, 68 insertions(+)
> 
> diff --git a/client/gatt.c b/client/gatt.c
> index 2e56e0c..342b60f 100644
> --- a/client/gatt.c
> +++ b/client/gatt.c
> @@ -1187,3 +1187,44 @@ void gatt_register_chrc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w)
>  
>  	print_chrc(chrc, COLORED_NEW);
>  }
> +
> +static struct chrc *chrc_find(const char *pattern)
> +{
> +	GList *l, *lc;
> +	struct service *service;
> +	struct chrc *chrc;
> +
> +	for (l = local_services; l; l = g_list_next(l)) {
> +		service = l->data;
> +
> +		for (lc = service->chrcs; lc; lc =  g_list_next(lc)) {
> +			chrc = lc->data;
> +
> +			/* match object path */
> +			if (!strcmp(chrc->path, pattern))
> +				return chrc;
> +
> +			/* match UUID */
> +			if (!strcmp(chrc->uuid, pattern))
> +				return chrc;
> +		}
> +	}
> +
> +	return NULL;
> +}
> +
> +void gatt_unregister_chrc(DBusConnection *conn, GDBusProxy *proxy,
> +								wordexp_t *w)
> +{
> +	struct chrc *chrc;
> +
> +	chrc = chrc_find(w->we_wordv[0]);
> +	if (!chrc) {
> +		rl_printf("Failed to unregister characteristic object\n");
> +		return;
> +	}
> +
> +	chrc->service->chrcs = g_list_remove(chrc->service->chrcs, chrc);
> +
> +	chrc_unregister(chrc);
> +}
> diff --git a/client/gatt.h b/client/gatt.h
> index 4ecf642..0acce4d 100644
> --- a/client/gatt.h
> +++ b/client/gatt.h
> @@ -50,3 +50,5 @@ void gatt_unregister_service(DBusConnection *conn, GDBusProxy *proxy,
>  								wordexp_t *w);
>  
>  void gatt_register_chrc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w);
> +void gatt_unregister_chrc(DBusConnection *conn, GDBusProxy *proxy,
> +								wordexp_t *w);
> diff --git a/client/main.c b/client/main.c
> index 76a731f..7eeeefa 100644
> --- a/client/main.c
> +++ b/client/main.c
> @@ -1905,6 +1905,28 @@ static void cmd_register_characteristic(const char *arg)
>  	wordfree(&w);
>  }
>  
> +static void cmd_unregister_characteristic(const char *arg)
> +{
> +	wordexp_t w;
> +
> +	if (check_default_ctrl() == FALSE)
> +		return;
> +
> +	if (wordexp(arg, &w, WRDE_NOCMD)) {
> +		rl_printf("Invalid argument\n");
> +		return;
> +	}
> +
> +	if (w.we_wordc < 1) {
> +		rl_printf("Missing arguments\n");
> +		return;

It seems that the memory of the variable w leaks.


Regards,
Eramoto

> +	}
> +
> +	gatt_unregister_chrc(dbus_conn, default_ctrl->proxy, &w);
> +
> +	wordfree(&w);
> +}
> +
>  static void cmd_version(const char *arg)
>  {
>  	rl_printf("Version %s\n", VERSION);
> @@ -2214,6 +2236,9 @@ static const struct {
>  	{ "register-characteristic", "<UUID> <Flags=read,write,notify...>",
>  					cmd_register_characteristic,
>  					"Register application characteristic" },
> +	{ "unregister-characteristic", "<UUID/object>",
> +				cmd_unregister_characteristic,
> +				"Unregister application characteristic" },
>  	{ "version",      NULL,       cmd_version, "Display version" },
>  	{ "quit",         NULL,       cmd_quit, "Quit program" },
>  	{ "exit",         NULL,       cmd_quit, "Quit program" },
> 

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH BlueZ 8/9] client: Add register-descriptor command
  2017-06-28 12:54 ` [PATCH BlueZ 8/9] client: Add register-descriptor command Luiz Augusto von Dentz
@ 2017-06-30  7:28   ` ERAMOTO Masaya
  0 siblings, 0 replies; 17+ messages in thread
From: ERAMOTO Masaya @ 2017-06-30  7:28 UTC (permalink / raw)
  To: Luiz Augusto von Dentz, linux-bluetooth

Hi Luiz,

On 2017年06月28日 21:54, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> This adds register-descriptor which can be used to register
> descriptors to a characteristic registered with register-characteristic:
> 
> register-descriptor 8260c653-1a54-426b-9e36-e84c238bc669 read,write
> [NEW] Descriptor
> 	/org/bluez/app/service0x902610/chrc0x91d690/desc0x9095a0
> 	8260c653-1a54-426b-9e36-e84c238bc669
> 	Vendor specific
> [/org/bluez/app/service0x902610/chrc0x91d690/desc0x9095a0] Enter value: 00
> ---
>  client/gatt.c | 241 ++++++++++++++++++++++++++++++++++++++++++++++++++++------
>  client/gatt.h |   2 +
>  client/main.c |  25 ++++++
>  3 files changed, 246 insertions(+), 22 deletions(-)
> 
> diff --git a/client/gatt.c b/client/gatt.c
> index 674795a..7cfdc54 100644
> --- a/client/gatt.c
> +++ b/client/gatt.c
> @@ -47,12 +47,22 @@
>  #define PROFILE_INTERFACE "org.bluez.GattProfile1"
>  #define SERVICE_INTERFACE "org.bluez.GattService1"
>  #define CHRC_INTERFACE "org.bluez.GattCharacteristic1"
> +#define DESC_INTERFACE "org.bluez.GattDescriptor1"
>  
>  /* String display constants */
>  #define COLORED_NEW	COLOR_GREEN "NEW" COLOR_OFF
>  #define COLORED_CHG	COLOR_YELLOW "CHG" COLOR_OFF
>  #define COLORED_DEL	COLOR_RED "DEL" COLOR_OFF
>  
> +struct desc {
> +	struct chrc *chrc;
> +	char *path;
> +	char *uuid;
> +	char **flags;
> +	int value_len;
> +	uint8_t *value;
> +};
> +
>  struct chrc {
>  	struct service *service;
>  	char *path;
> @@ -228,31 +238,40 @@ void gatt_remove_characteristic(GDBusProxy *proxy)
>  	print_characteristic(proxy, COLORED_DEL);
>  }
>  
> -static void print_descriptor(GDBusProxy *proxy, const char *description)
> +static void print_desc(struct desc *desc, const char *description)
>  {
> -	DBusMessageIter iter;
> -	const char *uuid, *text;
> -
> -	if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
> -		return;
> -
> -	dbus_message_iter_get_basic(&iter, &uuid);
> +	const char *text;
>  
> -	text = uuidstr_to_str(uuid);
> +	text = uuidstr_to_str(desc->uuid);
>  	if (!text)
>  		rl_printf("%s%s%sDescriptor\n\t%s\n\t%s\n",
>  					description ? "[" : "",
>  					description ? : "",
>  					description ? "] " : "",
> -					g_dbus_proxy_get_path(proxy),
> -					uuid);
> +					desc->path, desc->uuid);
>  	else
>  		rl_printf("%s%s%sDescriptor\n\t%s\n\t%s\n\t%s\n",
>  					description ? "[" : "",
>  					description ? : "",
>  					description ? "] " : "",
> -					g_dbus_proxy_get_path(proxy),
> -					uuid, text);
> +					desc->path, desc->uuid, text);
> +}
> +
> +static void print_descriptor(GDBusProxy *proxy, const char *description)
> +{
> +	struct desc desc;
> +	DBusMessageIter iter;
> +	const char *uuid;
> +
> +	if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
> +		return;
> +
> +	dbus_message_iter_get_basic(&iter, &uuid);
> +
> +	desc.path = (char *) g_dbus_proxy_get_path(proxy);
> +	desc.uuid = (char *) uuid;
> +
> +	print_desc(&desc, description);
>  }
>  
>  static gboolean descriptor_is_child(GDBusProxy *characteristic)
> @@ -842,10 +861,31 @@ void gatt_unregister_app(DBusConnection *conn, GDBusProxy *proxy)
>  	}
>  }
>  
> +static void desc_free(void *data)
> +{
> +	struct desc *desc = data;
> +
> +	g_free(desc->path);
> +	g_free(desc->uuid);
> +	g_strfreev(desc->flags);
> +	g_free(desc);
> +}
> +
> +static void desc_unregister(void *data)
> +{
> +	struct desc *desc = data;
> +
> +	print_desc(desc, COLORED_DEL);
> +
> +	g_dbus_unregister_interface(desc->chrc->service->conn, desc->path,
> +						DESC_INTERFACE);
> +}
> +
>  static void chrc_free(void *data)
>  {
>  	struct chrc *chrc = data;
>  
> +	g_list_free_full(chrc->descs, desc_unregister);
>  	g_free(chrc->path);
>  	g_free(chrc->uuid);
>  	g_strfreev(chrc->flags);
> @@ -1157,16 +1197,13 @@ static const GDBusMethodTable chrc_methods[] = {
>  	{ }
>  };
>  
> -static void chrc_set_value(const char *input, void *user_data)
> +static uint8_t *str2bytearray(char *arg, int *val_len)
>  {
> -	struct chrc *chrc = user_data;
>  	uint8_t value[512];
>  	char *entry;
>  	unsigned int i;
>  
> -	g_free(chrc->value);
> -
> -	for (i = 0; (entry = strsep((char **)&input, " \t")) != NULL; i++) {
> +	for (i = 0; (entry = strsep(&arg, " \t")) != NULL; i++) {
>  		long int val;
>  		char *endptr = NULL;
>  
> @@ -1175,20 +1212,30 @@ static void chrc_set_value(const char *input, void *user_data)
>  
>  		if (i >= G_N_ELEMENTS(value)) {
>  			rl_printf("Too much data\n");
> -			return;
> +			return NULL;
>  		}
>  
>  		val = strtol(entry, &endptr, 0);
>  		if (!endptr || *endptr != '\0' || val > UINT8_MAX) {
>  			rl_printf("Invalid value at index %d\n", i);
> -			return;
> +			return NULL;
>  		}
>  
>  		value[i] = val;
>  	}
>  
> -	chrc->value_len = i;
> -	chrc->value = g_memdup(value, i);
> +	*val_len = i;
> +
> +	return g_memdup(value, i);
> +}
> +
> +static void chrc_set_value(const char *input, void *user_data)
> +{
> +	struct chrc *chrc = user_data;
> +
> +	g_free(chrc->value);
> +
> +	chrc->value = str2bytearray((char *) input, &chrc->value_len);
>  }
>  
>  void gatt_register_chrc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w)
> @@ -1264,3 +1311,153 @@ void gatt_unregister_chrc(DBusConnection *conn, GDBusProxy *proxy,
>  
>  	chrc_unregister(chrc);
>  }
> +
> +static DBusMessage *desc_read_value(DBusConnection *conn, DBusMessage *msg,
> +							void *user_data)
> +{
> +	struct desc *desc = user_data;
> +
> +	return read_value(msg, desc->value, desc->value_len);
> +}
> +
> +static DBusMessage *desc_write_value(DBusConnection *conn, DBusMessage *msg,
> +							void *user_data)
> +{
> +	struct desc *desc = user_data;
> +	DBusMessageIter iter;
> +
> +	dbus_message_iter_init(msg, &iter);
> +
> +	if (parse_value_arg(&iter, &desc->value, &desc->value_len))
> +		return g_dbus_create_error(msg,
> +					"org.bluez.Error.InvalidArguments",
> +					NULL);
> +
> +	rl_printf("[" COLORED_CHG "] Attribute %s written" , desc->path);
> +
> +	g_dbus_emit_property_changed(conn, desc->path, CHRC_INTERFACE, "Value");
> +
> +	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
> +}
> +
> +static const GDBusMethodTable desc_methods[] = {
> +	{ GDBUS_ASYNC_METHOD("ReadValue", GDBUS_ARGS({ "options", "a{sv}" }),
> +					GDBUS_ARGS({ "value", "ay" }),
> +					desc_read_value) },
> +	{ GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" },
> +						{ "options", "a{sv}" }),
> +					NULL, desc_write_value) },
> +	{ }
> +};
> +
> +static gboolean desc_get_uuid(const GDBusPropertyTable *property,
> +					DBusMessageIter *iter, void *data)
> +{
> +	struct desc *desc = data;
> +
> +	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &desc->uuid);
> +
> +	return TRUE;
> +}
> +
> +static gboolean desc_get_chrc(const GDBusPropertyTable *property,
> +					DBusMessageIter *iter, void *data)
> +{
> +	struct desc *desc = data;
> +
> +	dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
> +						&desc->chrc->path);
> +
> +	return TRUE;
> +}
> +
> +static gboolean desc_get_value(const GDBusPropertyTable *property,
> +					DBusMessageIter *iter, void *data)
> +{
> +	struct desc *desc = data;
> +	DBusMessageIter array;
> +
> +	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
> +
> +	if (desc->value)
> +		dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
> +							&desc->value,
> +							desc->value_len);
> +
> +	dbus_message_iter_close_container(iter, &array);
> +
> +	return TRUE;
> +}
> +
> +static gboolean desc_get_flags(const GDBusPropertyTable *property,
> +					DBusMessageIter *iter, void *data)
> +{
> +	struct desc *desc = data;
> +	int i;
> +	DBusMessageIter array;
> +
> +	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &array);
> +
> +	for (i = 0; desc->flags[i]; i++)
> +		dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
> +							&desc->flags[i]);
> +
> +	dbus_message_iter_close_container(iter, &array);
> +
> +	return TRUE;
> +}
> +
> +static const GDBusPropertyTable desc_properties[] = {
> +	{ "UUID", "s", desc_get_uuid, NULL, NULL },
> +	{ "Characteristic", "o", desc_get_chrc, NULL, NULL },
> +	{ "Value", "ay", desc_get_value, NULL, NULL },
> +	{ "Flags", "as", desc_get_flags, NULL, NULL },
> +	{ }
> +};
> +
> +static void desc_set_value(const char *input, void *user_data)
> +{
> +	struct desc *desc = user_data;
> +
> +	g_free(desc->value);
> +
> +	desc->value = str2bytearray((char *) input, &desc->value_len);
> +}
> +
> +void gatt_register_desc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w)
> +{
> +	struct service *service;
> +	struct desc *desc;
> +
> +	if (!local_services) {
> +		rl_printf("No service registered\n");
> +		return;
> +	}
> +
> +	service = g_list_last(local_services)->data;
> +
> +	if (!service->chrcs) {
> +		rl_printf("No characteristic registered\n");
> +		return;
> +	}
> +
> +	desc = g_new0(struct desc, 1);
> +	desc->chrc = g_list_last(service->chrcs)->data;
> +	desc->uuid = g_strdup(w->we_wordv[0]);
> +	desc->path = g_strdup_printf("%s/desc%p", desc->chrc->path, desc);
> +	desc->flags = g_strsplit(w->we_wordv[1], ",", -1);
> +
> +	if (g_dbus_register_interface(conn, desc->path, DESC_INTERFACE,
> +					desc_methods, NULL, desc_properties,
> +					desc, desc_free) == FALSE) {
> +		rl_printf("Failed to register descriptor object\n");
> +		desc_free(desc);
> +		return;
> +	}
> +
> +	desc->chrc->descs = g_list_append(desc->chrc->descs, desc);
> +
> +	print_desc(desc, COLORED_NEW);
> +
> +	rl_prompt_input(desc->path, "Enter value:", desc_set_value, desc);
> +}
> diff --git a/client/gatt.h b/client/gatt.h
> index 0acce4d..4d1e63f 100644
> --- a/client/gatt.h
> +++ b/client/gatt.h
> @@ -52,3 +52,5 @@ void gatt_unregister_service(DBusConnection *conn, GDBusProxy *proxy,
>  void gatt_register_chrc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w);
>  void gatt_unregister_chrc(DBusConnection *conn, GDBusProxy *proxy,
>  								wordexp_t *w);
> +
> +void gatt_register_desc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w);
> diff --git a/client/main.c b/client/main.c
> index e5497f1..88dbdb3 100644
> --- a/client/main.c
> +++ b/client/main.c
> @@ -1927,6 +1927,28 @@ static void cmd_unregister_characteristic(const char *arg)
>  	wordfree(&w);
>  }
>  
> +static void cmd_register_descriptor(const char *arg)
> +{
> +	wordexp_t w;
> +
> +	if (check_default_ctrl() == FALSE)
> +		return;
> +
> +	if (wordexp(arg, &w, WRDE_NOCMD)) {
> +		rl_printf("Invalid argument\n");
> +		return;
> +	}
> +
> +	if (w.we_wordc < 2) {
> +		rl_printf("Missing arguments\n");
> +		return;

It seems that the memory of the variable w leaks.

> +	}
> +
> +	gatt_register_desc(dbus_conn, default_ctrl->proxy, &w);
> +
> +	wordfree(&w);
> +}
> +
>  static void cmd_version(const char *arg)
>  {
>  	rl_printf("Version %s\n", VERSION);
> @@ -2239,6 +2261,9 @@ static const struct {
>  	{ "unregister-characteristic", "<UUID/object>",
>  				cmd_unregister_characteristic,
>  				"Unregister application characteristic" },
> +	{ "register-descriptor", "<UUID> <Flags=read,write...>",
> +					cmd_register_descriptor,
> +					"Register application descriptor" },

I can not determine whether the second argument needs string 'Flags=' from
the help message. So, would you delete it below:

	{ "register-descriptor", "<UUID> <read,write...>",

>  	{ "version",      NULL,       cmd_version, "Display version" },
>  	{ "quit",         NULL,       cmd_quit, "Quit program" },
>  	{ "exit",         NULL,       cmd_quit, "Quit program" },
> 

Regards,
Eramoto

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH BlueZ 9/9] client: Add unregister-descriptor command
  2017-06-28 12:54 ` [PATCH BlueZ 9/9] client: Add unregister-descriptor command Luiz Augusto von Dentz
@ 2017-06-30  7:30   ` ERAMOTO Masaya
  0 siblings, 0 replies; 17+ messages in thread
From: ERAMOTO Masaya @ 2017-06-30  7:30 UTC (permalink / raw)
  To: Luiz Augusto von Dentz, linux-bluetooth

Hi Luiz,

It seems a memory leak occurs when do unregister-[characteristic|descriptor].
The following is valgrind output when I alternately repeated register and 
unregister three times.

==11130== 33 bytes in 3 blocks are definitely lost in loss record 69 of 190
==11130==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11130==    by 0x4E89718: g_malloc (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4800.2)
==11130==    by 0x4EA2527: g_memdup (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4800.2)
==11130==    by 0x40BB6A: str2bytearray (gatt.c:1229)
==11130==    by 0x40BC10: chrc_set_value (gatt.c:1238)
==11130==    by 0x409614: rl_release_prompt (display.c:161)
==11130==    by 0x407E6B: rl_handler (main.c:2375)
==11130==    by 0x53C16F4: rl_callback_read_char (in /lib/x86_64-linux-gnu/libreadline.so.6.3)
==11130==    by 0x40801C: input_handler (main.c:104)
==11130==    by 0x4E84049: g_main_context_dispatch (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4800.2)
==11130==    by 0x4E843EF: ??? (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4800.2)
==11130==    by 0x4E84711: g_main_loop_run (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4800.2)


On 2017年06月28日 21:54, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> This adds unregister-descriptor which can be used to unregister
> descriptors registered with register-descriptor:
> 
> unregister-descriptor /org/bluez/app/service0xf48150/chrc0xf49a40/desc0xf4d350
> [DEL] Descriptor
> 	/org/bluez/app/service0xf48150/chrc0xf49a40/desc0xf4d350
> 	8260c653-1a54-426b-9e36-e84c238bc669
> 	Vendor specific
> ---
>  client/gatt.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
>  client/gatt.h |  2 ++
>  client/main.c | 25 +++++++++++++++++++++++++
>  3 files changed, 73 insertions(+)
> 
> diff --git a/client/gatt.c b/client/gatt.c
> index 7cfdc54..47bf0ae 100644
> --- a/client/gatt.c
> +++ b/client/gatt.c
> @@ -1461,3 +1461,49 @@ void gatt_register_desc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w)
>  
>  	rl_prompt_input(desc->path, "Enter value:", desc_set_value, desc);
>  }
> +
> +static struct desc *desc_find(const char *pattern)
> +{
> +	GList *l, *lc, *ld;
> +	struct service *service;
> +	struct chrc *chrc;
> +	struct desc *desc;
> +
> +	for (l = local_services; l; l = g_list_next(l)) {
> +		service = l->data;
> +
> +		for (lc = service->chrcs; lc; lc = g_list_next(lc)) {
> +			chrc = lc->data;
> +
> +			for (ld = chrc->descs; ld; ld = g_list_next(ld)) {
> +				desc = ld->data;
> +
> +				/* match object path */
> +				if (!strcmp(desc->path, pattern))
> +					return desc;
> +
> +				/* match UUID */
> +				if (!strcmp(desc->uuid, pattern))
> +					return desc;
> +			}
> +		}
> +	}
> +
> +	return NULL;
> +}
> +
> +void gatt_unregister_desc(DBusConnection *conn, GDBusProxy *proxy,
> +								wordexp_t *w)
> +{
> +	struct desc *desc;
> +
> +	desc = desc_find(w->we_wordv[0]);
> +	if (!desc) {
> +		rl_printf("Failed to unregister descriptor object\n");
> +		return;
> +	}
> +
> +	desc->chrc->descs = g_list_remove(desc->chrc->descs, desc);
> +
> +	desc_unregister(desc);
> +}
> diff --git a/client/gatt.h b/client/gatt.h
> index 4d1e63f..8031a46 100644
> --- a/client/gatt.h
> +++ b/client/gatt.h
> @@ -54,3 +54,5 @@ void gatt_unregister_chrc(DBusConnection *conn, GDBusProxy *proxy,
>  								wordexp_t *w);
>  
>  void gatt_register_desc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w);
> +void gatt_unregister_desc(DBusConnection *conn, GDBusProxy *proxy,
> +								wordexp_t *w);
> diff --git a/client/main.c b/client/main.c
> index 88dbdb3..985859c 100644
> --- a/client/main.c
> +++ b/client/main.c
> @@ -1949,6 +1949,28 @@ static void cmd_register_descriptor(const char *arg)
>  	wordfree(&w);
>  }
>  
> +static void cmd_unregister_descriptor(const char *arg)
> +{
> +	wordexp_t w;
> +
> +	if (check_default_ctrl() == FALSE)
> +		return;
> +
> +	if (wordexp(arg, &w, WRDE_NOCMD)) {
> +		rl_printf("Invalid argument\n");
> +		return;
> +	}
> +
> +	if (w.we_wordc < 1) {
> +		rl_printf("Missing arguments\n");
> +		return;

It seems that the memory of the variable w leaks.

> +	}
> +
> +	gatt_unregister_desc(dbus_conn, default_ctrl->proxy, &w);
> +
> +	wordfree(&w);
> +}
> +
>  static void cmd_version(const char *arg)
>  {
>  	rl_printf("Version %s\n", VERSION);
> @@ -2264,6 +2286,9 @@ static const struct {
>  	{ "register-descriptor", "<UUID> <Flags=read,write...>",
>  					cmd_register_descriptor,
>  					"Register application descriptor" },
> +	{ "unregister-descriptor", "<UUID/object>",
> +					cmd_unregister_descriptor,
> +					"Unregister application descriptor" },
>  	{ "version",      NULL,       cmd_version, "Display version" },
>  	{ "quit",         NULL,       cmd_quit, "Quit program" },
>  	{ "exit",         NULL,       cmd_quit, "Quit program" },
> 

Regards,
Eramoto

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH BlueZ 2/9] client: Add register-service command
  2017-06-30  5:50   ` ERAMOTO Masaya
@ 2017-06-30  8:34     ` Luiz Augusto von Dentz
  0 siblings, 0 replies; 17+ messages in thread
From: Luiz Augusto von Dentz @ 2017-06-30  8:34 UTC (permalink / raw)
  To: ERAMOTO Masaya; +Cc: linux-bluetooth

Hi Eramoto,

On Fri, Jun 30, 2017 at 8:50 AM, ERAMOTO Masaya
<eramoto.masaya@jp.fujitsu.com> wrote:
> Hi Luiz,
>
> On 2017=E5=B9=B406=E6=9C=8828=E6=97=A5 21:54, Luiz Augusto von Dentz wrot=
e:
>> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>>
>> This adds register-service command which can be used to add GATT service=
s
>> to the application:
>>
>> [bluetooth]# register-service 00001820-0000-1000-8000-00805f9b34fb
>> [NEW] Primary Service
>>       /org/bluez/app/service0x92a150
>>       00001820-0000-1000-8000-00805f9b34fb
>>       Internet Protocol Support
>> [bluetooth]# register-application
>> [CHG] Controller 00:1B:DC:07:31:88 UUIDs: 00001112-0000-1000-8000-00805f=
9b34fb
>> [CHG] Controller 00:1B:DC:07:31:88 UUIDs: 00001801-0000-1000-8000-00805f=
9b34fb
>> [CHG] Controller 00:1B:DC:07:31:88 UUIDs: 0000110e-0000-1000-8000-00805f=
9b34fb
>> [CHG] Controller 00:1B:DC:07:31:88 UUIDs: 0000112d-0000-1000-8000-00805f=
9b34fb
>> [CHG] Controller 00:1B:DC:07:31:88 UUIDs: 00001800-0000-1000-8000-00805f=
9b34fb
>> [CHG] Controller 00:1B:DC:07:31:88 UUIDs: 00001820-0000-1000-8000-00805f=
9b34fb
>> [CHG] Controller 00:1B:DC:07:31:88 UUIDs: 00001200-0000-1000-8000-00805f=
9b34fb
>> [CHG] Controller 00:1B:DC:07:31:88 UUIDs: 0000110c-0000-1000-8000-00805f=
9b34fb
>> [CHG] Controller 00:1B:DC:07:31:88 UUIDs: 0000110a-0000-1000-8000-00805f=
9b34fb
>> [CHG] Controller 00:1B:DC:07:31:88 UUIDs: 0000110b-0000-1000-8000-00805f=
9b34fb
>>
>> Note: register-application still has to be called at the end to register
>> with bluetoothd as everything is done with ObjectManager.
>> ---
>>  client/gatt.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++--=
-------
>>  client/gatt.h |   3 ++
>>  client/main.c |  24 ++++++++++
>>  3 files changed, 145 insertions(+), 22 deletions(-)
>>
>> diff --git a/client/gatt.c b/client/gatt.c
>> index 8b7a9c6..282f07e 100644
>> --- a/client/gatt.c
>> +++ b/client/gatt.c
>> @@ -45,22 +45,55 @@
>>
>>  #define APP_PATH "/org/bluez/app"
>>  #define PROFILE_INTERFACE "org.bluez.GattProfile1"
>> +#define SERVICE_INTERFACE "org.bluez.GattService1"
>>
>>  /* String display constants */
>>  #define COLORED_NEW  COLOR_GREEN "NEW" COLOR_OFF
>>  #define COLORED_CHG  COLOR_YELLOW "CHG" COLOR_OFF
>>  #define COLORED_DEL  COLOR_RED "DEL" COLOR_OFF
>>
>> +struct service {
>> +     DBusConnection *conn;
>> +     char *path;
>> +     char *uuid;
>> +     bool primary;
>> +};
>> +
>> +static GList *local_services;
>>  static GList *services;
>>  static GList *characteristics;
>>  static GList *descriptors;
>>  static GList *managers;
>>  static GList *uuids;
>>
>> -static void print_service(GDBusProxy *proxy, const char *description)
>> +static void print_service(struct service *service, const char *descript=
ion)
>>  {
>> +     const char *text;
>> +
>> +     text =3D uuidstr_to_str(service->uuid);
>> +     if (!text)
>> +             rl_printf("%s%s%s%s Service\n\t%s\n\t%s\n",
>> +                                     description ? "[" : "",
>> +                                     description ? : "",
>> +                                     description ? "] " : "",
>> +                                     service->primary ? "Primary" :
>> +                                     "Secondary",
>> +                                     service->path, service->uuid);
>> +     else
>> +             rl_printf("%s%s%s%s Service\n\t%s\n\t%s\n\t%s\n",
>> +                                     description ? "[" : "",
>> +                                     description ? : "",
>> +                                     description ? "] " : "",
>> +                                     service->primary ? "Primary" :
>> +                                     "Secondary",
>> +                                     service->path, service->uuid, text=
);
>> +}
>> +
>> +static void print_service_proxy(GDBusProxy *proxy, const char *descript=
ion)
>> +{
>> +     struct service service;
>>       DBusMessageIter iter;
>> -     const char *uuid, *text;
>> +     const char *uuid;
>>       dbus_bool_t primary;
>>
>>       if (g_dbus_proxy_get_property(proxy, "UUID", &iter) =3D=3D FALSE)
>> @@ -73,30 +106,18 @@ static void print_service(GDBusProxy *proxy, const =
char *description)
>>
>>       dbus_message_iter_get_basic(&iter, &primary);
>>
>> -     text =3D uuidstr_to_str(uuid);
>> -     if (!text)
>> -             rl_printf("%s%s%s%s Service\n\t%s\n\t%s\n",
>> -                                     description ? "[" : "",
>> -                                     description ? : "",
>> -                                     description ? "] " : "",
>> -                                     primary ? "Primary" : "Secondary",
>> -                                     g_dbus_proxy_get_path(proxy),
>> -                                     uuid);
>> -     else
>> -             rl_printf("%s%s%s%s Service\n\t%s\n\t%s\n\t%s\n",
>> -                                     description ? "[" : "",
>> -                                     description ? : "",
>> -                                     description ? "] " : "",
>> -                                     primary ? "Primary" : "Secondary",
>> -                                     g_dbus_proxy_get_path(proxy),
>> -                                     uuid, text);
>> +     service.path =3D (char *) g_dbus_proxy_get_path(proxy);
>> +     service.uuid =3D (char *) uuid;
>> +     service.primary =3D primary;
>> +
>> +     print_service(&service, description);
>>  }
>>
>>  void gatt_add_service(GDBusProxy *proxy)
>>  {
>>       services =3D g_list_append(services, proxy);
>>
>> -     print_service(proxy, COLORED_NEW);
>> +     print_service_proxy(proxy, COLORED_NEW);
>>  }
>>
>>  void gatt_remove_service(GDBusProxy *proxy)
>> @@ -109,7 +130,7 @@ void gatt_remove_service(GDBusProxy *proxy)
>>
>>       services =3D g_list_delete_link(services, l);
>>
>> -     print_service(proxy, COLORED_DEL);
>> +     print_service_proxy(proxy, COLORED_DEL);
>>  }
>>
>>  static void print_characteristic(GDBusProxy *proxy, const char *descrip=
tion)
>> @@ -272,7 +293,7 @@ static void list_attributes(const char *path, GList =
*source)
>>                       continue;
>>
>>               if (source =3D=3D services) {
>> -                     print_service(proxy, NULL);
>> +                     print_service_proxy(proxy, NULL);
>>                       list_attributes(proxy_path, characteristics);
>>               } else if (source =3D=3D characteristics) {
>>                       print_characteristic(proxy, NULL);
>> @@ -798,3 +819,78 @@ void gatt_unregister_app(DBusConnection *conn, GDBu=
sProxy *proxy)
>>               return;
>>       }
>>  }
>> +
>> +static void service_free(void *data)
>> +{
>> +     struct service *service =3D data;
>> +
>> +     g_free(service->path);
>> +     g_free(service->uuid);
>> +     g_free(service);
>> +}
>> +
>> +static gboolean service_get_uuid(const GDBusPropertyTable *property,
>> +                                     DBusMessageIter *iter, void *data)
>> +{
>> +     struct service *service =3D data;
>> +
>> +     dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &service->u=
uid);
>> +
>> +     return TRUE;
>> +}
>> +
>> +static gboolean service_get_primary(const GDBusPropertyTable *property,
>> +                                     DBusMessageIter *iter, void *data)
>> +{
>> +     struct service *service =3D data;
>> +     dbus_bool_t primary;
>> +
>> +     primary =3D service->primary ? TRUE : FALSE;
>> +
>> +     dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &primary);
>> +
>> +     return TRUE;
>> +}
>> +
>> +static const GDBusPropertyTable service_properties[] =3D {
>> +     { "UUID", "s", service_get_uuid },
>> +     { "Primary", "b", service_get_primary },
>> +     { }
>> +};
>> +
>> +void gatt_register_service(DBusConnection *conn, GDBusProxy *proxy,
>> +                                                             wordexp_t =
*w)
>> +{
>> +     struct service *service;
>> +     bool primary =3D true;
>> +
>> +     if (w->we_wordc > 1) {
>> +             if (!strcmp(w->we_wordv[1], "yes")) {
>> +                     primary =3D true;
>> +             } else if (!strcmp(w->we_wordv[1], "no")) {
>> +                     primary =3D false;
>> +             } else {
>> +                     rl_printf("Invalid option: %s\n", w->we_wordv[0]);
>> +                     return;
>> +             }
>> +     }
>> +
>> +     service =3D g_new0(struct service, 1);
>> +     service->conn =3D conn;
>> +     service->uuid =3D g_strdup(w->we_wordv[0]);
>> +     service->path =3D g_strdup_printf("%s/service%p", APP_PATH, servic=
e);
>> +     service->primary =3D primary;
>> +
>> +     if (g_dbus_register_interface(conn, service->path,
>> +                                     SERVICE_INTERFACE, NULL, NULL,
>> +                                     service_properties, service,
>> +                                     service_free) =3D=3D FALSE) {
>> +             rl_printf("Failed to register service object\n");
>> +             service_free(service);
>> +             return;
>> +     }
>> +
>> +     rl_printf("Service registered at %s\n", service->path);
>> +
>> +     local_services =3D g_list_append(local_services, service);
>> +}
>> diff --git a/client/gatt.h b/client/gatt.h
>> index 4c9fd5b..7f116df 100644
>> --- a/client/gatt.h
>> +++ b/client/gatt.h
>> @@ -43,3 +43,6 @@ void gatt_remove_manager(GDBusProxy *proxy);
>>
>>  void gatt_register_app(DBusConnection *conn, GDBusProxy *proxy, wordexp=
_t *w);
>>  void gatt_unregister_app(DBusConnection *conn, GDBusProxy *proxy);
>> +
>> +void gatt_register_service(DBusConnection *conn, GDBusProxy *proxy,
>> +                                                             wordexp_t =
*w);
>> diff --git a/client/main.c b/client/main.c
>> index 31d06b8..2bcf02c 100644
>> --- a/client/main.c
>> +++ b/client/main.c
>> @@ -1839,6 +1839,28 @@ static void cmd_unregister_app(const char *arg)
>>       gatt_unregister_app(dbus_conn, default_ctrl->proxy);
>>  }
>>
>> +static void cmd_register_service(const char *arg)
>> +{
>> +     wordexp_t w;
>> +
>> +     if (check_default_ctrl() =3D=3D FALSE)
>> +             return;
>> +
>> +     if (wordexp(arg, &w, WRDE_NOCMD)) {
>> +             rl_printf("Invalid argument\n");
>> +             return;
>> +     }
>> +
>> +     if (w.we_wordc =3D=3D 0) {
>> +             rl_printf("Missing argument\n");
>> +             return;
>
> It seems that the memory of the variable w leaks.

It does indeed.

>> +     }
>> +
>> +     gatt_register_service(dbus_conn, default_ctrl->proxy, &w);
>> +
>> +     wordfree(&w);
>> +}
>> +
>>  static void cmd_version(const char *arg)
>>  {
>>       rl_printf("Version %s\n", VERSION);
>> @@ -2141,6 +2163,8 @@ static const struct {
>>                                               "Register profile to conne=
ct" },
>>       { "unregister-application", NULL, cmd_unregister_app,
>>                                               "Unregister profile" },
>> +     { "register-service", "<UUID> <primary=3Dyes/no>", cmd_register_se=
rvice,
>> +                                     "Register application service" },
>
>  - It seems that the second argument is optional.
>  - I can not determine whether it needs string 'primary=3D' from the help=
 message.
>
> So, if you do not restrict the description length, would you change to th=
e
> following description:
>
>         { "register-service", "<UUID> [yes/no]", cmd_register_service,
>                 "Register application service. If no, register as seconda=
ry" },

Sure thing.

>>       { "version",      NULL,       cmd_version, "Display version" },
>>       { "quit",         NULL,       cmd_quit, "Quit program" },
>>       { "exit",         NULL,       cmd_quit, "Quit program" },
>>
>
> Regards,
> Eramoto



--=20
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2017-06-30  8:34 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-28 12:54 [PATCH BlueZ 0/9] client: Add GATT application support Luiz Augusto von Dentz
2017-06-28 12:54 ` [PATCH BlueZ 1/9] client: Allow register-application without any UUID Luiz Augusto von Dentz
2017-06-28 12:54 ` [PATCH BlueZ 2/9] client: Add register-service command Luiz Augusto von Dentz
2017-06-30  5:50   ` ERAMOTO Masaya
2017-06-30  8:34     ` Luiz Augusto von Dentz
2017-06-28 12:54 ` [PATCH BlueZ 3/9] client: Add unregister-service command Luiz Augusto von Dentz
2017-06-30  5:52   ` ERAMOTO Masaya
2017-06-28 12:54 ` [PATCH BlueZ 4/9] client: Add register-characteristic command Luiz Augusto von Dentz
2017-06-30  6:13   ` ERAMOTO Masaya
2017-06-28 12:54 ` [PATCH BlueZ 5/9] client: Add unregister-characteristic command Luiz Augusto von Dentz
2017-06-30  6:46   ` ERAMOTO Masaya
2017-06-28 12:54 ` [PATCH BlueZ 6/9] client: Add generic way to request input from user Luiz Augusto von Dentz
2017-06-28 12:54 ` [PATCH BlueZ 7/9] client: Ask user the characteristic value Luiz Augusto von Dentz
2017-06-28 12:54 ` [PATCH BlueZ 8/9] client: Add register-descriptor command Luiz Augusto von Dentz
2017-06-30  7:28   ` ERAMOTO Masaya
2017-06-28 12:54 ` [PATCH BlueZ 9/9] client: Add unregister-descriptor command Luiz Augusto von Dentz
2017-06-30  7:30   ` ERAMOTO Masaya

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.