mirror of https://github.com/labapart/gattlib
dbus: Make gattlib based on D-Bus
parent
076067a2d7
commit
d998e0072a
|
@ -27,6 +27,8 @@ include(CrossCompilation.cmake)
|
|||
|
||||
project(gattlib)
|
||||
|
||||
set(GATTLIB_DBUS TRUE CACHE BOOLEAN "Build gattlib with D-Bus support")
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
# Show all the warnings
|
||||
|
@ -34,11 +36,17 @@ set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
|||
# Expose 'gattlib.h' to all sub-directories
|
||||
include_directories(include)
|
||||
|
||||
# Build bluez-based gattlib
|
||||
add_subdirectory(bluez)
|
||||
if (GATTLIB_DBUS)
|
||||
# Build dbus-based gattlib
|
||||
add_subdirectory(dbus)
|
||||
else()
|
||||
# Build bluez-based gattlib
|
||||
add_subdirectory(bluez)
|
||||
endif()
|
||||
|
||||
# Generate pkg-config file before building the examples
|
||||
configure_file(gattlib.pc.in gattlib.pc @ONLY)
|
||||
configure_file(dbus/gattlib.pc.in ${PROJECT_BINARY_DIR}/gattlib.pc @ONLY)
|
||||
|
||||
# Add the build directory to PKG_CONFIG_PATH
|
||||
set(ENV{PKG_CONFIG_PATH} "${PROJECT_BINARY_DIR}:$ENV{PKG_CONFIG_PATH}")
|
||||
|
||||
|
@ -46,9 +54,13 @@ set(ENV{PKG_CONFIG_PATH} "${PROJECT_BINARY_DIR}:$ENV{PKG_CONFIG_PATH}")
|
|||
add_subdirectory(examples/ble_scan)
|
||||
add_subdirectory(examples/discover)
|
||||
add_subdirectory(examples/read_write)
|
||||
add_subdirectory(examples/gatttool)
|
||||
add_subdirectory(examples/nordic_uart)
|
||||
|
||||
# Some examples require Bluez code and other DBus support
|
||||
if (NOT GATTLIB_DBUS)
|
||||
add_subdirectory(examples/gatttool)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Packaging
|
||||
#
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
#
|
||||
# GattLib - GATT Library
|
||||
#
|
||||
# Copyright (C) 2017 Olivier Martin <olivier@labapart.org>
|
||||
#
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
# Added Glib support to ensure we have 'gdbus-codegen'
|
||||
pkg_search_module(GLIB REQUIRED glib-2.0)
|
||||
|
||||
# For DBus support
|
||||
pkg_search_module(GIO_UNIX REQUIRED gio-unix-2.0)
|
||||
|
||||
# Needed by 'bluez5/lib/uuid.c'
|
||||
pkg_search_module(BLUEZ REQUIRED bluez)
|
||||
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/org-bluez-adaptater1.c
|
||||
COMMAND gdbus-codegen --interface-prefix org.bluez.Adapter1. --generate-c-code ${CMAKE_CURRENT_BINARY_DIR}/org-bluez-adaptater1 ${CMAKE_CURRENT_SOURCE_DIR}/interfaces/org.bluez.Adapter1.xml
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/interfaces/org.bluez.Adapter1.xml
|
||||
COMMENT "Generate D-Bus 'org.bluez.Adapter1.xml'"
|
||||
)
|
||||
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/org-bluez-device1.c
|
||||
COMMAND gdbus-codegen --interface-prefix org.bluez.Device1. --generate-c-code ${CMAKE_CURRENT_BINARY_DIR}/org-bluez-device1 ${CMAKE_CURRENT_SOURCE_DIR}/interfaces/org.bluez.Device1.xml
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/interfaces/org.bluez.Device1.xml
|
||||
COMMENT "Generate D-Bus 'org.bluez.Device1.xml'"
|
||||
)
|
||||
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/org-bluez-gattservice1.c
|
||||
COMMAND gdbus-codegen --interface-prefix org.bluez.GattService1. --generate-c-code ${CMAKE_CURRENT_BINARY_DIR}/org-bluez-gattservice1 ${CMAKE_CURRENT_SOURCE_DIR}/interfaces/org.bluez.GattService1.xml
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/interfaces/org.bluez.GattService1.xml
|
||||
COMMENT "Generate D-Bus 'org.bluez.GattService1.xml'"
|
||||
)
|
||||
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/org-bluez-gattcharacteristic1.c
|
||||
COMMAND gdbus-codegen --interface-prefix org.bluez.Characteristic1. --generate-c-code ${CMAKE_CURRENT_BINARY_DIR}/org-bluez-gattcharacteristic1 ${CMAKE_CURRENT_SOURCE_DIR}/interfaces/org.bluez.GattCharacteristic1.xml
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/interfaces/org.bluez.GattCharacteristic1.xml
|
||||
COMMENT "Generate D-Bus 'org.bluez.GattCharacteristic1.xml'"
|
||||
)
|
||||
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/org-bluez-gattdescriptor1.c
|
||||
COMMAND gdbus-codegen --interface-prefix org.bluez.Descriptor1. --generate-c-code ${CMAKE_CURRENT_BINARY_DIR}/org-bluez-gattdescriptor1 ${CMAKE_CURRENT_SOURCE_DIR}/interfaces/org.bluez.GattDescriptor1.xml
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/interfaces/org.bluez.GattDescriptor1.xml
|
||||
COMMENT "Generate D-Bus 'org.bluez.GattDescriptor1.xml'"
|
||||
)
|
||||
|
||||
# Extract Bluez version
|
||||
string(REPLACE "." ";" BLUEZ_VERSIONS "${BLUEZ_VERSION}")
|
||||
list(GET BLUEZ_VERSIONS 0 BLUEZ_VERSION_MAJOR)
|
||||
list(GET BLUEZ_VERSIONS 1 BLUEZ_VERSION_MINOR)
|
||||
add_definitions(-DBLUEZ_VERSION_MAJOR=${BLUEZ_VERSION_MAJOR} -DBLUEZ_VERSION_MINOR=${BLUEZ_VERSION_MINOR})
|
||||
message("Build gattlib for Bluez v${BLUEZ_VERSION_MAJOR}.${BLUEZ_VERSION_MINOR}")
|
||||
|
||||
include_directories(. ${CMAKE_CURRENT_BINARY_DIR} ${GIO_UNIX_INCLUDE_DIRS} ${BLUEZ_INCLUDE_DIRS})
|
||||
|
||||
set(gattlib_SRCS gattlib.c
|
||||
bluez5/lib/uuid.c
|
||||
../gattlib_common.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/org-bluez-adaptater1.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/org-bluez-device1.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/org-bluez-gattcharacteristic1.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/org-bluez-gattdescriptor1.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/org-bluez-gattservice1.c)
|
||||
|
||||
set(gattlib_LIBS ${GLIB_LIBRARIES} ${GIO_UNIX_LIBRARIES})
|
||||
|
||||
# Gattlib
|
||||
add_library(gattlib SHARED ${gattlib_SRCS})
|
||||
target_link_libraries(gattlib ${gattlib_LIBS})
|
||||
|
||||
install(TARGETS gattlib LIBRARY DESTINATION lib)
|
|
@ -0,0 +1,836 @@
|
|||
/*
|
||||
*
|
||||
* GattLib - GATT Library
|
||||
*
|
||||
* Copyright (C) 2016-2017 Olivier Martin <olivier@labapart.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "gattlib_internal.h"
|
||||
|
||||
#define CONNECT_TIMEOUT 4
|
||||
|
||||
int gattlib_adapter_open(const char* adapter_name, void** adapter) {
|
||||
char object_path[20];
|
||||
OrgBluezAdapter1 *adapter_proxy;
|
||||
GError *error = NULL;
|
||||
|
||||
if (adapter_name) {
|
||||
snprintf(object_path, sizeof(object_path), "/org/bluez/%s", adapter_name);
|
||||
} else {
|
||||
strncpy(object_path, "/org/bluez/hci0", sizeof(object_path));
|
||||
}
|
||||
|
||||
adapter_proxy = org_bluez_adapter1_proxy_new_for_bus_sync(
|
||||
G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE,
|
||||
"org.bluez",
|
||||
object_path,
|
||||
NULL, &error);
|
||||
if (adapter_proxy == NULL) {
|
||||
printf("Failed to get adapter %s\n", object_path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Ensure the adapter is powered on
|
||||
org_bluez_adapter1_set_powered(adapter_proxy, TRUE);
|
||||
|
||||
*adapter = adapter_proxy;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gboolean stop_scan_func(gpointer data) {
|
||||
g_main_loop_quit(data);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void on_dbus_object_added(GDBusObjectManager *device_manager,
|
||||
GDBusObject *object,
|
||||
gpointer user_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.Device1");
|
||||
if (!interface) {
|
||||
return;
|
||||
}
|
||||
|
||||
GError *error = NULL;
|
||||
OrgBluezDevice1* device1 = org_bluez_device1_proxy_new_for_bus_sync(
|
||||
G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
|
||||
"org.bluez",
|
||||
object_path,
|
||||
NULL,
|
||||
&error);
|
||||
|
||||
if (device1) {
|
||||
gattlib_discovered_device_t discovered_device_cb = user_data;
|
||||
|
||||
discovered_device_cb(
|
||||
org_bluez_device1_get_address(device1),
|
||||
org_bluez_device1_get_name(device1));
|
||||
g_object_unref(device1);
|
||||
}
|
||||
}
|
||||
|
||||
int gattlib_adapter_scan_enable(void* adapter, gattlib_discovered_device_t discovered_device_cb, int timeout) {
|
||||
GDBusObjectManager *device_manager;
|
||||
GError *error = NULL;
|
||||
|
||||
org_bluez_adapter1_call_start_discovery_sync((OrgBluezAdapter1*)adapter, NULL, &error);
|
||||
|
||||
//
|
||||
// Get notification when objects are removed from the Bluez ObjectManager.
|
||||
// We should get notified when the connection is lost with the target to allow
|
||||
// us to advertise us again
|
||||
//
|
||||
device_manager = g_dbus_object_manager_client_new_for_bus_sync (
|
||||
G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
|
||||
"org.bluez",
|
||||
"/",
|
||||
NULL, NULL, NULL, NULL,
|
||||
&error);
|
||||
if (device_manager == NULL) {
|
||||
puts("Failed to get Bluez Device Manager.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
GList *objects = g_dbus_object_manager_get_objects(device_manager);
|
||||
GList *l;
|
||||
for (l = objects; l != NULL; l = l->next) {
|
||||
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.Device1");
|
||||
if (!interface) {
|
||||
continue;
|
||||
}
|
||||
|
||||
error = NULL;
|
||||
OrgBluezDevice1* device1 = org_bluez_device1_proxy_new_for_bus_sync(
|
||||
G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
|
||||
"org.bluez",
|
||||
object_path,
|
||||
NULL,
|
||||
&error);
|
||||
|
||||
if (device1) {
|
||||
discovered_device_cb(
|
||||
org_bluez_device1_get_address(device1),
|
||||
org_bluez_device1_get_name(device1));
|
||||
g_object_unref(device1);
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free_full(objects, g_object_unref);
|
||||
|
||||
g_signal_connect (G_DBUS_OBJECT_MANAGER(device_manager),
|
||||
"object-added",
|
||||
G_CALLBACK (on_dbus_object_added),
|
||||
discovered_device_cb);
|
||||
|
||||
// Run Glib loop for 'timeout' seconds
|
||||
GMainLoop *loop = g_main_loop_new(NULL, 0);
|
||||
g_timeout_add_seconds (timeout, stop_scan_func, loop);
|
||||
g_main_loop_run(loop);
|
||||
g_main_loop_unref(loop);
|
||||
|
||||
g_object_unref(device_manager);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gattlib_adapter_scan_disable(void* adapter) {
|
||||
GError *error = NULL;
|
||||
|
||||
org_bluez_adapter1_call_stop_discovery_sync((OrgBluezAdapter1*)adapter, NULL, &error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gattlib_adapter_close(void* adapter) {
|
||||
g_object_unref(adapter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
gboolean on_handle_device_property_change(
|
||||
OrgBluezGattCharacteristic1 *object,
|
||||
GVariant *arg_changed_properties,
|
||||
const gchar *const *arg_invalidated_properties,
|
||||
gpointer user_data)
|
||||
{
|
||||
GMainLoop *loop = user_data;
|
||||
|
||||
// Retrieve 'Value' from 'arg_changed_properties'
|
||||
if (g_variant_n_children (arg_changed_properties) > 0) {
|
||||
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)) {
|
||||
if (strcmp(key, "UUIDs") == 0) {
|
||||
g_main_loop_quit(loop);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param src Local Adaptater interface
|
||||
* @param dst Remote Bluetooth address
|
||||
* @param dst_type Set LE address type (either BDADDR_LE_PUBLIC or BDADDR_LE_RANDOM)
|
||||
* @param sec_level Set security level (either BT_IO_SEC_LOW, BT_IO_SEC_MEDIUM, BT_IO_SEC_HIGH)
|
||||
* @param psm Specify the PSM for GATT/ATT over BR/EDR
|
||||
* @param mtu Specify the MTU size
|
||||
*/
|
||||
gatt_connection_t *gattlib_connect(const char *src, const char *dst,
|
||||
uint8_t dest_type, gattlib_bt_sec_level_t sec_level, int psm, int mtu)
|
||||
{
|
||||
GError *error = NULL;
|
||||
const char* adapter_name;
|
||||
char device_address_str[20];
|
||||
char object_path[100];
|
||||
int i;
|
||||
|
||||
if (src) {
|
||||
adapter_name = src;
|
||||
} else {
|
||||
adapter_name = "hci0";
|
||||
}
|
||||
|
||||
// Transform string from 'DA:94:40:95:E0:87' to 'dev_DA_94_40_95_E0_87'
|
||||
strncpy(device_address_str, dst, sizeof(device_address_str));
|
||||
for (i = 0; i < strlen(device_address_str); i++) {
|
||||
if (device_address_str[i] == ':') {
|
||||
device_address_str[i] = '_';
|
||||
}
|
||||
}
|
||||
|
||||
// Generate object path like: /org/bluez/hci0/dev_DA_94_40_95_E0_87
|
||||
snprintf(object_path, sizeof(object_path), "/org/bluez/%s/dev_%s", adapter_name, device_address_str);
|
||||
|
||||
gatt_connection_t* connection = calloc(sizeof(gatt_connection_t), 1);
|
||||
if (connection == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
OrgBluezDevice1* device = org_bluez_device1_proxy_new_for_bus_sync(
|
||||
G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
|
||||
"org.bluez",
|
||||
object_path,
|
||||
NULL,
|
||||
&error);
|
||||
if (device == NULL) {
|
||||
goto FREE_CONNECTION;
|
||||
} else {
|
||||
connection->io = device;
|
||||
}
|
||||
|
||||
error = NULL;
|
||||
org_bluez_device1_call_connect_sync(device, NULL, &error);
|
||||
if (error) {
|
||||
printf("Device connected error: %s\n", error->message);
|
||||
goto FREE_DEVICE;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// Register a handle for notification
|
||||
g_signal_connect(device,
|
||||
"g-properties-changed",
|
||||
G_CALLBACK (on_handle_device_property_change),
|
||||
loop);
|
||||
|
||||
g_timeout_add_seconds (CONNECT_TIMEOUT, stop_scan_func, loop);
|
||||
g_main_loop_run(loop);
|
||||
g_main_loop_unref(loop);
|
||||
|
||||
return connection;
|
||||
|
||||
FREE_DEVICE:
|
||||
g_object_unref(connection->io);
|
||||
|
||||
FREE_CONNECTION:
|
||||
free(connection);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gatt_connection_t *gattlib_connect_async(const char *src, const char *dst,
|
||||
uint8_t dest_type, gattlib_bt_sec_level_t sec_level, int psm, int mtu,
|
||||
gatt_connect_cb_t connect_cb)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int gattlib_disconnect(gatt_connection_t* connection) {
|
||||
g_object_unref(connection->io);
|
||||
free(connection);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
OrgBluezDevice1* device = conn_context->device;
|
||||
const gchar* const* service_str;
|
||||
GError *error = NULL;
|
||||
|
||||
const gchar* const* service_strs = org_bluez_device1_get_gatt_services(device);
|
||||
|
||||
if (service_strs == NULL) {
|
||||
*services = NULL;
|
||||
*services_count = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Maximum number of primary services
|
||||
int count_max = 0, count = 0;
|
||||
for (service_str = service_strs; *service_str != NULL; service_str++) {
|
||||
count_max++;
|
||||
}
|
||||
|
||||
gattlib_primary_service_t* primary_services = malloc(count_max * sizeof(gattlib_primary_service_t));
|
||||
if (primary_services == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
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,
|
||||
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
|
||||
"org.bluez",
|
||||
*service_str,
|
||||
NULL,
|
||||
&error);
|
||||
if (service_proxy == NULL) {
|
||||
printf("Failed to open service '%s'.\n", *service_str);
|
||||
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);
|
||||
}
|
||||
|
||||
*services = primary_services;
|
||||
*services_count = count;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int gattlib_discover_primary(gatt_connection_t* connection, gattlib_primary_service_t** services, int* services_count) {
|
||||
gattlib_context_t* conn_context = connection->context;
|
||||
OrgBluezDevice1* device = conn_context->device;
|
||||
const gchar* const* service_str;
|
||||
GError *error = NULL;
|
||||
|
||||
const gchar* const* service_strs = org_bluez_device1_get_uuids(device);
|
||||
|
||||
if (service_strs == NULL) {
|
||||
*services = NULL;
|
||||
*services_count = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Maximum number of primary services
|
||||
int count_max = 0, count = 0;
|
||||
for (service_str = service_strs; *service_str != NULL; service_str++) {
|
||||
count_max++;
|
||||
}
|
||||
|
||||
gattlib_primary_service_t* primary_services = malloc(count_max * sizeof(gattlib_primary_service_t));
|
||||
if (primary_services == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
GDBusObjectManager *device_manager = g_dbus_object_manager_client_new_for_bus_sync (
|
||||
G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
|
||||
"org.bluez",
|
||||
"/",
|
||||
NULL, NULL, NULL, NULL,
|
||||
&error);
|
||||
if (device_manager == NULL) {
|
||||
puts("Failed to get Bluez Device Manager.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
GList *objects = g_dbus_object_manager_get_objects(device_manager);
|
||||
GList *l;
|
||||
for (l = objects; l != NULL; l = l->next) {
|
||||
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;
|
||||
}
|
||||
|
||||
error = NULL;
|
||||
OrgBluezGattService1* service_proxy = org_bluez_gatt_service1_proxy_new_for_bus_sync(
|
||||
G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
|
||||
"org.bluez",
|
||||
object_path,
|
||||
NULL,
|
||||
&error);
|
||||
if (service_proxy == NULL) {
|
||||
printf("Failed to open service '%s'.\n", object_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ensure the service is attached to this device
|
||||
if (strcmp(conn_context->device_object_path, org_bluez_gatt_service1_get_device(service_proxy))) {
|
||||
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_list_free_full(objects, g_object_unref);
|
||||
g_object_unref(device_manager);
|
||||
|
||||
*services = primary_services;
|
||||
*services_count = count;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int gattlib_discover_char_range(gatt_connection_t* connection, int start, int end, gattlib_characteristic_t** characteristics, int* characteristics_count) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 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_char(gatt_connection_t* connection, gattlib_characteristic_t** characteristics, int* characteristic_count) {
|
||||
OrgBluezDevice1* device = conn_context->device;
|
||||
GError *error = NULL;
|
||||
|
||||
const gchar* const* service_strs = org_bluez_device1_get_gatt_services(device);
|
||||
const gchar* const* service_str;
|
||||
const gchar* const* characteristic_strs;
|
||||
const gchar* const* characteristic_str;
|
||||
|
||||
if (service_strs == NULL) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
// 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,
|
||||
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
|
||||
"org.bluez",
|
||||
*service_str,
|
||||
NULL,
|
||||
&error);
|
||||
if (service_proxy == NULL) {
|
||||
printf("Failed to open services '%s'.\n", *service_str);
|
||||
continue;
|
||||
}
|
||||
|
||||
characteristic_strs = org_bluez_gatt_service1_get_characteristics(service_proxy);
|
||||
if (characteristic_strs == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (characteristic_str = characteristic_strs; *characteristic_str != NULL; characteristic_str++) {
|
||||
count_max++;
|
||||
}
|
||||
g_object_unref(service_proxy);
|
||||
}
|
||||
|
||||
|
||||
gattlib_characteristic_t* characteristic_list = malloc(count_max * sizeof(gattlib_characteristic_t));
|
||||
if (characteristic_list == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
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,
|
||||
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
|
||||
"org.bluez",
|
||||
*service_str,
|
||||
NULL,
|
||||
&error);
|
||||
if (service_proxy == NULL) {
|
||||
printf("Failed to open service '%s'.\n", *service_str);
|
||||
continue;
|
||||
}
|
||||
|
||||
characteristic_strs = org_bluez_gatt_service1_get_characteristics(service_proxy);
|
||||
if (characteristic_strs == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (characteristic_str = characteristic_strs; *characteristic_str != NULL; characteristic_str++) {
|
||||
OrgBluezGattCharacteristic1 *characteristic_proxy = org_bluez_gatt_characteristic1_proxy_new_for_bus_sync(
|
||||
G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
|
||||
"org.bluez",
|
||||
*characteristic_str,
|
||||
NULL,
|
||||
&error);
|
||||
if (characteristic_proxy == NULL) {
|
||||
printf("Failed to open characteristic '%s'.\n", *characteristic_str);
|
||||
continue;
|
||||
} else {
|
||||
characteristic_list[count].handle = 0;
|
||||
characteristic_list[count].value_handle = 0;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
*characteristics = characteristic_list;
|
||||
*characteristic_count = count;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static void add_characteristics_from_service(GDBusObjectManager *device_manager, const char* service_object_path, gattlib_characteristic_t* characteristic_list, int* count) {
|
||||
GList *objects = g_dbus_object_manager_get_objects(device_manager);
|
||||
GError *error = NULL;
|
||||
GList *l;
|
||||
|
||||
for (l = objects; l != NULL; l = l->next) {
|
||||
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;
|
||||
}
|
||||
|
||||
OrgBluezGattCharacteristic1* characteristic = org_bluez_gatt_characteristic1_proxy_new_for_bus_sync(
|
||||
G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
|
||||
"org.bluez",
|
||||
object_path,
|
||||
NULL,
|
||||
&error);
|
||||
if (characteristic == NULL) {
|
||||
printf("Failed to open characteristic '%s'.\n", object_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(org_bluez_gatt_characteristic1_get_service(characteristic), service_object_path)) {
|
||||
continue;
|
||||
} else {
|
||||
characteristic_list[*count].handle = 0;
|
||||
characteristic_list[*count].value_handle = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int gattlib_discover_char(gatt_connection_t* connection, gattlib_characteristic_t** characteristics, int* characteristic_count) {
|
||||
gattlib_context_t* conn_context = connection->context;
|
||||
GError *error = NULL;
|
||||
GList *l;
|
||||
|
||||
// Get list of services
|
||||
GDBusObjectManager *device_manager = g_dbus_object_manager_client_new_for_bus_sync (
|
||||
G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
|
||||
"org.bluez",
|
||||
"/",
|
||||
NULL, NULL, NULL, NULL,
|
||||
&error);
|
||||
if (device_manager == NULL) {
|
||||
puts("Failed to get Bluez Device Manager.");
|
||||
return 1;
|
||||
}
|
||||
GList *objects = g_dbus_object_manager_get_objects(device_manager);
|
||||
|
||||
// Count the maximum number of characteristic to allocate the array (we count all the characterstic for all devices)
|
||||
int count_max = 0, count = 0;
|
||||
for (l = objects; l != NULL; l = l->next) {
|
||||
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;
|
||||
}
|
||||
count_max++;
|
||||
}
|
||||
|
||||
gattlib_characteristic_t* characteristic_list = malloc(count_max * sizeof(gattlib_characteristic_t));
|
||||
if (characteristic_list == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// List all services for this device
|
||||
for (l = objects; l != NULL; l = l->next) {
|
||||
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;
|
||||
}
|
||||
|
||||
error = NULL;
|
||||
OrgBluezGattService1* service_proxy = org_bluez_gatt_service1_proxy_new_for_bus_sync(
|
||||
G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
|
||||
"org.bluez",
|
||||
object_path,
|
||||
NULL,
|
||||
&error);
|
||||
if (service_proxy == NULL) {
|
||||
printf("Failed to open service '%s'.\n", object_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ensure the service is attached to this device
|
||||
const char* service_object_path = org_bluez_gatt_service1_get_device(service_proxy);
|
||||
if (strcmp(conn_context->device_object_path, service_object_path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add all characteristics attached to this service
|
||||
add_characteristics_from_service(device_manager, object_path, characteristic_list, &count);
|
||||
}
|
||||
|
||||
g_list_free_full(objects, g_object_unref);
|
||||
g_object_unref(device_manager);
|
||||
|
||||
*characteristics = characteristic_list;
|
||||
*characteristic_count = count;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static OrgBluezGattCharacteristic1 *get_characteristic_from_uuid(const uuid_t* uuid) {
|
||||
OrgBluezGattCharacteristic1 *characteristic = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
GDBusObjectManager *device_manager = g_dbus_object_manager_client_new_for_bus_sync (
|
||||
G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
|
||||
"org.bluez",
|
||||
"/",
|
||||
NULL, NULL, NULL, NULL,
|
||||
&error);
|
||||
if (device_manager == NULL) {
|
||||
puts("Failed to get Bluez Device Manager.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GList *objects = g_dbus_object_manager_get_objects(device_manager);
|
||||
GList *l;
|
||||
for (l = objects; l != NULL; l = l->next) {
|
||||
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;
|
||||
}
|
||||
|
||||
error = NULL;
|
||||
characteristic = org_bluez_gatt_characteristic1_proxy_new_for_bus_sync (
|
||||
G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
|
||||
"org.bluez",
|
||||
object_path,
|
||||
NULL,
|
||||
&error);
|
||||
if (characteristic) {
|
||||
uuid_t characteristic_uuid;
|
||||
const gchar *characteristic_uuid_str = org_bluez_gatt_characteristic1_get_uuid(characteristic);
|
||||
|
||||
gattlib_string_to_uuid(characteristic_uuid_str, strlen(characteristic_uuid_str) + 1, &characteristic_uuid);
|
||||
if (gattlib_uuid_cmp(uuid, &characteristic_uuid) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
g_object_unref(characteristic);
|
||||
}
|
||||
|
||||
// Ensure we set 'characteristic' back to NULL
|
||||
characteristic = NULL;
|
||||
}
|
||||
|
||||
g_list_free_full(objects, g_object_unref);
|
||||
g_object_unref(device_manager);
|
||||
return characteristic;
|
||||
}
|
||||
|
||||
int gattlib_discover_desc_range(gatt_connection_t* connection, int start, int end, gattlib_descriptor_t** descriptors, int* descriptor_count) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int gattlib_discover_desc(gatt_connection_t* connection, gattlib_descriptor_t** descriptors, int* descriptor_count) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int gattlib_read_char_by_uuid(gatt_connection_t* connection, uuid_t* uuid, void* buffer, size_t buffer_len) {
|
||||
OrgBluezGattCharacteristic1 *characteristic = get_characteristic_from_uuid(uuid);
|
||||
if (characteristic == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
GVariant *out_value;
|
||||
GError *error = NULL;
|
||||
|
||||
org_bluez_gatt_characteristic1_call_read_value_sync(
|
||||
characteristic, &out_value, NULL, &error);
|
||||
if (error != NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
gsize n_elements = 0;
|
||||
gconstpointer const_buffer = g_variant_get_fixed_array(out_value, &n_elements, sizeof(guchar));
|
||||
if (const_buffer) {
|
||||
n_elements = MIN(n_elements, buffer_len);
|
||||
memcpy(buffer, const_buffer, n_elements);
|
||||
}
|
||||
|
||||
g_object_unref(characteristic);
|
||||
return n_elements;
|
||||
}
|
||||
|
||||
int gattlib_read_char_by_uuid_async(gatt_connection_t* connection, uuid_t* uuid, gatt_read_cb_t gatt_read_cb) {
|
||||
OrgBluezGattCharacteristic1 *characteristic = get_characteristic_from_uuid(uuid);
|
||||
if (characteristic == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
GVariant *out_value;
|
||||
GError *error = NULL;
|
||||
|
||||
org_bluez_gatt_characteristic1_call_read_value_sync(
|
||||
characteristic, &out_value, NULL, &error);
|
||||
if (error != NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
gsize n_elements;
|
||||
gconstpointer const_buffer = g_variant_get_fixed_array(out_value, &n_elements, sizeof(guchar));
|
||||
if (const_buffer) {
|
||||
gatt_read_cb(const_buffer, n_elements);
|
||||
}
|
||||
|
||||
g_object_unref(characteristic);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gattlib_write_char_by_uuid(gatt_connection_t* connection, uuid_t* uuid, void* buffer, size_t buffer_len) {
|
||||
OrgBluezGattCharacteristic1 *characteristic = get_characteristic_from_uuid(uuid);
|
||||
if (characteristic == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
GVariant *value = g_variant_new_from_data(G_VARIANT_TYPE ("ay"), buffer, buffer_len, TRUE, NULL, NULL);
|
||||
GError *error = NULL;
|
||||
|
||||
org_bluez_gatt_characteristic1_call_write_value_sync(characteristic, value, NULL, &error);
|
||||
if (error != NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_object_unref(characteristic);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gattlib_write_char_by_handle(gatt_connection_t* connection, uint16_t handle, void* buffer, size_t buffer_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void gattlib_register_notification(gatt_connection_t* connection, gattlib_event_handler_t notification_handler, void* user_data) {
|
||||
}
|
||||
|
||||
void gattlib_register_indication(gatt_connection_t* connection, gattlib_event_handler_t indication_handler, void* user_data) {
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
prefix=@CPACK_PACKAGE_INSTALL_DIRECTORY@
|
||||
exec_prefix=${prefix}
|
||||
includedir=${prefix}/include
|
||||
libdir=${exec_prefix}/lib
|
||||
|
||||
Name: gattlib
|
||||
Description: @CPACK_PACKAGE_DESCRIPTION_SUMMARY@
|
||||
Requires: glib-2.0
|
||||
Version: @CPACK_PACKAGE_VERSION@
|
||||
Cflags: -I${includedir}
|
||||
Libs: -L${libdir} -lgattlib
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
*
|
||||
* GattLib - GATT Library
|
||||
*
|
||||
* Copyright (C) 2016-2017 Olivier Martin <olivier@labapart.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __GATTLIB_INTERNAL_H__
|
||||
#define __GATTLIB_INTERNAL_H__
|
||||
|
||||
#include "gattlib.h"
|
||||
|
||||
#include "org-bluez-adaptater1.h"
|
||||
#include "org-bluez-device1.h"
|
||||
#include "org-bluez-gattcharacteristic1.h"
|
||||
#include "org-bluez-gattdescriptor1.h"
|
||||
#include "org-bluez-gattservice1.h"
|
||||
|
||||
#include "bluez5/lib/uuid.h"
|
||||
|
||||
#define BLUEZ_VERSIONS(major, minor) (((major) << 8) | (minor))
|
||||
#define BLUEZ_VERSION BLUEZ_VERSIONS(BLUEZ_VERSION_MAJOR, BLUEZ_VERSION_MINOR)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,27 @@
|
|||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
|
||||
<node>
|
||||
<interface name="org.bluez.Adapter1">
|
||||
<method name="StartDiscovery"></method>
|
||||
<method name="SetDiscoveryFilter">
|
||||
<arg name="properties" type="a{sv}" direction="in"/>
|
||||
</method>
|
||||
<method name="StopDiscovery"></method>
|
||||
<method name="RemoveDevice">
|
||||
<arg name="device" type="o" direction="in"/>
|
||||
</method>
|
||||
<property name="Address" type="s" access="read"></property>
|
||||
<property name="Name" type="s" access="read"></property>
|
||||
<property name="Alias" type="s" access="readwrite"></property>
|
||||
<property name="Class" type="u" access="read"></property>
|
||||
<property name="Powered" type="b" access="readwrite"></property>
|
||||
<property name="Discoverable" type="b" access="readwrite"></property>
|
||||
<property name="DiscoverableTimeout" type="u" access="readwrite"></property>
|
||||
<property name="Pairable" type="b" access="readwrite"></property>
|
||||
<property name="PairableTimeout" type="u" access="readwrite"></property>
|
||||
<property name="Discovering" type="b" access="read"></property>
|
||||
<property name="UUIDs" type="as" access="read"></property>
|
||||
<property name="Modalias" type="s" access="read"></property>
|
||||
</interface>
|
||||
</node>
|
|
@ -0,0 +1,45 @@
|
|||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
|
||||
<node>
|
||||
<interface name="org.bluez.Device1">
|
||||
<method name="Disconnect"></method>
|
||||
<method name="Connect"></method>
|
||||
<method name="ConnectProfile">
|
||||
<arg name="UUID" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="DisconnectProfile">
|
||||
<arg name="UUID" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="Pair"></method>
|
||||
<method name="CancelPairing"></method>
|
||||
|
||||
<property name="Address" type="s" access="read"></property>
|
||||
<property name="Name" type="s" access="read"></property>
|
||||
<property name="Alias" type="s" access="readwrite"></property>
|
||||
<property name="Class" type="u" access="read"></property>
|
||||
<property name="Appearance" type="q" access="read"></property>
|
||||
<property name="Icon" type="s" access="read"></property>
|
||||
<property name="Paired" type="b" access="read"></property>
|
||||
<property name="Trusted" type="b" access="readwrite"></property>
|
||||
<property name="Blocked" type="b" access="readwrite"></property>
|
||||
<property name="LegacyPairing" type="b" access="read"></property>
|
||||
<property name="RSSI" type="n" access="read"></property>
|
||||
<property name="Connected" type="b" access="read"></property>
|
||||
<property name="UUIDs" type="as" access="read"></property>
|
||||
<property name="Modalias" type="s" access="read"></property>
|
||||
<property name="Adapter" type="o" access="read"></property>
|
||||
<property name="TxPower" type="n" access="read"></property>
|
||||
<!--<property name="ManufacturerData" type="" access="read"></property>-->
|
||||
<!--<property name="ServiceData" type="" access="read"></property>-->
|
||||
|
||||
<!-- Was available until Bluez v5.37 to expose the list of available org.bluez.GattService1 -->
|
||||
<property name="GattServices" type="ao" access="read"></property>
|
||||
|
||||
<signal name="PropertiesChanged">
|
||||
<arg name="interface" type="s"/>
|
||||
<arg name="changed_properties" type="a{sv}"/>
|
||||
<arg name="invalidated_properties" type="as"/>
|
||||
</signal>
|
||||
</interface>
|
||||
</node>
|
|
@ -0,0 +1,34 @@
|
|||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
|
||||
<node>
|
||||
<interface name="org.bluez.GattCharacteristic1">
|
||||
<method name="ReadValue">
|
||||
<arg name="value" type="ay" direction="out">
|
||||
<annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
|
||||
</arg>
|
||||
<!--<arg name="options" type="a{sv}" direction="in"/>-->
|
||||
</method>
|
||||
<method name="WriteValue">
|
||||
<arg name="value" type="ay" direction="in">
|
||||
<annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
|
||||
</arg>
|
||||
<!--<arg name="options" type="a{sv}" direction="in"/>-->
|
||||
</method>
|
||||
<method name="StartNotify"/>
|
||||
<method name="StopNotify"/>
|
||||
|
||||
<property name="UUID" type="s" access="read"/>
|
||||
<property name="Service" type="o" access="read"/>
|
||||
<property name="Value" type="ay" access="read"/>
|
||||
<property name="Notifying" type="b" access="read"/>
|
||||
<property name="Flags" type="as" access="read"/>
|
||||
<property name="Descriptors" type="ao" access="read"/>
|
||||
|
||||
<signal name="PropertiesChanged">
|
||||
<arg name="interface" type="s"/>
|
||||
<arg name="changed_properties" type="a{sv}"/>
|
||||
<arg name="invalidated_properties" type="as"/>
|
||||
</signal>
|
||||
</interface>
|
||||
</node>
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
|
||||
<node>
|
||||
<interface name="org.bluez.GattDescriptor1">
|
||||
<method name="ReadValue">
|
||||
<arg name="value" type="ay" direction="out"/>
|
||||
<arg name="options" type="a{sv}" direction="in"/>
|
||||
</method>
|
||||
<method name="WriteValue">
|
||||
<arg name="value" type="ay" direction="in"/>
|
||||
<arg name="options" type="a{sv}" direction="in"/>
|
||||
</method>
|
||||
|
||||
<property name="UUID" type="s" access="read"/>
|
||||
<property name="Characteristic" type="o" access="read"/>
|
||||
<property name="Value" type="ay" access="read"/>
|
||||
|
||||
<signal name="PropertiesChanged">
|
||||
<arg name="interface" type="s"/>
|
||||
<arg name="changed_properties" type="a{sv}"/>
|
||||
<arg name="invalidated_properties" type="as"/>
|
||||
</signal>
|
||||
</interface>
|
||||
</node>
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
|
||||
<node>
|
||||
<interface name="org.bluez.GattService1">
|
||||
<property name="UUID" type="s" access="read"></property>
|
||||
<property name="Device" type="o" access="read"></property>
|
||||
<property name="Primary" type="b" access="read"></property>
|
||||
<property name="Characteristics" type="ao" access="read"></property>
|
||||
|
||||
<signal name="PropertiesChanged">
|
||||
<arg name="interface" type="s"/>
|
||||
<arg name="changed_properties" type="a{sv}"/>
|
||||
<arg name="invalidated_properties" type="as"/>
|
||||
</signal>
|
||||
</interface>
|
||||
</node>
|
|
@ -48,6 +48,14 @@ extern "C" {
|
|||
#define ATT_MAX_MTU ATT_MAX_VALUE_LEN
|
||||
#endif
|
||||
|
||||
/* GATT Characteristic Properties Bitfield values */
|
||||
#define GATTLIB_CHARACTERISTIC_BROADCAST 0x01
|
||||
#define GATTLIB_CHARACTERISTIC_READ 0x02
|
||||
#define GATTLIB_CHARACTERISTIC_WRITE_WITHOUT_RESP 0x04
|
||||
#define GATTLIB_CHARACTERISTIC_WRITE 0x08
|
||||
#define GATTLIB_CHARACTERISTIC_NOTIFY 0x10
|
||||
#define GATTLIB_CHARACTERISTIC_INDICATE 0x20
|
||||
|
||||
typedef enum {
|
||||
BT_SEC_SDP = 0,
|
||||
BT_SEC_LOW,
|
||||
|
@ -72,7 +80,7 @@ typedef struct _gatt_connection_t {
|
|||
} gatt_connection_t;
|
||||
|
||||
typedef void (*gatt_connect_cb_t)(gatt_connection_t* connection);
|
||||
typedef void* (*gatt_read_cb_t)(void* buffer, size_t buffer_len);
|
||||
typedef void* (*gatt_read_cb_t)(const void* buffer, size_t buffer_len);
|
||||
|
||||
/**
|
||||
* @param src Local Adaptater interface
|
||||
|
|
Loading…
Reference in New Issue