diff --git a/dbus/gattlib.c b/dbus/gattlib.c index 79f7dc9..35a6fbc 100644 --- a/dbus/gattlib.c +++ b/dbus/gattlib.c @@ -220,7 +220,8 @@ gboolean on_handle_device_property_change( const gchar *const *arg_invalidated_properties, gpointer user_data) { - GMainLoop *loop = user_data; + gatt_connection_t* connection = user_data; + gattlib_context_t* conn_context = connection->context; // Retrieve 'Value' from 'arg_changed_properties' if (g_variant_n_children (arg_changed_properties) > 0) { @@ -231,8 +232,16 @@ gboolean on_handle_device_property_change( g_variant_get (arg_changed_properties, "a{sv}", &iter); while (g_variant_iter_loop (iter, "{&sv}", &key, &value)) { if (strcmp(key, "UUIDs") == 0) { - g_main_loop_quit(loop); + // When UUIDs properties appear, we are connected to the device + g_main_loop_quit(conn_context->connection_loop); break; + } else if (strcmp(key, "Connected") == 0) { + if (!g_variant_get_boolean(value)) { + // Disconnection case + if (connection->disconnection_handler) { + connection->disconnection_handler(connection->disconnection_user_data); + } + } } } } @@ -316,17 +325,19 @@ gatt_connection_t *gattlib_connect(const char *src, const char *dst, // Wait for the property 'UUIDs' to be changed. We assume 'org.bluez.GattService1 // and 'org.bluez.GattCharacteristic1' to be advertised at that moment. - GMainLoop *loop = g_main_loop_new(NULL, 0); + conn_context->connection_loop = g_main_loop_new(NULL, 0); // Register a handle for notification g_signal_connect(device, "g-properties-changed", G_CALLBACK (on_handle_device_property_change), - loop); + connection); - g_timeout_add_seconds (CONNECT_TIMEOUT, stop_scan_func, loop); - g_main_loop_run(loop); - g_main_loop_unref(loop); + g_timeout_add_seconds (CONNECT_TIMEOUT, stop_scan_func, conn_context->connection_loop); + g_main_loop_run(conn_context->connection_loop); + g_main_loop_unref(conn_context->connection_loop); + // Set the attribute to NULL even if not required + conn_context->connection_loop = NULL; return connection; @@ -364,6 +375,11 @@ int gattlib_disconnect(gatt_connection_t* connection) { return 0; } +void gattlib_register_on_disconnect(gatt_connection_t *connection, gattlib_disconnection_handler_t handler, void* user_data) { + connection->disconnection_handler = handler; + connection->disconnection_user_data = user_data; +} + // Bluez was using org.bluez.Device1.GattServices until 5.37 to expose the list of available GATT Services #if BLUEZ_VERSION < BLUEZ_VERSIONS(5, 38) int gattlib_discover_primary(gatt_connection_t* connection, gattlib_primary_service_t** services, int* services_count) { diff --git a/dbus/gattlib_internal.h b/dbus/gattlib_internal.h index b808031..bd22977 100644 --- a/dbus/gattlib_internal.h +++ b/dbus/gattlib_internal.h @@ -41,6 +41,10 @@ typedef struct { char* device_object_path; OrgBluezDevice1* device; + + // This attribute is only used during the connection stage. By placing the attribute here, we can pass + // `gatt_connection_t` to + GMainLoop *connection_loop; } gattlib_context_t; #endif diff --git a/include/gattlib.h b/include/gattlib.h index 075c833..fdb9478 100644 --- a/include/gattlib.h +++ b/include/gattlib.h @@ -69,6 +69,14 @@ typedef struct _GAttrib GAttrib; typedef void (*gattlib_event_handler_t)(const uuid_t* uuid, const uint8_t* data, size_t data_length, void* user_data); +/** + * @brief Handler called on disconnection + * + * @param connection Connection that is disconnecting + * @param user_data Data defined when calling `gattlib_register_on_disconnect()` + */ +typedef void (*gattlib_disconnection_handler_t)(void* user_data); + typedef struct _gatt_connection_t { void* context; @@ -77,17 +85,19 @@ typedef struct _gatt_connection_t { gattlib_event_handler_t indication_handler; void* indication_user_data; + + gattlib_disconnection_handler_t disconnection_handler; + void* disconnection_user_data; } gatt_connection_t; typedef void (*gattlib_discovered_device_t)(const char* addr, const char* name); typedef void (*gatt_connect_cb_t)(gatt_connection_t* connection, void* user_data); typedef void* (*gatt_read_cb_t)(const void* buffer, size_t buffer_len); - /** - * Open Bluetooth adapter + * @brief Open Bluetooth adapter * - * @adapter_name With value NULL, the default adapter will be selected. + * @param adapter_name With value NULL, the default adapter will be selected. */ int gattlib_adapter_open(const char* adapter_name, void** adapter); int gattlib_adapter_scan_enable(void* adapter, gattlib_discovered_device_t discovered_device_cb, int timeout); @@ -111,6 +121,8 @@ gatt_connection_t *gattlib_connect_async(const char *src, const char *dst, int gattlib_disconnect(gatt_connection_t* connection); +void gattlib_register_on_disconnect(gatt_connection_t *connection, gattlib_disconnection_handler_t handler, void* user_data); + typedef struct { uint16_t attr_handle_start; uint16_t attr_handle_end;