2017-08-15 01:22:42

by Yunhan Wang

[permalink] [raw]
Subject: [PATCH BlueZ] gdbus: add method to receive reply when property is updated

This add g_dbus_emit_property_changed_with_reply to receive reply when
property change is emitted.
If no reply is received in the given timeout_milliseconds or reply is
recieved, the notification function is called. If destroy function is
set, this function would be called after notification function completes.
---
gdbus/gdbus.h | 20 +++++++++++--
gdbus/object.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++----
src/gatt-client.c | 2 +-
3 files changed, 100 insertions(+), 9 deletions(-)

diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h
index e37385fa1..8099a9930 100644
--- a/gdbus/gdbus.h
+++ b/gdbus/gdbus.h
@@ -59,6 +59,8 @@ gboolean g_dbus_set_disconnect_function(DBusConnection *connection,
GDBusWatchFunction function,
void *user_data, DBusFreeFunction destroy);

+typedef void (* GDBusResultFunction) (const DBusError *error, void *user_data);
+
typedef void (* GDBusDestroyFunction) (void *user_data);

typedef DBusMessage * (* GDBusMethodFunction) (DBusConnection *connection,
@@ -314,10 +316,24 @@ void g_dbus_pending_property_error(GDBusPendingReply id, const char *name,
void g_dbus_emit_property_changed(DBusConnection *connection,
const char *path, const char *interface,
const char *name);
+
void g_dbus_emit_property_changed_full(DBusConnection *connection,
const char *path, const char *interface,
const char *name,
- GDbusPropertyChangedFlags flags);
+ GDbusPropertyChangedFlags flags,
+ GDBusResultFunction function,
+ void *user_data,
+ GDBusDestroyFunction destroy,
+ int timeout);
+
+void g_dbus_emit_property_changed_with_reply(DBusConnection *connection,
+ const char *path, const char *interface,
+ const char *name,
+ GDBusResultFunction function,
+ void *user_data,
+ GDBusDestroyFunction destroy,
+ int timeout);
+
gboolean g_dbus_get_properties(DBusConnection *connection, const char *path,
const char *interface, DBusMessageIter *iter);

@@ -341,8 +357,6 @@ gboolean g_dbus_proxy_get_property(GDBusProxy *proxy, const char *name,

gboolean g_dbus_proxy_refresh_property(GDBusProxy *proxy, const char *name);

-typedef void (* GDBusResultFunction) (const DBusError *error, void *user_data);
-
gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy,
const char *name, int type, const void *value,
GDBusResultFunction function, void *user_data,
diff --git a/gdbus/object.c b/gdbus/object.c
index afb458764..16d769c9b 100644
--- a/gdbus/object.c
+++ b/gdbus/object.c
@@ -59,6 +59,10 @@ struct generic_data {
gboolean pending_prop;
char *introspect;
struct generic_data *parent;
+ GDBusResultFunction function;
+ void *user_data;
+ GDBusDestroyFunction destroy;
+ int timeout;
};

struct interface_data {
@@ -84,6 +88,12 @@ struct property_data {
DBusMessage *message;
};

+struct process_property_data {
+ GDBusResultFunction function;
+ void *user_data;
+ GDBusDestroyFunction destroy;
+};
+
static int global_flags = 0;
static struct generic_data *root;
static GSList *pending = NULL;
@@ -1651,6 +1661,26 @@ fail:
return ret;
}

+static void process_property_reply(DBusPendingCall *call, void *user_data)
+{
+ struct process_property_data *data = user_data;
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ DBusError error;
+
+ dbus_error_init(&error);
+
+ dbus_set_error_from_message(&error, reply);
+
+ if (data->function)
+ data->function(&error, data->user_data);
+
+ if (data->destroy)
+ data->destroy(data->user_data);
+
+ dbus_error_free(&error);
+ dbus_message_unref(reply);
+}
+
static void process_properties_from_interface(struct generic_data *data,
struct interface_data *iface)
{
@@ -1658,7 +1688,7 @@ static void process_properties_from_interface(struct generic_data *data,
DBusMessage *signal;
DBusMessageIter iter, dict, array;
GSList *invalidated;
-
+ DBusPendingCall *call;
data->pending_prop = FALSE;

if (iface->pending_prop == NULL)
@@ -1713,8 +1743,35 @@ static void process_properties_from_interface(struct generic_data *data,
g_slist_free(iface->pending_prop);
iface->pending_prop = NULL;

- /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */
- dbus_connection_send(data->conn, signal, NULL);
+ if (data->function != NULL)
+ {
+ struct process_property_data *process_property_data;
+
+ process_property_data = g_try_new0(struct process_property_data, 1);
+ if (process_property_data == NULL)
+ return;
+
+ process_property_data->function = data->function;
+ process_property_data->user_data = data->user_data;
+ process_property_data->destroy = data->destroy;
+
+ /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */
+ if (g_dbus_send_message_with_reply(data->conn, signal,
+ &call, data->timeout) == FALSE) {
+ dbus_message_unref(signal);
+ g_free(process_property_data);
+ return;
+ }
+
+ dbus_pending_call_set_notify(call, process_property_reply, process_property_data, g_free);
+ dbus_pending_call_unref(call);
+ }
+ else
+ {
+ /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */
+ dbus_connection_send(data->conn, signal, NULL);
+ }
+
dbus_message_unref(signal);
}

@@ -1732,7 +1789,11 @@ static void process_property_changes(struct generic_data *data)
void g_dbus_emit_property_changed_full(DBusConnection *connection,
const char *path, const char *interface,
const char *name,
- GDbusPropertyChangedFlags flags)
+ GDbusPropertyChangedFlags flags,
+ GDBusResultFunction function,
+ void *user_data,
+ GDBusDestroyFunction destroy,
+ int timeout)
{
const GDBusPropertyTable *property;
struct generic_data *data;
@@ -1770,6 +1831,14 @@ void g_dbus_emit_property_changed_full(DBusConnection *connection,
iface->pending_prop = g_slist_prepend(iface->pending_prop,
(void *) property);

+ if (function != NULL)
+ {
+ data->function = function;
+ data->user_data = user_data;
+ data->destroy = destroy;
+ data->timeout = timeout;
+ }
+
if (flags & G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH)
process_property_changes(data);
else
@@ -1779,7 +1848,15 @@ void g_dbus_emit_property_changed_full(DBusConnection *connection,
void g_dbus_emit_property_changed(DBusConnection *connection, const char *path,
const char *interface, const char *name)
{
- g_dbus_emit_property_changed_full(connection, path, interface, name, 0);
+ g_dbus_emit_property_changed_full(connection, path, interface, name, 0, NULL, NULL, NULL, 0);
+}
+
+void g_dbus_emit_property_changed_with_reply(DBusConnection *connection, const char *path,
+ const char *interface, const char *name,
+ GDBusResultFunction function, void *user_data,
+ GDBusDestroyFunction destroy, int timeout)
+{
+ g_dbus_emit_property_changed_full(connection, path, interface, name, 0, function, user_data, destroy, timeout);
}

gboolean g_dbus_get_properties(DBusConnection *connection, const char *path,
diff --git a/src/gatt-client.c b/src/gatt-client.c
index 1cd7fbcf5..5fd94657c 100644
--- a/src/gatt-client.c
+++ b/src/gatt-client.c
@@ -878,7 +878,7 @@ static void write_characteristic_cb(struct gatt_db_attribute *attr, int err,

g_dbus_emit_property_changed_full(btd_get_dbus_connection(),
chrc->path, GATT_CHARACTERISTIC_IFACE,
- "Value", G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH);
+ "Value", G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH, NULL, NULL, NULL, 0);

}

--
2.14.0.434.g98096fd7a8-goog



2017-08-21 03:24:07

by Yunhan Wang

[permalink] [raw]
Subject: Re: [PATCH BlueZ] gdbus: add method to receive reply when property is updated

Hi, Luiz

I wanna setup a callback to check if GATT indication value happens in
peripheral side, but it seems g_dbus_client_set_proxy_handlers cannot
see property change for characteristic for peripheral role, for
example, indication value change. I am also trying to get proxy for
Gatt characteristics, but it seems it cannot be obtained in peripheral
side. Do you have any idea to do property change monitor for Gatt
Characteristic in peripheral side?

Thanks
Best wishes
Yunhan

On Thu, Aug 17, 2017 at 1:02 AM, Yunhan Wang <[email protected]> wrote:
> Hi, Luiz
>
> Yes, I am trying to add callback to monitor GATT indication value
> change, i think I can use g_dbus_client_set_proxy_handlers to monitor
> such property change, which is working.
>
> Thanks
> Best wishes
> Yunhan
>
> On Tue, Aug 15, 2017 at 2:32 AM, Luiz Augusto von Dentz
> <[email protected]> wrote:
>> Hi Yunhan,
>>
>> On Tue, Aug 15, 2017 at 4:22 AM, Yunhan Wang <[email protected]> wrote:
>>> This add g_dbus_emit_property_changed_with_reply to receive reply when
>>> property change is emitted.
>>> If no reply is received in the given timeout_milliseconds or reply is
>>> recieved, the notification function is called. If destroy function is
>>> set, this function would be called after notification function completes.
>>
>> Are you trying to implement what exactly, GATT indications?
>>
>>> ---
>>> gdbus/gdbus.h | 20 +++++++++++--
>>> gdbus/object.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++----
>>> src/gatt-client.c | 2 +-
>>> 3 files changed, 100 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h
>>> index e37385fa1..8099a9930 100644
>>> --- a/gdbus/gdbus.h
>>> +++ b/gdbus/gdbus.h
>>> @@ -59,6 +59,8 @@ gboolean g_dbus_set_disconnect_function(DBusConnection *connection,
>>> GDBusWatchFunction function,
>>> void *user_data, DBusFreeFunction destroy);
>>>
>>> +typedef void (* GDBusResultFunction) (const DBusError *error, void *user_data);
>>> +
>>> typedef void (* GDBusDestroyFunction) (void *user_data);
>>>
>>> typedef DBusMessage * (* GDBusMethodFunction) (DBusConnection *connection,
>>> @@ -314,10 +316,24 @@ void g_dbus_pending_property_error(GDBusPendingReply id, const char *name,
>>> void g_dbus_emit_property_changed(DBusConnection *connection,
>>> const char *path, const char *interface,
>>> const char *name);
>>> +
>>> void g_dbus_emit_property_changed_full(DBusConnection *connection,
>>> const char *path, const char *interface,
>>> const char *name,
>>> - GDbusPropertyChangedFlags flags);
>>> + GDbusPropertyChangedFlags flags,
>>> + GDBusResultFunction function,
>>> + void *user_data,
>>> + GDBusDestroyFunction destroy,
>>> + int timeout);
>>> +
>>> +void g_dbus_emit_property_changed_with_reply(DBusConnection *connection,
>>> + const char *path, const char *interface,
>>> + const char *name,
>>> + GDBusResultFunction function,
>>> + void *user_data,
>>> + GDBusDestroyFunction destroy,
>>> + int timeout);
>>> +
>>> gboolean g_dbus_get_properties(DBusConnection *connection, const char *path,
>>> const char *interface, DBusMessageIter *iter);
>>>
>>> @@ -341,8 +357,6 @@ gboolean g_dbus_proxy_get_property(GDBusProxy *proxy, const char *name,
>>>
>>> gboolean g_dbus_proxy_refresh_property(GDBusProxy *proxy, const char *name);
>>>
>>> -typedef void (* GDBusResultFunction) (const DBusError *error, void *user_data);
>>> -
>>> gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy,
>>> const char *name, int type, const void *value,
>>> GDBusResultFunction function, void *user_data,
>>> diff --git a/gdbus/object.c b/gdbus/object.c
>>> index afb458764..16d769c9b 100644
>>> --- a/gdbus/object.c
>>> +++ b/gdbus/object.c
>>> @@ -59,6 +59,10 @@ struct generic_data {
>>> gboolean pending_prop;
>>> char *introspect;
>>> struct generic_data *parent;
>>> + GDBusResultFunction function;
>>> + void *user_data;
>>> + GDBusDestroyFunction destroy;
>>> + int timeout;
>>> };
>>>
>>> struct interface_data {
>>> @@ -84,6 +88,12 @@ struct property_data {
>>> DBusMessage *message;
>>> };
>>>
>>> +struct process_property_data {
>>> + GDBusResultFunction function;
>>> + void *user_data;
>>> + GDBusDestroyFunction destroy;
>>> +};
>>> +
>>> static int global_flags = 0;
>>> static struct generic_data *root;
>>> static GSList *pending = NULL;
>>> @@ -1651,6 +1661,26 @@ fail:
>>> return ret;
>>> }
>>>
>>> +static void process_property_reply(DBusPendingCall *call, void *user_data)
>>> +{
>>> + struct process_property_data *data = user_data;
>>> + DBusMessage *reply = dbus_pending_call_steal_reply(call);
>>> + DBusError error;
>>> +
>>> + dbus_error_init(&error);
>>> +
>>> + dbus_set_error_from_message(&error, reply);
>>> +
>>> + if (data->function)
>>> + data->function(&error, data->user_data);
>>> +
>>> + if (data->destroy)
>>> + data->destroy(data->user_data);
>>> +
>>> + dbus_error_free(&error);
>>> + dbus_message_unref(reply);
>>> +}
>>> +
>>> static void process_properties_from_interface(struct generic_data *data,
>>> struct interface_data *iface)
>>> {
>>> @@ -1658,7 +1688,7 @@ static void process_properties_from_interface(struct generic_data *data,
>>> DBusMessage *signal;
>>> DBusMessageIter iter, dict, array;
>>> GSList *invalidated;
>>> -
>>> + DBusPendingCall *call;
>>> data->pending_prop = FALSE;
>>>
>>> if (iface->pending_prop == NULL)
>>> @@ -1713,8 +1743,35 @@ static void process_properties_from_interface(struct generic_data *data,
>>> g_slist_free(iface->pending_prop);
>>> iface->pending_prop = NULL;
>>>
>>> - /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */
>>> - dbus_connection_send(data->conn, signal, NULL);
>>> + if (data->function != NULL)
>>> + {
>>> + struct process_property_data *process_property_data;
>>> +
>>> + process_property_data = g_try_new0(struct process_property_data, 1);
>>> + if (process_property_data == NULL)
>>> + return;
>>> +
>>> + process_property_data->function = data->function;
>>> + process_property_data->user_data = data->user_data;
>>> + process_property_data->destroy = data->destroy;
>>> +
>>> + /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */
>>> + if (g_dbus_send_message_with_reply(data->conn, signal,
>>> + &call, data->timeout) == FALSE) {
>>
>> This shoudn't work as there is no reply to a signal:
>>
>> https://dbus.freedesktop.org/doc/dbus-tutorial.html#members
>>
>>> + dbus_message_unref(signal);
>>> + g_free(process_property_data);
>>> + return;
>>> + }
>>> +
>>> + dbus_pending_call_set_notify(call, process_property_reply, process_property_data, g_free);
>>> + dbus_pending_call_unref(call);
>>> + }
>>> + else
>>> + {
>>> + /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */
>>> + dbus_connection_send(data->conn, signal, NULL);
>>> + }
>>> +
>>> dbus_message_unref(signal);
>>> }
>>>
>>> @@ -1732,7 +1789,11 @@ static void process_property_changes(struct generic_data *data)
>>> void g_dbus_emit_property_changed_full(DBusConnection *connection,
>>> const char *path, const char *interface,
>>> const char *name,
>>> - GDbusPropertyChangedFlags flags)
>>> + GDbusPropertyChangedFlags flags,
>>> + GDBusResultFunction function,
>>> + void *user_data,
>>> + GDBusDestroyFunction destroy,
>>> + int timeout)
>>> {
>>> const GDBusPropertyTable *property;
>>> struct generic_data *data;
>>> @@ -1770,6 +1831,14 @@ void g_dbus_emit_property_changed_full(DBusConnection *connection,
>>> iface->pending_prop = g_slist_prepend(iface->pending_prop,
>>> (void *) property);
>>>
>>> + if (function != NULL)
>>> + {
>>> + data->function = function;
>>> + data->user_data = user_data;
>>> + data->destroy = destroy;
>>> + data->timeout = timeout;
>>> + }
>>> +
>>> if (flags & G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH)
>>> process_property_changes(data);
>>> else
>>> @@ -1779,7 +1848,15 @@ void g_dbus_emit_property_changed_full(DBusConnection *connection,
>>> void g_dbus_emit_property_changed(DBusConnection *connection, const char *path,
>>> const char *interface, const char *name)
>>> {
>>> - g_dbus_emit_property_changed_full(connection, path, interface, name, 0);
>>> + g_dbus_emit_property_changed_full(connection, path, interface, name, 0, NULL, NULL, NULL, 0);
>>> +}
>>> +
>>> +void g_dbus_emit_property_changed_with_reply(DBusConnection *connection, const char *path,
>>> + const char *interface, const char *name,
>>> + GDBusResultFunction function, void *user_data,
>>> + GDBusDestroyFunction destroy, int timeout)
>>> +{
>>> + g_dbus_emit_property_changed_full(connection, path, interface, name, 0, function, user_data, destroy, timeout);
>>> }
>>>
>>> gboolean g_dbus_get_properties(DBusConnection *connection, const char *path,
>>> diff --git a/src/gatt-client.c b/src/gatt-client.c
>>> index 1cd7fbcf5..5fd94657c 100644
>>> --- a/src/gatt-client.c
>>> +++ b/src/gatt-client.c
>>> @@ -878,7 +878,7 @@ static void write_characteristic_cb(struct gatt_db_attribute *attr, int err,
>>>
>>> g_dbus_emit_property_changed_full(btd_get_dbus_connection(),
>>> chrc->path, GATT_CHARACTERISTIC_IFACE,
>>> - "Value", G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH);
>>> + "Value", G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH, NULL, NULL, NULL, 0);
>>>
>>> }
>>>
>>> --
>>> 2.14.0.434.g98096fd7a8-goog
>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
>>> the body of a message to [email protected]
>>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>>
>>
>> --
>> Luiz Augusto von Dentz

2017-08-17 08:02:54

by Yunhan Wang

[permalink] [raw]
Subject: Re: [PATCH BlueZ] gdbus: add method to receive reply when property is updated

Hi, Luiz

Yes, I am trying to add callback to monitor GATT indication value
change, i think I can use g_dbus_client_set_proxy_handlers to monitor
such property change, which is working.

Thanks
Best wishes
Yunhan

On Tue, Aug 15, 2017 at 2:32 AM, Luiz Augusto von Dentz
<[email protected]> wrote:
> Hi Yunhan,
>
> On Tue, Aug 15, 2017 at 4:22 AM, Yunhan Wang <[email protected]> wrote:
>> This add g_dbus_emit_property_changed_with_reply to receive reply when
>> property change is emitted.
>> If no reply is received in the given timeout_milliseconds or reply is
>> recieved, the notification function is called. If destroy function is
>> set, this function would be called after notification function completes.
>
> Are you trying to implement what exactly, GATT indications?
>
>> ---
>> gdbus/gdbus.h | 20 +++++++++++--
>> gdbus/object.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++----
>> src/gatt-client.c | 2 +-
>> 3 files changed, 100 insertions(+), 9 deletions(-)
>>
>> diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h
>> index e37385fa1..8099a9930 100644
>> --- a/gdbus/gdbus.h
>> +++ b/gdbus/gdbus.h
>> @@ -59,6 +59,8 @@ gboolean g_dbus_set_disconnect_function(DBusConnection *connection,
>> GDBusWatchFunction function,
>> void *user_data, DBusFreeFunction destroy);
>>
>> +typedef void (* GDBusResultFunction) (const DBusError *error, void *user_data);
>> +
>> typedef void (* GDBusDestroyFunction) (void *user_data);
>>
>> typedef DBusMessage * (* GDBusMethodFunction) (DBusConnection *connection,
>> @@ -314,10 +316,24 @@ void g_dbus_pending_property_error(GDBusPendingReply id, const char *name,
>> void g_dbus_emit_property_changed(DBusConnection *connection,
>> const char *path, const char *interface,
>> const char *name);
>> +
>> void g_dbus_emit_property_changed_full(DBusConnection *connection,
>> const char *path, const char *interface,
>> const char *name,
>> - GDbusPropertyChangedFlags flags);
>> + GDbusPropertyChangedFlags flags,
>> + GDBusResultFunction function,
>> + void *user_data,
>> + GDBusDestroyFunction destroy,
>> + int timeout);
>> +
>> +void g_dbus_emit_property_changed_with_reply(DBusConnection *connection,
>> + const char *path, const char *interface,
>> + const char *name,
>> + GDBusResultFunction function,
>> + void *user_data,
>> + GDBusDestroyFunction destroy,
>> + int timeout);
>> +
>> gboolean g_dbus_get_properties(DBusConnection *connection, const char *path,
>> const char *interface, DBusMessageIter *iter);
>>
>> @@ -341,8 +357,6 @@ gboolean g_dbus_proxy_get_property(GDBusProxy *proxy, const char *name,
>>
>> gboolean g_dbus_proxy_refresh_property(GDBusProxy *proxy, const char *name);
>>
>> -typedef void (* GDBusResultFunction) (const DBusError *error, void *user_data);
>> -
>> gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy,
>> const char *name, int type, const void *value,
>> GDBusResultFunction function, void *user_data,
>> diff --git a/gdbus/object.c b/gdbus/object.c
>> index afb458764..16d769c9b 100644
>> --- a/gdbus/object.c
>> +++ b/gdbus/object.c
>> @@ -59,6 +59,10 @@ struct generic_data {
>> gboolean pending_prop;
>> char *introspect;
>> struct generic_data *parent;
>> + GDBusResultFunction function;
>> + void *user_data;
>> + GDBusDestroyFunction destroy;
>> + int timeout;
>> };
>>
>> struct interface_data {
>> @@ -84,6 +88,12 @@ struct property_data {
>> DBusMessage *message;
>> };
>>
>> +struct process_property_data {
>> + GDBusResultFunction function;
>> + void *user_data;
>> + GDBusDestroyFunction destroy;
>> +};
>> +
>> static int global_flags = 0;
>> static struct generic_data *root;
>> static GSList *pending = NULL;
>> @@ -1651,6 +1661,26 @@ fail:
>> return ret;
>> }
>>
>> +static void process_property_reply(DBusPendingCall *call, void *user_data)
>> +{
>> + struct process_property_data *data = user_data;
>> + DBusMessage *reply = dbus_pending_call_steal_reply(call);
>> + DBusError error;
>> +
>> + dbus_error_init(&error);
>> +
>> + dbus_set_error_from_message(&error, reply);
>> +
>> + if (data->function)
>> + data->function(&error, data->user_data);
>> +
>> + if (data->destroy)
>> + data->destroy(data->user_data);
>> +
>> + dbus_error_free(&error);
>> + dbus_message_unref(reply);
>> +}
>> +
>> static void process_properties_from_interface(struct generic_data *data,
>> struct interface_data *iface)
>> {
>> @@ -1658,7 +1688,7 @@ static void process_properties_from_interface(struct generic_data *data,
>> DBusMessage *signal;
>> DBusMessageIter iter, dict, array;
>> GSList *invalidated;
>> -
>> + DBusPendingCall *call;
>> data->pending_prop = FALSE;
>>
>> if (iface->pending_prop == NULL)
>> @@ -1713,8 +1743,35 @@ static void process_properties_from_interface(struct generic_data *data,
>> g_slist_free(iface->pending_prop);
>> iface->pending_prop = NULL;
>>
>> - /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */
>> - dbus_connection_send(data->conn, signal, NULL);
>> + if (data->function != NULL)
>> + {
>> + struct process_property_data *process_property_data;
>> +
>> + process_property_data = g_try_new0(struct process_property_data, 1);
>> + if (process_property_data == NULL)
>> + return;
>> +
>> + process_property_data->function = data->function;
>> + process_property_data->user_data = data->user_data;
>> + process_property_data->destroy = data->destroy;
>> +
>> + /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */
>> + if (g_dbus_send_message_with_reply(data->conn, signal,
>> + &call, data->timeout) == FALSE) {
>
> This shoudn't work as there is no reply to a signal:
>
> https://dbus.freedesktop.org/doc/dbus-tutorial.html#members
>
>> + dbus_message_unref(signal);
>> + g_free(process_property_data);
>> + return;
>> + }
>> +
>> + dbus_pending_call_set_notify(call, process_property_reply, process_property_data, g_free);
>> + dbus_pending_call_unref(call);
>> + }
>> + else
>> + {
>> + /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */
>> + dbus_connection_send(data->conn, signal, NULL);
>> + }
>> +
>> dbus_message_unref(signal);
>> }
>>
>> @@ -1732,7 +1789,11 @@ static void process_property_changes(struct generic_data *data)
>> void g_dbus_emit_property_changed_full(DBusConnection *connection,
>> const char *path, const char *interface,
>> const char *name,
>> - GDbusPropertyChangedFlags flags)
>> + GDbusPropertyChangedFlags flags,
>> + GDBusResultFunction function,
>> + void *user_data,
>> + GDBusDestroyFunction destroy,
>> + int timeout)
>> {
>> const GDBusPropertyTable *property;
>> struct generic_data *data;
>> @@ -1770,6 +1831,14 @@ void g_dbus_emit_property_changed_full(DBusConnection *connection,
>> iface->pending_prop = g_slist_prepend(iface->pending_prop,
>> (void *) property);
>>
>> + if (function != NULL)
>> + {
>> + data->function = function;
>> + data->user_data = user_data;
>> + data->destroy = destroy;
>> + data->timeout = timeout;
>> + }
>> +
>> if (flags & G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH)
>> process_property_changes(data);
>> else
>> @@ -1779,7 +1848,15 @@ void g_dbus_emit_property_changed_full(DBusConnection *connection,
>> void g_dbus_emit_property_changed(DBusConnection *connection, const char *path,
>> const char *interface, const char *name)
>> {
>> - g_dbus_emit_property_changed_full(connection, path, interface, name, 0);
>> + g_dbus_emit_property_changed_full(connection, path, interface, name, 0, NULL, NULL, NULL, 0);
>> +}
>> +
>> +void g_dbus_emit_property_changed_with_reply(DBusConnection *connection, const char *path,
>> + const char *interface, const char *name,
>> + GDBusResultFunction function, void *user_data,
>> + GDBusDestroyFunction destroy, int timeout)
>> +{
>> + g_dbus_emit_property_changed_full(connection, path, interface, name, 0, function, user_data, destroy, timeout);
>> }
>>
>> gboolean g_dbus_get_properties(DBusConnection *connection, const char *path,
>> diff --git a/src/gatt-client.c b/src/gatt-client.c
>> index 1cd7fbcf5..5fd94657c 100644
>> --- a/src/gatt-client.c
>> +++ b/src/gatt-client.c
>> @@ -878,7 +878,7 @@ static void write_characteristic_cb(struct gatt_db_attribute *attr, int err,
>>
>> g_dbus_emit_property_changed_full(btd_get_dbus_connection(),
>> chrc->path, GATT_CHARACTERISTIC_IFACE,
>> - "Value", G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH);
>> + "Value", G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH, NULL, NULL, NULL, 0);
>>
>> }
>>
>> --
>> 2.14.0.434.g98096fd7a8-goog
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
>> the body of a message to [email protected]
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
>
>
> --
> Luiz Augusto von Dentz

2017-08-15 09:32:33

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH BlueZ] gdbus: add method to receive reply when property is updated

Hi Yunhan,

On Tue, Aug 15, 2017 at 4:22 AM, Yunhan Wang <[email protected]> wrote:
> This add g_dbus_emit_property_changed_with_reply to receive reply when
> property change is emitted.
> If no reply is received in the given timeout_milliseconds or reply is
> recieved, the notification function is called. If destroy function is
> set, this function would be called after notification function completes.

Are you trying to implement what exactly, GATT indications?

> ---
> gdbus/gdbus.h | 20 +++++++++++--
> gdbus/object.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++----
> src/gatt-client.c | 2 +-
> 3 files changed, 100 insertions(+), 9 deletions(-)
>
> diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h
> index e37385fa1..8099a9930 100644
> --- a/gdbus/gdbus.h
> +++ b/gdbus/gdbus.h
> @@ -59,6 +59,8 @@ gboolean g_dbus_set_disconnect_function(DBusConnection *connection,
> GDBusWatchFunction function,
> void *user_data, DBusFreeFunction destroy);
>
> +typedef void (* GDBusResultFunction) (const DBusError *error, void *user_data);
> +
> typedef void (* GDBusDestroyFunction) (void *user_data);
>
> typedef DBusMessage * (* GDBusMethodFunction) (DBusConnection *connection,
> @@ -314,10 +316,24 @@ void g_dbus_pending_property_error(GDBusPendingReply id, const char *name,
> void g_dbus_emit_property_changed(DBusConnection *connection,
> const char *path, const char *interface,
> const char *name);
> +
> void g_dbus_emit_property_changed_full(DBusConnection *connection,
> const char *path, const char *interface,
> const char *name,
> - GDbusPropertyChangedFlags flags);
> + GDbusPropertyChangedFlags flags,
> + GDBusResultFunction function,
> + void *user_data,
> + GDBusDestroyFunction destroy,
> + int timeout);
> +
> +void g_dbus_emit_property_changed_with_reply(DBusConnection *connection,
> + const char *path, const char *interface,
> + const char *name,
> + GDBusResultFunction function,
> + void *user_data,
> + GDBusDestroyFunction destroy,
> + int timeout);
> +
> gboolean g_dbus_get_properties(DBusConnection *connection, const char *path,
> const char *interface, DBusMessageIter *iter);
>
> @@ -341,8 +357,6 @@ gboolean g_dbus_proxy_get_property(GDBusProxy *proxy, const char *name,
>
> gboolean g_dbus_proxy_refresh_property(GDBusProxy *proxy, const char *name);
>
> -typedef void (* GDBusResultFunction) (const DBusError *error, void *user_data);
> -
> gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy,
> const char *name, int type, const void *value,
> GDBusResultFunction function, void *user_data,
> diff --git a/gdbus/object.c b/gdbus/object.c
> index afb458764..16d769c9b 100644
> --- a/gdbus/object.c
> +++ b/gdbus/object.c
> @@ -59,6 +59,10 @@ struct generic_data {
> gboolean pending_prop;
> char *introspect;
> struct generic_data *parent;
> + GDBusResultFunction function;
> + void *user_data;
> + GDBusDestroyFunction destroy;
> + int timeout;
> };
>
> struct interface_data {
> @@ -84,6 +88,12 @@ struct property_data {
> DBusMessage *message;
> };
>
> +struct process_property_data {
> + GDBusResultFunction function;
> + void *user_data;
> + GDBusDestroyFunction destroy;
> +};
> +
> static int global_flags = 0;
> static struct generic_data *root;
> static GSList *pending = NULL;
> @@ -1651,6 +1661,26 @@ fail:
> return ret;
> }
>
> +static void process_property_reply(DBusPendingCall *call, void *user_data)
> +{
> + struct process_property_data *data = user_data;
> + DBusMessage *reply = dbus_pending_call_steal_reply(call);
> + DBusError error;
> +
> + dbus_error_init(&error);
> +
> + dbus_set_error_from_message(&error, reply);
> +
> + if (data->function)
> + data->function(&error, data->user_data);
> +
> + if (data->destroy)
> + data->destroy(data->user_data);
> +
> + dbus_error_free(&error);
> + dbus_message_unref(reply);
> +}
> +
> static void process_properties_from_interface(struct generic_data *data,
> struct interface_data *iface)
> {
> @@ -1658,7 +1688,7 @@ static void process_properties_from_interface(struct generic_data *data,
> DBusMessage *signal;
> DBusMessageIter iter, dict, array;
> GSList *invalidated;
> -
> + DBusPendingCall *call;
> data->pending_prop = FALSE;
>
> if (iface->pending_prop == NULL)
> @@ -1713,8 +1743,35 @@ static void process_properties_from_interface(struct generic_data *data,
> g_slist_free(iface->pending_prop);
> iface->pending_prop = NULL;
>
> - /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */
> - dbus_connection_send(data->conn, signal, NULL);
> + if (data->function != NULL)
> + {
> + struct process_property_data *process_property_data;
> +
> + process_property_data = g_try_new0(struct process_property_data, 1);
> + if (process_property_data == NULL)
> + return;
> +
> + process_property_data->function = data->function;
> + process_property_data->user_data = data->user_data;
> + process_property_data->destroy = data->destroy;
> +
> + /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */
> + if (g_dbus_send_message_with_reply(data->conn, signal,
> + &call, data->timeout) == FALSE) {

This shoudn't work as there is no reply to a signal:

https://dbus.freedesktop.org/doc/dbus-tutorial.html#members

> + dbus_message_unref(signal);
> + g_free(process_property_data);
> + return;
> + }
> +
> + dbus_pending_call_set_notify(call, process_property_reply, process_property_data, g_free);
> + dbus_pending_call_unref(call);
> + }
> + else
> + {
> + /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */
> + dbus_connection_send(data->conn, signal, NULL);
> + }
> +
> dbus_message_unref(signal);
> }
>
> @@ -1732,7 +1789,11 @@ static void process_property_changes(struct generic_data *data)
> void g_dbus_emit_property_changed_full(DBusConnection *connection,
> const char *path, const char *interface,
> const char *name,
> - GDbusPropertyChangedFlags flags)
> + GDbusPropertyChangedFlags flags,
> + GDBusResultFunction function,
> + void *user_data,
> + GDBusDestroyFunction destroy,
> + int timeout)
> {
> const GDBusPropertyTable *property;
> struct generic_data *data;
> @@ -1770,6 +1831,14 @@ void g_dbus_emit_property_changed_full(DBusConnection *connection,
> iface->pending_prop = g_slist_prepend(iface->pending_prop,
> (void *) property);
>
> + if (function != NULL)
> + {
> + data->function = function;
> + data->user_data = user_data;
> + data->destroy = destroy;
> + data->timeout = timeout;
> + }
> +
> if (flags & G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH)
> process_property_changes(data);
> else
> @@ -1779,7 +1848,15 @@ void g_dbus_emit_property_changed_full(DBusConnection *connection,
> void g_dbus_emit_property_changed(DBusConnection *connection, const char *path,
> const char *interface, const char *name)
> {
> - g_dbus_emit_property_changed_full(connection, path, interface, name, 0);
> + g_dbus_emit_property_changed_full(connection, path, interface, name, 0, NULL, NULL, NULL, 0);
> +}
> +
> +void g_dbus_emit_property_changed_with_reply(DBusConnection *connection, const char *path,
> + const char *interface, const char *name,
> + GDBusResultFunction function, void *user_data,
> + GDBusDestroyFunction destroy, int timeout)
> +{
> + g_dbus_emit_property_changed_full(connection, path, interface, name, 0, function, user_data, destroy, timeout);
> }
>
> gboolean g_dbus_get_properties(DBusConnection *connection, const char *path,
> diff --git a/src/gatt-client.c b/src/gatt-client.c
> index 1cd7fbcf5..5fd94657c 100644
> --- a/src/gatt-client.c
> +++ b/src/gatt-client.c
> @@ -878,7 +878,7 @@ static void write_characteristic_cb(struct gatt_db_attribute *attr, int err,
>
> g_dbus_emit_property_changed_full(btd_get_dbus_connection(),
> chrc->path, GATT_CHARACTERISTIC_IFACE,
> - "Value", G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH);
> + "Value", G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH, NULL, NULL, NULL, 0);
>
> }
>
> --
> 2.14.0.434.g98096fd7a8-goog
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html



--
Luiz Augusto von Dentz