diff --git a/src/gatt-client.c b/src/gatt-client.c
index 462753c..c8ef584 100644
--- a/src/gatt-client.c
+++ b/src/gatt-client.c
#include <stdbool.h>
#include <stdint.h>
+#include <dbus/dbus.h>
+#include <gdbus/gdbus.h>
+
#include <bluetooth/bluetooth.h>
#include "log.h"
#include "src/shared/gatt-client.h"
#include "src/shared/util.h"
#include "gatt-client.h"
+#include "dbus-common.h"
+
+#define GATT_SERVICE_IFACE "org.bluez.GattService1"
struct btd_gatt_client {
struct btd_device *device;
struct queue *services;
};
+struct service {
+ struct btd_gatt_client *client;
+ bool primary;
+ uint16_t start_handle;
+ uint16_t end_handle;
+ bt_uuid_t uuid;
+ char *path;
+};
+
+static gboolean service_get_uuid(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ char uuid[MAX_LEN_UUID_STR + 1];
+ const char *ptr = uuid;
+ struct service *service = data;
+
+ bt_uuid_to_string(&service->uuid, uuid, sizeof(uuid));
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &ptr);
+
+ return TRUE;
+}
+
+static gboolean service_get_device(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct service *service = data;
+ const char *str = device_get_path(service->client->device);
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &str);
+
+ 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 gboolean service_get_characteristics(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ DBusMessageIter array;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "o", &array);
+
+ /* TODO: Implement this once characteristics are exported */
+
+ dbus_message_iter_close_container(iter, &array);
+
+ return TRUE;
+}
+
+static const GDBusPropertyTable service_properties[] = {
+ { "UUID", "s", service_get_uuid, NULL, NULL,
+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+ { "Device", "o", service_get_device, NULL, NULL,
+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+ { "Primary", "b", service_get_primary, NULL, NULL,
+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+ { "Characteristics", "ao", service_get_characteristics, NULL, NULL,
+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+ { }
+};
+
static void service_free(void *data)
{
- /* TODO */
+ struct service *service = data;
+
+ g_free(service->path);
+ free(service);
+}
+
+static struct service *service_create(struct gatt_db_attribute *attr,
+ struct btd_gatt_client *client)
+{
+ struct service *service;
+ const char *device_path = device_get_path(client->device);
+ bt_uuid_t uuid;
+
+ service = new0(struct service, 1);
+ if (!service)
+ return NULL;
+
+ service->client = client;
+
+ gatt_db_attribute_get_service_data(attr, &service->start_handle,
+ &service->end_handle,
+ &service->primary,
+ &uuid);
+ bt_uuid_to_uuid128(&uuid, &service->uuid);
+
+ service->path = g_strdup_printf("%s/service%04x", device_path,
+ service->start_handle);
+
+ if (!g_dbus_register_interface(btd_get_dbus_connection(), service->path,
+ GATT_SERVICE_IFACE,
+ NULL, NULL,
+ service_properties,
+ service, service_free)) {
+ error("Unable to register GATT service with handle 0x%04x for "
+ "device %s:",
+ service->start_handle,
+ client->devaddr);
+ service_free(service);
+
+ return NULL;
+ }
+
+ DBG("Exported GATT service: %s", service->path);
+
+ return service;
+}
+
+static void unregister_service(void *data)
+{
+ struct service *service = data;
+
+ DBG("Removing GATT service: %s", service->path);
+
+ g_dbus_unregister_interface(btd_get_dbus_connection(), service->path,
+ GATT_SERVICE_IFACE);
+}
+
+static void export_service(struct gatt_db_attribute *attr, void *user_data)
+{
+ struct btd_gatt_client *client = user_data;
+ struct service *service;
+
+ service = service_create(attr, client);
+ if (!service)
+ return;
+
+ queue_push_tail(client->services, service);
}
static void create_services(struct btd_gatt_client *client)
{
DBG("Exporting objects for GATT services: %s", client->devaddr);
- /* TODO */
+ gatt_db_foreach_service(client->db, NULL, export_service, client);
}
struct btd_gatt_client *btd_gatt_client_new(struct btd_device *device)
if (!client)
return;
- queue_destroy(client->services, service_free);
+ queue_destroy(client->services, unregister_service);
bt_gatt_client_unref(client->gatt);
gatt_db_unref(client->db);
free(client);
DBG("Device disconnected. Cleaning up");
+ /*
+ * Remove all services. We'll recreate them when a new bt_gatt_client
+ * becomes ready.
+ */
+ queue_remove_all(client->services, NULL, NULL, unregister_service);
+
bt_gatt_client_unref(client->gatt);
client->gatt = NULL;
}