首页 > 其他分享 >低功耗蓝牙ble开发(三)——bluez5接口及glib相关函数开发说明

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

时间:2024-06-17 18:32:13浏览次数:23  
标签:glib 对象 Bus 低功耗 iter bluez5 bluez org 属性

在 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:属性值

标签:glib,对象,Bus,低功耗,iter,bluez5,bluez,org,属性
From: https://blog.csdn.net/wjj970802/article/details/139751450

相关文章

  • cglib 代理类自己equals自己 返回false问题
    问题:通过debug发现result.removeAll的时候删不了publicbooleanequals(Objectobj){returnobjinstanceofOspSpringBoot2Initializer.OspBean&&this.bean.equals(((OspSpringBoot2Initializer.OspBean)obj).bean);}this.bean.equals(((OspSpri......
  • glibc函数malloc的工作原理
    glibc提供了malloc函数来动态分配内存,我们只知道调用malloc会返回给我们一个指针,指向一块内存空间或NULL,那么malloc的工作原理是什么呢?概述:1.小于128kB的空间,使用内存池(在堆上)或brk或sbrk系统调用在堆上分配2.大于128kB的空间,使用mmap在文件映射区分配+----------------......
  • 代理设计模式之JDK动态代理&CGLIB动态代理原理与源码剖析
    代理设计模式代理模式(Proxy),为其它对象提供一种代理以控制对这个对象的访问。如下图从上面的类图可以看出,通过代理模式,客户端访问接口时的实例实际上是Proxy对象,Proxy对象持有RealSubject的引用,这样一来Proxy在可以在实际执行RealSubject前后做一些操作,相当于是对RealSubject......
  • linux:centos7升级glibc到2.36
    #安装依赖的东东yuminstall-ygccgcc-c++glibc-developenssl-developenssl-staticzlib-devellzmatk-develxz-develbisonbzip2bzip2-develncurses-develgdbm-develreadline-develsqlite-devellibffi-develtexinfolibmpc-devel#安装makecd/chz/ins......
  • glibc中的localtime方法源码分析
    localtime方法会加锁,当TZ环境变量为空或者变更时,还会读取文件,还有个问题就是这个方法返回的指针是一个全局变量,可以使用redis无锁的localtime方法来优化这个性能。localtime方法调用链:localtime->__localtime64->__tz_convert(加锁、调用tzset_internal方法解释TZ环境变量,如果......
  • SpringAOP-代理方式-Cglib动态代理
    文章目录cglib动态代理cglib是基于继承的方式实现的是继承目标类从而产生代理类springaop底层使用的就是cglib的动态代理packagecom.itheima.cjlibproxy;importnet.sf.cglib.proxy.Callback;importnet.sf.cglib.proxy.Enhancer;importnet.sf.cglib.proxy.......
  • SD321BF 低功耗单运算放大器芯片IC
    一般说明    SD321为低功耗系统带来性能和经济性。具有高单位增益频率和保证0.4V/在此情况下,静态电流仅为430μa/aef(5V)。输入通用模式范围包括地面,因此该设备能够在单电源应用和双电源应用中工作。它还能够舒适地驱动大容量负载。    SD321可在SOT23-5封装......
  • OM6626国产BLE5.3高性能低功耗蓝牙SoC芯片
    OM6626简介OM6626是功能强大、性能稳定、超低功耗的国产蓝牙SoC芯片,适用于各种低功耗蓝牙和专有的2.4GHz应用场景。OM6626还集成了电源管理单元(PMU),可提供高效电源管理。可实现从小体积医疗监测到低功耗智能穿戴等健康监测设备,从SmartTag(物品追踪器)到高性能电脑键鼠等生活便利......
  • BK7258--wifi音视频soc芯片,1080P H264 wifi低功耗保活,内置BLE,音频code,psram,flash,USB2.
    BK7258是上海博通推出的高度集成的Wi-Fi+BLE combo音视频芯片,支持UVC和DVP摄像头,该芯片集成音视频外设及接口,1080P,H.264,低功耗,内置flash,dsp,psram,驱屏,回声消除及降噪等,广泛适用于可视猫眼,门锁,门铃,ipc,内窥,儿童相机等应用市场。可视门铃应用:DVP接口支持720p25fps图像采集;MJPE......
  • 01.Alpine编译glibc
    概要本文档采用glibc2.28版本作为示例,模拟内网环境无法访问github等开源社区为精简docker容器镜像,采用Alpine镜像,需要手动编译glibc源代码制作编译好的glibc二进制文件获取glibc二进制文件构建工具#内网环境可下载该工具包手动上传到服务器gitpullhttps://github.com/s......