【嵌入式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 = 0;dbus_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的介绍
- g_dbus_connection_new_sync: 此函数用于创建新的GDBusConnection连接。它需要指定一个连接名和一个连接地址,还可以指定DBus连接的选项。
- g_dbus_connection_call_sync: 此函数用于在给定的GDBus连接上同步调用远程对象的方法。它需要指定对象的名称、接口名称、方法名称和方法的参数。此外,还可以指定调用超时时间和DBus调用的选项。
- g_dbus_proxy_new_sync: 此函数用于创建一个新的GDBus代理。它需要指定一个GDBusConnection连接、一个DBus代理的名称、代理接口的名称以及DBus代理的选项。
- g_dbus_proxy_call_sync: 此函数用于在给定的GDBus代理上同步调用远程对象的方法。它需要指定方法名称、方法的参数、调用超时时间和DBus调用的选项。
- g_dbus_proxy_set_default_timeout: 此函数用于设置DBus调用的默认超时时间(以毫秒为单位)。这个超时时间将应用于调用同步方法和在DBus代理上调用异步方法时未指定超时时间的调用。
- g_dbus_proxy_call: 此函数用于在给定的GDBus代理上异步调用远程对象的方法。它需要指定方法名称、方法的参数、DBus调用的选项以及一个回调函数来处理异步调用结果。
- g_dbus_proxy_call_finish: 此函数用于完成由g_dbus_proxy_call启动的异步DBus调用,并返回调用结果。
- g_dbus_proxy_new_for_bus_sync: 此函数用于在指定的DBus总线上创建一个新的GDBus代理。它需要指定DBus总线类型、DBus代理的名称、代理接口的名称以及DBus代理的选项。
- g_dbus_connection_new_for_address_sync():建立与DBus daemon的连接。在bluez开发中,我们需要通过该API建立与BlueZ daemon的连接。
- g_dbus_connection_register_object():用于注册一个对象到DBus系统总线上。在bluez开发中,我们可以用它将自定义的蓝牙服务以及属性注册到BlueZ daemon上。
- g_dbus_connection_call_sync():用于同步调用DBus方法。在bluez开发中,我们可以用它来调用BlueZ daemon上的方法,比如获取蓝牙设备、服务或特征的属性等。
- g_dbus_connection_signal_subscribe():用于订阅DBus signal。在bluez开发中,我们可以用它来订阅蓝牙设备的状态改变、蓝牙服务的添加或删除、蓝牙特征的值变化等事件。
- g_dbus_proxy_new_sync():用于创建一个代理对象。在bluez开发中,我们可以用它来创建一个代理对象,从而方便地操作蓝牙设备、服务或特征。
- g_dbus_proxy_call_sync():用于同步调用代理对象上的DBus方法。在bluez开发中,我们可以用它来调用代理对象上的方法,比如读取或写入蓝牙特征的值。
- g_dbus_proxy_get_property():用于获取代理对象上的属性值。在bluez开发中,我们可以用它来获取蓝牙设备、服务或特征的属性值。
- 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(D-Bus)是一个在不同程序之间传递消息的系统总线。DBus为不同的程序之间提供了一种通信机制,这种通信制可以在不需要知道对方程序的情况下进行通信。 DBus可以使用多种编程语言来开发,包括C、C、Python、Java等。在…...

如何在电脑更换新硬盘后迁移window11系统?2种迁移方法分享!
随着时间的流逝,数据量也在逐渐增多,就会导致您的硬盘空间也变得越来越小,因此系统运行速度可能会受到一些影响而越来越慢。为了摆脱这种情况,您可以选择升级到更大的硬盘来使计算机获取更大的磁盘空间,或者迁移系统到…...
6、Elasticsearch优化
一、Elasticsearch集群配置 1、硬件选择 Elasticsearch的基础是 Lucene ,所有的索引和文档数据是存储在本地的磁盘中, 具体的路径可在 ES 的配置文件 ../config/elasticsearch.yml 中配置,如下:磁盘在现代服务器上通常都是瓶颈。…...

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

CIMCAI smart shipping company product container damage identify
世界港航人工智能领军者企业CIMCAI,领先智能航运船公司集装箱管理产品ceaspectusS™全球规模化应用落地智能化航运,全球前三船公司认可验箱标准应用。全球港航人工智能领军者企业CIMCAI,是全球第一家完成两百万次人工智能验箱,上亿…...
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提示文件已损坏可能是受保护视图的问题。如果打开文件碰到此提示,可以先点确定。在按以下步骤操作:1)在空白程序界面,点击功能栏的【文件】࿰…...

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

Spring事务介绍
文章目录一、编程式事务二、声明式事务(常用)三、事务实战详解3.1)事务的回滚机制3.2)事务的传播3.3)事务超时时间3.4)事务隔离级别3.5)事务回滚条件Spring中对事务有两种支持方式,分…...
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-什么时候不能使用箭头函数
箭头函数的缺点 题目 什么时候不能使用箭头函数? 箭头函数的缺点 没有 arguments const fn1 () > {console.log(this, arguments) // 报错,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,JRE,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 浮点表示规格化和非规格化舍入浮点运算现代计算机存储和处理的信息以二值信号表示,这些二进制数字称为位,为什么要用二进制来进行编码?因为二进制只有1和0两种…...

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

老马闲评数字化「4」做数字化会不会被供应商拿捏住
原文作者:行云创新CEO 马洪喜 导语 开年过后业务特别的繁忙,出差也比较多,所以有段时间没更新了,对不住大家! 上一集(您可以查看“行云创新”主页阅读原文)咱们聊了数字化转型的“想转、急转、…...

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析取范式(基本积之和),合取范式(基本和之积)1.3.6合式公式1…...

IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...

Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
PostgreSQL——环境搭建
一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在࿰…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...