GATT 服务的核心函数bt_gatt_discover的介绍

news2025/5/27 20:53:41

目录

概述

1 GATT 基本概念

1.1 GATT 的介绍

1.2 GATT 的角色

 1.3 核心组件

1.4 客户端操作

2  bt_gatt_discover函数的功能和应用

2.1 函数介绍

 2.1 发现类型(Discover Type)

3 典型使用流程

3.1 服务发现示例

3.2 级联发现模式

 3.3 按UUID过滤发现

 3.4 发现描述符

4 错误处理 

4.1 常见错误码

4.2 错误处理示例

5 性能优化建议

6 资源管理注意事项

6.1 参数生命周期

6.2 取消发现


概述

本文介绍了蓝牙低功耗(BLE)中的GATT协议及其核心功能。GATT定义了BLE设备通过服务和特征交换数据的标准框架,包含服务器和客户端两种角色。文章详细解析了GATT的核心组件(服务、特性、描述符)及其层级结构,并以Zephyr协议栈中的bt_gatt_discover函数为例,说明其参数配置、发现类型和使用流程,包括服务发现、级联发现、UUID过滤等典型应用场景。最后还列举了常见错误码及处理方法,为BLE应用的开发提供了实用指导。

1 GATT 基本概念

1.1 GATT 的介绍

GATT (Generic Attribute Profile) 是 Bluetooth Low Energy (BLE) 的核心协议,定义了 数据通信的标准框架,使BLE设备能够通过 服务(Services) 和 特征(Characteristics) 交换数据。

1.2 GATT 的角色

角色说明典型设备
GATT 服务器(Server)存储并提供数据(如传感器数据)心率带、温度计
GATT 客户端(Client)读取或写入服务器数据手机、中央设备

 1.3 核心组件

 1)层级结构

GATT Profile
├── Services (服务)
│   ├── Characteristics (特性)
│   │   ├── Value (值)
│   │   ├── Descriptors (描述符)
│   │   │   └── Client Characteristic Configuration (CCC)
│   │   └── Properties (属性)
│   └── Includes (包含服务)
└── Attributes (属性)

2) 关键组件说明

组件说明示例UUID
服务(Service)功能逻辑集合0x180A (设备信息服务)
特性(Characteristic)服务中的数据项0x2A29 (厂商名称)
描述符(Descriptor)特性的元数据0x2902 (CCC描述符)
属性(Attribute)数据库基本单元由协议栈管理

1.4 客户端操作

操作函数(Zephyr示例)说明
发现服务bt_gatt_discover()扫描远程设备的GATT表
读取特征值bt_gatt_read()读取数据(如电池电量)
写入特征值bt_gatt_write()发送命令或配置
启用通知bt_gatt_subscribe()订阅实时数据(如心率)

2  bt_gatt_discover函数的功能和应用

2.1 函数介绍

bt_gatt_discover 是 Zephyr BLE 协议栈中用于发现远程设备 GATT 服务的核心函数,下面我将从多个维度进行详细说明:

1) 函数原型与参数

int bt_gatt_discover(
    struct bt_conn *conn,
    struct bt_gatt_discover_params *params
);

2)参数说明:

  • conn:已建立的BLE连接句柄

  • params:发现参数结构体,包含以下关键字段:

struct bt_gatt_discover_params {
    const struct bt_uuid *uuid;      // 目标UUID(可选过滤条件)
    uint16_t start_handle;           // 起始属性句柄(通常0x0001)
    uint16_t end_handle;             // 结束属性句柄(通常0xFFFF)
    enum bt_gatt_discover_type type; // 发现类型
    void (*func)(struct bt_conn *conn,
                const struct bt_gatt_attr *attr,
                struct bt_gatt_discover_params *params);
};

 2.1 发现类型(Discover Type)

类型枚举值说明对应ATT操作
BT_GATT_DISCOVER_PRIMARY发现主服务ATT Read By Group Type Req
BT_GATT_DISCOVER_SECONDARY发现次要服务ATT Read By Group Type Req
BT_GATT_DISCOVER_INCLUDE发现包含的服务ATT Read By Type Req
BT_GATT_DISCOVER_CHARACTERISTIC发现特性ATT Read By Type Req
BT_GATT_DISCOVER_DESCRIPTOR发现描述符ATT Find Information Req
BT_GATT_DISCOVER_STD_CHAR_DESC发现标准特性描述符ATT Read By Type Req

3 典型使用流程

3.1 服务发现示例

static struct bt_gatt_discover_params discover_params;

static void discover_cb(struct bt_conn *conn,
                      const struct bt_gatt_attr *attr,
                      struct bt_gatt_discover_params *params)
{
    if (!attr) {
        printk("Discovery complete\n");
        return;
    }

    switch (params->type) {
    case BT_GATT_DISCOVER_PRIMARY: {
        struct bt_gatt_service_val *svc = attr->user_data;
        printk("Service found: start_handle=0x%04X, end_handle=0x%04X\n",
              attr->handle, svc->end_handle);
        break;
    }
    case BT_GATT_DISCOVER_CHARACTERISTIC: {
        struct bt_gatt_chrc *chrc = attr->user_data;
        printk("Characteristic: handle=0x%04X, properties=0x%02X\n",
              chrc->value_handle, chrc->properties);
        break;
    }
    }
}

void start_discovery(struct bt_conn *conn)
{
    discover_params.uuid = NULL;  // 发现所有主服务
    discover_params.start_handle = 0x0001;
    discover_params.end_handle = 0xFFFF;
    discover_params.type = BT_GATT_DISCOVER_PRIMARY;
    discover_params.func = discover_cb;

    int err = bt_gatt_discover(conn, &discover_params);
    if (err) {
        printk("Discovery failed to start (err %d)\n", err);
    }
}

3.2 级联发现模式

static void discover_chars(struct bt_conn *conn, uint16_t start, uint16_t end)
{
    static struct bt_gatt_discover_params params;
    
    params.start_handle = start;
    params.end_handle = end;
    params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
    params.func = discover_cb;
    
    bt_gatt_discover(conn, &params);
}

static void discover_cb(...)
{
    if (params->type == BT_GATT_DISCOVER_PRIMARY) {
        // 发现主服务后继续发现特性
        struct bt_gatt_service_val *svc = attr->user_data;
        discover_chars(conn, attr->handle + 1, svc->end_handle);
    }
}

 3.3 按UUID过滤发现

static struct bt_uuid_16 find_uuid = BT_UUID_INIT_16(0x180F); // 电池服务

void find_battery_service(struct bt_conn *conn)
{
    discover_params.uuid = &find_uuid.uuid;
    discover_params.type = BT_GATT_DISCOVER_PRIMARY;
    bt_gatt_discover(conn, &discover_params);
}

 3.4 发现描述符

void discover_descriptors(struct bt_conn *conn, uint16_t start, uint16_t end)
{
    discover_params.start_handle = start;
    discover_params.end_handle = end;
    discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
    bt_gatt_discover(conn, &discover_params);
}

4 错误处理 

4.1 常见错误码

错误码说明
0成功
-ENOTCONN未建立连接
-EINVAL无效参数
-ENOMEM内存不足
-EOPNOTSUPP操作不支持

4.2 错误处理示例

int err = bt_gatt_discover(conn, &params);
if (err) {
    printk("Error %d during discovery\n", err);
    switch (err) {
    case -ENOTCONN:
        // 处理连接问题
        break;
    case -EINVAL:
        // 检查参数有效性
        break;
    }
}

5 性能优化建议

  1. 分阶段发现:先发现服务,再根据需要发现特性和描述符

  2. 缓存发现结果:避免重复发现

  3. 合理设置句柄范围:缩小start_handle/end_handle范围

  4. 使用UUID过滤:减少不必要的发现操作

6 资源管理注意事项

6.1 参数生命周期

// 错误:使用栈变量(函数返回后失效)
void start_temp_discovery(struct bt_conn *conn) {
    struct bt_gatt_discover_params temp_params = {...};
    bt_gatt_discover(conn, &temp_params); // 危险!
}

// 正确:使用静态或动态分配
static struct bt_gatt_discover_params persistent_params;

6.2 取消发现

void cancel_discovery(struct bt_conn *conn) {
    bt_gatt_discover_cancel(conn, &discover_params);
}

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

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

相关文章

【短距离通信】【WiFi】WiFi7关键技术之4096-QAM、MRU

目录 3. 4096-QAM 3.1 4096-QAM 3.2 QAM 的阶数越高越好吗? 4. MRU 4.1 OFDMA 和 RU 4.2 MRU 资源分配 3. 4096-QAM 摘要 本章主要介绍了Wi-Fi 7引入的4096-QAM对数据传输速率的提升。 3.1 4096-QAM 对速率的提升 Wi-Fi 标准一直致力于提升数据传输速率&a…

线程池实战——数据库连接池

引言 作者在前面写了很多并发编程知识深度探索系列文章,反馈得知友友们收获颇丰,同时我也了解到友友们也有了对知识如何应用感到很模糊的问题。所以作者就打算写一个实战系列文章,让友友们切身感受一下怎么应用知识。话不多说,开…

基于moonshot模型的Dify大语言模型应用开发核心场景

基于moonshot模型的Dify大语言模型应用开发核心场景学习总结 一、Dify环境部署 1.Docker环境部署 这里使用vagrant部署,下载vagrant之后,vagrant up登陆,vagrant ssh,在vagrant 中使用 vagrant centos/7 init 快速创建虚拟机 安装…

华为OD机试真题——字符串序列判定(2025B卷:100分)Java/python/JavaScript/C/C++/GO最佳实现

2025 B卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…

工商总局可视化模版-Echarts的纯HTML源码

概述 基于ECharts的工商总局数据可视化HTML模版,帮助开发者快速搭建专业级工商广告数据展示平台。这款模版设计规范,功能完善,适合各类工商监管场景使用。 主要内容 本套模版采用现代化设计风格,主要包含以下核心功能模块&…

Spring AI 和 Elasticsearch 作为你的向量数据库

作者:来自 Elastic Josh Long, Philipp Krenn 及 Laura Trotta 使用 Spring AI 和 Elasticsearch 构建一个完整的 AI 应用程序。 Elasticsearch 原生集成了业界领先的生成式 AI 工具和服务提供商。查看我们关于超越 RAG 基础或使用 Elastic 向量数据库构建生产级应用…

集群聊天服务器学习 配置开发环境(VScode远程连接虚拟机Linux开发)(2)

配置远程开发环境 第一步:Linux系统运行sshd服务 第二步:在vscode上安装Remote Deve I opment插件,其依赖插件会自动安装 第三步:配置远程Linux主机的信息 第四步:在vscode上开发远程连接Linux 第一步:…

rabbitmq的使用介绍

一.队列工作模式介绍 1.WorkQueues模型 生产者直接把消息发送给队列,然后消费者订阅队列 特点: 消息不会重复, 分配给不同的消费者. 代码实现: 消费者代码: Component Slf4j public class SpringRabbitListener {RabbitListener(queues &q…

系统编程day04

一.进程的基本概念 一.定义 进程是一个程序执行的过程(也可以说是正在运行的程序),是系统分配资源的基本单位,由cpu对各个进程指挥调度,在单核cpu的情况下,各个进程可以通过一定规则在cpu上并发运行。 二.PCB块 1.PC…

Arduino Uno KY-037声音传感器实验

KY-037声音传感器实验 KY-037声音传感器实验1、 实验内容2、KY-037声音传感器介绍3、实验注意事项4、代码和实验现象 KY-037声音传感器实验 1、 实验内容 通过对KY-037声音传感器吹气,控制LED的打开和关闭,吹一下LED打开,在吹一下LED关闭。…

基于音频Transformer与动作单元的多模态情绪识别算法设计与实现(在RAVDESS数据集上的应用)

摘要:情感识别技术在医学、自动驾驶等多个领域的广泛应用,正吸引着研究界的持续关注。本研究提出了一种融合语音情感识别(SER)与面部情感识别(FER)的自动情绪识别系统。在SER方面,我们采用两种迁…

什么是VR实景?有哪些高价值场景?

在数字化浪潮的推动下,虚拟现实技术正以前所未有的速度改变着我们的生活方式和工作模式。 其中,VR实景作为VR技术的一个重要应用场景,独特的沉浸感和交互性,在众多领域展现出应用潜力和高价值场景。什么是VR实景?VR实…

同一无线网络下的设备IP地址是否相同?

在家庭和办公网络普及的今天,许多人都会好奇:连接同一个Wi-Fi的设备是否共享相同的IP地址?这个问题看似简单,实则涉及多个角度。本文将为您揭示其中的技术奥秘。 用一个无线网IP地址一样吗?同一无线网络(如…

第2周 PINN核心技术揭秘: 如何用神经网络求解偏微分方程

1. PDEs与传统数值方法回顾 (Review of PDEs & Traditional Numerical Methods) 1.1 什么是偏微分方程 (Partial Differential Equations, PDEs)? 偏微分方程是描述自然界和工程领域中各种物理现象(如热量传播、流体流动、波的振动、电磁场分布等)的基本数学语言。 1.…

【C语言】习题练手套餐 2

每日习题分享。 字符串函数的运用 首先回顾一下字符串函数。 字符串长度 strlen(const char *s);功能:计算字符串的长度,不包含终止符\0。 字符串连接 char *strcat(char *dest, const char *src); char *strncat(char *dest, const char *src, si…

[项目总结] 基于Docker与Nginx对项目进行部署

🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏: 🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 🍕 Collection与…

神经正切核推导(2)

对神经正切核的理解和推导(1)-CSDN博客 这篇文章包括很多概念的理解 声明: 本篇文章来自于Neural Tangent Kernel (NTK)基础推导 - Gearlesskai - 博客园 旨在对上述推导过程进行再推导与理解 手写推导部分与其他颜…

Ctrl+鼠标滚动阻止页面放大/缩小

项目场景: 提示:这里简述项目相关背景: 一般在我们做大屏的时候,不希望Ctrl鼠标上下滚动的时候页面会放大/缩小,那么在有时候,又不希望影响到别的页面,比如说这个大屏是在另一个管理后台中&am…

3d世界坐标系转屏幕坐标系

世界坐标 ——> NDC标准设备坐标 ——> 屏幕坐标 标准设备NDC坐标系 屏幕坐标系 .project方法将 将向量(坐标)从世界空间投影到相机的标准化设备坐标 (NDC) 空间。 手动实现HTML元素定位到模型位置,实现模型标签效果(和css2Render原理同理&#…

【2025】基于Springboot + vue + 协同过滤算法实现的旅游推荐系统

项目描述 本系统包含管理员和用户两个角色。 管理员角色: 用户管理:管理系统中所有用户的信息,包括添加、删除和修改用户。 配置管理:管理系统配置参数,如上传图片的路径等。 权限管理:分配和管理不同角…