【嵌入式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…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...
Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...
