【嵌入式Bluetooth应用开发笔记】第一篇:DBUS概述与蓝牙开发小试牛刀

本文介绍了Linux系统中基于GDBus的蓝牙应用开发,包括DBUS概述、DBus开发步骤、蓝牙dbus接口及常用方法。文章详细讲解了如何使用GDBus API调用蓝牙BlueZ接口,通过示例代码展示了创建DBus连接、注册对象、发送和接收消息等步骤,以及如何处理蓝牙设备的发现、连接和配对操作。同时,文章还讨论了DBus开发中的一些难点,如消息结构、线程安全和错误处理。最后,提到了gdbus作为Glib库提供的DBus API封装,使得DBus开发变得更加简单和高效。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

DBUS概述

DBus(D-Bus)是一个在不同程序之间传递消息的系统总线。DBus为不同的程序之间提供了一种通信机制,这种通信制可以在不需要知道对方程序的情况下进行通信。
DBus可以使用多种编程语言来开发,包括C、C++、Python、Java等。在这里,我们以C语言为例来讲解DBus的开发过程。
DBus的主要特点包括:
1. 语言独立性:DBus支持多种编程语言,包括C、C++、Python、Java等。
2. 灵活性:DBus的通信机制非常灵活,支持广播、点对点、异步和同步通信。
3. 安全性:DBus提供了一些安全机制,如身份验证和权限控制,以确保通信的安全性。
4. 可扩展性:DBus支持多个会话总线,可以用于在多个计算机之间进行通信,同时还可以在运行时动态添加和删除对象。
DBus接口(DBus interface)是DBus对象(DBus object)上的一个虚拟界面,它定义了可以通过DBus对象访问的DBus方法、DBus信号和DBus属性。DBus接口使用DBus编程语言中的XML描述符来定义,它具有以下特点:
* DBus接口具有一个名称,它使用类似于UNIX文件系统路径的命名方式来组织,例如 “com.example.Calculator”。
* DBus接口可以继承其他DBus接口。
* DBus接口可以定义DBus方法,DBus方法可以具有零个或多个输入参数和零个或一个输出参数。
* DBus接口可以定义DBus信号,DBus信号是DBus对象发出的一种事件通知,它可以包含任意数量的参数。
* DBus接口可以定义DBus属性,DBus属性是DBus对象的状态信息,它可以被读取或写入。DBus属性可以是只读、可写或读写的。

DBus接口通常是DBus应用程序的主要组成部分,因为它定义了DBus对象的可用功能。在DBus编程中,我们通常使用DBus接口来定义DBus对象的行为,然后在DBus对象上注册DBus接口。这样,在DBus客户端与DBus对象进行通信时,DBus客户端可以查询DBus接口以了解DBus对象的功能,并调用DBus方法、监听DBus信号和读取或写入DBus属性。

DBus的开发步骤

DBus的开发过程可以分为以下几个步骤:
1. 创建DBus连接
在使用DBus进行通信之前,需要先创建一个DBus连接。DBus连接可以通过函数 dbus_bus_get() 来获取。
2. 注册DBus对象
在DBus中,所有的对象都必须先注册才能被其他程序访问。DBus对象可以使用 dbus_connection_register_object() 函数进行注册。
3. 创建DBus消息
在DBus中,消息是所有通信的基本单元。DBus消息可以使用 dbus_message_new() 函数进行创建。
4. 发送DBus消息
创建好DBus消息之后,需要使用 dbus_connection_send() 函数将消息发送出去。
5. 接收DBus消息
在DBus中,需要使用事件循环来等待消息的到来。DBus消息可以使用 dbus_connection_pop_message() 函数来获取。
6. 处理DBus消息
获取到DBus消息之后,需要对消息进行解析和处理。
7. 清理DBus连接
在程序退出之前,需要释放所有的DBus资源。DBus连接可以使用 dbus_connection_unref() 函数来释放。

下面我们通过一个简单的示例来演示DBus的开发过程。示例程序
在本例中,我们将创建一个DBus服务,这个服务可以将两个整数相加并返回结果。

1. 创建DBus连接

首先,我们需要创建DBus连接。DBus连接可以通过函数 dbus_bus_get() 来获取。

DBusError err; 
DBusConnection* conn; 
dbus_error_init(&err); 
conn = dbus_bus_get(DBUS_BUS_SESSION, &err); 
if(dbus_error_is_set(&err)) 
{ 
  printf("DBus connection error: %s\n", err.message); 
  dbus_error_free(&err); 
  return-1; 
}

2.注册DBus对象

我们需要将一个对象注册到DBus上。在本例中,我们将一个对象 /com/example/Calculator 注册到DBus上,并定义两个方法 Add 和 Quit。

DBusObjectPathVTable vtable = { .message_function = &dbus_message_handler }; 
DBusError err; 
DBusObjectPath* path; 
DBusObject* object; 
dbus_error_init(&err); 
path = dbus_object_path_new("/com/example/Calculator"); 
object = dbus_object_new(conn, path); 
dbus_connection_register_object(conn, path, &vtable, object); 
if(dbus_error_is_set(&err)) 
{ 
  printf("DBus object registration error: %s\n", err.message); 
  dbus_error_free(&err);return-1; 
}

在上述代码中,我们定义了一个 DBusObjectPathVTable 结构体,用于注册DBus对象时的消息处理函数 dbus_message_handler()。在本例中,我们需要实现两个方法 Add 和 Quit,因此我们需要在消息处理函数中对这两个方法进行处理。

DBusHandlerResultdbus_message_handler(DBusConnection* conn, DBusMessage* msg,void* user_data) 
{ 
  if(dbus_message_is_method_call(msg,"com.example.Calculator","Add")) 
  { 
      // 处理 Add 方法
      DBusMessageIter iter;inta, b, sum; 
      dbus_message_iter_init(msg, &iter); 
      dbus_message_iter_get_basic(&iter, &a);
      dbus_message_iter_next(&iter); 
      dbus_message_iter_get_basic(&iter, &b); 
      sum = a + b; 
      DBusMessage* reply = dbus_message_new_method_return(msg); 
      DBusMessageIter reply_iter; dbus_message_iter_init_append(reply, &reply_iter); 
      dbus_message_iter_append_basic(&reply_iter, DBUS_TYPE_INT32, &sum); 
      dbus_connection_send(conn, reply,NULL); 
      dbus_message_unref(reply); 
      return DBUS_HANDLER_RESULT_HANDLED; 
	}else if(
    dbus_message_is_method_call(msg,"com.example.Calculator","Quit")) 
  { 
      // 处理 Quit 方法
      dbus_connection_close(conn); 
      return DBUS_HANDLER_RESULT_HANDLED;
   } 
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 
}

在上述代码中,我们首先判断消息是否为 Add 方法的调用。如果是,我们就从消息中获取两个整数 a 和 b,然后将它们相加得到 sum。接下来,我们将 sum 封装到一个新的DBus消息中,并将这个消息通过 dbus_connection_send() 函数发送出去。
如果消息是 Quit 方法的调用,我们就通过 dbus_connection_close() 函数关闭DBus连接。

3.创建DBus消息

在本例中,我们需要创建一个DBus消息来调用 Add 方法。

DBusMessage* msg = dbus_message_new_method_call("com.example.Calculator","/com/example/Calculator","com.example.Calculator","Add"); 
DBusMessageIter args;
dbus_message_iter_init_append(msg, &args); 
dbus_message_iter_append_basic(&args, DBUS_TYPE_INT32, &a); 
dbus_message_iter_append_basic(&args, DBUS_TYPE_INT32, &b);

在上述代码中,我们首先创建了一个DBus消息 msg,然后将消息类型设置为方法调用,方法名为 Add,对象路径为 /com/example/Calculator。
接下来,我们使用 dbus_message_iter_init_append() 函数初始化一个DBus消息迭代器,并将两个整数 a 和 b 追加到DBus消息中。

4. 发送DBus消息

创建好DBus消息之后,我们可以使用 dbus_connection_send() 函数将消息发送出去。

DBusPendingCall* pending; 
dbus_connection_send_with_reply(conn, msg, &pending,-1); 
dbus_connection_flush(conn);

在上述代码中,我们使用 dbus_connection_send_with_reply() 函数将DBus消息发送出去,并等待DBus服务器的应答。应答消息将存储在 pending 变量中。我们还可以使用 dbus_connection_flush() 函数强制刷新DBus连接,以确
保消息被发送出去。

5. 接收DBus应答

当DBus服务器收到DBus消息并处理完成后,会通过DBus连接向客户端发送应答消息。在上述代码中,我们使用 dbus_pending_call_set_notify() 函数注册回调函数 dbus_reply_handler()。当DBus应答消息到达时,回调函数将被调用,并将DBus应答消息中的整数 sum 传递给它。

6. 处理DBus应答

当DBus应答消息到达时,回调函数 dbus_reply_handler() 将被调用。在本例中,我们需要从DBus应答消息中获取整数 sum 并打印出来。

void dbus_reply_handler(DBusPendingCall* pending,void* user_data)
{ 
  int* sum = (int*)user_data; 
  DBusMessage* reply = dbus_pending_call_steal_reply(pending); 
  DBusMessageIter iter; 
  if(reply) 
  { 
  	if(dbus_message_iter_init(reply, &iter)) 	
  { 
    dbus_message_iter_get_basic(&iter, sum); 
    printf("The sum is: %d\n", *sum); 
  } 
  	dbus_message_unref(reply); 
  }
  dbus_pending_call_unref(pending); 
}

在上述代码中,我们首先从回调函数参数 user_data 中获取整数指针 sum,然后使用 dbus_pending_call_steal_reply() 函数从DBus应答消息中提取应答消息。如果应答消息存在,我们就从消息中获取整数 sum 并打印出来。最后,我们释放DBus应答消息和DBus挂起调用。

完整示例代码


#include<stdio.h> 
#include<stdlib.h> 
#include<dbus/dbus.h> 
DBusHandlerResult dbus_message_handler(DBusConnection* conn, DBusMessage* msg,void* user_data) 
{ 
    if(dbus_message_is_method_call(msg,"com.example.Calculator","Add")) 
    {
        // 处理 Add 方法
        DBusMessageIter iter; 
        inta, b, sum;
        dbus_message_iter_init(msg, &iter); 
        dbus_message_iter_get_basic(&iter, &a); 
        dbus_message_iter_next(&iter);
        dbus_message_iter_get_basic(&iter, &b); 
        sum = a + b; DBusMessage* reply = dbus_message_new_method_return(msg); 
        DBusMessageIter reply_iter; 
        dbus_message_iter_init_append(reply, &reply_iter); 
        dbus_message_iter_append_basic(&reply_iter, DBUS_TYPE_INT32, &sum);
        dbus_connection_send(conn, reply,NULL); 
        dbus_message_unref(reply); 
    	returnDBUS_HANDLER_RESULT_HANDLED; 
    }else if(
      dbus_message_is_method_call(msg,"com.example.Calculator","Quit")){ 
        // 处理 Quit 方法 
        dbus_connection_close(conn); 
        returnDBUS_HANDLER_RESULT_HANDLED;
     } 
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 
} 
voiddbus_reply_handler(DBusPendingCall* pending,void* user_data) 
{
  int* sum = (int*)user_data;
  DBusMessage* reply =dbus_pending_call_steal_reply(pending);
  DBusMessageIter iter;
  if (reply)
  {
    if (dbus_message_iter_init(reply, &iter))
    { 
      dbus_message_iter_get_basic(&iter, sum); 
      printf("The sum is: %d\n", *sum);
    } 
  	dbus_message_unref(reply);
  } 
  dbus_pending_call_unref(pending);
}
int main() 
{ 
	DBusError error; 
    DBusConnection* conn; 
    DBusMessage* msg; 
    DBusPendingCall* pending;
    int sum = 0dbus_error_init(&error);

    // 建立到系统DBus总线的连接
    conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error);

    if (dbus_error_is_set(&error)) {
        fprintf(stderr, "Error connecting to system bus: %s\n", error.message);
        dbus_error_free(&error);
        return EXIT_FAILURE;
    }

    // 注册对象路径和消息处理函数
    dbus_bus_request_name(conn, "com.example.Calculator", 0, &error);

    if (dbus_error_is_set(&error)) {
        fprintf(stderr, "Error requesting name: %s\n", error.message);
        dbus_error_free(&error);
        return EXIT_FAILURE;
    }

    dbus_connection_register_object_path(conn, "/com/example/Calculator", &dbus_interface, NULL);

    // 创建DBus消息
    msg = dbus_message_new_method_call("com.example.Calculator", "/com/example/Calculator", "com.example.Calculator", "Add");

    // 将参数添加到DBus消息中
    DBusMessageIter iter;
    dbus_message_iter_init_append(msg, &iter);
    int a = 2, b = 3;
    dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &a);
    dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &b);

    // 发送DBus消息并等待应答
    dbus_connection_send_with_reply(conn, msg, &pending, -1);
    dbus_message_unref(msg);

    dbus_pending_call_set_notify(pending, dbus_reply_handler, &sum, NULL);

    while (dbus_connection_read_write_dispatch(conn, -1)) {

    }

    dbus_connection_unref(conn);

    return EXIT_SUCCESS;
}

在上述代码中,我们首先建立到系统DBus总线的连接,然后注册对象路径和消息处理函数。接下来,我们创建一个DBus消息,并将参数添加到消息中。然后,我们使用 dbus_connection_send_with_reply() 函数将DBus消息发送到DBus服务器,并等待应答。在等待期间,我们使用 dbus_connection_read_write_dispatch() 函数循环调用DBus连接以便处理DBus消息。当DBus应答消息到达时,回调函数 dbus_reply_handler() 将被调用。

常用的蓝牙dbus接口

在Linux系统中,蓝牙的实现通常使用DBus进行管理和控制。下面介绍一些常用的蓝牙DBus接口及其功能:
1. org.bluez.Agent1

这个接口用于管理蓝牙代理,实现了蓝牙认证和授权功能。在进行蓝牙配对时,代理程序将被调用来执行认证和授权操作。该接口定义了以下方法:

* RequestConfirmation (in uint32_t, out uint32_t)
* RequestAuthorization (in uint32_t, out uint32_t)
* AuthorizeService (in object path, out boolean)
* Cancel ()

2.org.bluez.Adapter1
这个接口用于管理蓝牙适配器,实现了蓝牙设备的搜索和管理功能。该接口定义了以下方法:
* StartDiscovery ()
* StopDiscovery ()
* GetProperties ()
* SetProperty (in string, in variant)
* GetAllProperties ()
* CreateDevice (in string, out object path)
* RemoveDevice (in object path)
* GetDevice (in object path, out object path)
* GetDevices (out array of object path)
* GetDeviceProperties (in object path, out dict of string variant)

3.org.bluez.Device1
这个接口用于管理蓝牙设备,实现了设备的配对、连接和断开连接等功能。该接口定义了以下方法:
* Connect ()
* Disconnect ()
* Pair ()
* CancelPairing ()
* GetProperties ()
* SetProperty (in string, in variant)
* GetAllProperties ()
* GetServices (out array of object path)

4.org.bluez.MediaTransport1
这个接口用于管理蓝牙音频传输,实现了音频的传输和控制功能。该接口定义了以下方法:
* SetConfiguration (in dict of string variant)
* SelectConfiguration (in dict of string variant)
* ClearConfiguration ()
* Release ()
* Acquire (out string)
* GetProperties ()
* SetProperty (in string, in variant)
* GetAllProperties ()
这些接口定义了蓝牙管理和控制的基本方法,开发人员可以通过DBus API来调用这些方法实现蓝牙应用程序的开发。需要注意的是,这些接口在不同版本的蓝牙协议中可能存在差异,开发人员需要根据具体情况进行调整。

初试dbus调用蓝牙接口

在Linux系统中,DBus API可以使用C语言或其他编程语言进行调用。下面以C语言为例介绍如何使用DBus API调用这些接口。

1. 首先需要包含DBus头文件

#include<dbus/dbus.h>

2.初始化DBus连接

DBusError error; 
DBusConnection* conn; 
dbus_error_init(&error); 
conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error); 
if(dbus_error_is_set(&error)) 
{ 
  printf("Error connecting to the daemon bus: %s\n", error.message);
  dbus_error_free(&error); 
  return; 
}

3.调用DBus方法

DBusMessage* msg; 
DBusMessageIter args; 
DBusPendingCall* pending; 
msg = dbus_message_new_method_call("org.bluez","/org/bluez/hci0","org.bluez.Adapter1","StartDiscovery"); 
if(!msg) { 
	printf("Error creating dbus message\n"); 
	return; 
} 
if(!dbus_connection_send_with_reply(conn, msg, &pending,-1)) 
{ 
	printf("Error sending dbus message\n"); 
	dbus_message_unref(msg); 
	return; 
} 
dbus_connection_flush(conn); 
dbus_message_unref(msg); 
dbus_pending_call_block(pending); 
msg = dbus_pending_call_steal_reply(pending); 
if(msg) 
{ 
	dbus_message_iter_init(msg, &args); 
	dbus_pending_call_unref(pending); 
	dbus_message_unref(msg); 
}

在上面的例子中,我们调用了org.bluez.Adapter1接口的StartDiscovery方法。其中,dbus_message_new_method_call函数用于创建DBus方法调用消息,第一个参数是服务名称,第二个参数是对象路径,第三个参数是接口名称,第四个参数是方法名称。dbus_connection_send_with_reply函数用于发送DBus消息并等待回复,第一个参数是DBus连接,第二个参数是DBus消息,第三个参数是DBus异步调用,第四个参数是超时时间。dbus_pending_call_block函数用于阻塞DBus调用直到接收到回复,dbus_pending_call_steal_reply函数用于获取DBus调用的回复。
通过以上步骤,我们可以使用DBus API调用蓝牙相关的接口实现蓝牙应用程序的开发。需要注意的是,DBus API的调用方式和参数类型在不同版本的DBus协议中可能存在差异,开发人员需要根据具体情况进行调整。

一些难点注意

1.D-Bus消息的结构

DBus消息是由一系列DBus类型构成的结构,开发人员需要了解DBus消息的类型和结构,才能正确地创建和解析DBus消息。DBus类型包括基本类型(如整型、字符串、布尔型等)和复合类型(如结构体、数组、字典等)。DBus消息的结构和类型定义在DBus规范中,开发人员需要根据规范进行编程。

2. DBus连接和线程安全

DBus连接是DBus消息传输的基础,开发人员需要了解DBus连接的创建、销毁和使用方法。同时,DBus连接还涉及到线程安全的问题,因为DBus连接是多线程共享的资源。开发人员需要了解DBus连接的线程安全特性,合理地管理DBus连接的生命周期和使用方法,避免出现线程安全问题。

3. DBus错误处理

DBus API的调用过程中,可能会出现各种错误,包括DBus连接错误、DBus消息格式错误、DBus方法调用错误等。开发人员需要了解DBus错误处理的方法,正确地捕获和处理DBus错误,避免出现程序崩溃等严重问题。

4. DBus调试工具

在DBus开发过程中,可能会遇到DBus调用失败、消息格式错误等问题,需要进行调试。DBus提供了一些调试工具,如dbus-monitor、dbus-send等,开发人员需要了解这些工具的使用方法,以便快速定位和解决DBus调试问题。
总之,在进行Linux C中DBus开发时,开发人员需要深入了解DBus规范、DBus API和DBus调试工具,才能够高效地进行DBus开发。同时,需要注意DBus连接的线程安全问题和DBus错误处理问题,以提高程序的可靠性和稳定性。

GDBUS概述

gdbus是Glib库提供的DBus API的实现,是基于DBus C API的一层封装。Glib是GNOME桌面环境的核心库,提供了许多常用的工具和组件,如事件循环、线程、内存管理、字符串处理、数据结构等。
gdbus封装了DBus API,提供了一组更易用的API,比DBus C API更加简洁、直观、安全和高效。使用gdbus开发DBus应用程序,可以大大提高开发效率和代码质量。
gdbus的特点包括:
1. 对DBus API进行了封装,提供了更易用的API接口,简化了DBus开发的过程和代码量。
2. 提供了自动类型转换和参数检查机制,避免了DBus API的错误使用。
3. 使用Glib的事件循环机制,提供了异步DBus调用的支持,能够更好地处理DBus的异步消息。
4. 提供了DBus接口的代理机制,支持DBus的远程调用。

总之,gdbus是Glib库提供的DBus API的实现,是DBus开发的一种高层次的抽象,能够大大简化DBus开发的过程和代码量,并提供了异步DBus调用和DBus远程调用的支持。

GDBUS API的介绍

  1. g_dbus_connection_new_sync: 此函数用于创建新的GDBusConnection连接。它需要指定一个连接名和一个连接地址,还可以指定DBus连接的选项。
  2. g_dbus_connection_call_sync: 此函数用于在给定的GDBus连接上同步调用远程对象的方法。它需要指定对象的名称、接口名称、方法名称和方法的参数。此外,还可以指定调用超时时间和DBus调用的选项。
  3. g_dbus_proxy_new_sync: 此函数用于创建一个新的GDBus代理。它需要指定一个GDBusConnection连接、一个DBus代理的名称、代理接口的名称以及DBus代理的选项。
  4. g_dbus_proxy_call_sync: 此函数用于在给定的GDBus代理上同步调用远程对象的方法。它需要指定方法名称、方法的参数、调用超时时间和DBus调用的选项。
  5. g_dbus_proxy_set_default_timeout: 此函数用于设置DBus调用的默认超时时间(以毫秒为单位)。这个超时时间将应用于调用同步方法和在DBus代理上调用异步方法时未指定超时时间的调用。
  6. g_dbus_proxy_call: 此函数用于在给定的GDBus代理上异步调用远程对象的方法。它需要指定方法名称、方法的参数、DBus调用的选项以及一个回调函数来处理异步调用结果。
  7. g_dbus_proxy_call_finish: 此函数用于完成由g_dbus_proxy_call启动的异步DBus调用,并返回调用结果。
  8. g_dbus_proxy_new_for_bus_sync: 此函数用于在指定的DBus总线上创建一个新的GDBus代理。它需要指定DBus总线类型、DBus代理的名称、代理接口的名称以及DBus代理的选项。
  9. g_dbus_connection_new_for_address_sync():建立与DBus daemon的连接。在bluez开发中,我们需要通过该API建立与BlueZ daemon的连接。
  10. g_dbus_connection_register_object():用于注册一个对象到DBus系统总线上。在bluez开发中,我们可以用它将自定义的蓝牙服务以及属性注册到BlueZ daemon上。
  11. g_dbus_connection_call_sync():用于同步调用DBus方法。在bluez开发中,我们可以用它来调用BlueZ daemon上的方法,比如获取蓝牙设备、服务或特征的属性等。
  12. g_dbus_connection_signal_subscribe():用于订阅DBus signal。在bluez开发中,我们可以用它来订阅蓝牙设备的状态改变、蓝牙服务的添加或删除、蓝牙特征的值变化等事件。
  13. g_dbus_proxy_new_sync():用于创建一个代理对象。在bluez开发中,我们可以用它来创建一个代理对象,从而方便地操作蓝牙设备、服务或特征。
  14. g_dbus_proxy_call_sync():用于同步调用代理对象上的DBus方法。在bluez开发中,我们可以用它来调用代理对象上的方法,比如读取或写入蓝牙特征的值。
  15. g_dbus_proxy_get_property():用于获取代理对象上的属性值。在bluez开发中,我们可以用它来获取蓝牙设备、服务或特征的属性值。
  16. g_dbus_proxy_set_property():用于设置代理对象上的属性值。在bluez开发中,我们可以用它来设置蓝牙设备、服务或特征的属性值。

GDBUS的开发步骤

1.定义DBus接口

定义DBus接口,包括接口名称、方法名称、参数等,可以通过GDBusNodeInfo结构体来描述DBus接口。GDBusNodeInfo结构体包含一个或多个GDBusInterfaceInfo结构体,每个GDBusInterfaceInfo结构体描述一个DBus接口。可以使用GDBusNodeInfoBuilder结构体来动态地创建GDBusNodeInfo结构体。

2.注册DBus接口

将DBus接口注册到DBus总线上,可以通过GDBusConnection结构体的g_dbus_connection_register_object()函数来实现。该函数的参数包括DBus总线连接、对象路径、DBus接口信息、DBus方法回调函数等。

3.连接DBus总线

通过g_bus_get_sync()函数连接DBus总线。该函数返回一个GDBusConnection结构体指针,可以通过该结构体指针来发送DBus消息、注册DBus接口、监听DBus信号等。

4.发送DBus消息

使用GDBusConnection结构体的g_dbus_connection_send_message_with_reply_sync()函数或g_dbus_connection_send_message_with_reply_async()函数来发送DBus消息。这些函数的参数包括DBus总线连接、DBus消息、DBus消息类型、超时时间等。

5. 接收DBus消息

使用GDBusConnection结构体的g_dbus_connection_signal_subscribe()函数来接收DBus消息。该函数的参数包括DBus总线连接、DBus接口名称、信号名称、回调函数、用户数据等。

6. 处理DBus方法调用

使用GDBusConnection结构体的g_dbus_connection_register_object()函数注册DBus方法回调函数。当DBus客户端调用DBus方法时,DBus守护进程将会调用相应的DBus方法回调函数。可以在DBus方法回调函数中处理DBus方法调用并返回结果。

7. 启动事件循环

使用g_main_loop_run()函数启动事件循环,以便接收DBus消息、处理DBus方法调用等。
以上是使用gdbus开发DBus应用程序的基本步骤。需要注意的是,gdbus是Glib库提供的DBus API的实现,因此需要安装Glib库和gio库才能进行gdbus开发。

GDBus调用蓝牙BlueZ 接口

1.创建 GDBus 连接

GDBusConnection *bus =NULL; 
GError *error =NULL; 
bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM,NULL, &error); 
if(!bus) 
{ 
  g_error("Failed to get system bus: %s", error->message); 
  g_error_free(error); 
  return; 
}

2.创建 GDBus 代理对象

#define BLUEZ_SERVICE "org.bluez" 
#define ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter1"
GDBusProxy *adapter_proxy =NULL;
GError *error =NULL; 
// 这里的 hci0 根据实际情况来修改 
adapter_proxy = g_dbus_proxy_new_sync( bus, G_DBUS_PROXY_FLAGS_NONE,NULL, BLUEZ_SERVICE,"/org/bluez/hci0", ADAPTER_INTERFACE,NULL, &error); 
if(!adapter_proxy) 
{ 
    g_error("Failed to create adapter proxy: %s", error->message); 
    g_error_free(error);
    return; 
}

3.调用 GDBus 代理对象的方法

GVariant *result =NULL; 
GError *error =NULL; 
result = g_dbus_proxy_call_sync( adapter_proxy,"StartDiscovery",NULL, G_DBUS_CALL_FLAGS_NONE,-1,NULL, &error); 
if(!result)
{ 
    g_error("Failed to call StartDiscovery: %s", error->message); 
    g_error_free(error); 
    return; 
}

完整示例代码

#include<gio/gio.h> 
#define BLUEZ_SERVICE "org.bluez" 
#define ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter1" 
int main(intargc,char*argv[])
{ 
    // 创建 GDBus 连接 
    GDBusConnection *bus =NULL;
     GError *error =NULL; 
    bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM,NULL, &error); 
    if(!bus) 
    { 
        g_error("Failed to get system bus: %s", error->message); 
        g_error_free(error); 
        return 1; 
    } 
    // 创建 GDBus 代理对象 
    GDBusProxy *adapter_proxy =NULL; 
    // 这里的 hci0 根据实际情况来修改 
    adapter_proxy = g_dbus_proxy_new_sync( bus, G_DBUS_PROXY_FLAGS_NONE,NULL, BLUEZ_SERVICE,"/org/bluez/hci0", ADAPTER_INTERFACE,NULL, &error); 
    if(!adapter_proxy) 
    { 
        g_error("Failed to create adapter proxy: %s", error->message); g_error_free(error); 
        return 1; 
    } 
    // 调用 GDBus 代理对象的方法 
    GVariant *result =NULL; 
    result = g_dbus_proxy_call_sync( adapter_proxy,"StartDiscovery",NULL, G_DBUS_CALL_FLAGS_NONE,-1,NULL, &error); 
    if(!result) 
    { 
        g_error("Failed to call StartDiscovery: %s", error->message); 
        g_error_free(error); 
        return 1; 
    } 
    g_object_unref(adapter_proxy); 
    g_variant_unref(result); 
    g_dbus_connection_unref(bus);
}

对于GDBus方法,我们需要使用GVariant对象来表示参数和返回值。例如,为了调用org.bluez.Adapter1接口的StartDiscovery方法,我们需要使用以下代码:

GError *error =NULL; 
GVariant *result = g_dbus_connection_call_sync( connection,"org.bluez","/org/bluez/hci0","org.bluez.Adapter1","StartDiscovery",NULL,NULL, G_DBUS_CALL_FLAGS_NONE,-1,NULL, &error);
if(error !=NULL) 
{
 	g_error("Error calling StartDiscovery: %s", error->message); 
} 
g_variant_unref(result);

这里的connection是一个GDBusConnection对象,它是通过g_dbus_connection_new_for_address_sync()函数创建的。注意,我们没有传递任何参数给StartDiscovery方法,因为它不需要任何参数。对于需要传递参数的方法,我们需要构造一个GVariant对象来表示参数。例如,为了调用org.bluez.Device1接口的Pair方法,我们可以使用以下代码:

GError *error =NULL; 
GVariant *params = g_variant_new("(s)","Keyboard"); 
// 参数是字符串"Keyboard" 
GVariant *result = g_dbus_connection_call_sync( connection,"org.bluez","/org/bluez/hci0/dev_00_11_22_33_44_55","org.bluez.Device1","Pair", params,NULL, G_DBUS_CALL_FLAGS_NONE,-1,NULL, &error);
if(error !=NULL) 
{ 
	g_error("Error calling Pair: %s", error->message); 
} 
g_variant_unref(result); 
g_variant_unref(params);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

林零七

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

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

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

打赏作者

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

抵扣说明:

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

余额充值