* [PATCH v2 1/8] client: Allow register-application without any UUID
2017-06-30 10:18 [PATCH v2 BlueZ 0/9] client: Add GATT application support Luiz Augusto von Dentz
@ 2017-06-30 10:18 ` Luiz Augusto von Dentz
2017-06-30 10:18 ` [PATCH v2 2/8] client: Add generic way to request input from user Luiz Augusto von Dentz
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Luiz Augusto von Dentz @ 2017-06-30 10:18 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] 10+ messages in thread
* [PATCH v2 2/8] client: Add generic way to request input from user
2017-06-30 10:18 [PATCH v2 BlueZ 0/9] client: Add GATT application support Luiz Augusto von Dentz
2017-06-30 10:18 ` [PATCH v2 1/8] client: Allow register-application without any UUID Luiz Augusto von Dentz
@ 2017-06-30 10:18 ` Luiz Augusto von Dentz
2017-06-30 10:18 ` [PATCH v2 3/8] client: Add register-service command Luiz Augusto von Dentz
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Luiz Augusto von Dentz @ 2017-06-30 10:18 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 31d06b8..c42bf50 100644
--- a/client/main.c
+++ b/client/main.c
@@ -2223,6 +2223,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] 10+ messages in thread
* [PATCH v2 3/8] client: Add register-service command
2017-06-30 10:18 [PATCH v2 BlueZ 0/9] client: Add GATT application support Luiz Augusto von Dentz
2017-06-30 10:18 ` [PATCH v2 1/8] client: Allow register-application without any UUID Luiz Augusto von Dentz
2017-06-30 10:18 ` [PATCH v2 2/8] client: Add generic way to request input from user Luiz Augusto von Dentz
@ 2017-06-30 10:18 ` Luiz Augusto von Dentz
2017-06-30 10:18 ` [PATCH v2 4/8] client: Add unregister-service command Luiz Augusto von Dentz
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Luiz Augusto von Dentz @ 2017-06-30 10:18 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/service0x8c2610
00001820-0000-1000-8000-00805f9b34fb
Internet Protocol Support
[/org/bluez/app/service0x8c2610] Primary (yes/no): yes
[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 | 149 +++++++++++++++++++++++++++++++++++++++++++++++++---------
client/gatt.h | 3 ++
client/main.c | 25 ++++++++++
3 files changed, 155 insertions(+), 22 deletions(-)
diff --git a/client/gatt.c b/client/gatt.c
index 8b7a9c6..82e7851 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,87 @@ 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 },
+ { }
+};
+
+static void service_set_primary(const char *input, void *user_data)
+{
+ struct service *service = user_data;
+
+ if (!strcmp(input, "yes"))
+ service->primary = true;
+ else if (!strcmp(input, "no")) {
+ service->primary = false;
+ } else {
+ rl_printf("Invalid option: %s\n", input);
+ local_services = g_list_remove(local_services, service);
+ print_service(service, COLORED_DEL);
+ g_dbus_unregister_interface(service->conn, service->path,
+ SERVICE_INTERFACE);
+ }
+}
+
+void gatt_register_service(DBusConnection *conn, GDBusProxy *proxy,
+ wordexp_t *w)
+{
+ struct service *service;
+ bool primary = true;
+
+ 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);
+
+ rl_prompt_input(service->path, "Primary (yes/no):", service_set_primary,
+ 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 c42bf50..726d749 100644
--- a/client/main.c
+++ b/client/main.c
@@ -1839,6 +1839,29 @@ 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");
+ goto done;
+ }
+
+ gatt_register_service(dbus_conn, default_ctrl->proxy, &w);
+
+done:
+ wordfree(&w);
+}
+
static void cmd_version(const char *arg)
{
rl_printf("Version %s\n", VERSION);
@@ -2141,6 +2164,8 @@ static const struct {
"Register profile to connect" },
{ "unregister-application", NULL, cmd_unregister_app,
"Unregister profile" },
+ { "register-service", "<UUID>", 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] 10+ messages in thread
* [PATCH v2 4/8] client: Add unregister-service command
2017-06-30 10:18 [PATCH v2 BlueZ 0/9] client: Add GATT application support Luiz Augusto von Dentz
` (2 preceding siblings ...)
2017-06-30 10:18 ` [PATCH v2 3/8] client: Add register-service command Luiz Augusto von Dentz
@ 2017-06-30 10:18 ` Luiz Augusto von Dentz
2017-06-30 10:18 ` [PATCH v2 5/8] client: Add register-characteristic command Luiz Augusto von Dentz
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Luiz Augusto von Dentz @ 2017-06-30 10:18 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 | 25 +++++++++++++++++++++++++
3 files changed, 66 insertions(+), 1 deletion(-)
diff --git a/client/gatt.c b/client/gatt.c
index 82e7851..3ceea45 100644
--- a/client/gatt.c
+++ b/client/gatt.c
@@ -896,10 +896,48 @@ 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);
rl_prompt_input(service->path, "Primary (yes/no):", service_set_primary,
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 726d749..dd18eb8 100644
--- a/client/main.c
+++ b/client/main.c
@@ -1862,6 +1862,29 @@ done:
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");
+ goto done;
+ }
+
+ gatt_unregister_service(dbus_conn, default_ctrl->proxy, &w);
+
+done:
+ wordfree(&w);
+}
+
static void cmd_version(const char *arg)
{
rl_printf("Version %s\n", VERSION);
@@ -2166,6 +2189,8 @@ static const struct {
"Unregister profile" },
{ "register-service", "<UUID>", 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] 10+ messages in thread
* [PATCH v2 5/8] client: Add register-characteristic command
2017-06-30 10:18 [PATCH v2 BlueZ 0/9] client: Add GATT application support Luiz Augusto von Dentz
` (3 preceding siblings ...)
2017-06-30 10:18 ` [PATCH v2 4/8] client: Add unregister-service command Luiz Augusto von Dentz
@ 2017-06-30 10:18 ` Luiz Augusto von Dentz
2017-06-30 10:18 ` [PATCH v2 6/8] client: Add unregister-characteristic command Luiz Augusto von Dentz
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Luiz Augusto von Dentz @ 2017-06-30 10:18 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 | 322 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
client/gatt.h | 2 +
client/main.c | 26 +++++
3 files changed, 335 insertions(+), 15 deletions(-)
diff --git a/client/gatt.c b/client/gatt.c
index 3ceea45..3185c31 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,32 @@ 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->value);
+ 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);
@@ -941,3 +985,251 @@ 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) },
+ { }
+};
+
+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;
+ 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);
+
+ rl_prompt_input(chrc->path, "Enter value:", chrc_set_value, chrc);
+}
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 dd18eb8..34271aa 100644
--- a/client/main.c
+++ b/client/main.c
@@ -1885,6 +1885,29 @@ done:
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");
+ goto done;
+ }
+
+ gatt_register_chrc(dbus_conn, default_ctrl->proxy, &w);
+
+done:
+ wordfree(&w);
+}
+
static void cmd_version(const char *arg)
{
rl_printf("Version %s\n", VERSION);
@@ -2191,6 +2214,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] 10+ messages in thread
* [PATCH v2 6/8] client: Add unregister-characteristic command
2017-06-30 10:18 [PATCH v2 BlueZ 0/9] client: Add GATT application support Luiz Augusto von Dentz
` (4 preceding siblings ...)
2017-06-30 10:18 ` [PATCH v2 5/8] client: Add register-characteristic command Luiz Augusto von Dentz
@ 2017-06-30 10:18 ` Luiz Augusto von Dentz
2017-06-30 10:18 ` [PATCH v2 7/8] client: Add register-descriptor command Luiz Augusto von Dentz
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Luiz Augusto von Dentz @ 2017-06-30 10:18 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 | 26 ++++++++++++++++++++++++++
3 files changed, 69 insertions(+)
diff --git a/client/gatt.c b/client/gatt.c
index 3185c31..4466490 100644
--- a/client/gatt.c
+++ b/client/gatt.c
@@ -1233,3 +1233,44 @@ void gatt_register_chrc(DBusConnection *conn, GDBusProxy *proxy, wordexp_t *w)
rl_prompt_input(chrc->path, "Enter value:", chrc_set_value, chrc);
}
+
+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 34271aa..f3dfa2c 100644
--- a/client/main.c
+++ b/client/main.c
@@ -1908,6 +1908,29 @@ done:
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");
+ goto done;
+ }
+
+ gatt_unregister_chrc(dbus_conn, default_ctrl->proxy, &w);
+
+done:
+ wordfree(&w);
+}
+
static void cmd_version(const char *arg)
{
rl_printf("Version %s\n", VERSION);
@@ -2217,6 +2240,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] 10+ messages in thread
* [PATCH v2 7/8] client: Add register-descriptor command
2017-06-30 10:18 [PATCH v2 BlueZ 0/9] client: Add GATT application support Luiz Augusto von Dentz
` (5 preceding siblings ...)
2017-06-30 10:18 ` [PATCH v2 6/8] client: Add unregister-characteristic command Luiz Augusto von Dentz
@ 2017-06-30 10:18 ` Luiz Augusto von Dentz
2017-06-30 10:18 ` [PATCH v2 8/8] client: Add unregister-descriptor command Luiz Augusto von Dentz
2017-07-03 12:12 ` [PATCH v2 BlueZ 0/9] client: Add GATT application support Luiz Augusto von Dentz
8 siblings, 0 replies; 10+ messages in thread
From: Luiz Augusto von Dentz @ 2017-06-30 10:18 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 | 242 ++++++++++++++++++++++++++++++++++++++++++++++++++++------
client/gatt.h | 2 +
client/main.c | 26 +++++++
3 files changed, 248 insertions(+), 22 deletions(-)
diff --git a/client/gatt.c b/client/gatt.c
index 4466490..e7d9a03 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,32 @@ 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->value);
+ 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);
@@ -1167,16 +1208,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;
@@ -1185,20 +1223,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)
@@ -1274,3 +1322,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 f3dfa2c..2c5fe26 100644
--- a/client/main.c
+++ b/client/main.c
@@ -1931,6 +1931,29 @@ done:
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");
+ goto done;
+ }
+
+ gatt_register_desc(dbus_conn, default_ctrl->proxy, &w);
+
+done:
+ wordfree(&w);
+}
+
static void cmd_version(const char *arg)
{
rl_printf("Version %s\n", VERSION);
@@ -2243,6 +2266,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] 10+ messages in thread
* [PATCH v2 8/8] client: Add unregister-descriptor command
2017-06-30 10:18 [PATCH v2 BlueZ 0/9] client: Add GATT application support Luiz Augusto von Dentz
` (6 preceding siblings ...)
2017-06-30 10:18 ` [PATCH v2 7/8] client: Add register-descriptor command Luiz Augusto von Dentz
@ 2017-06-30 10:18 ` Luiz Augusto von Dentz
2017-07-03 12:12 ` [PATCH v2 BlueZ 0/9] client: Add GATT application support Luiz Augusto von Dentz
8 siblings, 0 replies; 10+ messages in thread
From: Luiz Augusto von Dentz @ 2017-06-30 10:18 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 | 26 ++++++++++++++++++++++++++
3 files changed, 74 insertions(+)
diff --git a/client/gatt.c b/client/gatt.c
index e7d9a03..8a4491a 100644
--- a/client/gatt.c
+++ b/client/gatt.c
@@ -1472,3 +1472,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 2c5fe26..3af533e 100644
--- a/client/main.c
+++ b/client/main.c
@@ -1954,6 +1954,29 @@ done:
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");
+ goto done;
+ }
+
+ gatt_unregister_desc(dbus_conn, default_ctrl->proxy, &w);
+
+done:
+ wordfree(&w);
+}
+
static void cmd_version(const char *arg)
{
rl_printf("Version %s\n", VERSION);
@@ -2269,6 +2292,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] 10+ messages in thread
* Re: [PATCH v2 BlueZ 0/9] client: Add GATT application support
2017-06-30 10:18 [PATCH v2 BlueZ 0/9] client: Add GATT application support Luiz Augusto von Dentz
` (7 preceding siblings ...)
2017-06-30 10:18 ` [PATCH v2 8/8] client: Add unregister-descriptor command Luiz Augusto von Dentz
@ 2017-07-03 12:12 ` Luiz Augusto von Dentz
8 siblings, 0 replies; 10+ messages in thread
From: Luiz Augusto von Dentz @ 2017-07-03 12:12 UTC (permalink / raw)
To: linux-bluetooth
Hi,
On Fri, Jun 30, 2017 at 1:18 PM, Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> 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
>
> v2: Fix memory leaks pointed out by Eramoto, make register-service ask for primary
> property.
>
> 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
Applied.
--
Luiz Augusto von Dentz
^ permalink raw reply [flat|nested] 10+ messages in thread