2017-03-14 13:38:45 +01:00
|
|
|
/*
|
2021-09-01 10:42:20 +02:00
|
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
2017-03-14 13:38:45 +01:00
|
|
|
*
|
2024-02-12 13:29:40 +01:00
|
|
|
* Copyright (c) 2016-2024, Olivier Martin <olivier@labapart.org>
|
2017-03-14 13:38:45 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <glib.h>
|
|
|
|
#include <stdbool.h>
|
2019-06-03 12:03:56 +02:00
|
|
|
#include <stdio.h>
|
2017-03-14 13:38:45 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include "gattlib_internal.h"
|
|
|
|
|
2024-02-19 17:47:16 +01:00
|
|
|
#define CONNECT_TIMEOUT_SEC 10
|
2017-03-14 13:38:45 +01:00
|
|
|
|
2019-06-27 12:26:30 +02:00
|
|
|
static const char *m_dbus_error_unknown_object = "GDBus.Error:org.freedesktop.DBus.Error.UnknownObject";
|
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
static void _on_device_connect(gattlib_connection_t* connection) {
|
2024-02-12 13:29:40 +01:00
|
|
|
GDBusObjectManager *device_manager;
|
2024-02-15 21:44:34 +01:00
|
|
|
GError *error = NULL;
|
2024-02-12 13:29:40 +01:00
|
|
|
|
2024-04-05 13:25:51 +02:00
|
|
|
g_rec_mutex_lock(&m_gattlib_mutex);
|
|
|
|
|
|
|
|
if (!gattlib_device_is_valid(connection->device)) {
|
|
|
|
goto EXIT;
|
|
|
|
}
|
|
|
|
|
2024-02-12 13:29:40 +01:00
|
|
|
// Stop the timeout for connection
|
2024-04-05 11:43:21 +02:00
|
|
|
if (connection->backend.connection_timeout_id) {
|
|
|
|
g_source_remove(connection->backend.connection_timeout_id);
|
|
|
|
connection->backend.connection_timeout_id = 0;
|
2024-02-12 13:29:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get list of objects belonging to Device Manager
|
2024-04-05 11:43:21 +02:00
|
|
|
device_manager = get_device_manager_from_adapter(connection->device->adapter, &error);
|
2024-02-12 13:29:40 +01:00
|
|
|
if (device_manager == NULL) {
|
2024-02-15 21:44:34 +01:00
|
|
|
if (error != NULL) {
|
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "gattlib_connect: Failed to get device manager from adapter (%d, %d).", error->domain, error->code);
|
|
|
|
g_error_free(error);
|
|
|
|
} else {
|
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "gattlib_connect: Failed to get device manager from adapter");
|
|
|
|
}
|
2024-02-12 13:29:40 +01:00
|
|
|
//TODO: Free device
|
2024-04-05 13:25:51 +02:00
|
|
|
goto EXIT;
|
2024-02-12 13:29:40 +01:00
|
|
|
}
|
2024-04-05 11:43:21 +02:00
|
|
|
connection->backend.dbus_objects = g_dbus_object_manager_get_objects(device_manager);
|
2024-02-12 13:29:40 +01:00
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
gattlib_device_set_state(connection->device->adapter, connection->device->device_id, CONNECTED);
|
2024-04-03 17:36:17 +02:00
|
|
|
|
2024-02-12 13:29:40 +01:00
|
|
|
gattlib_on_connected_device(connection);
|
2024-04-05 13:25:51 +02:00
|
|
|
|
|
|
|
EXIT:
|
|
|
|
g_rec_mutex_unlock(&m_gattlib_mutex);
|
2024-02-12 13:29:40 +01:00
|
|
|
}
|
|
|
|
|
2017-03-14 13:38:45 +01:00
|
|
|
gboolean on_handle_device_property_change(
|
2024-04-05 13:25:51 +02:00
|
|
|
GDBusProxy *proxy,
|
2017-03-14 13:38:45 +01:00
|
|
|
GVariant *arg_changed_properties,
|
|
|
|
const gchar *const *arg_invalidated_properties,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
2024-04-05 11:43:21 +02:00
|
|
|
gattlib_connection_t* connection = user_data;
|
2017-03-14 13:38:45 +01:00
|
|
|
|
|
|
|
// Retrieve 'Value' from 'arg_changed_properties'
|
|
|
|
if (g_variant_n_children (arg_changed_properties) > 0) {
|
2024-04-05 13:25:51 +02:00
|
|
|
const gchar* device_object_path = g_dbus_proxy_get_object_path(proxy);
|
2017-03-14 13:38:45 +01:00
|
|
|
GVariantIter *iter;
|
|
|
|
const gchar *key;
|
|
|
|
GVariant *value;
|
|
|
|
|
|
|
|
g_variant_get (arg_changed_properties, "a{sv}", &iter);
|
|
|
|
while (g_variant_iter_loop (iter, "{&sv}", &key, &value)) {
|
2019-05-20 16:21:27 +02:00
|
|
|
if (strcmp(key, "Connected") == 0) {
|
2019-06-27 14:49:55 +02:00
|
|
|
if (!g_variant_get_boolean(value)) {
|
2024-04-05 13:25:51 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_DEBUG, "DBUS: device_property_change(%s): Disconnection", device_object_path);
|
2024-02-12 13:29:40 +01:00
|
|
|
gattlib_on_disconnected_device(connection);
|
2024-02-15 19:27:30 +01:00
|
|
|
} else {
|
2024-04-05 13:25:51 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_DEBUG, "DBUS: device_property_change(%s): Connection", device_object_path);
|
2019-05-03 09:47:58 +02:00
|
|
|
}
|
2019-06-27 14:49:55 +02:00
|
|
|
} else if (strcmp(key, "ServicesResolved") == 0) {
|
2019-07-07 12:46:15 +02:00
|
|
|
if (g_variant_get_boolean(value)) {
|
2024-04-05 13:25:51 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_DEBUG, "DBUS: device_property_change(%s): Service Resolved", device_object_path);
|
2024-02-12 13:29:40 +01:00
|
|
|
_on_device_connect(connection);
|
2019-07-07 12:46:15 +02:00
|
|
|
}
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
}
|
2019-07-18 20:26:16 +02:00
|
|
|
g_variant_iter_free(iter);
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2019-07-09 18:17:28 +02:00
|
|
|
void get_device_path_from_mac_with_adapter(OrgBluezAdapter1* adapter, const char *mac_address, char *object_path, size_t object_path_len)
|
|
|
|
{
|
|
|
|
char device_address_str[20 + 1];
|
|
|
|
const char* adapter_path = g_dbus_proxy_get_object_path((GDBusProxy *)ORG_BLUEZ_ADAPTER1_PROXY(adapter));
|
|
|
|
|
|
|
|
// Transform string from 'DA:94:40:95:E0:87' to 'dev_DA_94_40_95_E0_87'
|
2024-02-20 23:53:45 +01:00
|
|
|
strncpy(device_address_str, mac_address, sizeof(device_address_str) - 1);
|
2024-03-07 08:53:42 +01:00
|
|
|
for (size_t i = 0; i < strlen(device_address_str); i++) {
|
2019-07-09 18:17:28 +02:00
|
|
|
if (device_address_str[i] == ':') {
|
|
|
|
device_address_str[i] = '_';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Force a null-terminated character
|
|
|
|
device_address_str[20] = '\0';
|
|
|
|
|
|
|
|
// Generate object path like: /org/bluez/hci0/dev_DA_94_40_95_E0_87
|
|
|
|
snprintf(object_path, object_path_len, "%s/dev_%s", adapter_path, device_address_str);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void get_device_path_from_mac(const char *adapter_name, const char *mac_address, char *object_path, size_t object_path_len)
|
2017-03-14 13:38:45 +01:00
|
|
|
{
|
2019-03-05 13:08:33 +01:00
|
|
|
char device_address_str[20 + 1];
|
2019-07-09 18:26:22 +02:00
|
|
|
const char* adapter;
|
2017-03-14 13:38:45 +01:00
|
|
|
|
2019-07-09 18:26:22 +02:00
|
|
|
if (adapter_name) {
|
|
|
|
adapter = adapter_name;
|
2017-03-14 13:38:45 +01:00
|
|
|
} else {
|
2019-07-09 18:26:22 +02:00
|
|
|
adapter = "hci0";
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Transform string from 'DA:94:40:95:E0:87' to 'dev_DA_94_40_95_E0_87'
|
2024-02-20 23:53:45 +01:00
|
|
|
strncpy(device_address_str, mac_address, sizeof(device_address_str) - 1);
|
2024-03-07 08:53:42 +01:00
|
|
|
for (size_t i = 0; i < strlen(device_address_str); i++) {
|
2017-03-14 13:38:45 +01:00
|
|
|
if (device_address_str[i] == ':') {
|
|
|
|
device_address_str[i] = '_';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-05 13:08:33 +01:00
|
|
|
// Force a null-terminated character
|
|
|
|
device_address_str[20] = '\0';
|
|
|
|
|
2017-03-14 13:38:45 +01:00
|
|
|
// Generate object path like: /org/bluez/hci0/dev_DA_94_40_95_E0_87
|
2019-07-09 18:26:22 +02:00
|
|
|
snprintf(object_path, object_path_len, "/org/bluez/%s/dev_%s", adapter, device_address_str);
|
|
|
|
}
|
|
|
|
|
2024-02-12 00:28:34 +01:00
|
|
|
static gboolean _stop_connect_func(gpointer data) {
|
2024-04-05 11:43:21 +02:00
|
|
|
gattlib_connection_t *connection = data;
|
2024-02-12 00:28:34 +01:00
|
|
|
|
2024-04-05 13:25:51 +02:00
|
|
|
g_rec_mutex_lock(&m_gattlib_mutex);
|
|
|
|
|
|
|
|
if (!gattlib_device_is_valid(connection->device)) {
|
|
|
|
goto EXIT;
|
|
|
|
}
|
|
|
|
|
2024-02-12 00:28:34 +01:00
|
|
|
// Reset the connection timeout
|
2024-04-05 11:43:21 +02:00
|
|
|
connection->backend.connection_timeout_id = 0;
|
2024-02-12 00:28:34 +01:00
|
|
|
|
2024-04-05 13:25:51 +02:00
|
|
|
EXIT:
|
|
|
|
g_rec_mutex_unlock(&m_gattlib_mutex);
|
|
|
|
|
2024-02-12 00:28:34 +01:00
|
|
|
// We return FALSE when it is a one-off event
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2019-07-09 18:26:22 +02:00
|
|
|
/**
|
2024-02-22 19:52:48 +01:00
|
|
|
* @brief Function to asynchronously connect to a BLE device
|
|
|
|
*
|
|
|
|
* @note This function is mainly used before Bluez v5.42 (prior to D-BUS support)
|
|
|
|
*
|
|
|
|
* @param adapter Local Adaptater interface. When passing NULL, we use default adapter.
|
2019-07-09 18:26:22 +02:00
|
|
|
* @param dst Remote Bluetooth address
|
2024-02-22 19:52:48 +01:00
|
|
|
* @param options Options to connect to BLE device. See `GATTLIB_CONNECTION_OPTIONS_*`
|
|
|
|
* @param connect_cb is the callback to call when the connection is established
|
|
|
|
* @param user_data is the user specific data to pass to the callback
|
|
|
|
*
|
|
|
|
* @return GATTLIB_SUCCESS on success or GATTLIB_* error code
|
2019-07-09 18:26:22 +02:00
|
|
|
*/
|
2024-04-05 11:43:21 +02:00
|
|
|
int gattlib_connect(gattlib_adapter_t* adapter, const char *dst,
|
2024-02-22 19:52:48 +01:00
|
|
|
unsigned long options,
|
|
|
|
gatt_connect_cb_t connect_cb,
|
|
|
|
void* user_data)
|
2019-07-09 18:26:22 +02:00
|
|
|
{
|
2020-04-08 14:10:13 +02:00
|
|
|
const char* adapter_name = NULL;
|
2019-07-09 18:26:22 +02:00
|
|
|
GError *error = NULL;
|
2024-04-05 13:25:51 +02:00
|
|
|
char object_path[GATTLIB_DBUS_OBJECT_PATH_SIZE_MAX];
|
2024-02-22 19:52:48 +01:00
|
|
|
int ret = GATTLIB_SUCCESS;
|
2019-07-09 18:26:22 +02:00
|
|
|
|
2020-04-08 15:43:30 +02:00
|
|
|
// In case NULL is passed, we initialized default adapter
|
2024-04-05 11:43:21 +02:00
|
|
|
if (adapter == NULL) {
|
|
|
|
adapter = init_default_adapter();
|
|
|
|
if (adapter == NULL) {
|
|
|
|
GATTLIB_LOG(GATTLIB_DEBUG, "gattlib_connect: No default adapter");
|
|
|
|
return GATTLIB_NOT_FOUND;
|
|
|
|
}
|
2020-07-20 20:00:26 +02:00
|
|
|
} else {
|
2024-04-05 11:43:21 +02:00
|
|
|
adapter_name = adapter->name;
|
2020-04-08 14:10:13 +02:00
|
|
|
}
|
|
|
|
|
2024-03-28 10:17:30 +01:00
|
|
|
if (connect_cb == NULL) {
|
|
|
|
GATTLIB_LOG(GATTLIB_DEBUG, "gattlib_connect: Missing connection callback");
|
|
|
|
return GATTLIB_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
2020-04-08 14:10:13 +02:00
|
|
|
get_device_path_from_mac(adapter_name, dst, object_path, sizeof(object_path));
|
2017-03-14 13:38:45 +01:00
|
|
|
|
2024-04-05 13:25:51 +02:00
|
|
|
g_rec_mutex_lock(&m_gattlib_mutex);
|
|
|
|
|
|
|
|
if (!gattlib_adapter_is_valid(adapter)) {
|
|
|
|
ret = GATTLIB_INVALID_PARAMETER;
|
|
|
|
goto EXIT;
|
|
|
|
}
|
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
gattlib_device_t* device = gattlib_device_get_device(adapter, object_path);
|
|
|
|
if (device == NULL) {
|
2024-04-03 17:36:17 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_DEBUG, "gattlib_connect: Cannot find connection %s", dst);
|
2024-04-05 13:25:51 +02:00
|
|
|
ret = GATTLIB_INVALID_PARAMETER;
|
|
|
|
goto EXIT;
|
2024-04-05 11:43:21 +02:00
|
|
|
} else if (device->state != DISCONNECTED) {
|
2024-04-03 17:36:17 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_DEBUG, "gattlib_connect: Cannot connect to '%s'. Device is in state %s",
|
2024-04-05 11:43:21 +02:00
|
|
|
dst, device_state_str[device->state]);
|
2024-04-05 13:25:51 +02:00
|
|
|
ret = GATTLIB_BUSY;
|
|
|
|
goto EXIT;
|
2024-04-03 17:36:17 +02:00
|
|
|
}
|
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
device->connection.on_connection.callback.connection_handler = connect_cb;
|
|
|
|
device->connection.on_connection.user_data = user_data;
|
2024-02-12 13:29:40 +01:00
|
|
|
|
2024-04-03 17:36:17 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_DEBUG, "Connecting bluetooth device %s", dst);
|
|
|
|
|
|
|
|
// Mark the device has disconnected
|
2024-04-05 11:43:21 +02:00
|
|
|
gattlib_device_set_state(device->adapter, device->device_id, CONNECTING);
|
2024-03-07 23:58:35 +01:00
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
OrgBluezDevice1* bluez_device = org_bluez_device1_proxy_new_for_bus_sync(
|
2017-03-14 13:38:45 +01:00
|
|
|
G_BUS_TYPE_SYSTEM,
|
2024-03-12 20:38:31 +01:00
|
|
|
G_DBUS_PROXY_FLAGS_NONE,
|
2017-03-14 13:38:45 +01:00
|
|
|
"org.bluez",
|
|
|
|
object_path,
|
|
|
|
NULL,
|
|
|
|
&error);
|
2024-04-05 11:43:21 +02:00
|
|
|
if (bluez_device == NULL) {
|
2024-02-22 19:52:48 +01:00
|
|
|
ret = GATTLIB_ERROR_DBUS;
|
2019-05-03 09:47:02 +02:00
|
|
|
if (error) {
|
2024-04-04 21:54:28 +02:00
|
|
|
ret = GATTLIB_ERROR_DBUS_WITH_ERROR(error);
|
2021-10-18 01:25:29 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Failed to connect to DBus Bluez Device: %s", error->message);
|
2019-05-03 09:47:02 +02:00
|
|
|
g_error_free(error);
|
2024-02-08 00:06:09 +01:00
|
|
|
} else {
|
2024-02-22 19:52:48 +01:00
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "gattlib_connect: Failed to connect to DBus Bluez Device");
|
2019-05-03 09:47:02 +02:00
|
|
|
}
|
2024-04-05 13:25:51 +02:00
|
|
|
goto EXIT;
|
2017-03-14 13:38:45 +01:00
|
|
|
} else {
|
2024-04-05 11:43:21 +02:00
|
|
|
device->connection.backend.device = bluez_device;
|
|
|
|
device->connection.backend.device_object_path = strdup(object_path);
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
|
2019-05-20 18:15:05 +02:00
|
|
|
// Register a handle for notification
|
2024-04-05 11:43:21 +02:00
|
|
|
device->connection.backend.on_handle_device_property_change_id = g_signal_connect(bluez_device,
|
2019-05-20 18:15:05 +02:00
|
|
|
"g-properties-changed",
|
2024-04-05 11:43:21 +02:00
|
|
|
G_CALLBACK(on_handle_device_property_change),
|
|
|
|
&device->connection);
|
2019-05-20 18:15:05 +02:00
|
|
|
|
2017-03-14 13:38:45 +01:00
|
|
|
error = NULL;
|
2024-04-05 11:43:21 +02:00
|
|
|
org_bluez_device1_call_connect_sync(bluez_device, NULL, &error);
|
2017-03-14 13:38:45 +01:00
|
|
|
if (error) {
|
2019-06-27 12:26:30 +02:00
|
|
|
if (strncmp(error->message, m_dbus_error_unknown_object, strlen(m_dbus_error_unknown_object)) == 0) {
|
|
|
|
// You might have this error if the computer has not scanned or has not already had
|
|
|
|
// pairing information about the targetted device.
|
2024-02-22 19:52:48 +01:00
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Device '%s' cannot be found (%d, %d)", dst, error->domain, error->code);
|
|
|
|
ret = GATTLIB_NOT_FOUND;
|
2024-03-05 22:46:38 +01:00
|
|
|
} else if ((error->domain == 238) && (error->code == 60952)) {
|
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Device '%s': %s", dst, error->message);
|
2024-03-28 11:52:57 +01:00
|
|
|
ret = GATTLIB_TIMEOUT;
|
2024-03-05 22:46:38 +01:00
|
|
|
} else {
|
2021-10-18 01:25:29 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Device connected error (device:%s): %s",
|
2024-04-05 11:43:21 +02:00
|
|
|
device->connection.backend.device_object_path,
|
2019-06-27 12:26:30 +02:00
|
|
|
error->message);
|
2024-03-05 22:46:38 +01:00
|
|
|
ret = GATTLIB_ERROR_DBUS_WITH_ERROR(error);
|
2019-06-27 12:26:30 +02:00
|
|
|
}
|
|
|
|
|
2019-05-03 09:47:02 +02:00
|
|
|
g_error_free(error);
|
2024-04-04 21:54:28 +02:00
|
|
|
|
|
|
|
// Fail to connect. Mark the device has disconnected to be able to reconnect
|
2024-04-05 11:43:21 +02:00
|
|
|
gattlib_device_set_state(adapter, device->device_id, DISCONNECTED);
|
2024-04-04 21:54:28 +02:00
|
|
|
|
2017-03-14 13:38:45 +01:00
|
|
|
goto FREE_DEVICE;
|
|
|
|
}
|
|
|
|
|
2024-02-19 17:47:16 +01:00
|
|
|
// Wait for the property 'UUIDs' to be changed. We assume 'org.bluez.GattService1
|
|
|
|
// and 'org.bluez.GattCharacteristic1' to be advertised at that moment.
|
2024-04-05 11:43:21 +02:00
|
|
|
device->connection.backend.connection_timeout_id = g_timeout_add_seconds(CONNECT_TIMEOUT_SEC, _stop_connect_func, &device->connection);
|
2021-03-03 01:08:21 +01:00
|
|
|
|
2024-04-05 13:25:51 +02:00
|
|
|
g_rec_mutex_unlock(&m_gattlib_mutex);
|
2024-02-22 19:52:48 +01:00
|
|
|
return GATTLIB_SUCCESS;
|
2017-03-14 13:38:45 +01:00
|
|
|
|
|
|
|
FREE_DEVICE:
|
2024-04-05 11:43:21 +02:00
|
|
|
free(device->connection.backend.device_object_path);
|
2022-03-28 09:03:13 +02:00
|
|
|
|
|
|
|
// destroy default adapter
|
2024-02-08 00:06:09 +01:00
|
|
|
if(adapter == NULL) {
|
2024-04-05 11:43:21 +02:00
|
|
|
gattlib_adapter_close(adapter);
|
2022-03-28 09:03:13 +02:00
|
|
|
}
|
|
|
|
|
2024-04-05 13:25:51 +02:00
|
|
|
EXIT:
|
2024-02-22 19:52:48 +01:00
|
|
|
if (ret != GATTLIB_SUCCESS) {
|
|
|
|
connect_cb(adapter, dst, NULL, ret /* error */, user_data);
|
2019-05-19 00:19:33 +02:00
|
|
|
}
|
|
|
|
|
2024-04-05 13:25:51 +02:00
|
|
|
g_rec_mutex_unlock(&m_gattlib_mutex);
|
2024-02-22 19:52:48 +01:00
|
|
|
return ret;
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
|
2024-03-13 13:33:07 +01:00
|
|
|
/**
|
|
|
|
* Clean GATTLIB connection on disconnection
|
|
|
|
*
|
|
|
|
* This function is called by the disconnection callback to always be called on explicit
|
|
|
|
* and implicit disconnection.
|
|
|
|
*/
|
2024-04-05 11:43:21 +02:00
|
|
|
void gattlib_connection_free(gattlib_connection_t* connection) {
|
2024-04-03 17:36:17 +02:00
|
|
|
char* device_id;
|
2024-03-13 13:33:07 +01:00
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
device_id = connection->device->device_id;
|
2024-03-13 13:33:07 +01:00
|
|
|
|
|
|
|
// Remove signal
|
2024-04-05 11:43:21 +02:00
|
|
|
if (connection->backend.on_handle_device_property_change_id != 0) {
|
|
|
|
g_signal_handler_disconnect(connection->backend.device, connection->backend.on_handle_device_property_change_id);
|
|
|
|
connection->backend.on_handle_device_property_change_id = 0;
|
2024-03-13 13:33:07 +01:00
|
|
|
}
|
|
|
|
|
2024-03-29 09:18:53 +01:00
|
|
|
// Stop the timeout for connection
|
2024-04-05 11:43:21 +02:00
|
|
|
if (connection->backend.connection_timeout_id) {
|
|
|
|
g_source_remove(connection->backend.connection_timeout_id);
|
|
|
|
connection->backend.connection_timeout_id = 0;
|
2024-03-29 09:18:53 +01:00
|
|
|
}
|
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
free(connection->backend.device_object_path);
|
|
|
|
g_list_free_full(connection->backend.dbus_objects, g_object_unref);
|
2024-03-13 13:33:07 +01:00
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
disconnect_all_notifications(&connection->backend);
|
2024-03-13 13:33:07 +01:00
|
|
|
|
2024-03-28 10:17:30 +01:00
|
|
|
// Free all handler
|
2024-03-29 00:17:50 +01:00
|
|
|
//TODO: Fixme - there is a memory leak by not freeing the handlers
|
|
|
|
//gattlib_handler_free(&connection->on_connection);
|
|
|
|
//gattlib_handler_free(&connection->on_disconnection);
|
|
|
|
//gattlib_handler_free(&connection->indication);
|
|
|
|
//gattlib_handler_free(&connection->notification);
|
2024-03-28 10:17:30 +01:00
|
|
|
|
2024-03-13 13:33:07 +01:00
|
|
|
// Note: We do not free adapter as it might still be used by other devices
|
|
|
|
|
2024-04-03 17:36:17 +02:00
|
|
|
// Mark the device has disconnected
|
2024-04-05 11:43:21 +02:00
|
|
|
gattlib_device_set_state(connection->device->adapter, device_id, DISCONNECTED);
|
2024-03-13 13:33:07 +01:00
|
|
|
}
|
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
int gattlib_disconnect(gattlib_connection_t* connection, bool wait_disconnection) {
|
2017-03-15 01:37:33 +01:00
|
|
|
GError *error = NULL;
|
2024-04-05 13:25:51 +02:00
|
|
|
int ret = GATTLIB_SUCCESS;
|
2017-03-15 01:37:33 +01:00
|
|
|
|
2024-02-08 00:06:09 +01:00
|
|
|
if (connection == NULL) {
|
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Cannot disconnect - connection parameter is not valid.");
|
|
|
|
return GATTLIB_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
2024-04-05 13:25:51 +02:00
|
|
|
g_rec_mutex_lock(&m_gattlib_mutex);
|
2024-02-08 00:06:09 +01:00
|
|
|
|
2024-04-05 13:25:51 +02:00
|
|
|
if (!gattlib_connection_is_connected(connection)) {
|
2024-04-03 17:36:17 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Cannot disconnect - connection is not in connected state (state=%s).",
|
2024-04-05 11:43:21 +02:00
|
|
|
device_state_str[connection->device->state]);
|
2024-04-05 13:25:51 +02:00
|
|
|
g_rec_mutex_unlock(&m_gattlib_mutex);
|
|
|
|
return GATTLIB_BUSY;
|
2024-02-08 00:06:09 +01:00
|
|
|
}
|
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_DEBUG, "Disconnecting bluetooth device %s", connection->backend.device_object_path);
|
2024-03-07 23:58:35 +01:00
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
org_bluez_device1_call_disconnect_sync(connection->backend.device, NULL, &error);
|
2019-05-03 09:47:02 +02:00
|
|
|
if (error) {
|
2021-10-18 01:25:29 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Failed to disconnect DBus Bluez Device: %s", error->message);
|
2019-05-03 09:47:02 +02:00
|
|
|
g_error_free(error);
|
2024-04-05 13:25:51 +02:00
|
|
|
|
|
|
|
// We continue, we still want to set the correct state
|
2019-05-03 09:47:02 +02:00
|
|
|
}
|
2017-03-15 01:37:33 +01:00
|
|
|
|
2024-04-03 17:36:17 +02:00
|
|
|
// Mark the device has disconnected
|
2024-04-05 11:43:21 +02:00
|
|
|
gattlib_device_set_state(connection->device->adapter, connection->device->device_id, DISCONNECTING);
|
2024-04-03 17:36:17 +02:00
|
|
|
|
2024-03-13 13:33:07 +01:00
|
|
|
//Note: Signals and memory will be removed/clean on disconnction callback
|
|
|
|
// See _gattlib_clean_on_disconnection()
|
2024-02-15 19:24:33 +01:00
|
|
|
|
2024-04-05 13:25:51 +02:00
|
|
|
// We must release the mutex before the loop to leave other threads to signal the disconnection
|
|
|
|
g_rec_mutex_unlock(&m_gattlib_mutex);
|
|
|
|
|
2024-03-28 11:52:57 +01:00
|
|
|
if (wait_disconnection) {
|
|
|
|
gint64 end_time;
|
|
|
|
|
2024-04-05 13:25:51 +02:00
|
|
|
g_mutex_lock(&m_gattlib_signal.mutex);
|
|
|
|
|
2024-03-28 11:52:57 +01:00
|
|
|
end_time = g_get_monotonic_time() + GATTLIB_DISCONNECTION_WAIT_TIMEOUT_SEC * G_TIME_SPAN_SECOND;
|
|
|
|
|
2024-04-05 13:25:51 +02:00
|
|
|
while (gattlib_connection_is_connected(connection)) {
|
|
|
|
if (!g_cond_wait_until(&m_gattlib_signal.condition, &m_gattlib_signal.mutex, end_time)) {
|
2024-03-28 11:52:57 +01:00
|
|
|
ret = GATTLIB_TIMEOUT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2024-04-05 13:25:51 +02:00
|
|
|
|
|
|
|
g_mutex_unlock(&m_gattlib_signal.mutex);
|
2024-03-28 11:52:57 +01:00
|
|
|
}
|
|
|
|
|
2024-02-15 19:24:33 +01:00
|
|
|
return ret;
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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)
|
2024-04-05 11:43:21 +02:00
|
|
|
int gattlib_discover_primary(gattlib_connection_t* connection, gattlib_primary_service_t** services, int* services_count) {
|
2024-04-05 13:25:51 +02:00
|
|
|
const gchar* const* service_str;
|
|
|
|
GError *error = NULL;
|
|
|
|
int ret = GATTLIB_SUCCESS;
|
|
|
|
|
|
|
|
g_rec_mutex_lock(&m_gattlib_mutex);
|
|
|
|
|
2022-05-11 16:42:19 +02:00
|
|
|
if (connection == NULL) {
|
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Gattlib connection not initialized.");
|
2024-04-05 13:25:51 +02:00
|
|
|
g_rec_mutex_unlock(&m_gattlib_mutex);
|
2022-05-11 16:42:19 +02:00
|
|
|
return GATTLIB_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
2024-04-05 13:25:51 +02:00
|
|
|
if (!gattlib_device_is_valid(connection->device)) {
|
|
|
|
g_rec_mutex_unlock(&m_gattlib_mutex);
|
|
|
|
return GATTLIB_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Increase 'bluez_device' reference counter to avoid to keep the lock longer
|
2024-04-05 11:43:21 +02:00
|
|
|
OrgBluezDevice1* bluez_device = connection->backend.device;
|
2024-04-05 13:25:51 +02:00
|
|
|
g_object_ref(bluez_device);
|
|
|
|
g_rec_mutex_unlock(&m_gattlib_mutex);
|
2017-03-14 13:38:45 +01:00
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
const gchar* const* service_strs = org_bluez_device1_get_gatt_services(bluez_device);
|
2017-03-14 13:38:45 +01:00
|
|
|
|
|
|
|
if (service_strs == NULL) {
|
2019-06-27 11:04:48 +02:00
|
|
|
if (services != NULL) {
|
|
|
|
*services = NULL;
|
|
|
|
}
|
|
|
|
if (services_count != NULL) {
|
|
|
|
*services_count = 0;
|
|
|
|
}
|
2019-05-21 21:25:04 +02:00
|
|
|
return GATTLIB_SUCCESS;
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Maximum number of primary services
|
|
|
|
int count_max = 0, count = 0;
|
|
|
|
for (service_str = service_strs; *service_str != NULL; service_str++) {
|
|
|
|
count_max++;
|
|
|
|
}
|
|
|
|
|
2024-03-28 14:26:22 +01:00
|
|
|
gattlib_primary_service_t* primary_services = calloc(count_max * sizeof(gattlib_primary_service_t), 1);
|
2017-03-14 13:38:45 +01:00
|
|
|
if (primary_services == NULL) {
|
2024-04-05 13:25:51 +02:00
|
|
|
ret = GATTLIB_OUT_OF_MEMORY;
|
|
|
|
goto EXIT;
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (service_str = service_strs; *service_str != NULL; service_str++) {
|
|
|
|
error = NULL;
|
|
|
|
OrgBluezGattService1* service_proxy = org_bluez_gatt_service1_proxy_new_for_bus_sync(
|
|
|
|
G_BUS_TYPE_SYSTEM,
|
2024-03-12 20:38:31 +01:00
|
|
|
G_DBUS_PROXY_FLAGS_NONE,
|
2017-03-14 13:38:45 +01:00
|
|
|
"org.bluez",
|
|
|
|
*service_str,
|
|
|
|
NULL,
|
|
|
|
&error);
|
|
|
|
if (service_proxy == NULL) {
|
2019-05-03 09:47:02 +02:00
|
|
|
if (error) {
|
2021-10-18 01:25:29 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Failed to open service '%s': %s", *service_str, error->message);
|
2019-05-03 09:47:02 +02:00
|
|
|
g_error_free(error);
|
|
|
|
} else {
|
2021-10-18 01:25:29 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Failed to open service '%s'.", *service_str);
|
2019-05-03 09:47:02 +02:00
|
|
|
}
|
2017-03-14 13:38:45 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (org_bluez_gatt_service1_get_primary(service_proxy)) {
|
|
|
|
primary_services[count].attr_handle_start = 0;
|
|
|
|
primary_services[count].attr_handle_end = 0;
|
|
|
|
|
|
|
|
gattlib_string_to_uuid(
|
|
|
|
org_bluez_gatt_service1_get_uuid(service_proxy),
|
|
|
|
MAX_LEN_UUID_STR + 1,
|
|
|
|
&primary_services[count].uuid);
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_object_unref(service_proxy);
|
|
|
|
}
|
|
|
|
|
2019-06-27 11:04:48 +02:00
|
|
|
if (services != NULL) {
|
|
|
|
*services = primary_services;
|
|
|
|
}
|
|
|
|
if (services_count != NULL) {
|
|
|
|
*services_count = count;
|
|
|
|
}
|
2024-04-05 13:25:51 +02:00
|
|
|
|
|
|
|
EXIT:
|
|
|
|
g_object_unref(bluez_device);
|
|
|
|
return ret;
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
#else
|
2024-04-05 11:43:21 +02:00
|
|
|
int gattlib_discover_primary(gattlib_connection_t* connection, gattlib_primary_service_t** services, int* services_count) {
|
2024-04-05 13:25:51 +02:00
|
|
|
GError *error = NULL;
|
|
|
|
const gchar* const* service_str;
|
|
|
|
int ret = GATTLIB_SUCCESS;
|
|
|
|
|
|
|
|
g_rec_mutex_lock(&m_gattlib_mutex);
|
|
|
|
|
2022-05-11 16:42:19 +02:00
|
|
|
if (connection == NULL) {
|
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Gattlib connection not initialized.");
|
2024-04-05 13:25:51 +02:00
|
|
|
ret = GATTLIB_INVALID_PARAMETER;
|
|
|
|
goto EXIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!gattlib_device_is_valid(connection->device)) {
|
|
|
|
ret = GATTLIB_INVALID_PARAMETER;
|
|
|
|
goto EXIT;
|
2022-05-11 16:42:19 +02:00
|
|
|
}
|
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
GDBusObjectManager *device_manager = get_device_manager_from_adapter(connection->device->adapter, &error);
|
|
|
|
OrgBluezDevice1* device = connection->backend.device;
|
2017-03-14 13:38:45 +01:00
|
|
|
|
|
|
|
const gchar* const* service_strs = org_bluez_device1_get_uuids(device);
|
|
|
|
|
2020-04-08 15:43:30 +02:00
|
|
|
if (device_manager == NULL) {
|
2024-02-15 21:44:34 +01:00
|
|
|
if (error != NULL) {
|
|
|
|
ret = GATTLIB_ERROR_DBUS_WITH_ERROR(error);
|
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Gattlib Context not initialized (%d, %d).", error->domain, error->code);
|
|
|
|
g_error_free(error);
|
|
|
|
} else {
|
|
|
|
ret = GATTLIB_ERROR_DBUS;
|
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Gattlib Context not initialized.");
|
|
|
|
}
|
2024-04-05 13:25:51 +02:00
|
|
|
goto EXIT;
|
2020-04-08 15:43:30 +02:00
|
|
|
}
|
|
|
|
|
2017-03-14 13:38:45 +01:00
|
|
|
if (service_strs == NULL) {
|
2019-06-27 11:04:48 +02:00
|
|
|
if (services != NULL) {
|
|
|
|
*services = NULL;
|
|
|
|
}
|
|
|
|
if (services_count != NULL) {
|
|
|
|
*services_count = 0;
|
|
|
|
}
|
2024-04-05 13:25:51 +02:00
|
|
|
goto EXIT;
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Maximum number of primary services
|
|
|
|
int count_max = 0, count = 0;
|
|
|
|
for (service_str = service_strs; *service_str != NULL; service_str++) {
|
|
|
|
count_max++;
|
|
|
|
}
|
|
|
|
|
2024-03-28 14:26:22 +01:00
|
|
|
gattlib_primary_service_t* primary_services = calloc(count_max * sizeof(gattlib_primary_service_t), 1);
|
2017-03-14 13:38:45 +01:00
|
|
|
if (primary_services == NULL) {
|
2024-04-05 13:25:51 +02:00
|
|
|
ret = GATTLIB_OUT_OF_MEMORY;
|
|
|
|
goto EXIT;
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
GList *l;
|
2024-04-05 11:43:21 +02:00
|
|
|
for (l = connection->backend.dbus_objects; l != NULL; l = l->next) {
|
2017-03-14 13:38:45 +01:00
|
|
|
GDBusObject *object = l->data;
|
|
|
|
const char* object_path = g_dbus_object_get_object_path(G_DBUS_OBJECT(object));
|
|
|
|
|
|
|
|
GDBusInterface *interface = g_dbus_object_manager_get_interface(device_manager, object_path, "org.bluez.GattService1");
|
|
|
|
if (!interface) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-07-18 20:26:16 +02:00
|
|
|
g_object_unref(interface);
|
|
|
|
|
2017-03-14 13:38:45 +01:00
|
|
|
error = NULL;
|
|
|
|
OrgBluezGattService1* service_proxy = org_bluez_gatt_service1_proxy_new_for_bus_sync(
|
|
|
|
G_BUS_TYPE_SYSTEM,
|
2024-03-12 20:38:31 +01:00
|
|
|
G_DBUS_PROXY_FLAGS_NONE,
|
2017-03-14 13:38:45 +01:00
|
|
|
"org.bluez",
|
|
|
|
object_path,
|
|
|
|
NULL,
|
|
|
|
&error);
|
|
|
|
if (service_proxy == NULL) {
|
2019-05-03 09:47:02 +02:00
|
|
|
if (error) {
|
2021-10-18 01:25:29 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Failed to open service '%s': %s", object_path, error->message);
|
2019-05-03 09:47:02 +02:00
|
|
|
g_error_free(error);
|
|
|
|
} else {
|
2021-10-18 01:25:29 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Failed to open service '%s'.", object_path);
|
2019-05-03 09:47:02 +02:00
|
|
|
}
|
2017-03-14 13:38:45 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure the service is attached to this device
|
2022-03-04 09:35:13 +01:00
|
|
|
const gchar * service_property = org_bluez_gatt_service1_get_device(service_proxy);
|
|
|
|
if (service_property == NULL) {
|
|
|
|
if (error) {
|
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Failed to get service property '%s': %s", object_path, error->message);
|
|
|
|
g_error_free(error);
|
|
|
|
} else {
|
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Failed to get service property '%s'.", object_path);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2024-04-05 11:43:21 +02:00
|
|
|
if (strcmp(connection->backend.device_object_path, service_property)) {
|
2019-05-21 21:27:35 +02:00
|
|
|
g_object_unref(service_proxy);
|
2017-03-14 13:38:45 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (org_bluez_gatt_service1_get_primary(service_proxy)) {
|
2021-03-02 20:42:19 +01:00
|
|
|
// Object path is in the form '/org/bluez/hci0/dev_DE_79_A2_A1_E9_FA/service0024
|
|
|
|
// We convert the last 4 hex characters into the handle
|
2024-03-07 23:57:58 +01:00
|
|
|
unsigned int service_handle = 0xFFFF; // Initialize with an invalid value.
|
2021-03-02 20:42:19 +01:00
|
|
|
sscanf(object_path + strlen(object_path) - 4, "%x", &service_handle);
|
|
|
|
primary_services[count].attr_handle_start = service_handle;
|
|
|
|
primary_services[count].attr_handle_end = service_handle;
|
|
|
|
|
|
|
|
// Loop through all objects, as ordering is not guaranteed.
|
2024-04-05 11:43:21 +02:00
|
|
|
for (GList *m = connection->backend.dbus_objects; m != NULL; m = m->next) {
|
2019-06-03 12:03:56 +02:00
|
|
|
GDBusObject *characteristic_object = m->data;
|
|
|
|
const char* characteristic_path = g_dbus_object_get_object_path(G_DBUS_OBJECT(characteristic_object));
|
|
|
|
interface = g_dbus_object_manager_get_interface(device_manager, characteristic_path, "org.bluez.GattCharacteristic1");
|
2021-03-02 20:42:19 +01:00
|
|
|
|
2019-06-03 12:03:56 +02:00
|
|
|
if (!interface) {
|
|
|
|
continue;
|
|
|
|
} else if (strncmp(object_path, characteristic_path, strlen(object_path)) != 0) {
|
2021-03-02 20:42:19 +01:00
|
|
|
// The selected characteristic does not belong to the object, ignore.
|
2019-07-18 20:26:16 +02:00
|
|
|
g_object_unref(interface);
|
2019-06-03 12:03:56 +02:00
|
|
|
continue;
|
|
|
|
} else {
|
2021-03-02 20:42:19 +01:00
|
|
|
// Release the interface object to prevent memory leak.
|
2019-07-18 20:26:16 +02:00
|
|
|
g_object_unref(interface);
|
|
|
|
|
2019-06-03 12:03:56 +02:00
|
|
|
// Object path is in the form '/org/bluez/hci0/dev_DE_79_A2_A1_E9_FA/service0024/char0029'.
|
|
|
|
// We convert the last 4 hex characters into the handle
|
2024-03-07 23:57:58 +01:00
|
|
|
unsigned int char_handle = primary_services[count].attr_handle_end; // Initialize with existing good value for safety.
|
2019-06-03 12:03:56 +02:00
|
|
|
sscanf(characteristic_path + strlen(characteristic_path) - 4, "%x", &char_handle);
|
|
|
|
|
2021-03-02 20:42:19 +01:00
|
|
|
// Once here, update the end handle of the service
|
|
|
|
primary_services[count].attr_handle_end = MAX(primary_services[count].attr_handle_end, char_handle);
|
2019-06-03 12:03:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-14 13:38:45 +01:00
|
|
|
gattlib_string_to_uuid(
|
|
|
|
org_bluez_gatt_service1_get_uuid(service_proxy),
|
|
|
|
MAX_LEN_UUID_STR + 1,
|
|
|
|
&primary_services[count].uuid);
|
|
|
|
count++;
|
|
|
|
}
|
2019-05-21 21:27:35 +02:00
|
|
|
|
|
|
|
g_object_unref(service_proxy);
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
|
2019-06-27 11:04:48 +02:00
|
|
|
if (services != NULL) {
|
|
|
|
*services = primary_services;
|
|
|
|
}
|
|
|
|
if (services_count != NULL) {
|
|
|
|
*services_count = count;
|
|
|
|
}
|
2019-05-21 21:25:32 +02:00
|
|
|
|
|
|
|
if (ret != GATTLIB_SUCCESS) {
|
|
|
|
free(primary_services);
|
|
|
|
}
|
2024-04-05 13:25:51 +02:00
|
|
|
|
|
|
|
EXIT:
|
|
|
|
g_rec_mutex_unlock(&m_gattlib_mutex);
|
2019-05-21 21:25:32 +02:00
|
|
|
return ret;
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// 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)
|
2024-04-05 11:43:21 +02:00
|
|
|
int gattlib_discover_char_range(gattlib_connection_t* connection, uint16_t start, uint16_t end, gattlib_characteristic_t** characteristics, int* characteristics_count) {
|
2017-03-14 13:38:45 +01:00
|
|
|
GError *error = NULL;
|
2019-06-03 12:03:56 +02:00
|
|
|
int handle;
|
2024-04-05 13:25:51 +02:00
|
|
|
int ret = GATTLIB_SUCCESS;
|
|
|
|
|
|
|
|
// Increase bluez_device object reference counter to avoid to keep locking the mutex
|
|
|
|
g_rec_mutex_lock(&m_gattlib_mutex);
|
|
|
|
|
|
|
|
if (!gattlib_device_is_valid(connection->device)) {
|
|
|
|
g_rec_mutex_unlock(&m_gattlib_mutex);
|
|
|
|
return GATTLIB_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
OrgBluezDevice1* bluez_device = connection->backend.bluez_device;
|
|
|
|
g_object_ref(bluez_device);
|
|
|
|
g_rec_mutex_unlock(&m_gattlib_mutex);
|
2017-03-14 13:38:45 +01:00
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
const gchar* const* service_strs = org_bluez_device1_get_gatt_services(bluez_device);
|
2017-03-14 13:38:45 +01:00
|
|
|
const gchar* const* service_str;
|
|
|
|
const gchar* const* characteristic_strs;
|
2019-06-03 12:03:56 +02:00
|
|
|
const gchar* characteristic_str;
|
2017-03-14 13:38:45 +01:00
|
|
|
|
|
|
|
if (service_strs == NULL) {
|
2024-04-05 13:25:51 +02:00
|
|
|
ret = GATTLIB_INVALID_PARAMETER;
|
|
|
|
goto EXIT;
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Maximum number of primary services
|
|
|
|
int count_max = 0, count = 0;
|
|
|
|
for (service_str = service_strs; *service_str != NULL; service_str++) {
|
|
|
|
error = NULL;
|
|
|
|
OrgBluezGattService1* service_proxy = org_bluez_gatt_service1_proxy_new_for_bus_sync(
|
|
|
|
G_BUS_TYPE_SYSTEM,
|
2024-03-12 20:38:31 +01:00
|
|
|
G_DBUS_PROXY_FLAGS_NONE,
|
2017-03-14 13:38:45 +01:00
|
|
|
"org.bluez",
|
|
|
|
*service_str,
|
|
|
|
NULL,
|
|
|
|
&error);
|
|
|
|
if (service_proxy == NULL) {
|
2019-05-03 09:47:02 +02:00
|
|
|
if (error) {
|
2021-10-18 01:25:29 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Failed to open services '%s': %s", *service_str, error->message);
|
2019-05-03 09:47:02 +02:00
|
|
|
g_error_free(error);
|
|
|
|
} else {
|
2021-10-18 01:25:29 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Failed to open services '%s'.", *service_str);
|
2019-05-03 09:47:02 +02:00
|
|
|
}
|
2017-03-14 13:38:45 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
characteristic_strs = org_bluez_gatt_service1_get_characteristics(service_proxy);
|
|
|
|
if (characteristic_strs == NULL) {
|
2019-05-21 21:27:35 +02:00
|
|
|
g_object_unref(service_proxy);
|
2017-03-14 13:38:45 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-07-07 20:40:12 +02:00
|
|
|
for (characteristic_str = *characteristic_strs; characteristic_str != NULL; characteristic_str++) {
|
2019-06-03 12:03:56 +02:00
|
|
|
// Object path is in the form '/org/bluez/hci0/dev_DE_79_A2_A1_E9_FA/service0024/char0029'.
|
|
|
|
// We convert the last 4 hex characters into the handle
|
|
|
|
sscanf(characteristic_str + strlen(characteristic_str) - 4, "%x", &handle);
|
|
|
|
|
|
|
|
// Check if handle is in range
|
|
|
|
if ((handle < start) || (handle > end)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-03-14 13:38:45 +01:00
|
|
|
count_max++;
|
|
|
|
}
|
2019-05-21 21:27:35 +02:00
|
|
|
|
2017-03-14 13:38:45 +01:00
|
|
|
g_object_unref(service_proxy);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-03-28 14:26:22 +01:00
|
|
|
gattlib_characteristic_t* characteristic_list = calloc(count_max * sizeof(gattlib_characteristic_t), 1);
|
2017-03-14 13:38:45 +01:00
|
|
|
if (characteristic_list == NULL) {
|
2024-04-05 13:25:51 +02:00
|
|
|
ret = GATTLIB_OUT_OF_MEMORY;
|
|
|
|
goto EXIT;
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (service_str = service_strs; *service_str != NULL; service_str++) {
|
|
|
|
error = NULL;
|
|
|
|
OrgBluezGattService1* service_proxy = org_bluez_gatt_service1_proxy_new_for_bus_sync(
|
|
|
|
G_BUS_TYPE_SYSTEM,
|
2024-03-12 20:38:31 +01:00
|
|
|
G_DBUS_PROXY_FLAGS_NONE,
|
2017-03-14 13:38:45 +01:00
|
|
|
"org.bluez",
|
|
|
|
*service_str,
|
|
|
|
NULL,
|
|
|
|
&error);
|
|
|
|
if (service_proxy == NULL) {
|
2019-05-03 09:47:02 +02:00
|
|
|
if (error) {
|
2021-10-18 01:25:29 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Failed to open service '%s': %s", *service_str, error->message);
|
2019-05-03 09:47:02 +02:00
|
|
|
g_error_free(error);
|
|
|
|
} else {
|
2021-10-18 01:25:29 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Failed to open service '%s'.", *service_str);
|
2019-05-03 09:47:02 +02:00
|
|
|
}
|
2017-03-14 13:38:45 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
characteristic_strs = org_bluez_gatt_service1_get_characteristics(service_proxy);
|
|
|
|
if (characteristic_strs == NULL) {
|
2019-05-21 21:27:35 +02:00
|
|
|
g_object_unref(service_proxy);
|
2017-03-14 13:38:45 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-07-07 20:40:12 +02:00
|
|
|
for (characteristic_str = *characteristic_strs; characteristic_str != NULL; characteristic_str++) {
|
2019-06-03 12:03:56 +02:00
|
|
|
// Object path is in the form '/org/bluez/hci0/dev_DE_79_A2_A1_E9_FA/service0024/char0029'.
|
|
|
|
// We convert the last 4 hex characters into the handle
|
|
|
|
sscanf(characteristic_str + strlen(characteristic_str) - 4, "%x", &handle);
|
|
|
|
|
|
|
|
// Check if handle is in range
|
|
|
|
if ((handle < start) || (handle > end)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-03-14 13:38:45 +01:00
|
|
|
OrgBluezGattCharacteristic1 *characteristic_proxy = org_bluez_gatt_characteristic1_proxy_new_for_bus_sync(
|
|
|
|
G_BUS_TYPE_SYSTEM,
|
2024-03-12 20:38:31 +01:00
|
|
|
G_DBUS_PROXY_FLAGS_NONE,
|
2017-03-14 13:38:45 +01:00
|
|
|
"org.bluez",
|
2019-07-07 20:40:12 +02:00
|
|
|
characteristic_str,
|
2017-03-14 13:38:45 +01:00
|
|
|
NULL,
|
|
|
|
&error);
|
|
|
|
if (characteristic_proxy == NULL) {
|
2019-05-03 09:47:02 +02:00
|
|
|
if (error) {
|
2021-10-18 01:25:29 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Failed to open characteristic '%s': %s", characteristic_str, error->message);
|
2019-05-03 09:47:02 +02:00
|
|
|
g_error_free(error);
|
|
|
|
} else {
|
2021-10-18 01:25:29 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Failed to open characteristic '%s'.", characteristic_str);
|
2019-05-03 09:47:02 +02:00
|
|
|
}
|
2017-03-14 13:38:45 +01:00
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
characteristic_list[count].handle = 0;
|
|
|
|
characteristic_list[count].value_handle = 0;
|
2021-07-27 07:08:15 +02:00
|
|
|
characteristic_list[count].properties = 0;
|
2017-03-14 13:38:45 +01:00
|
|
|
|
|
|
|
const gchar *const * flags = org_bluez_gatt_characteristic1_get_flags(characteristic_proxy);
|
|
|
|
for (; *flags != NULL; flags++) {
|
|
|
|
if (strcmp(*flags,"broadcast") == 0) {
|
|
|
|
characteristic_list[count].properties |= GATTLIB_CHARACTERISTIC_BROADCAST;
|
|
|
|
} else if (strcmp(*flags,"read") == 0) {
|
|
|
|
characteristic_list[count].properties |= GATTLIB_CHARACTERISTIC_READ;
|
|
|
|
} else if (strcmp(*flags,"write") == 0) {
|
|
|
|
characteristic_list[count].properties |= GATTLIB_CHARACTERISTIC_WRITE;
|
|
|
|
} else if (strcmp(*flags,"write-without-response") == 0) {
|
|
|
|
characteristic_list[count].properties |= GATTLIB_CHARACTERISTIC_WRITE_WITHOUT_RESP;
|
|
|
|
} else if (strcmp(*flags,"notify") == 0) {
|
|
|
|
characteristic_list[count].properties |= GATTLIB_CHARACTERISTIC_NOTIFY;
|
|
|
|
} else if (strcmp(*flags,"indicate") == 0) {
|
|
|
|
characteristic_list[count].properties |= GATTLIB_CHARACTERISTIC_INDICATE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gattlib_string_to_uuid(
|
|
|
|
org_bluez_gatt_characteristic1_get_uuid(characteristic_proxy),
|
|
|
|
MAX_LEN_UUID_STR + 1,
|
|
|
|
&characteristic_list[count].uuid);
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
g_object_unref(characteristic_proxy);
|
|
|
|
}
|
|
|
|
g_object_unref(service_proxy);
|
|
|
|
}
|
|
|
|
|
2019-06-03 12:03:56 +02:00
|
|
|
*characteristics = characteristic_list;
|
|
|
|
*characteristics_count = count;
|
2024-04-05 13:25:51 +02:00
|
|
|
|
|
|
|
EXIT:
|
|
|
|
g_object_unref(bluez_device);
|
|
|
|
return ret;
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
#else
|
2024-04-05 11:43:21 +02:00
|
|
|
static void add_characteristics_from_service(struct _gattlib_connection_backend* backend, GDBusObjectManager *device_manager,
|
2020-04-08 15:43:30 +02:00
|
|
|
const char* service_object_path,
|
2024-03-07 23:57:58 +01:00
|
|
|
unsigned int start, unsigned int end,
|
2020-04-08 15:43:30 +02:00
|
|
|
gattlib_characteristic_t* characteristic_list, int* count)
|
2019-06-03 12:03:56 +02:00
|
|
|
{
|
2017-03-14 13:38:45 +01:00
|
|
|
GError *error = NULL;
|
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
for (GList *l = backend->dbus_objects; l != NULL; l = l->next) {
|
2017-03-14 13:38:45 +01:00
|
|
|
GDBusObject *object = l->data;
|
|
|
|
const char* object_path = g_dbus_object_get_object_path(G_DBUS_OBJECT(object));
|
|
|
|
GDBusInterface *interface = g_dbus_object_manager_get_interface(device_manager, object_path, "org.bluez.GattCharacteristic1");
|
|
|
|
if (!interface) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-07-18 20:26:16 +02:00
|
|
|
g_object_unref(interface);
|
|
|
|
|
2017-03-14 13:38:45 +01:00
|
|
|
OrgBluezGattCharacteristic1* characteristic = org_bluez_gatt_characteristic1_proxy_new_for_bus_sync(
|
|
|
|
G_BUS_TYPE_SYSTEM,
|
2024-03-12 20:38:31 +01:00
|
|
|
G_DBUS_PROXY_FLAGS_NONE,
|
2017-03-14 13:38:45 +01:00
|
|
|
"org.bluez",
|
|
|
|
object_path,
|
|
|
|
NULL,
|
|
|
|
&error);
|
|
|
|
if (characteristic == NULL) {
|
2019-05-03 09:47:02 +02:00
|
|
|
if (error) {
|
2021-10-18 01:25:29 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Failed to open characteristic '%s': %s", object_path, error->message);
|
2019-05-03 09:47:02 +02:00
|
|
|
g_error_free(error);
|
|
|
|
} else {
|
2021-10-18 01:25:29 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Failed to open characteristic '%s'.", object_path);
|
2019-05-03 09:47:02 +02:00
|
|
|
}
|
2017-03-14 13:38:45 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-03-04 10:21:16 +01:00
|
|
|
const gchar * property_value = org_bluez_gatt_characteristic1_get_service(characteristic);
|
|
|
|
if (property_value == NULL){
|
|
|
|
if (error) {
|
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Failed to get service '%s': %s", object_path, error->message);
|
|
|
|
g_error_free(error);
|
|
|
|
} else {
|
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Failed to get service '%s'.", object_path);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (strcmp(property_value, service_object_path)) {
|
2019-05-21 21:27:35 +02:00
|
|
|
g_object_unref(characteristic);
|
2017-03-14 13:38:45 +01:00
|
|
|
continue;
|
|
|
|
} else {
|
2024-03-07 23:57:58 +01:00
|
|
|
unsigned int handle;
|
2019-06-03 12:03:56 +02:00
|
|
|
|
|
|
|
// Object path is in the form '/org/bluez/hci0/dev_DE_79_A2_A1_E9_FA/service0024/char0029'.
|
|
|
|
// We convert the last 4 hex characters into the handle
|
|
|
|
sscanf(object_path + strlen(object_path) - 4, "%x", &handle);
|
|
|
|
|
|
|
|
// Check if handle is in range
|
|
|
|
if ((handle < start) || (handle > end)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
characteristic_list[*count].handle = handle;
|
|
|
|
characteristic_list[*count].value_handle = handle;
|
2021-07-27 07:08:15 +02:00
|
|
|
characteristic_list[*count].properties = 0;
|
2017-03-14 13:38:45 +01:00
|
|
|
|
|
|
|
const gchar *const * flags = org_bluez_gatt_characteristic1_get_flags(characteristic);
|
|
|
|
for (; *flags != NULL; flags++) {
|
|
|
|
if (strcmp(*flags,"broadcast") == 0) {
|
|
|
|
characteristic_list[*count].properties |= GATTLIB_CHARACTERISTIC_BROADCAST;
|
|
|
|
} else if (strcmp(*flags,"read") == 0) {
|
|
|
|
characteristic_list[*count].properties |= GATTLIB_CHARACTERISTIC_READ;
|
|
|
|
} else if (strcmp(*flags,"write") == 0) {
|
|
|
|
characteristic_list[*count].properties |= GATTLIB_CHARACTERISTIC_WRITE;
|
|
|
|
} else if (strcmp(*flags,"write-without-response") == 0) {
|
|
|
|
characteristic_list[*count].properties |= GATTLIB_CHARACTERISTIC_WRITE_WITHOUT_RESP;
|
|
|
|
} else if (strcmp(*flags,"notify") == 0) {
|
|
|
|
characteristic_list[*count].properties |= GATTLIB_CHARACTERISTIC_NOTIFY;
|
|
|
|
} else if (strcmp(*flags,"indicate") == 0) {
|
|
|
|
characteristic_list[*count].properties |= GATTLIB_CHARACTERISTIC_INDICATE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gattlib_string_to_uuid(
|
|
|
|
org_bluez_gatt_characteristic1_get_uuid(characteristic),
|
|
|
|
MAX_LEN_UUID_STR + 1,
|
|
|
|
&characteristic_list[*count].uuid);
|
|
|
|
*count = *count + 1;
|
|
|
|
}
|
2019-05-21 21:27:35 +02:00
|
|
|
|
|
|
|
g_object_unref(characteristic);
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
int gattlib_discover_char_range(gattlib_connection_t* connection, uint16_t start, uint16_t end, gattlib_characteristic_t** characteristics, int* characteristics_count) {
|
2017-03-14 13:38:45 +01:00
|
|
|
GError *error = NULL;
|
2024-04-05 13:25:51 +02:00
|
|
|
GDBusObjectManager *device_manager;
|
2017-03-14 13:38:45 +01:00
|
|
|
GList *l;
|
2024-04-05 13:25:51 +02:00
|
|
|
int ret = GATTLIB_SUCCESS;
|
|
|
|
|
|
|
|
g_rec_mutex_lock(&m_gattlib_mutex);
|
|
|
|
|
|
|
|
if (!gattlib_device_is_valid(connection->device)) {
|
|
|
|
ret = GATTLIB_INVALID_PARAMETER;
|
|
|
|
goto EXIT;
|
|
|
|
}
|
2017-03-14 13:38:45 +01:00
|
|
|
|
2024-04-05 13:25:51 +02:00
|
|
|
device_manager = get_device_manager_from_adapter(connection->device->adapter, &error);
|
2017-03-14 13:38:45 +01:00
|
|
|
if (device_manager == NULL) {
|
2024-02-15 21:44:34 +01:00
|
|
|
if (error != NULL) {
|
|
|
|
ret = GATTLIB_ERROR_DBUS_WITH_ERROR(error);
|
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Gattlib Context not initialized (%d, %d).", error->domain, error->code);
|
|
|
|
g_error_free(error);
|
|
|
|
} else {
|
|
|
|
ret = GATTLIB_ERROR_DBUS;
|
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Gattlib Context not initialized.");
|
|
|
|
}
|
2024-04-05 13:25:51 +02:00
|
|
|
goto EXIT;
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Count the maximum number of characteristic to allocate the array (we count all the characterstic for all devices)
|
|
|
|
int count_max = 0, count = 0;
|
2024-04-05 11:43:21 +02:00
|
|
|
for (l = connection->backend.dbus_objects; l != NULL; l = l->next) {
|
2017-03-14 13:38:45 +01:00
|
|
|
GDBusObject *object = l->data;
|
|
|
|
const char* object_path = g_dbus_object_get_object_path(G_DBUS_OBJECT(object));
|
|
|
|
GDBusInterface *interface = g_dbus_object_manager_get_interface(device_manager, object_path, "org.bluez.GattCharacteristic1");
|
|
|
|
if (!interface) {
|
2022-05-16 20:56:00 +02:00
|
|
|
// Check if this DBUS Path is actually the Battery interface
|
|
|
|
interface = g_dbus_object_manager_get_interface(device_manager, object_path, "org.bluez.Battery1");
|
|
|
|
if (!interface) {
|
|
|
|
continue;
|
|
|
|
}
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
2019-07-18 20:26:16 +02:00
|
|
|
|
|
|
|
g_object_unref(interface);
|
|
|
|
|
2017-03-14 13:38:45 +01:00
|
|
|
count_max++;
|
|
|
|
}
|
|
|
|
|
2024-03-28 14:26:22 +01:00
|
|
|
gattlib_characteristic_t* characteristic_list = calloc(count_max * sizeof(gattlib_characteristic_t), 1);
|
2017-03-14 13:38:45 +01:00
|
|
|
if (characteristic_list == NULL) {
|
2024-04-05 13:25:51 +02:00
|
|
|
ret = GATTLIB_OUT_OF_MEMORY;
|
|
|
|
goto EXIT;
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// List all services for this device
|
2024-04-05 11:43:21 +02:00
|
|
|
for (l = connection->backend.dbus_objects; l != NULL; l = l->next) {
|
2017-03-14 13:38:45 +01:00
|
|
|
GDBusObject *object = l->data;
|
|
|
|
const char* object_path = g_dbus_object_get_object_path(G_DBUS_OBJECT(object));
|
|
|
|
|
|
|
|
GDBusInterface *interface = g_dbus_object_manager_get_interface(device_manager, object_path, "org.bluez.GattService1");
|
|
|
|
if (!interface) {
|
2022-05-16 20:56:00 +02:00
|
|
|
// Check if this DBUS Path is actually the Battery interface. In this case,
|
|
|
|
// we add a fake characteristic for the battery.
|
|
|
|
interface = g_dbus_object_manager_get_interface(device_manager, object_path, "org.bluez.Battery1");
|
|
|
|
if (interface) {
|
|
|
|
g_object_unref(interface);
|
2024-02-08 00:06:09 +01:00
|
|
|
|
2022-05-16 20:56:00 +02:00
|
|
|
characteristic_list[count].handle = 0;
|
|
|
|
characteristic_list[count].value_handle = 0;
|
|
|
|
characteristic_list[count].properties = GATTLIB_CHARACTERISTIC_READ | GATTLIB_CHARACTERISTIC_NOTIFY;
|
|
|
|
|
|
|
|
gattlib_string_to_uuid(
|
|
|
|
"00002a19-0000-1000-8000-00805f9b34fb",
|
|
|
|
MAX_LEN_UUID_STR + 1,
|
|
|
|
&characteristic_list[count].uuid);
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
2017-03-14 13:38:45 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-07-18 20:26:16 +02:00
|
|
|
g_object_unref(interface);
|
|
|
|
|
2017-03-14 13:38:45 +01:00
|
|
|
error = NULL;
|
|
|
|
OrgBluezGattService1* service_proxy = org_bluez_gatt_service1_proxy_new_for_bus_sync(
|
|
|
|
G_BUS_TYPE_SYSTEM,
|
2024-03-12 20:38:31 +01:00
|
|
|
G_DBUS_PROXY_FLAGS_NONE,
|
2017-03-14 13:38:45 +01:00
|
|
|
"org.bluez",
|
|
|
|
object_path,
|
|
|
|
NULL,
|
|
|
|
&error);
|
|
|
|
if (service_proxy == NULL) {
|
2019-05-03 09:47:02 +02:00
|
|
|
if (error) {
|
2021-10-18 01:25:29 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Failed to open service '%s': %s", object_path, error->message);
|
2019-05-03 09:47:02 +02:00
|
|
|
g_error_free(error);
|
|
|
|
} else {
|
2021-10-18 01:25:29 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Failed to open service '%s'.", object_path);
|
2019-05-03 09:47:02 +02:00
|
|
|
}
|
2017-03-14 13:38:45 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure the service is attached to this device
|
|
|
|
const char* service_object_path = org_bluez_gatt_service1_get_device(service_proxy);
|
2024-04-05 11:43:21 +02:00
|
|
|
if (strcmp(connection->backend.device_object_path, service_object_path)) {
|
2019-05-21 21:27:35 +02:00
|
|
|
g_object_unref(service_proxy);
|
2017-03-14 13:38:45 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add all characteristics attached to this service
|
2024-04-05 11:43:21 +02:00
|
|
|
add_characteristics_from_service(&connection->backend, device_manager, object_path, start, end, characteristic_list, &count);
|
2019-05-21 21:27:35 +02:00
|
|
|
g_object_unref(service_proxy);
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
|
2019-06-03 12:03:56 +02:00
|
|
|
*characteristics = characteristic_list;
|
|
|
|
*characteristics_count = count;
|
2024-04-05 13:25:51 +02:00
|
|
|
EXIT:
|
|
|
|
g_rec_mutex_unlock(&m_gattlib_mutex);
|
|
|
|
return ret;
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
int gattlib_discover_char(gattlib_connection_t* connection, gattlib_characteristic_t** characteristics, int* characteristics_count)
|
2019-06-03 12:03:56 +02:00
|
|
|
{
|
|
|
|
return gattlib_discover_char_range(connection, 0x00, 0xFF, characteristics, characteristics_count);
|
|
|
|
}
|
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
int gattlib_discover_desc_range(gattlib_connection_t* connection, int start, int end, gattlib_descriptor_t** descriptors, int* descriptor_count) {
|
2019-05-21 21:25:04 +02:00
|
|
|
return GATTLIB_NOT_SUPPORTED;
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
int gattlib_discover_desc(gattlib_connection_t* connection, gattlib_descriptor_t** descriptors, int* descriptor_count) {
|
2019-05-21 21:25:04 +02:00
|
|
|
return GATTLIB_NOT_SUPPORTED;
|
2017-03-14 13:38:45 +01:00
|
|
|
}
|
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
int get_bluez_device_from_mac(struct _gattlib_adapter *adapter, const char *mac_address, OrgBluezDevice1 **bluez_device1)
|
2019-07-09 18:17:28 +02:00
|
|
|
{
|
|
|
|
GError *error = NULL;
|
2024-04-05 13:25:51 +02:00
|
|
|
char object_path[GATTLIB_DBUS_OBJECT_PATH_SIZE_MAX];
|
|
|
|
|
|
|
|
g_rec_mutex_lock(&m_gattlib_mutex);
|
|
|
|
|
|
|
|
if (!gattlib_adapter_is_valid(adapter)) {
|
|
|
|
g_rec_mutex_unlock(&m_gattlib_mutex);
|
|
|
|
return GATTLIB_INVALID_PARAMETER;
|
|
|
|
}
|
2019-07-09 18:17:28 +02:00
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
if (adapter->backend.adapter_proxy == NULL) {
|
2024-04-05 13:25:51 +02:00
|
|
|
g_rec_mutex_unlock(&m_gattlib_mutex);
|
2024-02-20 23:23:39 +01:00
|
|
|
return GATTLIB_NO_ADAPTER;
|
|
|
|
}
|
|
|
|
|
2019-07-09 18:17:28 +02:00
|
|
|
if (adapter != NULL) {
|
2024-04-05 11:43:21 +02:00
|
|
|
get_device_path_from_mac_with_adapter(adapter->backend.adapter_proxy, mac_address, object_path, sizeof(object_path));
|
2019-07-09 18:17:28 +02:00
|
|
|
} else {
|
|
|
|
get_device_path_from_mac(NULL, mac_address, object_path, sizeof(object_path));
|
|
|
|
}
|
|
|
|
|
2024-04-05 13:25:51 +02:00
|
|
|
// No need to keep the mutex longer. After it is DBUS specific operations not depending on gattlib structure
|
|
|
|
g_rec_mutex_unlock(&m_gattlib_mutex);
|
|
|
|
|
2019-07-14 23:26:47 +02:00
|
|
|
*bluez_device1 = org_bluez_device1_proxy_new_for_bus_sync(
|
2019-07-09 18:17:28 +02:00
|
|
|
G_BUS_TYPE_SYSTEM,
|
2024-03-12 20:38:31 +01:00
|
|
|
G_DBUS_PROXY_FLAGS_NONE,
|
2019-07-09 18:17:28 +02:00
|
|
|
"org.bluez",
|
|
|
|
object_path,
|
|
|
|
NULL,
|
|
|
|
&error);
|
|
|
|
if (error) {
|
2021-10-18 01:25:29 +02:00
|
|
|
GATTLIB_LOG(GATTLIB_ERROR, "Failed to connection to new DBus Bluez Device: %s", error->message);
|
2019-07-09 18:17:28 +02:00
|
|
|
g_error_free(error);
|
2024-04-05 13:25:51 +02:00
|
|
|
return GATTLIB_ERROR_DBUS_WITH_ERROR(error);
|
2019-07-09 18:17:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return GATTLIB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
int gattlib_get_rssi(gattlib_connection_t *connection, int16_t *rssi)
|
2019-07-09 14:03:06 +02:00
|
|
|
{
|
2024-04-05 13:25:51 +02:00
|
|
|
if (rssi == NULL) {
|
|
|
|
return GATTLIB_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_rec_mutex_lock(&m_gattlib_mutex);
|
|
|
|
|
2022-05-13 22:38:06 +02:00
|
|
|
if (connection == NULL) {
|
2024-04-05 13:25:51 +02:00
|
|
|
g_rec_mutex_unlock(&m_gattlib_mutex);
|
2022-05-13 22:38:06 +02:00
|
|
|
return GATTLIB_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
2024-04-05 13:25:51 +02:00
|
|
|
if (!gattlib_device_is_valid(connection->device)) {
|
|
|
|
g_rec_mutex_unlock(&m_gattlib_mutex);
|
2019-07-14 23:26:47 +02:00
|
|
|
return GATTLIB_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
2024-04-05 13:25:51 +02:00
|
|
|
// device is actually a GObject. Increasing its reference counter prevents to
|
|
|
|
// be freed if the connection is released.
|
|
|
|
OrgBluezDevice1* dbus_device = connection->backend.device;
|
|
|
|
g_object_ref(dbus_device);
|
|
|
|
g_rec_mutex_unlock(&m_gattlib_mutex);
|
|
|
|
|
|
|
|
*rssi = org_bluez_device1_get_rssi(dbus_device);
|
|
|
|
|
|
|
|
g_object_unref(dbus_device);
|
2019-07-14 23:26:47 +02:00
|
|
|
|
|
|
|
return GATTLIB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2024-04-05 11:43:21 +02:00
|
|
|
int gattlib_get_rssi_from_mac(gattlib_adapter_t* adapter, const char *mac_address, int16_t *rssi)
|
2019-07-14 23:26:47 +02:00
|
|
|
{
|
|
|
|
OrgBluezDevice1 *bluez_device1;
|
|
|
|
int ret;
|
|
|
|
|
2021-03-18 23:49:58 +01:00
|
|
|
if (rssi == NULL || mac_address == NULL) {
|
2019-07-14 23:26:47 +02:00
|
|
|
return GATTLIB_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
2024-04-05 13:25:51 +02:00
|
|
|
//
|
|
|
|
// No need of locking the mutex in this function. get_bluez_device_from_mac() ensures the adapter is valid.
|
|
|
|
//
|
|
|
|
|
2019-07-14 23:26:47 +02:00
|
|
|
ret = get_bluez_device_from_mac(adapter, mac_address, &bluez_device1);
|
|
|
|
if (ret != GATTLIB_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
*rssi = org_bluez_device1_get_rssi(bluez_device1);
|
2019-07-18 20:26:16 +02:00
|
|
|
|
|
|
|
g_object_unref(bluez_device1);
|
2019-07-14 23:26:47 +02:00
|
|
|
return GATTLIB_SUCCESS;
|
2019-07-09 14:03:06 +02:00
|
|
|
}
|