ESP32 BLE学习(1) — GAP和GATT回调函数作用

2024-06-19 14:04

本文主要是介绍ESP32 BLE学习(1) — GAP和GATT回调函数作用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

(1)学习本文之前,需要先了解的基础知识:ESP32 BLE学习(0) — 基础架构
(2)该部分只是对GAPGATT回调函数进行简单的介绍,因为这两个回调函数中参数太多,个人认为没必要全部进行讲解。因此只有当我认为需要使用的时候,才会讲解对应的内容。

回调函数作用介绍

(1)在学习蓝牙基础架构的时候,我们知道GAP主要用来进行广播,扫描和发起连接等。而GATT用来规范属性(Attribute)中的数据内容,并运用分组(group)的概念对属性(Attribute)进行分类管理。
(2)在ESP32中,GAPGATT的所有操作将分别在esp_ble_gatts_register_callback()esp_ble_gap_register_callback()这两个函数注册的回调函数中进行。

    // 注册 GATT 回调函数,处理所有的 GATT 事件ret = esp_ble_gatts_register_callback(gatts_event_handler);if (ret){ESP_LOGE(GATTS_TABLE_TAG, "gatts register error, error code = %x", ret);return;}// 注册 GAP 回调函数,ret = esp_ble_gap_register_callback(gap_event_handler);if (ret){ESP_LOGE(GATTS_TABLE_TAG, "gap register error, error code = %x", ret);return;}

(3)在这两个回调函数中的类型如下:

// GATT 回调函数
typedef void (* esp_gatts_cb_t)(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);
// GAP 回调函数
typedef void (* esp_gap_ble_cb_t)(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);

回调函数参数具体分析

GATT回调函数

esp_gatts_cb_event_t结构体

(1)esp_gatts_cb_event_t就是一个enmu枚举参数。当出现对应的GATT事件的时候,底层协议栈就会触发GATT回调函数,并将对应事件以esp_gatts_cb_event_t枚举形式进行通知。
(2)接下来我将会讲解常见的几种GATT事件及其如何进行触发。

  • ESP_GATTS_REG_EVT : 当调用 esp_ble_gatts_app_register() 函数注册应用ID触发该事件。
  • ESP_GATTS_READ_EVT :当客户端发送读命令,ESP32作为服务端将会触发该事件。
  • ESP_GATTS_WRITE_EVT : 当客户端发送一个写请求并且写的数据<=(MTU-3)ESP32作为从设备将会触发该事件。
  • ESP_GATTS_EXEC_WRITE_EVT : 当客户端发送一个写请求并且写的数据>(MTU-3)ESP32作为从设备将会触发该事件。
  • ESP_GATTS_MTU_EVT :当客户端发送设置MTU请求时,ESP32作为服务端触发该事件。
  • ESP_GATTS_CONF_EVT : 当ESP32作为服务端收到客户端对之前发送的指示(Indication)或通知(Notification)的确认时,就会触发该事件。
  • ESP_GATTS_START_EVT : 当ESP32作为服务端成功启动,该事件触发。
  • ESP_GATTS_CONNECT_EVT : 当客户端发起连接事件,ESP32作为服务端,该事件触发。
  • ESP_GATTS_DISCONNECT_EVT : 当客户端断开连接,ESP32作为服务端,该事件触发。
  • ESP_GATTS_CREAT_ATTR_TAB_EVTesp_ble_gatts_create_attr_tab() 创建 GATT 完成时触发该事件。

esp_gatt_if_t

(1)这其实就是一个无符号的8bit数据,它用于标识不同的GATT客户端,该参数与esp_ble_gatts_app_register()函数注册的app_id成对应关系。
(2)当我们调用esp_ble_gatts_app_register()函数注册的app_id时候,协议栈会为其分配一个对应的 gatts_if,用于标识一个 GATT 服务。同时会触发esp_ble_gatts_register_callback() 注册的回调函数中的 ESP_GATTS_REG_EVT 事件。

typedef uint8_t    esp_gatt_if_t;   

esp_ble_gatts_cb_param_t结构体

(1)esp_ble_gatts_cb_param_t是一个联合体,该联合体和esp_gatts_cb_event_t这个enmu枚举参数是存在对应关系的。
(2)如下为对应图:

/* --- ESP_GATTS_REG_EVT --- */
param->reg.status // 注册应用ID的操作状态
param->reg.app_id // esp_ble_gatts_app_register()注册函数中输入的app_id
/* --- ESP_GATTS_READ_EVT --- */
param->read.conn_id // GATT读事件的连接ID,用于标识当前读取操作所涉及的连接的唯一标识符
param->read.trans_id // 确保了每个读操作的事务一致性,防止响应被错误地关联到其他读请求
param->read.bda // 写入的蓝牙设备地址
param->read.handle // GATT 句柄
param->read.offset // 如果需要读取的值太长,该值为偏移量
param->read.is_long // 需要读取的值是否过长,与.offset进行配合
param->read.need_rsp // 该写操是否需要回复
/* --- ESP_GATTS_WRITE_EVT --- */
param->write.conn_id // GATT写事件的连接ID,用于标识当前写操作所涉及的连接的唯一标识符
param->write.trans_id // 确保了每个写操作的事务一致性,防止响应被错误地关联到其他读请求
param->write.bda // 要被写入的蓝牙设备地址
param->write.handle // GATT 句柄
param->write.offset // 如果需要写的值太长,该值为偏移量
param->write.need_rsp // 该写操是否需要回复
param->write.is_prep // GATT(通用属性配置文件)服务器的写入操作是否为预备写入(Prepare Write)
param->write.len // 该写操作的值长度
param->write.value // 该写操作的值
/* --- ESP_GATTS_EXEC_WRITE_EVT --- */
param->exec_write.conn_id // 连接ID
param->exec_write.trans_id // 传递ID
param->exec_write.bda // 要被写入的蓝牙设备地址
param->exec_write.exec_write_flag // 执行写标志
/* --- ESP_GATTS_MTU_EVT --- */
param->mtu.conn_id // 连接ID
param->mtu.mtu // MTU大小
/* --- ESP_GATTS_CONF_EVT --- */
param->conf.status  // 客户端的确认状态
param->conf.conn_id // 连接ID
param->conf.handle  // GATT句柄
param->conf.len     //  指示(Indication)或通知(Notification)的值长度,在发送指示(Indication)或通知(Notification)失败的时候,该值有效
param->conf.value   // 指示(Indication)或通知(Notification)的值,在发送指示(Indication)或通知(Notification)失败的时候,该值有效
/* --- ESP_GATTS_START_EVT --- */
param->start.status         // GATT服务启动状态
param->start.service_handle // GATT服务句柄
/* --- ESP_GATTS_CONNECT_EVT --- */
param->connect.conn_id       // 连接ID
param->connect.link_role     // 链路层角色,0标识主设备,1标识从设备
param->connect.remote_bda    // 对端蓝牙地址
param->connect.conn_params   // 当前的连接参数
param->connect.ble_addr_type // 对端蓝牙设备地址类型
param->connect.conn_handle   // HCI层连接句柄
/* --- ESP_GATTS_DISCONNECT_EVT --- */
param->disconnect.conn_id    // 连接ID
param->disconnect.remote_bda // 对端蓝牙设备地址
param->disconnect.reason     // 蓝牙断连原因
/* --- ESP_GATTS_CREAT_ATTR_TAB_EVT --- */
param->add_attr_tab.status      // GATT服务创建状态
param->add_attr_tab.svc_uuid    // 创建的GATT服务UUID类型,有16bit、32bit、128bit
param->add_attr_tab.svc_inst_id // 创建的GATT服务UUID ID号
param->add_attr_tab.num_handle  // 要添加到GATT数据库的属性句柄编号
param->add_attr_tab.handles     // GATT句柄编号

GAP回调函数

esp_gap_ble_cb_event_t

(1)esp_gap_ble_cb_event_t就是一个enmu枚举参数。当出现对应的GAP事件的时候,底层协议栈就会触发GAP回调函数,并将对应事件以esp_gap_ble_cb_event_t枚举形式进行通知。
(2)接下来我将会讲解常见的几种GAP事件及其如何进行触发。

  • ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT : 当调用 esp_ble_gap_config_adv_data_raw() 函数设置了广播包成功后触发该事件。
  • ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT : 当调用 esp_ble_gap_config_scan_rsp_data_raw() 函数设置了广播扫描响应包成功后触发该事件。
  • ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT : 当调用 esp_ble_gap_config_adv_data() 函数,其中.set_scan_rsp = false设置广播包成功后触发该事件。
  • ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT : 当调用 esp_ble_gap_config_adv_data() 函数,其中.set_scan_rsp = true设置广播扫描响应包成功后触发该事件。
  • ESP_GAP_BLE_ADV_START_COMPLETE_EVT : 当调用esp_ble_gap_start_advertising()函数成功启动广播之后触发该事件。
  • ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT : 当调用esp_ble_gap_stop_advertising()函数成功启动广播之后触发该事件。不过在BLE5.0之后的广播包在连接时有ESP_GAP_BLE_ADV_TERMINATED_EVT事件报上来。
  • ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT : 很多应用场景中,从设备主设备刚建立连接时,会使用“快速”的连接参数以达到迅速交换信息的目的,但是,从设备主设备机之间并不是一直需要快速的交换信息,因为这样会加快从机电池能量的消耗,这时候,从设备就希望能降低连接事件的频度(连接间隔),从而降低功耗,延长电池工作时间。因此,这里从设备就可以向主设备发起链路层连接参数更新控制(Connection Parameter Update Control)。连接参数更新成功,那么该事件就会被触发。

esp_ble_gap_cb_param_t

(1)esp_ble_gap_cb_param_t是一个联合体,该联合体和esp_gap_ble_cb_event_t这个enmu枚举参数是存在对应关系的。
(2)如下为对应图:

/* --- ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT --- */
param->adv_data_raw_cmpl.status // 设置广播包操作成功状态
/* --- ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT --- */
param->scan_rsp_data_raw_cmpl.status // 设置扫描回应包操作成功状态
/* --- ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT --- */
param->adv_data_cmpl.status // 设置广播包操作成功状态
/* --- ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT --- */
param->scan_rsp_data_cmpl.status // 设置扫描回应包操作成功状态
/* --- ESP_GAP_BLE_ADV_START_COMPLETE_EVT --- */
param->adv_start_cmpl.status // 设置广播开始操作成功状态
/* --- ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT --- */
param->adv_stop_cmpl.status // 设置广播停止操作成功状态
/* --- ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT --- */
param->update_conn_params.status   // 设置连接更新参数操作成功状态
param->update_conn_params.bda      // 蓝牙设备地址
param->update_conn_params.min_int  // 最小连接间隔
param->update_conn_params.max_int  // 最大连接间隔
param->update_conn_params.latency  // 从机连接延迟时间(以连接事件数为单位)。范围:0x0000 ~ 0x01F3
param->update_conn_params.conn_int // 当前连接间隔
param->update_conn_params.timeout  // LE Link的监督超时。取值范围:0x000A ~ 0x0C80。Time = N * 10 msec

参考

(1)乐鑫官方文档
(2)乐鑫官方论坛:Write a string to characteristic

这篇关于ESP32 BLE学习(1) — GAP和GATT回调函数作用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1075229

相关文章

Java学习手册之Filter和Listener使用方法

《Java学习手册之Filter和Listener使用方法》:本文主要介绍Java学习手册之Filter和Listener使用方法的相关资料,Filter是一种拦截器,可以在请求到达Servl... 目录一、Filter(过滤器)1. Filter 的工作原理2. Filter 的配置与使用二、Listen

Python的time模块一些常用功能(各种与时间相关的函数)

《Python的time模块一些常用功能(各种与时间相关的函数)》Python的time模块提供了各种与时间相关的函数,包括获取当前时间、处理时间间隔、执行时间测量等,:本文主要介绍Python的... 目录1. 获取当前时间2. 时间格式化3. 延时执行4. 时间戳运算5. 计算代码执行时间6. 转换为指

Python正则表达式语法及re模块中的常用函数详解

《Python正则表达式语法及re模块中的常用函数详解》这篇文章主要给大家介绍了关于Python正则表达式语法及re模块中常用函数的相关资料,正则表达式是一种强大的字符串处理工具,可以用于匹配、切分、... 目录概念、作用和步骤语法re模块中的常用函数总结 概念、作用和步骤概念: 本身也是一个字符串,其中

基于Java实现回调监听工具类

《基于Java实现回调监听工具类》这篇文章主要为大家详细介绍了如何基于Java实现一个回调监听工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录监听接口类 Listenable实际用法打印结果首先,会用到 函数式接口 Consumer, 通过这个可以解耦回调方法,下面先写一个

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

MySQL高级查询之JOIN、子查询、窗口函数实际案例

《MySQL高级查询之JOIN、子查询、窗口函数实际案例》:本文主要介绍MySQL高级查询之JOIN、子查询、窗口函数实际案例的相关资料,JOIN用于多表关联查询,子查询用于数据筛选和过滤,窗口函... 目录前言1. JOIN(连接查询)1.1 内连接(INNER JOIN)1.2 左连接(LEFT JOI

MySQL中FIND_IN_SET函数与INSTR函数用法解析

《MySQL中FIND_IN_SET函数与INSTR函数用法解析》:本文主要介绍MySQL中FIND_IN_SET函数与INSTR函数用法解析,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友一... 目录一、功能定义与语法1、FIND_IN_SET函数2、INSTR函数二、本质区别对比三、实际场景案例分

Spring Boot项目部署命令java -jar的各种参数及作用详解

《SpringBoot项目部署命令java-jar的各种参数及作用详解》:本文主要介绍SpringBoot项目部署命令java-jar的各种参数及作用的相关资料,包括设置内存大小、垃圾回收... 目录前言一、基础命令结构二、常见的 Java 命令参数1. 设置内存大小2. 配置垃圾回收器3. 配置线程栈大小

C++ Sort函数使用场景分析

《C++Sort函数使用场景分析》sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变,如果某些场景需要保持相同元素间的相对顺序,可使... 目录C++ Sort函数详解一、sort函数调用的两种方式二、sort函数使用场景三、sort函数排序

C语言函数递归实际应用举例详解

《C语言函数递归实际应用举例详解》程序调用自身的编程技巧称为递归,递归做为一种算法在程序设计语言中广泛应用,:本文主要介绍C语言函数递归实际应用举例的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录前言一、递归的概念与思想二、递归的限制条件 三、递归的实际应用举例(一)求 n 的阶乘(二)顺序打印