Hello maintainers, This patch adds a method to be called over DBus to be able to send a notification or indication to only one device rather than all connected devices as a peripheral. This is motivated by similar functionality in the corebluetooth API with CBPeripheralManager's updateValue() method as well as the Android API's notifyCharacteristicChanged() method. I implemented the method in the gatt database file as that was where the send_notification_to_devices method was implemented which has similar functionality. The params for the method were picked to be able to get the data needed to populate the notify struct and fetch the device state from the gatt database in order to call send_notification_to_device. --- src/gatt-database.c | 97 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/src/gatt-database.c b/src/gatt-database.c index 99c95f2d6..08609d3a4 100644 --- a/src/gatt-database.c +++ b/src/gatt-database.c @@ -3615,6 +3615,97 @@ 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; + DBusMessage *reply; + bdaddr_t device_bdaddr; + 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 +3714,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) }, { } }; -- 2.17.1