Manage device state during its life cycle

latest-fixes
Olivier Martin 2024-04-03 17:36:17 +02:00
parent 0c1334c5b4
commit 709b76019e
2 changed files with 56 additions and 48 deletions

View File

@ -40,6 +40,8 @@ static void _on_device_connect(gatt_connection_t* connection) {
}
conn_context->dbus_objects = g_dbus_object_manager_get_objects(device_manager);
gattlib_device_set_state(conn_context->adapter, connection->device_id, CONNECTED);
gattlib_on_connected_device(connection);
}
@ -183,6 +185,16 @@ int gattlib_connect(void *adapter, const char *dst,
get_device_path_from_mac(adapter_name, dst, object_path, sizeof(object_path));
gatt_connection_t* connection = gattlib_device_get_device(adapter, object_path);
if (connection == NULL) {
GATTLIB_LOG(GATTLIB_DEBUG, "gattlib_connect: Cannot find connection %s", dst);
return GATTLIB_INVALID_PARAMETER;
} else if (connection->state != DISCONNECTED) {
GATTLIB_LOG(GATTLIB_DEBUG, "gattlib_connect: Cannot connect to '%s'. Device is in state %s",
dst, device_state_str[connection->state]);
return GATTLIB_BUSY;
}
gattlib_context_t* conn_context = calloc(sizeof(gattlib_context_t), 1);
if (conn_context == NULL) {
GATTLIB_LOG(GATTLIB_DEBUG, "gattlib_connect: Cannot allocate context");
@ -190,18 +202,14 @@ int gattlib_connect(void *adapter, const char *dst,
}
conn_context->adapter = gattlib_adapter;
gatt_connection_t* connection = calloc(sizeof(gatt_connection_t), 1);
if (connection == NULL) {
GATTLIB_LOG(GATTLIB_DEBUG, "gattlib_connect: Cannot allocate connection");
ret = GATTLIB_OUT_OF_MEMORY;
goto FREE_CONN_CONTEXT;
}
connection->context = conn_context;
connection->on_connection.callback.connection_handler = connect_cb;
connection->on_connection.user_data = user_data;
GATTLIB_LOG(GATTLIB_DEBUG, "Connect bluetooth device %s", dst);
GATTLIB_LOG(GATTLIB_DEBUG, "Connecting bluetooth device %s", dst);
// Mark the device has disconnected
gattlib_device_set_state(connection->adapter, connection->device_id, CONNECTING);
OrgBluezDevice1* device = org_bluez_device1_proxy_new_for_bus_sync(
G_BUS_TYPE_SYSTEM,
@ -219,7 +227,7 @@ int gattlib_connect(void *adapter, const char *dst,
} else {
GATTLIB_LOG(GATTLIB_ERROR, "gattlib_connect: Failed to connect to DBus Bluez Device");
}
goto FREE_CONNECTION;
goto FREE_CONNECTION_CONTEXT;
} else {
conn_context->device = device;
conn_context->device_object_path = strdup(object_path);
@ -263,10 +271,7 @@ FREE_DEVICE:
free(conn_context->device_object_path);
g_object_unref(conn_context->device);
FREE_CONNECTION:
free(connection);
FREE_CONN_CONTEXT:
FREE_CONNECTION_CONTEXT:
free(conn_context);
// destroy default adapter
@ -289,9 +294,13 @@ FREE_CONN_CONTEXT:
*/
void gattlib_connection_free(gatt_connection_t* connection) {
gattlib_context_t* conn_context;
void* adapter;
char* device_id;
g_mutex_lock(&connection->device_mutex);
conn_context = connection->context;
adapter = conn_context->adapter;
device_id = connection->device_id;
// Remove signal
if (conn_context->on_handle_device_property_change_id != 0) {
@ -326,10 +335,10 @@ void gattlib_connection_free(gatt_connection_t* connection) {
free(connection->context);
connection->context = NULL;
g_mutex_unlock(&connection->device_mutex);
// Mark the device has disconnected
gattlib_device_set_state(adapter, device_id, DISCONNECTED);
// And finally free the connection
free(connection);
g_mutex_unlock(&connection->device_mutex);
}
int gattlib_disconnect(gatt_connection_t* connection, bool wait_disconnection) {
@ -349,9 +358,14 @@ int gattlib_disconnect(gatt_connection_t* connection, bool wait_disconnection) {
GATTLIB_LOG(GATTLIB_ERROR, "Cannot disconnect - connection context is not valid.");
ret = GATTLIB_NOT_SUPPORTED;
goto EXIT;
} else if (connection->state != CONNECTED) {
GATTLIB_LOG(GATTLIB_ERROR, "Cannot disconnect - connection is not in connected state (state=%s).",
device_state_str[connection->state]);
ret = GATTLIB_BUSY;
goto EXIT;
}
GATTLIB_LOG(GATTLIB_DEBUG, "Disconnect bluetooth device %s", conn_context->device_object_path);
GATTLIB_LOG(GATTLIB_DEBUG, "Disconnecting bluetooth device %s", conn_context->device_object_path);
org_bluez_device1_call_disconnect_sync(conn_context->device, NULL, &error);
if (error) {
@ -359,6 +373,9 @@ int gattlib_disconnect(gatt_connection_t* connection, bool wait_disconnection) {
g_error_free(error);
}
// Mark the device has disconnected
gattlib_device_set_state(connection->adapter, connection->device_id, DISCONNECTING);
//Note: Signals and memory will be removed/clean on disconnction callback
// See _gattlib_clean_on_disconnection()

View File

@ -143,12 +143,9 @@ static void device_manager_on_added_device1_signal(const char* device1_path, str
//TODO: Add support for connected device with 'gboolean org_bluez_device1_get_connected (OrgBluezDevice1 *object);'
// When the device is connected, we potentially need to initialize some attributes
ret = gattlib_device_set_state(gattlib_adapter, address, DISCONNECTED);
ret = gattlib_device_set_state(gattlib_adapter, device1_path, DISCONNECTED);
if (ret == GATTLIB_SUCCESS) {
if (gattlib_adapter->ble_scan.enabled_filters & GATTLIB_DISCOVER_FILTER_NOTIFY_CHANGE) {
gattlib_on_discovered_device(gattlib_adapter, device1);
}
gattlib_on_discovered_device(gattlib_adapter, device1);
}
g_rec_mutex_unlock(&gattlib_adapter->mutex);
@ -226,40 +223,28 @@ on_interface_proxy_properties_changed (GDBusObjectManagerClient *device_manager,
return;
}
const char* device_mac_address = org_bluez_device1_get_address(device1);
// Check if the device has been disconnected
GVariantDict dict;
g_variant_dict_init(&dict, changed_properties);
GVariant* connected = g_variant_dict_lookup_value(&dict, "Connected", NULL);
GVariant* rssi = g_variant_dict_lookup_value(&dict, "RSSI", NULL);
GVariant* has_rssi = g_variant_dict_lookup_value(&dict, "RSSI", NULL);
GVariant* has_manufacturer_data = g_variant_dict_lookup_value(&dict, "ManufacturerData", NULL);
g_mutex_lock(&gattlib_adapter->ble_scan.discovered_devices_mutex);
g_rec_mutex_lock(&gattlib_adapter->mutex);
// Check if the device is already part of the list
GSList *found_device = g_slist_find_custom(gattlib_adapter->ble_scan.discovered_devices, device_mac_address, (GCompareFunc)g_ascii_strcasecmp);
enum _gattlib_device_state old_device_state = gattlib_device_get_state(gattlib_adapter, proxy_object_path);
if (connected && !g_variant_get_boolean(connected)) {
// The device has been disconnected. We will remove it from the list of discovered device.
// In case the device has been found again, it will be seen as a new device
GATTLIB_LOG(GATTLIB_INFO, "Device %s has been disconnected", device_mac_address);
if (found_device) {
gattlib_adapter->ble_scan.discovered_devices = g_slist_remove(gattlib_adapter->ble_scan.discovered_devices, found_device);
}
} else if (rssi) {
// First time this device is in the list
if (found_device == NULL) {
// Add the device to the list
gattlib_adapter->ble_scan.discovered_devices = g_slist_append(gattlib_adapter->ble_scan.discovered_devices, g_strdup(device_mac_address));
gattlib_on_discovered_device(gattlib_adapter, device1);
if (old_device_state == NOT_FOUND) {
if (has_rssi || has_manufacturer_data) {
int ret = gattlib_device_set_state(gattlib_adapter, proxy_object_path, DISCONNECTED);
if (ret == GATTLIB_SUCCESS) {
gattlib_on_discovered_device(gattlib_adapter, device1);
}
}
}
g_mutex_unlock(&gattlib_adapter->ble_scan.discovered_devices_mutex);
g_rec_mutex_unlock(&gattlib_adapter->mutex);
g_variant_dict_end(&dict);
g_object_unref(device1);
}
}
@ -549,9 +534,15 @@ EXIT:
return GATTLIB_SUCCESS;
}
int gattlib_adapter_close(void* adapter)
{
int gattlib_adapter_close(void* adapter) {
struct gattlib_adapter *gattlib_adapter = adapter;
bool are_devices_disconnected;
are_devices_disconnected = gattlib_devices_are_disconnected(adapter);
if (!are_devices_disconnected) {
GATTLIB_LOG(GATTLIB_ERROR, "Adapter cannot be closed as some devices are not disconnected");
return GATTLIB_BUSY;
}
g_mutex_lock(&m_adapter_list_mutex);
GSList *adapter_entry = g_slist_find(m_adapter_list, adapter);