【蓝牙协议栈】【BlueZ】史上最详细BlueZ应用开发示例(初始化、扫描、配对等)

1. 精讲蓝牙协议栈Bluetooth Stack):SPP/A2DP/AVRCP/HFP/PBAP/IAP2/HID/MAP/OPP/PAN/GATTC/GATTS/HOGP等协议理论 

2. 欢迎大家关注和订阅,【蓝牙协议栈】【Android Bluetooth Stack】专栏会持续更新中.....敬请期待

目录

1. BlueZ概述

2. 蓝牙初始化

2.1 从蓝牙初始化窥探接口使用

3. 实现蓝牙设备扫描的功能

4. 蓝牙设备配对的功能

4.1 获取目标设备的地址     

4.2 创建GDBusProxy

4.3 获取配对属性的接口对象

4.4 调用StartPairing函数

5. 输入PIN码

6. 确认配对请求

7. 等待配对完成信号

8. 蓝牙管理


1. BlueZ概述

         BlueZ是一个开源的 蓝牙协议栈Q,提供了丰富的AP!和工具,支持Linux系统中的蓝牙应用开发。BlueZ提供的API包括D-BuS API、HCIAPI、L2CAP API、RFCOMM API、SDP API、MGMTAPI等,开发者可以使用这些API实现自己的蓝牙应用程序。
        BlueZ的架构由多个模块组成,其中主要的模块包括蓝牙协议栈(Bluetootha Stack)、蓝牙管理器(Bluetooth Manager)、蓝牙核心服务(Bluetooth Core Services)和蓝牙应用(Bluetooth Applications)蓝牙协议栈是Bluez的核心组件,它实现了蓝牙协议的所有层次,包括物理层、链路控制层、逻辑链路控制昙、RFCOMM层、L2CAP层和SDP层等,蓝牙协议栈提供了标准的蓝牙协议接口,可以通过不同的接口与其他模块进行通信。
        蓝牙管理器是BlueZ的用户空间组件,它提供了基于D-Bus的API,用于管理蓝牙适配器、蓝牙设备和蓝牙连接等。通过蓝牙管理器,用户可以扫描周围的蓝牙设备,建立蓝牙连接,管理蓝牙设备的配对、绑定、授权和解绑等操作。
        蓝牙核心服务是BlueZ提供的一组标准的蓝牙服务,包括SDP服务、RFCOMM服务、L2CAP服务和AVRCP服务等。蓝牙应用可以通过这些服务与其他蓝牙设备进行通信和控制。蓝牙应用是BlueZ的上层组件,它提供了各种各样的蓝牙应用程序,例如音频传输、文件传输、串口通信、输入设备等。用户可以通过这些应用程序实现不同的蓝牙应用场景。


2. 蓝牙初始化


示例代码

#include<stdio.h> 
#include<gio/gio.h> 
int main(intargc,char*argv[]) 
{ 
    GDBusConnection *conn; 
    GError *error =NULL; 
    /* Initialize GIO library */ 
    g_type_init(); 
    g_bus_own_name(G_BUS_TYPE_SYSTEM,"com.example.bluetooth",0,NULL,NULL,NULL,NULL); 
    /* Get a connection to the Bluetooth daemon */ 
    conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM,NULL, &error); 
    if(error !=NULL) 
    { 
        g_print("Failed to get bus connection: %s\n", error->message);
        g_error_free(error); 
        return 1; 
    } 
    /* Initialize the Bluetooth adapter */ 
    /* Name of the remote object to invoke */
    GVariant *result = g_dbus_connection_call_sync(conn,"org.bluez", "/org/bluez/hci0", "org.freedesktop.DBus.Properties", "Set", g_variant_new("(ssv)","org.bluez.Adapter1","Powered", g_variant_new_boolean(TRUE)),NULL,G_DBUS_CALL_FLAGS_NONE,-1, NULL,&error); 
    /* Error */ 
    if(error !=NULL) { 
        g_print("Failed to initialize Bluetooth adapter: %s\n", error->message); g_error_free(error); 
        return1; 
    }
    g_variant_unref(result); 
    g_object_unref(conn); 
    return 0; 
}

        在这个例子中,我们使用g_bus_get_sync函数获取到了DBus连接,然后使用g_dbus_ connection_call_sync函数来调用org.freedesktop.DBus.Properties接口中的Set方法,以初始化蓝牙适配器。我们将org.bluez.Adapter1作为第一个参数传递给Set方法,这是一个由BlueZ定义的DBus对象,用于代表蓝牙适配器。第二个参数是一个字符串,指定我们要设置的属性名为Powered,第三个参数是一个布尔值,表示要将适配器开启或关闭。
        如果没有错误发生,g_dbus_connection_call_sync函数将返回一个GVariant对象,其中包含调用方法的结果在这个例子中,我们没有使用调用结果,因此我们可以简单地将它解引用并丢弃。最后,我们使用g_object_unref函数释放DBus连接对象的引用。当然,这只是一个简单的示例,实际的蓝牙应用开发还需要考虑更多的因素,例如扫描和连接远程设备,管理蓝牙设备和服务等。
        org.freedesktop.DBus.Properties 是DBus的标准接口之一,提供了访问对象属性的方法。通过调用 Get 方法,可以获取对象的某个属性值,通过调用 Set 方法,可以设置对象的某个属性值,通过调用 GetAl方法可以获取对象的所有属性值。在蓝牙开发中,org.freedesktop.DBus.Properties 接口常被用于获取和设置蓝牙设备的属性。例如,通过调用Get 方法,可以获取蓝牙设备的名称、地址、服务UUID等信息。通过调用 Set 方法,可以设置蓝牙设备的名称等属性。通过调用 GetA 方法,可以获取蓝牙设备的所有属性值。总之,通过调用 orq.freedesktop.DBus.Properties 接口,我们可以方便地访问DBus对象的属性,从而实现对DBus对象的控制。


2.1 从蓝牙初始化窥探接口使用

g_type_init
        在使用 GObject 类型之前,需要先调用 g_type_init()函数进行初始化。这个函数会初始化 GLib 库的类型系统,包括预定义类型和自定义类型。在初始化后,我们就可以创建自己的 GObject 类型,并使用 GObiect 类型系统的各种功能了,比如创建对象实例、注册信号、添加属性等等。需要注意的是,从 GLib 2.36 开始,g_type_init()被废弃,建议使用g_type_init_with_ debug_flags()或g_type_init_with_options()函数进行类型系统的初始化。其中,g_type_init_with _debug flags()可以接受一个调试标志参数,用于在调试模式下启用 GObject 类型的更多检查和错误报告;g_type init_with_options()可以接受一组选项参数,用于控制类型系统的行为和属性。
g_bus_own_name
        g_bus_own_name 是 GDBus 库中的一个函数,用于注册 D-Bus 名称并监听其相关的 D-Bus 信号。在 Linux 系统中,进程可以使用 D-Bus 通信协议与其他进程通信。在使用 D.Bus 协议进行通信时,每个进程需要有一个唯一的名称,以便其他进程可以找到它并与之通信。因此,在使用 D-Bus 协议进行通信时,进程需要首先注册一个名称。
        g_bus_own_name 函数可以帮助进程在 D-Bus 总线上注册一个名称,并将该名称的相关信号(例如名称所有权的变化)连接到回调函数上。当名称注册成功时,g_bus_own_name函数将调用 bus_acquired_handler 回调函数;当名称所有权发生变化时,将调用name_acquired_handler 或 name_lost_handler 回调函数。

在蓝牙应用开发中,通常需要使用g_bus_own_name 函数来注册一个唯一的 D-Bus 名称,以便其他蓝牙应用或系统组件可以与之通信。
g_bus_get_sync
        g_bus_get_sync()是一个GDBuS AP!,用于同步地获取一个指定名称的DBus总线。DBus总线是DBus系统中的一个重要概念,用于进程间通信。

g_dbus_connection_call_sync
g_dbus_connection_call_sync是 GDBus 库中的一个同步函数,用于在 D-Bus 连接上同步地调用一个远程对象上的方法,并等待方法的返回值。它的函数原型为:

GVariant *g_dbus_connection_call_sync (
  GDBusConnection *connection,
  const gchar *bus_name,
  const gchar *object_path,
  const gchar *interface_name,
  const gchar *method_name, 
  GVariant *parameters, 
  GVariantType *reply_type, 
  GDBusCallFlags flags, 
  gint timeout_msec, 
  GCancellable *cancellable, 
  GError **error);

函数参数说明:
要使用的 D-Bus 连接。connection:
bus_name:要调用的远程对象的名称。
object_path:要调用的远程对象的对象路径。
interface_name:要调用的远程对象的接口名称。
method_name:要调用的远程对象的方法名称。
parameters:要传递给远程方法的参数。
*reply_type:远程方法的返回类型。
flags:调用的标志。
timeout_msec:超时时间,以事秒为单位。
cancellable:用于取消操作的可取消对象。error:如果出错,则设置一个 GError,
该函数会阻塞直到方法调用完成或超时。如果方法调用成功,则返回调用结果的 GVariant 值。如果调用失
败,则会返回 NULL 并设置 error 参数。g_dbus_connection_call_sync 的调用过程与使用 dbus-send 命令进行 D-Bus 调用类似。这个函数实际上是封装了 GDBusMessage 和 GDBusProxy 两个对象的操作,使用该函数可以方便地进行同步调用。在蓝牙应用开发中,可可以使用 g_dbus_connection_call_sync函数来调用 BlueZ 的 D-Bus 接口,实现对蓝牙设备的控制和管理。

3. 实现蓝牙设备扫描的功能

示例代码

#include<gio/gio.h> 
// 扫描到蓝牙设备的信号处理函数 
static void on_device_found(GDBusProxy *proxy, gchar *name, GVariant *properties, GPtrArray *devices) 
{ 
    GVariant *address_variant = g_variant_lookup_value(properties,"Address", G_VARIANT_TYPE_STRING); 
    GVariant *name_variant = g_variant_lookup_value(properties,"Name", G_VARIANT_TYPE_STRING);
    gchar *address = g_variant_get_string(address_variant,NULL); 
    gchar *name = g_variant_get_string(name_variant,NULL); 
    // 打印扫描到的蓝牙设备信息 
    g_print("Found device: %s (%s)\n", name, address); 
    g_variant_unref(address_variant); 
    g_variant_unref(name_variant); 
}

g_variant_lookup_value和g variant get的区别
g_variant_lookup_value()和 g_variant_get() 都是 GVariant 对象中获取值的函数,但它们的用途略有不同:g_variant _lookup_value()用于在一个包含字典的 GVariant 对象中,通过给定的 key 获取对应的 value。如果 key 不存在或对应的 value 类型不匹配,则返回 NULL。该函数的返回值需要手动释放。g_variant get() 则用于从 GVariant 对象中提取其值。如果 GVariant 对象的类型与提取时指定的类型不匹配,则函数调用失败。该函数的返回值是提取出的值,不需要手动释放。当使用g_variant_get() 时,如果无法找到指定的 key,那么会触发一个错误并返回 NULL。而当使用g_variant_lookup_value()时,如果找不到指定的 key,则会返回默认值(通过函数的第三个参数指定),不会触发错误。
举个例子,假设我们有以下的 GVariant:

{ name: "John", age: 25 }

        如果我们使用 g_variant get()获取 name,则会返回一个类型为s(字符串类型)的 GVariant,其值为“John”。而如果我们使用 g_variant get()获取 gender,则会触发一个错误。
而如果我们使用 g_variant_lookup_value()获取 gender,并将默认值设置为“Unknown”,则会返回一个类型为s的 GVariant,其值为“Unknown”,而不会触发错误。
        总的来说,g_variant_lookup_value()主要用于字典类型的 GVariant 对象,而g_variant get() 则用于普通的GVariant 对象。
        那我怎么知道通过g_variant get获取到的就是name而不是uuid呢
在调用g_variant_lookup_value时,需要指定属性名,而属性名通常是在蓝牙开发文档或者buez源代码中定义的,或者通过dbus-monitor工具进行监听蓝牙服务的信号获取。你可以参考bluez官方文档中关于蓝牙设备属性的定义,了解各属性名称及其类型。在获得属性的GVariant后,需要使用a variant aet*()系列函数按照属性的类型进行获取。如果你不知道具体属性名和类型,可以通过DBus和GVariant APl进行调试,获取其属性名和类型信息。
        假设我们有一个 GVariant,内容是“"uuid”:<string“1234>,“name”:<string“example”>},我们想要获取其中的 name 属性值。可以使用以下代码:

GVariant *properties_variant; 
// 假设已经获取到了该 GVariant 
GVariant *name_variant; 
gchar *name; 
g_variant_lookup(properties_variant,"name","s", &name_variant);
g_variant_get(name_variant,"s", &name);
g_variant_unref(name_variant); 
g_print("Name: %s\n", name);
g_free(name);

        其中g_variant_lookup 用于查找 GVariant 中的指定属性,并返回相应的 GVariant。它的第一个参数是要查找的GVariant,第二个参数是要査找的属性名称(字符串类型),第三个参数是指定返回的 GVariant 的类型。在这个例子中,我们要查找的是属性名为“name”的字符串类型属性,所以第三个参数是“s”。g variant get 用于从返回的 GVariant 中提取值,并将其存储在指定的变量中。它的第二个参数指定要提取的值的类型在这个例子中,我们要获取的是字符串类型的属性值,所以第二个参数也是“s”。最后,我们需要使用g_variant_unref 释放我们从g_variant_lookup 中获取的 GVariant,以避免内存泄漏。


4. 蓝牙设备配对的功能


4.1 获取目标设备的地址     

        可以使用蓝牙设备扫描功能获取到目标设备的地址,也可以手动输入目标设备的地址。设备地址通常是由六个十六进制数表示的,例如:12:34:56:78:90:AB。
获取目标设备的地址可以通过在设备被发现时收到的信号中获取。具体来说,当执行扫描操作时,可以通过调用 StartDiscovery 方法启动设备发现,然后注册一个回调函数来接收扫描结果的信号。在回调函数中,可以通过信号参数获取扫描到的设备信息,包括设备的地址。以下是一个使用 GDBus 实现设备发现并获取目标设备地址的示例代码:

#include<gio/gio.h> 
static voidon_device_found(GDBusProxy *proxy, gchar *name, GVariant *properties, GDBusConnection *connection) 
{
    gchar *address =NULL; 
    // 从设备属性中获取地址 
    g_variant_lookup(properties,"Address","s", &address); 
    if(address !=NULL) 
    { 
    	g_print("Found device with address: %s\n", address);
    } 
    g_free(address); 
}
int main() 
{ 
    GError *error =NULL; 
    GDBusProxy *proxy =NULL;
    GDBusConnection *connection =NULL; 
    gchar *adapter_path =NULL; 
    // 初始化 GDBus 
    g_type_init(); 
    // 获取系统 D-Bus 连接 
    connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM,NULL, &error); 
    if(connection ==NULL) { 
        g_printerr("Failed to connect to the D-Bus system bus: %s\n", error->message); 
        g_error_free(error); 
        return 1; 
    } 
    // 获取蓝牙适配器的代理对象 
    proxy = g_dbus_proxy_new_sync(connection, G_DBUS_PROXY_FLAGS_NONE,NULL,"org.bluez","/org/bluez/hci0","org.bluez.Adapter1",NULL, &error); 
    if(proxy ==NULL) 
    { 
        g_printerr("Failed to get adapter proxy: %s\n", error->message); 
        g_error_free(error); 
        return 1; 
    } 
    // 启动设备发现 
    g_dbus_proxy_call_sync(proxy,"StartDiscovery",NULL, G_DBUS_CALL_FLAGS_NONE,-1,NULL, &error); 
    if(error !=NULL) 
    { 
        g_printerr("Failed to start discovery: %s\n", error->message); g_error_free(error); 
        return 1; 
    } 
    // 注册设备发现信号的回调函数 
    g_signal_connect(proxy,"g-properties-changed", G_CALLBACK(on_device_found), connection); 
    // 进入主循环 
    g_main_loop_run(g_main_loop_new(NULL, FALSE)); 
    // 释放资源 
    g_free(adapter_path); 
    g_object_unref(proxy); 
    g_object_unref(connection); 
    return0; 
}

        在设备被扫描到时,回调函数 on_device_found 将被调用,并从设备属性中获取设备的地址信息。可以根据需求修改回调函数来实现设备扫描时的各种操作。


4.2 创建GDBusProxy


        使用目标设备的地址和bluetooth.service这个服务名称,创建GDBusProxy对象。这里需要调用g dbus proxy new for bus synck数。


4.3 获取配对属性的接口对象


        在GDBusProxy对象中调用g_dbus_proxy_get_interface sync函数获取配对属性的接口对象,接口名称为org.bluez.Device1。这里也可以使用g_dbus_proxy_call_sync函数来获取接囗对象。


4.4 调用StartPairing函数


        在配对属性的接口对象中调用StartPairing函数进行配对。可以使用g_dbus_proxy_call_sync函数或g_dbus_proxy_cal方法。

示例代码

#include<gio/gio.h> 
typedef struct
{ 
    GDBusConnection *connection; 
    GDBusProxy *proxy; 
    gchar *object_path; 
    gchar *device_address;
 } BluetoothDevice; 

BluetoothDevice *bluetooth_device_new(constgchar *device_address) 
{ 
    BluetoothDevice *device = g_new0(BluetoothDevice,1); 
    device->device_address = g_strdup(device_address); 
    device->connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM,NULL,NULL); 
    if(!device->connection) 
    { 
    g_printerr("Failed to connect to system bus.\n"); 
    goto failed; 
    } 
    device->proxy = g_dbus_proxy_new_for_bus_sync( G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE,NULL,"org.bluez", device->object_path,"org.bluez.Device1",NULL,NULL); 
    if(!device->proxy) 
    { 
    g_printerr("Failed to create dbus proxy for device.\n"); 
    goto failed; 
    } 
    return device; 
failed: 
    bluetooth_device_free(device); 
    return NULL; 
} 
void bluetooth_device_free(BluetoothDevice *device)
{ 
    if(device->connection) 
    { 
    	g_object_unref(device->connection); 
    } 
    if(device->proxy) 
    { 
    	g_object_unref(device->proxy); 
    } 
    if(device->object_path) 
    { 
    	g_free(device->object_path); 
    } 
    if(device->device_address) 
    { 
    	g_free(device->device_address); 
    } 
    g_free(device); 
} 
gboolean bluetooth_device_is_connected(BluetoothDevice *device) 
{ 
    GError *error =NULL; 
    GVariant *value; value = g_dbus_proxy_get_cached_property(device->proxy,"Connected"); 
    if(value ==NULL) 
    { 
    	return FALSE; 
    } 
    gboolean connected; 
    g_variant_get(value,"b", &connected); 
    g_variant_unref(value); 
    return connected; 
} 
gboolean bluetooth_device_pair(BluetoothDevice *device) 
{ 
    GError *error =NULL; 
    GVariant *result; 
    GVariant *options; 
    gboolean paired; 
    options = g_variant_new("(a{sv})",NULL); 
    result = g_dbus_proxy_call_sync( device->proxy,"Pair", options, G_DBUS_CALL_FLAGS_NONE,-1,NULL, &error ); 
    if(result ==NULL) 
    { 
      g_printerr("Pairing failed: %s\n", error->message); 
      g_error_free(error); 
      return FALSE; 
    } 
    g_variant_get(result,"(b)", &paired); 
    g_variant_unref(result);
  	return paired;
 }

5. 输入PIN码

        如果目标设备需要输入PIN码,则需要使用g_dbus_proxy_call sync函数调用org.bluez.Agent1.RequestPinCode方法,然后输入PIN码。
示例代码

gboolean request_pin_code(GDBusProxy *device_proxy,constgchar *pin_code) 
{ 
    GVariant *result =NULL; 
    GError *error =NULL; 
    // Prepare parameters for org.bluez.Agent1.RequestPinCode 
    GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE("()")); 
    // Call org.bluez.Agent1.RequestPinCode 
    result = g_dbus_proxy_call_sync(device_proxy,"org.bluez.Agent1","RequestPinCode", g_variant_builder_end(builder), G_VARIANT_TYPE("(s)"), G_DBUS_CALL_FLAGS_NONE,-1,NULL, &error); 
    if(error) 
    { 
        g_printerr("Failed to call RequestPinCode: %s\n", error->message); 
        g_error_free(error); 
        return FALSE; 
    } 
    // Extract the returned PIN code and print it out 
    constgchar *returned_pin_code =NULL; 
    g_variant_get(result,"(s)", &returned_pin_code); 
    g_print("Received PIN code: %s\n", returned_pin_code); 
    // Clean up 
    g_variant_unref(result); 
    g_variant_builder_unref(builder); 
    // Input the PIN code 
    if(pin_code) 
    { 
              g_dbus_proxy_call_sync(
                device_proxy,
                "org.bluez.Device1",
                "PasskeyEntered", 
                g_variant_new("(uq)", g_ascii_strtoull(pin_code,NULL,10), (guint16)0),NULL, G_DBUS_CALL_FLAGS_NONE,-1,NULL, &error); 
        if(error) 
        { 
            g_printerr("Failed to call PasskeyEntered: %s\n", error->message); g_error_free(error); 
            return FALSE; 
        } 
    } 
    return TRUE; 
}

6. 确认配对请求


        如果目标设备需要用户确认配对请求,则需要使用g_dbus_proxy_call sync函数调用org.bluez.Agent1.RequestConfirmation方法,然后进行确认操作。
示例代码

void pair_device_confirm(GDBusProxy *proxy,constchar*pincode) 
{ 
    GError *error =NULL; 
    GVariant *result =NULL; 
    gboolean confirm = TRUE; 
    result = g_dbus_proxy_call_sync(proxy,"org.bluez.Agent1.RequestConfirmation", g_variant_new("(oq)","/org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX", confirm), G_DBUS_CALL_FLAGS_NONE,-1,NULL, &error); 
    if(error !=NULL) 
    { 
      g_printerr("Error calling org.bluez.Agent1.RequestConfirmation: %s\n", error->message); 
      g_error_free(error); 
    }else{ 
      g_variant_unref(result); 
      g_print("Pairing confirmed for device\n"); 
    } 
}

        其中,第一个参数proxy为创建的GDBusProxy对象,第二个参数pincode为输入的PIN码。该函数调用了org.bluez.Agent1.RequestConfirmation方法来确认配对请求,并将confirm参数设置为TRUE以接受请求,注意替换方法调用中的设备地址字符串"/orq/bluez/hci0/dev XX XX XX XX XX XX"为实际设备的地址。


7. 等待配对完成信号


        等待配对完成信号,可以使用g signal connect函数来连接配对完成信号的回调函数。配对完成信号为org.bluez.Device1.Paired.
示例代码

void wait_pair_completed(GDBusProxy *device_proxy) 
{ 
    GError *error =NULL; 
    guint signal_handler_id; 
    // 等待配对完成信号 
    signal_handler_id = g_signal_connect(device_proxy,"g-signal", G_CALLBACK(on_signal_received), &error); 
    // 如果连接信号失败 
    if(signal_handler_id ==0) 
    { 
        g_print("Failed to connect signal: %s\n", error->message); 
        g_error_free(error); 
        return;
     } 
    // 等待信号触发 
    g_main_loop_run(main_loop); 
    // 断开信号连接 
    g_signal_handler_disconnect(device_proxy, signal_handler_id);
 }

其中,on signal received为配对完成信号的回调函数。这个函数的具体实现可以根据具体雲求自行实现。mainloop为主事件循环对象,需要在程序初始化时创建。


8. 蓝牙管理


实现步骤

1.使用g_dbus proxy new for bus sync函数创建GDBusProxy对象,指定目标设备的地址和org.bluez.Device1接口,2.使用g dbus proxy call sync函数调用org.bluez.Device1.Connect方法连接设备。
3.使用g dbus proxy call sync函数调用org.bluez.Device1.Disconnect方法断开设备连接。
4.使用g signal connect函数连接设备连接状态改变的信号org.bluez.Device1.ConnectionStateChanged。在回调函数中可以处理设备连接状态的改变,包括连接、断开、重连等操作。


示例代码
        下面是一个使用GDBusProxy管理蓝牙设备连接状态的例子代码,其中连接状态改变的信号回调函数为on connection state changed:

#include<gio/gio.h> 
staticvoidon_connection_state_changed(GDBusProxy *proxy, GVariant *changed_properties, GStrv invalidated_properties, gpointer user_data) 
{ 
    gboolean connected; 
    GVariant *prop_val = g_variant_lookup_value(changed_properties,"Connected", G_VARIANT_TYPE_BOOLEAN); 
    if(prop_val) 
    { 
        connected = g_variant_get_boolean(prop_val); g_variant_unref(prop_val); 
        if(connected) 
        { 
        	g_print("Device connected!\n");
        }else{ 
        	g_print("Device disconnected!\n"); 
        } 
    } 
} 
int main(intargc,char*argv[]) 
{ 
    GError *error =NULL; 
    GDBusProxy *proxy; gchar *device_address ="XX:XX:XX:XX:XX:XX"; 
    gchar *device_path =NULL; 
    // 1. 创建GDBusProxy对象 
    proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE,NULL,"org.bluez", device_path,"org.bluez.Device1",NULL, &error); 
    if(error) { 
        g_print("Error creating proxy: %s\n", error->message); 
        g_error_free(error); 
        return 1; 
    } 
    // 2. 连接设备 
    error =NULL; 
    GVariant *result = g_dbus_proxy_call_sync(proxy,"Connect",NULL, G_DBUS_CALL_FLAGS_NONE,-1,NULL, &error); 
    if(error) 
    { 
        g_print("Error connecting device: %s\n", error->message); 
        g_error_free(error); 
        return 1; 
    } 
    g_variant_unref(result); 
    // 3. 断开设备连接 
    error =NULL; 
    result = g_dbus_proxy_call_sync(proxy,"Disconnect",NULL, G_DBUS_CALL_FLAGS_NONE,-1,NULL, &error); 
    if(error) 
    { 
        g_print("Error disconnecting device: %s\n", error->message); 
        g_error_free(error);
        return1; 
    } 
    g_variant_unref(result); 
    // 4. 监听设备连接状态改变信号 
    g_signal_connect(proxy,"g-properties-changed", G_CALLBACK(on_connection_state_changed),NULL); 
    // 循环等待 
    GMainLoop *loop = g_main_loop_new(NULL, FALSE); 
    g_main_loop_run(loop); 
    return0; 
}

最近更新

  1. TCP协议是安全的吗?

    2024-04-09 13:16:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-09 13:16:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-09 13:16:01       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-09 13:16:01       20 阅读

热门阅读

  1. 原生js封装请求组件

    2024-04-09 13:16:01       12 阅读
  2. ChatGPT革新学术论文写作:提升写作效率与质量

    2024-04-09 13:16:01       16 阅读
  3. 【算法】最长连续递增序列 - 贪心算法

    2024-04-09 13:16:01       13 阅读
  4. 渗透测试概述

    2024-04-09 13:16:01       13 阅读
  5. hadoop中hdfs的fsimage文件与edits文件

    2024-04-09 13:16:01       13 阅读