【嵌入式Bluetooth应用开发笔记】第二篇:上手BLUEZ应用开发

概述

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

蓝牙初始化

示例代码

#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 方法,可以设置对象的某个属性值,通过调用 GetAll 方法,可以获取对象的所有属性值。
在蓝牙开发中,org.freedesktop.DBus.Properties 接口常被用于获取和设置蓝牙设备的属性。例如,通过调用 Get 方法,可以获取蓝牙设备的名称、地址、服务UUID等信息。通过调用 Set 方法,可以设置蓝牙设备的名称等属性。通过调用 GetAll 方法,可以获取蓝牙设备的所有属性值。
总之,通过调用 org.freedesktop.DBus.Properties 接口,我们可以方便地访问DBus对象的属性,从而实现对DBus对象的控制。

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

g_type_init

在使用 GObject 类型之前,需要先调用 g_type_init() 函数进行初始化。这个函数会初始化 GLib 库的类型系统,包括预定义类型和自定义类型。在初始化后,我们就可以创建自己的 GObject 类型,并使用 GObject 类型系统的各种功能了,比如创建对象实例、注册信号、添加属性等等。
需要注意的是,从 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 API,用于同步地获取一个指定名称的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);

函数参数说明:
* connection:要使用的 D-Bus 连接。
* 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 接口,实现对蓝牙设备的控制和管理。

实现蓝牙设备扫描的功能

示例代码

#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时,需要指定属性名,而属性名通常是在蓝牙开发文档或者bluez源代码中定义的,或者通过dbus-monitor工具进行监听蓝牙服务的信号获取。你可以参考bluez官方文档中关于蓝牙设备属性的定义,了解各属性名称及其类型。在获得属性的GVariant后,需要使用g_variant_get_*()系列函数按照属性的类型进行获取。如果你不知道具体属性名和类型,可以通过DBus和GVariant API进行调试,获取其属性名和类型信息。

假设我们有一个 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,以避免内存泄漏。

蓝牙设备配对的功能

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 将被调用,并从设备属性中获取设备的地址信息。可以根据需求修改回调函数来实现设备扫描时的各种操作。

2.创建GDBusProxy

使用目标设备的地址和bluetooth.service这个服务名称,创建GDBusProxy对象。这里需要调用g_dbus_proxy_new_for_bus_sync函数。

3.获取配对属性的接口对象

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

4.调用StartPairing函数

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

示例代码

#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以接受请求。注意替换方法调用中的设备地址字符串"/org/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为配对完成信号的回调函数。这个函数的具体实现可以根据具体需求自行实现。main_loop为主事件循环对象,需要在程序初始化时创建。

蓝牙管理

实现步骤

  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; 
}
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林零七

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值