当前位置: 首页 > news >正文

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

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);

相关文章:

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

DBUS概述 DBus&#xff08;D-Bus&#xff09;是一个在不同程序之间传递消息的系统总线。DBus为不同的程序之间提供了一种通信机制&#xff0c;这种通信制可以在不需要知道对方程序的情况下进行通信。 DBus可以使用多种编程语言来开发&#xff0c;包括C、C、Python、Java等。在…...

如何在电脑更换新硬盘后迁移window11系统?2种迁移方法分享!

随着时间的流逝&#xff0c;数据量也在逐渐增多&#xff0c;就会导致您的硬盘空间也变得越来越小&#xff0c;因此系统运行速度可能会受到一些影响而越来越慢。为了摆脱这种情况&#xff0c;您可以选择升级到更大的硬盘来使计算机获取更大的磁盘空间&#xff0c;或者迁移系统到…...

6、Elasticsearch优化

一、Elasticsearch集群配置 1、硬件选择 Elasticsearch的基础是 Lucene &#xff0c;所有的索引和文档数据是存储在本地的磁盘中&#xff0c; 具体的路径可在 ES 的配置文件 ../config/elasticsearch.yml 中配置&#xff0c;如下&#xff1a;磁盘在现代服务器上通常都是瓶颈。…...

给力|这是一个专业的开源快速开发框架!

在低代码开发市场&#xff0c;专业的开源快速开发框架可以助力企业提升办公协作效率&#xff0c;实现提质增效的办公自动化的发展目标。 流辰信息低代码技术开发平台服务商&#xff0c;拥有丰富的技术经验和案例合作经验&#xff0c;针对不同的客户需求&#xff0c;提供个性化、…...

CIMCAI smart shipping company product container damage identify

世界港航人工智能领军者企业CIMCAI&#xff0c;领先智能航运船公司集装箱管理产品ceaspectusS™全球规模化应用落地智能化航运&#xff0c;全球前三船公司认可验箱标准应用。全球港航人工智能领军者企业CIMCAI&#xff0c;是全球第一家完成两百万次人工智能验箱&#xff0c;上亿…...

ego微商小程序项目-接口测试

文章目录 1.接口理论回顾1.1 接口测试相关概念1.2 接口测试流程2.接口测试文档2.1 接口测试文档基础2.2 ego微商小程序的接口文档解析3.设计接口测试用例3.1 接口测试用例基础3.2 ego微商小程序接口测试用例4. 执行测试用例4.1 ego小程序测试用例执行4.1.1 首页-轮播图4.1.2 用…...

excel文件已经损坏怎么办

1. excel文件突然损坏怎么办Excel修复不成功还可以尝试其他修复方式。1、Excel提示文件已损坏可能是受保护视图的问题。如果打开文件碰到此提示&#xff0c;可以先点确定。在按以下步骤操作&#xff1a;1&#xff09;在空白程序界面&#xff0c;点击功能栏的【文件】&#xff0…...

Java【数据结构入门OJ题33道】——力扣刷题记录1

文章目录第一天存在重复元素最大子数组和第二天两数之和合并两个有序数组第三天两个数组的交集买卖股票最佳时机第四天重塑矩阵杨辉三角第五天有效的数独矩阵置零第六天字符串中第一个唯一字符救赎金第七天判断链表是否有环合并两个有序链表移除链表元素第八天反转链表删除重复…...

Spring事务介绍

文章目录一、编程式事务二、声明式事务&#xff08;常用&#xff09;三、事务实战详解3.1&#xff09;事务的回滚机制3.2&#xff09;事务的传播3.3&#xff09;事务超时时间3.4&#xff09;事务隔离级别3.5&#xff09;事务回滚条件Spring中对事务有两种支持方式&#xff0c;分…...

Intellij Idea如何使用VM

打开Run/Debug Configuration 然后在More option 里选择 add VM options 根据要实现的目的选择main class 比如说要建造class diagram 那就选择app.ClassDiagramGenerator 然后在下面那行输入 D:\software-engineering\2023\commons-compress\target\classes true true org.apa…...

基础04-什么时候不能使用箭头函数

箭头函数的缺点 题目 什么时候不能使用箭头函数&#xff1f; 箭头函数的缺点 没有 arguments const fn1 () > {console.log(this, arguments) // 报错&#xff0c;arguments is not defined } fn1(100, 200)无法通过 call apply bind 等改变 this const fn1 () >…...

算法小抄5-原地哈希

书接上回,学会了数组中重复数字的解法三,相信接下来的题也难不倒你 找到数组中消失的数字 题目链接 题意 对于一个大小为n的数组,数组中所有的数都在[1,n]内,其中有些数字重复了,由于有些数字重复了,另一些数字就一定会确实,这次需要找到所有缺少的数字并且返回结果 有没有发…...

java零基础入门(1)

java零基础入门一、JRE和JDK1.1 JRE1.2 JDK1.3 IDK&#xff0c;JRE&#xff0c;JVM三者的包含关系二、CMD2.1 打开CMD2.2 常用CMD命令2.2.1 盘符名称 冒号2.2.2 dir2.2.3 cd 目录2.2.4 cd ..2.2.5 cls2.2.6 exit2.2.7 cd \2.2.8 cd \目录\目录\目录\目录2.3 利用快捷cmd打开 Q…...

java socket实例

/*** 启动项目后就创建Server Socket服务*/PostConstructpublic void runServerSocket() {try {ExecutorService executorService Executors.newFixedThreadPool(10);// 创建线程池ServerSocket serverSocket new ServerSocket(9090);// 在设备上配置的服务端监听端口为9090e…...

计算机中信息的表示和处理 整数和小数的二进制表示

信息的表示和处理整数进制字移位运算无符号数和有符号数加法运算小数定点表示IEEE 浮点表示规格化和非规格化舍入浮点运算现代计算机存储和处理的信息以二值信号表示&#xff0c;这些二进制数字称为位&#xff0c;为什么要用二进制来进行编码&#xff1f;因为二进制只有1和0两种…...

Chapter2.2:线性表的顺序表示

该系列属于计算机基础系列中的《数据结构基础》子系列&#xff0c;参考书《数据结构考研复习指导》(王道论坛 组编)&#xff0c;完整内容请阅读原书。 2.线性表的顺序表示 2.1 顺序表的定义 线性表的顺序存储亦称为顺序表&#xff0c;是用一组地址连续的存储单元依次存储线性表…...

老马闲评数字化「4」做数字化会不会被供应商拿捏住

原文作者&#xff1a;行云创新CEO 马洪喜 导语 开年过后业务特别的繁忙&#xff0c;出差也比较多&#xff0c;所以有段时间没更新了&#xff0c;对不住大家&#xff01; 上一集&#xff08;您可以查看“行云创新”主页阅读原文&#xff09;咱们聊了数字化转型的“想转、急转、…...

robosuite添加无碰撞的模型

1 前言 最近在使用robosuite时,需要在仿真环境中可视化物体的目标位置,从而方便观察训练情况,可视化的物体有以下要求: 形状尺寸与操作的物体一样半透明只有visual,不与场景其他物体有碰撞可以在每次step后设置位置,且固定在设定的位置,不受重力影响 2 方法 找了半天,最终确…...

JS学习笔记day03

今日内容 零、 复习昨日 CSS 美化,复用,样式文件和表现文件分离便于维护 选择器 {属性:值;…} 引入css 内联文件内部使用style标签外部文件 <link href"路径" rel"stylesheet" type"text/css"> 选择器 基本 idclass标签名 属性 标签名…...

离散数学笔记_第一章:逻辑和证明(3)

1.3 命题等价式1.3.1 逻辑等价式 1.3.2 条件命题和双条件命题的逻辑等价式 1.3.3 德摩根律 1.3.4 可满足性 可满足的 不可满足的 可满足性问题的解 1.3.5析取范式&#xff08;基本积之和&#xff09;&#xff0c;合取范式&#xff08;基本和之积&#xff09;1.3.6合式公式1…...

软件测试分类知识分享,第三方软件测试机构收费贵不贵?

软件测试可以很好的检验软件产品的质量以及规避产品上线之后可能会发生的错误&#xff0c;随着技术的发展&#xff0c;软件测试已经是一个完整且体系庞大的测试活动&#xff0c;不同的测试领域有着不同的测试方法、技术与名称&#xff0c;那么具体有哪些分类呢? 一、软件测试…...

爬虫(二)解析数据

文章目录1. Xpath2. jsonpath3. BeautifulSoup4. 正则表达式4.1 特殊符号4.2 特殊字符4.3 限定符4.3 常用函数4.4 匹配策略4.5 常用正则爬虫将数据爬取到后&#xff0c;并不是全部的数据都能用&#xff0c;我们只需要截取里面的一些数据来用&#xff0c;这也就是解析爬取到的信…...

【C++、C++11】可变参数模板、lambda表达式、包装器

文章目录&#x1f4d6; 前言1. 可变参数模板1.1 万能模板&#xff1a;1.2 完美转发&#xff1a;1.3 可变参数模板的使用&#xff1a;1.4 emplace_back&#xff1a;2. lambda表达式2.1 lambda表达式的定义&#xff1a;2.2 lambda表达式的用法&#xff1a;2.2 - 1 捕捉列表的用法…...

外贸主机测评

一、俄罗斯vps 服务商&#xff1a; JUSTG: Home - Sun Network Company Limited LOCVPS: LOCVPS 全球云 - 十年老牌 为跨境外贸/远程办公/网站建设提供澎湃动力 JUSTHOST: justhost.ru RUVDS: Gcorelabs: 二、主机测评指标&#xff1a; 1、速度、延迟、丢包、路由测试…...

Meta CTO:Quest 2生命周期或比预期更久

前不久&#xff0c;Meta未来4年路线图遭曝光&#xff0c;泄露了该公司正在筹备中的一些AR/VR原型。除此之外&#xff0c;还有消息称Quest Pro或因销量不佳&#xff0c;而不再迭代。毫无疑问&#xff0c;Meta的一举一动持续受到行业关注&#xff0c;而面对最近的爆料&#xff0c…...

Vector - CAPL - 文件处理函数

在当前平台化的趋势下,就算是协议层测试依然需要适配各种各样的项目,也需要处理各类型的文件,那我们如何对文件进行读取、写入、修改等类型的操作呢?今天我们就会介绍此类型的函数,主要适用于text、bin文件的处理。 打开文件 Open...

实力加持!RestCloud完成多方国产化适配,携手共建信创生态

近年来&#xff0c;随着数字化建设进入深水区&#xff0c;企事业单位对信息安全重视程度与日俱增&#xff0c;核心技术自主可控已成为时代呼唤&#xff0c;国产化浪潮日益汹涌澎湃。近日&#xff0c;RestCloud在国产化方面取得新进展&#xff0c;完成了全部产品线信创环境的多方…...

Unity 3D GUI教程||OnGUI TextArea 控件||OnGUI ScrollView 控件

OnGUI TextArea 控件 Unity 3D TextArea 控件用于创建一个多行的文本编辑区。用户可以在多行文本编辑区编辑文本内容。 该控件可以对超出控件宽度的文本内容实现换行操作。 TextArea 控件同样会将当前文本编辑区中的文本内容以字符串形式返回。 开发人员可以通过创建 Strin…...

Leetcode.828 统计子串中的唯一字符

题目链接 Leetcode.828 统计子串中的唯一字符 Rating &#xff1a; 2034 题目描述 我们定义了一个函数 countUniqueChars(s)来统计字符串 s中的唯一字符&#xff0c;并返回唯一字符的个数。 例如&#xff1a;s "LEETCODE"&#xff0c;则其中 "L", "…...

Hibernate 相关特性

1. Hibernate一般使用hql进行查询&#xff0c;但也有sql执行的方法 Native sql 查询,。需要注意的是&#xff0c;使用Native SQL查询可能会破坏Hibernate的缓存机制&#xff0c;并可能导致性能问题 String sql "SELECT * FROM users WHERE age > :age"; Query …...

【研究生学术英语读写教程翻译 中国科学院大学Unit1-Unit8】

Unit1 Descartes Was Wrong 笛卡尔错了:“他人在,故我在” Unit2 Are we ready for the next volcanic catastrophe?我们准备好应对下一次火山灾难了吗? Unit3 Theorists,experimentalists and the bias in popular physics理论家,实验家和大众物理学的偏见 unit4 Magic Nu…...

ListView 控件的使用

第一步&#xff1a;找到ListView的控件通过findViewById 找到ListView的控件 ListView listView findViewById(R.id.listView);第二步&#xff1a;创建Bean类 得到set和get的方法解析获取的数据创建Bean类 得到set和get的方法public class Bean {String nanm""; pub…...

域控制器搭建以及成员加入

需要iso&#xff1a;windows server 2016软件使用&#xff1a;vmwarewindows server 2016系统搭建自己选iso&#xff0c;一直下一步就可以安装完成。&#xff08;记得要设置密码&#xff09;&#xff08;密码要求大小写字母数字符号&#xff09;等待就能安装完成。安装和配置Ac…...

利用 MLP(多层感知器)和 RBF(径向基函数)神经网络解决的近似和分类示例问题(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 1、径向基神经网络 径向基函数网络是由三层构成的前向网络&#xff1a;第一层为输入层&#xff0c;节点个数的能与输入的维数&…...

进阶C语言——数据的存储【详解】

文章目录1. 数据类型介绍1.1 类型的基本归类2. 整形在内存中的存储2.1 原码、反码、补码2.2 大小端介绍2.3 练习3. 浮点型在内存中的存储3.1 一个例子3.2 浮点数存储的规则1. 数据类型介绍 前面我们已经学习了基本的内置类型&#xff1a; char //字符数据类型 short //短整型 …...

KUKA机器人修改机器人名称和IP地址的具体方法示例

KUKA机器人修改机器人名称和IP地址的具体方法示例 修改机器人名称 如下图所示,首先切换用户组到管理员,输入默认密码:kuka, 如下图所示,点击菜单键—投入运行—机器人数据, 如下图所示,此时可以看到机器人的名称为rrr445, 如下图所示,修改之后,点击左侧的“”…...

【数据分析师求职面试指南】必备基础知识整理

数据分析师基础知识统计 数据分析知识基础概念随机变量常用特征正态分布与大数定律、中心极限定律假设检验模型、数据挖掘知识常用概念数据集划分欠拟合过拟合模型分类方法常见模型介绍线性回归模型&#xff1a;逻辑回归模型决策树模型随机森林模型Boosting模型XGBoost模型模型…...

《开关电源宝典 降压电路(BUCK)的原理与应用》

嗨&#xff0c;硬件攻城狮或电源工程师同行们&#xff0c;我想写本专门解析BUCK电源电路的书籍&#xff0c;以下是“前言”内容的部分摘录以及当前的目录&#xff0c;当前已经完成22万多字500多页了&#xff0c;即使如此&#xff0c;离真正出版书籍&#xff0c;还有很长的路要走…...

R语言基础(一):注释、变量

R语言用于统计分析和绘制图表等操作。不同于Java等其它语言&#xff0c;R用于统计&#xff0c;而不是做一个网站或者软件&#xff0c;所以R的一些开发习惯和其它语言不同。如果你是一个编程小白&#xff0c;那么可以放心大胆的学。如果你是一个有编程基础的人&#xff0c;那么需…...

Java 集合进阶(二)

文章目录一、Set1. 概述2. 哈希值3. 元素唯一性4. 哈希表5. 遍历学生对象6. LinkedHashSet7. TreeSet7.1 自然排序7.2 比较器排序8. 不重复的随机数二、泛型1. 概述2. 泛型类3. 泛型方法4. 泛型接口5. 类型通配符6. 可变参数7. 可变参数的使用一、Set 1. 概述 Set 集合特点&am…...

小孩用什么样的台灯比较好?2023眼科医生青睐的儿童台灯推荐

小孩子属于眼睛比较脆弱的人群&#xff0c;所以选购护眼台灯时&#xff0c;选光线温和的比较好&#xff0c;而且调光、显色效果、色温、防蓝光等方面也要出色&#xff0c;否则容易导致孩子近视。 1、调光。台灯首先是照度高&#xff0c;国AA级&#xff0b;大功率发光&#xff0…...

Ubuntu c++ MySQL数据库操作

mysql安装sudo apt-get install updatesudo apt-get install mysql-server libmysqlclient-dev mysql-workbenchmysql启动/重启/停止sudo service mysql start/restart/stop登录mysql命令&#xff1a;mysql -uroot -p错误异常&#xff1a;解决办法&#xff1a;修改mysqld.cnf配…...

C++11:lambda表达式

文章目录1. 概念2. 语法3. 示例示例1示例2示例3示例44. 捕捉方式基本方式隐式和混合补充5. 传递lambda表达式示例6. 原理7. 内联属性1. 概念 lambda表达式实际上是一个匿名类的成员函数&#xff0c;该类由编译器为lambda创建&#xff0c;该函数被隐式地定义为内联。因此&#…...

【Android -- 开源库】表格 SmartTable 的基本使用

介绍 1. 功能 快速配置自动生成表格&#xff1b;自动计算表格宽高&#xff1b;表格列标题组合&#xff1b;表格固定左序列、顶部序列、第一行、列标题、统计行&#xff1b;自动统计&#xff0c;排序&#xff08;自定义统计规则&#xff09;&#xff1b;表格图文、序列号、列标…...

自动化测试实战篇(9),jmeter常用断言方法,一文搞懂9种测试字段与JSON断言

Jmeter常用的断言主要有&#xff0c;JSON断言和响应断言这两种方式。 断言主要就是帮助帮助人工进行快速接口信息验证避免繁杂的重复的人工去验证数据 第一种响应断言Apply to&#xff1a;表示应用范围测试字段&#xff1a;针对响应数据进行不同的匹配响应文本响应代码响应信息…...

vue-virtual-scroll-list虚拟列表

当DOM中渲染的列表数据过多时&#xff0c;页面会非常卡顿&#xff0c;非常占用浏览器内存。可以使用虚拟列表来解决这个问题&#xff0c;即使有成百上千条数据&#xff0c;页面DOM元素始终控制在指定数量。 一、参考文档 https://www.npmjs.com/package/vue-virtual-scroll-li…...

C++学习笔记(以供复习查阅)

视频链接 代码讲义 提取密码: 62bb 文章目录1、C基础1.1 C初识&#xff08;1&#xff09; 第一个C程序&#xff08;2&#xff09;注释&#xff08;3&#xff09;变量&#xff08;4&#xff09;常量&#xff08;5&#xff09;关键字&#xff08;6&#xff09;标识符命名规则1.2 …...

备份时间缩短为原来 1/4,西安交大云数据中心的软件定义存储实践

XEDP 统一数据平台为西安交通大学云平台业务提供可靠的备份空间和强大的容灾能力&#xff0c;同时确保数据安全。西安交通大学&#xff08;简称“西安交大”&#xff09;是我国最早兴办、享誉海内外的著名高等学府&#xff0c;是教育部直属重点大学。学校现有兴庆、雁塔、曲江和…...

我国近视眼的人数已经超过了六亿,国老花眼人数超过三亿人

眼镜是一种用于矫正视力问题、改善视力、减轻眼睛疲劳的光学器件&#xff0c;在我们的生活中不可忽略的一部分&#xff0c;那么我国眼镜市场发展情况是怎样了&#xff1f;下面小编通过可视化互动平台对我国眼镜市场的状况进行分析。我国是一个近视眼高发的国家&#xff0c;据统…...

设计模式(十八)----行为型模式之策略模式

1、概述 先看下面的图片&#xff0c;我们去旅游选择出行模式有很多种&#xff0c;可以骑自行车、可以坐汽车、可以坐火车、可以坐飞机。 作为一个程序猿&#xff0c;开发需要选择一款开发工具&#xff0c;当然可以进行代码开发的工具有很多&#xff0c;可以选择Idea进行开发&a…...