低功耗蓝牙ble开发(三)——bluez5接口及glib相关函数开发说明

在 D-Bus 编程中,代理对象(proxy object)是一个方便的抽象,用于简化与远程 D-Bus 服务的交互。代理对象代表远程 D-Bus 服务的某个对象,使得你可以像调用本地对象的方法一样调用远程对象的方法、获取属性以及监听信号。虽然使用代理对象并不是必须的,但它极大地简化了 D-Bus 编程,特别是对于复杂的 D-Bus 接口。

代理对象的作用

  1. 方法调用简化: 代理对象提供了调用远程方法的简单接口,你可以直接调用代理对象的方法,而不需要手动构建和解析 D-Bus 消息。
  2. 属性访问简化: 代理对象允许你直接访问远程对象的属性,而不需要手动处理 D-Bus 的 GetSet 请求。
  3. 信号处理简化: 代理对象可以自动处理从远程对象发出的信号,简化信号监听和处理过程。
  4. 错误处理: 代理对象提供一致的错误处理机制,使得处理 D-Bus 方法调用和属性访问中的错误更加方便。

6、bluez提供的基于dbus的api

BlueZ 是 Linux 下的官方蓝牙协议栈,提供了丰富的 D-Bus 接口来管理蓝牙设备。BlueZ 中的主要接口和方法涉及设备发现、配对、连接以及管理 GATT 服务和特征。以下是 BlueZ 中的关键接口、方法及其之间的关系的详细说明。

(1)主要接口
  1. org.bluez.Adapter1
    • 描述:表示蓝牙适配器,负责设备发现和管理。
    • 常用方法:
      • StartDiscovery:开始扫描周围的蓝牙设备。
      • StopDiscovery:停止扫描。
      • RemoveDevice:移除已配对的设备。
    • 常用属性:
      • Address:适配器的地址。
      • Name:适配器的名称。
      • Powered:适配器的电源状态。
  2. org.bluez.Device1
    • 描述:表示蓝牙设备,可以配对和连接。
    • 常用方法:
      • Connect:连接到设备。
      • Disconnect:断开连接。
      • Pair:配对设备。
      • CancelPairing:取消配对过程。
    • 常用属性:
      • Address:设备的地址。
      • Name:设备的名称。
      • Paired:配对状态。
      • Connected:连接状态。
  3. org.bluez.GattService1
    • 描述:表示 GATT 服务。
    • 常用属性:
      • UUID:服务的 UUID。
      • Primary:是否为主服务。
      • Device:所属设备。
  4. org.bluez.GattCharacteristic1
    • 描述:表示 GATT 特征。
    • 常用方法:
      • ReadValue:读取特征值。
      • WriteValue:写入特征值。
      • StartNotify:开始通知。
      • StopNotify:停止通知。
    • 常用属性:
      • UUID:特征的 UUID。
      • Service:所属服务。
      • Value:当前特征值。
  5. org.bluez.GattDescriptor1
    • 描述:表示 GATT 描述符。
    • 常用方法:
      • ReadValue:读取描述符值。
      • WriteValue:写入描述符值。
    • 常用属性:
      • UUID:描述符的 UUID。
      • Characteristic:所属特征。
      • Value:当前描述符值。
  6. org.freedesktop.DBus.ObjectManager
    • 描述:用于管理和监控 D-Bus 对象,通常用于获取所有对象及其接口和属性。
    • 常用方法:
      • GetManagedObjects:获取所有受管理的对象及其接口和属性。
    • 常用信号:
      • InterfacesAdded:当新对象添加时发出信号。
      • InterfacesRemoved:当对象接口移除时发出信号。
(2)方法之间的关系和流程

以下是使用 BlueZ 进行 BLE 设备发现、连接和操作的常见流程:

  1. 启动设备发现
    • 调用 org.bluez.Adapter1.StartDiscovery 开始扫描设备。
    • 订阅 org.freedesktop.DBus.ObjectManager.InterfacesAdded 信号,获取新发现的设备。
  2. 配对设备
    • InterfacesAdded 信号回调中,检查是否是目标设备。
    • 调用 org.bluez.Device1.Pair 进行配对。
  3. 连接设备
    • 配对成功后,调用 org.bluez.Device1.Connect 连接到设备。
  4. 发现服务和特征
    • 连接成功后,调用 org.freedesktop.DBus.ObjectManager.GetManagedObjects 获取设备的所有服务和特征。
    • 遍历返回的对象,找到 org.bluez.GattService1org.bluez.GattCharacteristic1
  5. 操作特征
    • 使用 org.bluez.GattCharacteristic1.ReadValue 读取特征值。
    • 使用 org.bluez.GattCharacteristic1.WriteValue 写入特征值。
    • 使用 org.bluez.GattCharacteristic1.StartNotify 订阅通知。

7、main_loop和dbus

“main_loop” 和 “dbus” 是两个在 Linux 环境下开发桌面应用和系统服务时经常会遇到的概念。

(1)Main Loop (主循环)

主循环是事件驱动编程的核心概念,广泛应用于图形用户界面(GUI)和其他需要持续处理事件的应用中。它的主要作用是不断地检查和处理事件,如用户输入、网络数据、定时器等。

在一个典型的主循环中,应用程序会做以下工作:

  1. 检查是否有任何事件发生(如鼠标点击、键盘输入)。
  2. 处理这些事件并执行相应的回调函数。
  3. 如果没有事件发生,则应用程序通常会等待(通常是阻塞操作),直到有事件需要处理。

在 Linux 环境下,许多 GUI 库如 GTK 和 Qt 都实现了自己的主循环。例如,GTK 使用 GMainLoop 进行事件处理。

(2)D-Bus (Desktop Bus)

D-Bus 是一个消息总线系统,用于在同一台机器上运行的多个程序之间进行通信。它的设计初衷是提供一个简单的方式,允许应用程序相互通信并协调工作。

D-Bus 有两个主要的总线:

  1. 系统总线:用于系统服务与应用程序之间的通信,例如网络管理器、音量控制等系统服务。
  2. 会话总线:用于同一用户会话中的应用程序之间的通信,例如桌面环境的组件。

D-Bus 的通信模型基于消息传递,包括方法调用、信号和属性。应用程序可以通过 D-Bus 接口来调用其他应用程序的方法、接收信号或查询/设置属性。

(3)Main Loop 和 D-Bus 的结合

在实际开发中,D-Bus 通常需要集成到应用程序的主循环中,以便处理来自 D-Bus 的消息。这种集成通常通过库来实现,例如:

  • GLib(用于 GTK 应用):GLib 提供了对 D-Bus 的支持,可以将 D-Bus 消息处理集成到 GMainLoop 中。
  • QtDBus(用于 Qt 应用):QtDBus 提供了对 D-Bus 的支持,可以将 D-Bus 消息处理集成到 Qt 的事件循环中。

例如,在一个使用 GLib 的应用程序中,您可以这样使用 D-Bus:

#include <glib.h>
#include <gio/gio.h>int main(int argc, char *argv[]) {GMainLoop *loop = g_main_loop_new(NULL, FALSE);GDBusConnection *connection;GError *error = NULL;connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);if (error != NULL) {g_printerr("Error connecting to D-Bus: %s\n", error->message);g_error_free(error);return 1;}// 设置 D-Bus 信号处理等g_main_loop_run(loop);// 清理资源g_main_loop_unref(loop);g_object_unref(connection);return 0;
}

在这个示例中,g_main_loop_run 会启动主循环,g_bus_get_sync 用于连接到会话总线,之后可以设置 D-Bus 信号处理等操作。

总之,main loop 和 D-Bus 在 Linux 环境下的桌面应用开发中是两个非常重要的组件,前者负责事件处理循环,后者提供了进程间通信机制。通过将 D-Bus 集成到主循环中,可以让应用程序更高效地处理系统事件和进程间通信。

8、GVariant格式

GVariant 是 GLib 库中的一种数据类型,用于在 D-Bus 上表示和传输复杂的数据结构。格式字符串 (a{oa{sa{sv}}}) 描述了 GVariant 的一种复合结构,常用于表示对象树及其属性。这种格式在 BlueZ 和其他使用 D-Bus 的应用中非常常见,尤其是在实现 org.freedesktop.DBus.ObjectManager 接口时。

结构说明

  • ( ... ):表示一个元组。
  • a{ ... }:表示一个键值对的数组(字典)。
  • o:表示一个对象路径(D-Bus 中的对象路径以 / 开头的字符串)。
  • a{ ... }:嵌套的键值对数组。
  • s:表示一个字符串。
  • a{ ... }:再次嵌套的键值对数组。
  • v:表示一个变体(可以是任意类型)。

解释 (a{oa{sa{sv}}})

  • 最外层的括号 () 表示这是一个元组。
  • a{oa{sa{sv}}} 描述了元组中的一个元素,这是一个数组,每个元素是一个键值对,其中键是对象路径(o),值是另一个字典(a{sa{sv}})。
  • a{sa{sv}} 描述了对象路径对应的值,这是一个字典,其中键是接口名称(s),值是属性字典(a{sv})。
  • a{sv} 描述了属性字典,其中键是属性名称(s),值是属性值(v,表示变体类型)。

bluez和dbus的开发中,很多该格式的操作,glib库中提供了很多该格式的函数方法,具体情况具体分析使用。

(1)具体示例

假设我们有如下的 GVariant 数据表示一个蓝牙设备和其服务:

({"/org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX" : {  // 设备对象路径"org.bluez.Device1" : {  // 接口"Address" : <"XX:XX:XX:XX:XX:XX">,  // 属性"Name" : <"DeviceName">}},"/org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX/service0001" : {  // 服务对象路径"org.bluez.GattService1" : {  // 接口"UUID" : <"00001800-0000-1000-8000-00805f9b34fb">,  // 属性"Primary" : <true>}}}
)
(2)解析示例
void parse_managed_objects(GVariant *result) {GVariantIter *iter;gchar *object_path;GVariant *interfaces;// 解析结果g_variant_get(result, "(a{oa{sa{sv}}})", &iter);// 遍历每个对象路径while (g_variant_iter_next(iter, "{oa{sa{sv}}}", &object_path, &interfaces)) {g_print("Object Path: %s\n", object_path);GVariantIter *iface_iter;gchar *interface;GVariant *props;// 解析接口g_variant_get(interfaces, "a{sa{sv}}", &iface_iter);while (g_variant_iter_next(iface_iter, "{sa{sv}}", &interface, &props)) {g_print("  Interface: %s\n", interface);GVariantIter *prop_iter;gchar *prop_name;GVariant *prop_value;// 解析属性g_variant_get(props, "a{sv}", &prop_iter);while (g_variant_iter_next(prop_iter, "{sv}", &prop_name, &prop_value)) {gchar *value_str = g_variant_print(prop_value, TRUE);g_print("    %s: %s\n", prop_name, value_str);g_free(value_str);g_variant_unref(prop_value);g_free(prop_name);}g_variant_iter_free(prop_iter);g_variant_unref(props);g_free(interface);}g_variant_iter_free(iface_iter);g_variant_unref(interfaces);g_free(object_path);}g_variant_iter_free(iter);
}

9、Dbus接口

org.freedesktop.DBus.ObjectManagerorg.freedesktop.DBus.Properties 是两个不同的 D-Bus 接口,分别用于管理对象和处理属性。它们在 BlueZ(Linux 上的 Bluetooth 栈)以及其他基于 D-Bus 的系统中广泛使用。以下是它们的详细介绍。

(1)org.freedesktop.DBus.ObjectManager

org.freedesktop.DBus.ObjectManager 接口用于管理对象树,主要用于枚举和监视对象的生命周期变化。它有两个主要方法:

  1. GetManagedObjects

    • 描述:返回对象路径和它们对应的接口和属性。

    • 方法签名a{oa{sa{sv}}}

    • 示例代码:

      GVariant *result = g_dbus_connection_call_sync(connection,"org.bluez","/","org.freedesktop.DBus.ObjectManager","GetManagedObjects",NULL,G_VARIANT_TYPE("(a{oa{sa{sv}}})"),G_DBUS_CALL_FLAGS_NONE,-1,NULL,&error
      );if (error != NULL) {g_printerr("Error getting managed objects: %s\n", error->message);g_error_free(error);return;
      }
      

信号

  1. InterfacesAdded
    • 描述:在新对象添加到对象树时发出信号。
    • 信号签名(oa{sa{sv}})
  2. InterfacesRemoved
    • 描述:在对象从对象树中移除时发出信号。
    • 信号签名(oas)
(2)org.freedesktop.DBus.Properties

org.freedesktop.DBus.Properties 接口用于获取和设置对象属性,并监听属性变化。它有几个主要方法和一个信号:

方法

  1. Get

    • 描述:获取对象的特定属性值。

    • 方法签名(ss) -> (v)

    • 示例代码:

      GVariant *result = g_dbus_connection_call_sync(connection,"org.bluez",object_path,"org.freedesktop.DBus.Properties","Get",g_variant_new("(ss)", interface_name, property_name),G_VARIANT_TYPE("(v)"),G_DBUS_CALL_FLAGS_NONE,-1,NULL,&error
      );if (error != NULL) {g_printerr("Error getting property: %s\n", error->message);g_error_free(error);return;
      }GVariant *property_value = g_variant_get_child_value(result, 0);
      // 处理属性值
      g_variant_unref(property_value);
      g_variant_unref(result);
      
  2. Set

    • 描述:设置对象的特定属性值。
    • 方法签名(ssv) -> ()
  3. GetAll

    • 描述:获取对象的所有属性值。
    • 方法签名(s) -> (a{sv})

信号

  1. PropertiesChanged
    • 描述:当对象的属性发生变化时发出信号。
    • 信号签名(sa{sv}as)
(3)信号签名

上述中的信号签名可以理解为调用方法的输入参数类型(箭头后面的表示输出参数类型)

(ss) -> (v) 是 D-Bus 方法调用的签名格式,描述了方法的输入参数和返回值类型。这种签名在 org.freedesktop.DBus.Properties 接口的 Get 方法中非常常见。

签名解释

  • (ss):表示方法的输入参数是两个字符串。
  • ->:表示从输入参数到返回值的转换。
  • (v):表示方法的返回值是一个变体类型。

具体来说,这个签名表示一个方法,它接收两个字符串参数并返回一个变体。

org.freedesktop.DBus.Properties.Get 方法

这个签名用于 org.freedesktop.DBus.Properties 接口中的 Get 方法,该方法用于获取某个对象属性的值。

  • 方法名称Get
  • 输入参数:
    • s:接口名称
    • s:属性名称
  • 返回值:
    • v:属性值

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/28879.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】线性表之《顺序表》超详细实现

顺序表 一.数据结构1.逻辑结构2.物理结构 二.顺序表的分类1.静态顺序表2.动态顺序表 三.顺序表的实现1.创建顺序表2.初始化顺序表3.判断是否扩容4.打印顺序表5.插入操作1.头插2.尾插3.按照下标插入 6.删除操作1.头删2.尾删3.按照下标删除 7.查找数据8.修改数据9.清空顺序表10.销…

【文末附gpt升级秘笈】OpenAI CTO采访揭底:GPT-4是否已触及大模型能力瓶颈?

OpenAI CTO采访揭底&#xff1a;GPT-4是否已触及大模型能力瓶颈&#xff1f; 一、引言 近年来&#xff0c;人工智能&#xff08;AI&#xff09;领域的发展日新月异&#xff0c;其中大型语言模型&#xff08;LLM&#xff09;如GPT系列更是引领了新一轮的技术浪潮。然而&#x…

从11个视角看全球Rust程序员2/4:深度解读JetBrains最新报告

讲动人的故事,写懂人的代码 5 Rust代码最常使用什么协议与其他代码交互? REST API: 2022年:51%2023年:51%看上去REST API的使用比例挺稳定的,没啥变化。语言互操作性(Language Interop): 2022年:53%2023年:43%语言互操作性的比例在2023年下来了一些,掉了10个百分点…

示例:WPF中DataGrid设置多级分组样式

一、目的&#xff1a;应用CollectionViewSource和GroupStyle设置DataGrid多级分组样式 二、实现 一级分组效果如下 二级分组效果如下 三、环境 VS2022 四、示例 具体实现代码如下 <TabItem Header"DataGrid - 多级分组"><TabItem.Resources><Colle…

ansible-Role角色批量按照node_export节点,并追加信息到Prometheus文件中

文章目录 剧本功能 inventory.yaml文件定义deploy.yaml角色定义node_exporter_lock角色定义任务角色main.yamlnode_exporter_tasks.yml角色触发任务notifyextra_tasks.yml角色prometheus_node_config.j2模板文件 执行命令查看变量 剧本功能 功能1&#xff1a; 批量执行node_ex…

Java数据结构与算法(多重背包)

前言: 多重背包问题&#xff08;Multiple Knapsack Problem, MKP&#xff09;是背包问题的一个变种。在这种问题中&#xff0c;你有多个背包&#xff0c;每个背包都有一定的容量。你需要选择一些物品放入这些背包中&#xff0c;以使放入物品的总价值最大化。每个物品都有一个价…

【Nvidia+AI摄像头】面向机器人双目视觉相机

随着人工智能和机器人技术的不断发展&#xff0c;双目深度相机作为一种重要的传感器&#xff0c;正在被广泛应用于各种机器人系统中。双目深度相机作为机器人不可或缺的感知器件&#xff0c;其高精度深度信息为机器人提供环境感知、立体视觉、姿态识别等功能&#xff0c;让机器…

Flink 窗口函数

一、Window 概述 Flink 流式计算是一种被设计用于处理无限数据集的数据处理引擎&#xff0c;而无限数据集是指一种不断增长的本质上无限的数据集&#xff0c;而 window 是一种切割无线数据为有限块进行处理的手段。 二、Window 分类 Window 可以分为两类&#xff1a; Count…

程序员画图工具?那必然是你了!!【送源码】

作为一个程序员&#xff0c;画图是必不可少的技巧。当然此画图不是搞艺术&#xff0c;而是画各种架构图、流程图、泳道图以及各种示意图。 平时我不论是记笔记、写技术文章&#xff0c;还是工作中写文档&#xff0c;都需要配上各种各样的示意图。不管是帮助自己更好的掌握知识…

云动态摘要 2024-06-17

给您带来云厂商的最新动态&#xff0c;最新产品资讯和最新优惠更新。 最新优惠与活动 [低至1折]腾讯混元大模型产品特惠 腾讯云 2024-06-06 腾讯混元大模型产品特惠&#xff0c;新用户1折起&#xff01; 云服务器ECS试用产品续用 阿里云 2024-04-14 云服务器ECS试用产品续用…

Thinkpad系列产品进入Bios并设置U盘启动

Thinkpad系列产品&#xff0c;进入Bios并设置U盘启动&#xff0c;常用于以下场景&#xff1a; 1. 安装操作系统。 通过U盘启动盘&#xff0c;用户可以在电脑无法从硬盘启动或需要重装系统时&#xff0c;将操作系统安装到电脑中。这种方法简单且有效&#xff0c;节省了时间并方便…

夏季家里粉尘螨虫满天飞?一招搞定!好用家用空气净化器品牌分享

每到夏季&#xff0c;是家中尘螨滋生的高发期。夏季无论是开窗通风还是关窗开空调&#xff0c;都很容易造成空气中的浮尘堆积&#xff0c;不注意卫生清洁&#xff0c;容易滋生细菌、尘螨。 易过敏、体质弱的人群长时间在空气污染环境中&#xff0c;很容易就会过敏或者发生其他…

成员变量和for循环里面的变量不冲突原因

今天写项目&#xff0c;发现一个类中有一个成员变量与for循环块中的局部变量重名了&#xff0c;但是也没有报错&#xff0c;功能也是正常的&#xff0c;然后了解了一下原因&#xff1a; 成员变量和 for 循环块中的变量不冲突的原因在于它们的作用域&#xff08;Scope&#xff…

2024年最新消防设施操作员(初级)题库

16.LQG10-30表示消防供水管用&#xff0c;设计工作压力为&#xff08; &#xff09;MPa&#xff0c;水带长度为&#xff08; &#xff09;m的轻便消防水龙。 A.10、30 B.10、3.0 C.1.0、30 D.1.0、3.0 答案:C 解析:根据初级教材179页&#xff0c;LQG10-30表示消防供水管用…

Hive笔记-2

第 3 章 DDL (Data Definition Language) 数据定义 DDL数据定义语言 DML数据操作语言 3.1 数据库 (database) 3.1.1 创建数据库 1) 语法 CREATE DATABASE [IF NOT EXISTS] database_name [COMMENT database_comment] [LOCATION hdfs_path] [WITH DBPROPERTIES (property_…

leetcode153. 寻找旋转排序数组中的最小值

leetcode153. 寻找旋转排序数组中的最小值 使用二分法。中间值如果小于等于最右边的值&#xff0c;去左边部分找&#xff1b;中间值如果大于最右边的值&#xff0c;去右半部分找。 def rotate_array_min(nums):n len(nums)low 0high n - 1while low < high:mid low (h…

Git 代码管理规范 !

分支命名 master 分支 master 为主分支&#xff0c;也是用于部署生产环境的分支&#xff0c;需要确保master分支稳定性。master 分支一般由 release 以及 hotfix 分支合并&#xff0c;任何时间都不能直接修改代码。 develop 分支 develop 为开发环境分支&#xff0c;始终保持最…

在微信公众号上怎么添加预定房间功能

在这个快节奏的现代社会&#xff0c;人们对于便捷与高效的需求日益增加。特别是在旅行或出差时&#xff0c;能够快速、方便地预订一间舒适的房间&#xff0c;无疑是每个人心中的小确幸。今天&#xff0c;我们为您带来了一项革命性的服务——微信公众号上的房间预定功能&#xf…

力扣 50.pow(x,n)

class Solution { public: double quickMul(double x,long long N){ if(N0) return 1; double valuequickMul(x,N/2); return N%20?value*value:value*value*x; } double myPow(double x, int n) { long long Nn; return N>0?quickMul(x, N):1.0/quickMul(x, N); } };

Serverless如何赋能餐饮行业数字化?乐凯撒思变之道

导语 | 在数字化浪潮席卷全球的今天&#xff0c;每一个行业都在经历着前所未有的变革。餐饮行业作为人们日常生活中不可或缺的一部分&#xff0c;更是面临着巨大的转型压力。如何完成数字化转型&#xff0c;打破传统经营模式的限制&#xff0c;成为摆在众多餐饮商家面前的一道难…