Hi Bernie, On Tue, Aug 17, 2021 at 10:30 AM Bernie Conrad <bernie@xxxxxxxxxxxxxxxxx> wrote: > > Implementation of the method and modification of the dbus method table. > > --- > src/gatt-database.c | 93 +++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 93 insertions(+) > > diff --git a/src/gatt-database.c b/src/gatt-database.c > index 99c95f2d6..7e6b70a80 100644 > --- a/src/gatt-database.c > +++ b/src/gatt-database.c > @@ -3615,6 +3615,93 @@ static DBusMessage *manager_unregister_app(DBusConnection *conn, > return dbus_message_new_method_return(msg); > } > > +static DBusMessage *notify_characteristic_changed(DBusConnection *conn, > + DBusMessage *msg, void *user_data) > +{ > + struct btd_gatt_database *database = user_data; > + uint8_t *value = NULL; > + int value_len = 0; > + DBusMessageIter args; > + DBusMessageIter array; > + const char *characteristic_path; > + const char *client_path; > + const char *application_path; > + struct svc_match_data match_data; > + const char *sender = dbus_message_get_sender(msg); > + struct gatt_app *app; > + struct external_service *service; > + struct external_chrc *chrc; > + struct notify notify; > + struct device_state *client_state; > + struct btd_device *client_device; > + > + if (!dbus_message_iter_init(msg, &args)) > + return btd_error_invalid_args(msg); > + > + if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) > + return btd_error_invalid_args(msg); > + dbus_message_iter_get_basic(&args, &application_path); > + > + dbus_message_iter_next(&args); > + if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) > + return btd_error_invalid_args(msg); > + dbus_message_iter_get_basic(&args, &client_path); > + > + dbus_message_iter_next(&args); > + if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) > + return btd_error_invalid_args(msg); > + dbus_message_iter_get_basic(&args, &characteristic_path); > + > + dbus_message_iter_next(&args); > + if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY) > + return btd_error_invalid_args(msg); > + > + > + dbus_message_iter_recurse(&args, &array); > + dbus_message_iter_get_fixed_array(&array, &value, &value_len); > + > + match_data.path = application_path; > + match_data.sender = sender; > + app = queue_find(database->apps, match_app, &match_data); > + if (!app) > + return btd_error_does_not_exist(msg); > + > + > + service = queue_find(app->services, match_service_by_chrc, > + characteristic_path); > + if (!service) > + return btd_error_does_not_exist(msg); > + > + > + chrc = queue_find(service->chrcs, match_chrc, characteristic_path); > + if (!chrc) > + return btd_error_agent_not_available(msg); > + > + > + client_device = btd_adapter_find_device_by_path(database->adapter, > + client_path); > + if (!client_device) > + return btd_error_does_not_exist(msg); > + > + client_state = find_device_state(database, > + device_get_address(client_device), > + btd_device_get_bdaddr_type(client_device)); > + if (!client_state) > + return btd_error_does_not_exist(msg); > + > + > + notify.handle = gatt_db_attribute_get_handle(chrc->attrib); > + notify.ccc_handle = gatt_db_attribute_get_handle(chrc->ccc); > + notify.database = database; > + notify.value = value; > + notify.len = value_len; > + notify.conf = conf_cb; > + > + send_notification_to_device(client_state, ¬ify); > + DBG("Notification/Indication sent to %s.", client_path); > + return dbus_message_new_method_return(msg); > +} > + > static const GDBusMethodTable manager_methods[] = { > { GDBUS_ASYNC_METHOD("RegisterApplication", > GDBUS_ARGS({ "application", "o" }, > @@ -3623,6 +3710,12 @@ static const GDBusMethodTable manager_methods[] = { > { GDBUS_ASYNC_METHOD("UnregisterApplication", > GDBUS_ARGS({ "application", "o" }), > NULL, manager_unregister_app) }, > + { GDBUS_ASYNC_METHOD("NotifyCharacteristicChanged", > + GDBUS_ARGS({"application", "o" }, > + { "device", "o" }, > + { "characteristic_path", "o"}, > + { "value", "ay"}), > + NULL, notify_characteristic_changed) }, I don't think this will gonna fly, we should actually emit for the server object and not directly to the device so I rather have a different property e.g. object, array{byte} DeviceValue, that said this is a bit of a layer violation since the GATT layer should be in controller of things like device address, etc, in fact it doesn't know which devices are subscribed to its CCC. In zephyr the way we handled this was to push this to the application by having it handling the CCC attribute, that said I think that can create non-compliant implementation of CCC so Im not sure if we should do that either, anyway we could block the DeviceValue notification if the device set is not in fact subscribed. > { } > }; > > -- > 2.17.1 > -- Luiz Augusto von Dentz