2017-06-28 12:54:14

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 0/9] client: Add GATT application support

From: Luiz Augusto von Dentz <[email protected]>

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



2017-06-30 08:34:27

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH BlueZ 2/9] client: Add register-service command

Hi Eramoto,

On Fri, Jun 30, 2017 at 8:50 AM, ERAMOTO Masaya
<[email protected]> 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 <[email protected]>
>>
>> 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

2017-06-30 07:30:16

by ERAMOTO Masaya

[permalink] [raw]
Subject: Re: [PATCH BlueZ 9/9] client: Add unregister-descriptor command

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 <[email protected]>
>
> 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

2017-06-30 07:28:20

by ERAMOTO Masaya

[permalink] [raw]
Subject: Re: [PATCH BlueZ 8/9] client: Add register-descriptor command

Hi Luiz,

On 2017年06月28日 21:54, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <[email protected]>
>
> 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

2017-06-30 06:46:54

by ERAMOTO Masaya

[permalink] [raw]
Subject: Re: [PATCH BlueZ 5/9] client: Add unregister-characteristic command

Hi Luiz,

On 2017年06月28日 21:54, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <[email protected]>
>
> 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" },
>

2017-06-30 06:13:45

by ERAMOTO Masaya

[permalink] [raw]
Subject: Re: [PATCH BlueZ 4/9] client: Add register-characteristic command

Hi Luiz,

On 2017年06月28日 21:54, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <[email protected]>
>
> 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

2017-06-30 05:52:37

by ERAMOTO Masaya

[permalink] [raw]
Subject: Re: [PATCH BlueZ 3/9] client: Add unregister-service command

Hi Luiz,

On 2017年06月28日 21:54, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <[email protected]>
>
> 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

2017-06-30 05:50:22

by ERAMOTO Masaya

[permalink] [raw]
Subject: Re: [PATCH BlueZ 2/9] client: Add register-service command

Hi Luiz,

On 2017年06月28日 21:54, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <[email protected]>
>
> 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

2017-06-28 12:54:23

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 9/9] client: Add unregister-descriptor command

From: Luiz Augusto von Dentz <[email protected]>

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


2017-06-28 12:54:22

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 8/9] client: Add register-descriptor command

From: Luiz Augusto von Dentz <[email protected]>

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


2017-06-28 12:54:21

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 7/9] client: Ask user the characteristic value

From: Luiz Augusto von Dentz <[email protected]>

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


2017-06-28 12:54:20

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 6/9] client: Add generic way to request input from user

From: Luiz Augusto von Dentz <[email protected]>

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


2017-06-28 12:54:19

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 5/9] client: Add unregister-characteristic command

From: Luiz Augusto von Dentz <[email protected]>

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


2017-06-28 12:54:18

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 4/9] client: Add register-characteristic command

From: Luiz Augusto von Dentz <[email protected]>

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


2017-06-28 12:54:17

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 3/9] client: Add unregister-service command

From: Luiz Augusto von Dentz <[email protected]>

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


2017-06-28 12:54:16

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 2/9] client: Add register-service command

From: Luiz Augusto von Dentz <[email protected]>

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


2017-06-28 12:54:15

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 1/9] client: Allow register-application without any UUID

From: Luiz Augusto von Dentz <[email protected]>

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