- 由 zhongluqiang创建, 最后修改于2月 07, 2025
贴几段ChatGPT中对蓝牙相关内容的描述:
GAP
GAP(Generic Access Profile)是蓝牙规范中的一个基本协议,它定义了蓝牙设备如何与其他设备建立连接以及如何管理这些连接。简单来说,GAP负责蓝牙设备之间的发现和配对过程,是蓝牙通信中的一个核心部分。
在GAP中,主要有以下几个角色和功能:
设备角色:
- 中央设备(Central):通常是主动发起连接的设备,比如手机或电脑。
- 外设设备(Peripheral):被中央设备发起连接的设备,如蓝牙耳机、传感器等。
- 观察者(Observer):只监听蓝牙广播,不参与连接。
- 广播者(Broadcaster):只广播信号,不接收连接请求。
连接过程: GAP负责蓝牙设备之间的发现(Device Discovery)和连接管理。设备通过扫描、广播等方式相互发现,发现后通过配对过程(Pairing)进行安全验证,然后建立连接。
配对和绑定(Pairing and Bonding): 配对是蓝牙设备建立安全连接的过程,通常涉及输入PIN码或使用其他认证方式。而绑定是指设备在首次配对后,存储配对信息,以便下次连接时能更快地建立连接。
简而言之,GAP为蓝牙设备之间的相互识别、连接和管理提供了标准化的流程,使得设备间的通信更加顺畅和安全。
GATT
GATT(Generic Attribute Profile)是蓝牙低功耗(BLE)协议栈中的另一个重要组成部分,它定义了设备如何以结构化的方式通过服务和特征进行数据交换。与GAP负责设备发现和连接管理不同,GATT更侧重于设备间的数据传输,特别是在BLE(蓝牙低功耗)环境下的应用。
GATT的主要特点:
服务和特征(Services and Characteristics):
- 服务(Service):服务是由一组相关特征组成的逻辑集合。每个服务都有一个唯一的UUID(统一标识符),比如
Heart Rate Service
(心率服务)或者Battery Service
(电池服务)。 - 特征(Characteristic):每个服务内可以有多个特征,特征包含数据值并可具有不同的属性,如只读、可写或可通知等。每个特征也有一个唯一的UUID。
- 服务(Service):服务是由一组相关特征组成的逻辑集合。每个服务都有一个唯一的UUID(统一标识符),比如
操作(Operations): GATT定义了几种操作,允许设备之间交换数据:
- 读取(Read):从特征中读取数据。
- 写入(Write):向特征写入数据。
- 通知(Notify):当特征值发生变化时,设备可以向已连接的设备发送通知,通知设备不需要主动读取。
- 指示(Indicate):类似于通知,但需要接收方确认收到数据后,才认为数据交换成功。
客户端和服务器(Client and Server):
- GATT客户端(Client):通常是请求数据的设备,比如手机、计算机等。
- GATT服务器(Server):提供数据的设备,如传感器、穿戴设备等。GATT服务器维护着服务和特征,响应客户端的请求。
数据交换流程: GATT通过定义具体的操作(如读取、写入、通知等)来实现客户端与服务器之间的数据交互。比如,手机(客户端)可能会请求读取一个智能手表(服务器)上的心率值,智能手表会通过GATT协议返回该数据。
举个例子:
假设你有一个智能手环,它提供心率监测功能。这个手环的GATT服务器上会有一个“心率服务”(Heart Rate Service),其中包含多个特征(如心率测量值、心率阈值等)。手机(客户端)通过GATT协议来读取手环的心率测量值,或者接收手环发来的心率变化通知。
总结:
GATT协议是蓝牙低功耗设备间的“数据交换协议”,它通过服务和特征的形式组织设备上的数据,并提供多种操作方式(读取、写入、通知等)来实现设备之间的高效数据交互。
ATT
ATT(Attribute Protocol)是蓝牙低功耗(BLE)协议栈中的一个关键协议,它为 GATT(Generic Attribute Profile)提供了基本的底层数据传输机制。ATT定义了设备间交换数据的基本规则,具体是通过 属性(Attribute) 的形式进行管理和传输数据的。实际上,GATT的工作就是通过ATT协议在蓝牙设备之间进行数据交互。
ATT的核心概念
在ATT中,属性(Attribute) 是数据的基本单位。每个属性都有一个唯一的标识符,包含了具体的数据值以及属性的其他信息(如权限、类型等)。
- 属性(Attribute)
- 属性是GATT协议中用来描述设备数据的最基本单元。它可以是任何类型的数据,包括服务(Service)、特征(Characteristic)等。
- 每个属性有一个属性句柄(Handle),用来标识该属性。
- 属性还包含一个属性值(Value),这就是存储的数据内容。例如,心率值、温度值等。
- 属性的结构
每个属性在ATT协议中有以下几个组成部分:- 属性句柄(Handle):一个唯一的标识符,区分不同的属性。
- 属性类型(Type):表示属性的数据类型,如服务类型、特征类型等,通常由UUID(通用唯一标识符)表示。
- 属性权限(Permissions):定义该属性是否可读、可写、是否可以通知等。
- 属性值(Value):实际的数据值,通常是字节序列。
- GATT与ATT的关系
- GATT建立在ATT之上,GATT通过ATT提供的机制来管理和交换数据。GATT中的每个服务和特征,实际上就是一个个具体的ATT属性。
- ATT负责定义如何访问和操作这些属性,例如读取或写入数据、发出通知等。
ATT中的常见操作
在ATT协议中,常见的操作包括以下几种:
Read Request(读取请求):
- 客户端可以向服务端发送一个读取请求,请求特定属性的值。服务端根据请求返回属性值。
Write Request(写入请求):
- 客户端可以向服务端发送写入请求,更新某个特定属性的值。服务端根据写入请求对数据进行更新。
Notification(通知):
- 当服务端的数据发生变化时,它可以通过通知的方式告知客户端,而不需要客户端主动去读取。客户端在收到通知后可以更新数据。
- Notification是无确认的,客户端不需要确认是否成功接收到通知。
Indication(指示):
- 类似于通知,但与通知不同的是,指示要求客户端对收到的数据进行确认。客户端在收到指示后必须发送确认响应,服务端才能认为操作完成。
Find Information Request(查找信息请求):
- 客户端可以发送请求,查询服务端的某些属性信息,如服务或特征的UUID等。
Read Blob Request(读取大块数据请求):
- 当请求的数据较大时,客户端可以分段读取属性值,这时使用的是读取大块数据的请求。
ATT的数据交换示例
客户端读取服务端的特征值:
- 客户端通过ATT协议发送读取请求,要求服务端提供某个特征的值(例如心率测量值)。服务端响应后,客户端接收到该特征的当前值。
客户端写入数据到服务端:
- 比如客户端向服务端的一个温控设备写入温度设置,客户端通过ATT协议发送写入请求,服务端接收到请求并更新对应属性。
ATT与GATT的对比
特性 | ATT | GATT |
---|---|---|
作用 | 提供底层的属性管理和数据交换机制 | 定义设备间如何通过服务和特征进行数据交换 |
数据单位 | 属性(Attribute) | 服务(Service)、特征(Characteristic) |
主要任务 | 管理属性的读、写、通知等基本操作 | 提供高层次的服务和特征管理 |
连接方式 | 基于GATT进行数据传输和管理 | 基于ATT协议组织服务和特征 |
操作类型 | 读、写、通知、指示等 | 提供数据服务、进行配对、绑定等 |
总结
ATT(Attribute Protocol) 是蓝牙低功耗通信中的基础协议,用来描述设备间数据交换的基本规则和方式。GATT协议基于ATT协议构建,通过定义具体的服务和特征,使设备能够通过属性(Attribute)进行高层次的数据交互。ATT协议主要负责如何组织、读取、写入、通知和指示这些属性的操作,而GATT则是在这个基础上通过服务和特征来组织和提供实际的数据交换功能。
蓝牙介绍
官网:https://www.bluetooth.com/zh-cn/。
wiki:蓝牙 - 维基百科,自由的百科全书。
分为经典蓝牙和低功耗蓝牙(BLE),前者支持传统的点对点通信,比如无线耳机,无线打印机等,后者支持低功耗,支持更多的拓扑结构,比如蓝牙广播,mesh等。BLE除了数据传输,还支持设备定位,比如苹果公司的iBeacon技术。(参考链接:https://www.bluetooth.com/zh-cn/learn-about-bluetooth/tech-overview/)
蓝牙规范:https://www.bluetooth.com/zh-cn/specifications/specs/。
蓝牙协议栈
参考链接:
- https://docs.espressif.com/projects/esp-idf/zh_CN/stable/esp32/api-guides/ble/overview.html
- https://www.espressif.com/sites/default/files/documentation/esp32_bluetooth_architecture_cn.pdf
有 ESP-Bluedroid 和 ESP-NimBLE 两个主机,其主要区别如下:
虽然两者都支持低功耗蓝牙,但 ESP-NimBLE 需要的堆和 flash 空间更少。
ESP-Bluedroid 支持经典蓝牙和低功耗蓝牙,而 ESP-NimBLE 仅支持低功耗蓝牙。
从整体结构上,蓝⽛可分为控制器 (Controller) 和 主机 (Host) 两⼤部分:控制器包括了PHY、 Baseband、 Link Controller、 Link Manager、 Device Manager、 HCI 等模块,⽤于硬件接⼝管理、链路管理等等;主机则包括了 L2CAP、 SMP、 SDP、 ATT、 GATT、 GAP 以及各种规范,构建了向应⽤层提供接⼝的基础,⽅便应⽤层对蓝⽛系统的访问。主机可以与控制器运⾏在同⼀个宿主上,也可以分布在不同的宿主上。
控制器提供蓝牙能力,比如射频,PHY,链路控制等,主机提供软件能力,比如蓝牙协议栈实现,两者通过总线解耦,方便将蓝牙能力拓展到不同的主机上。
GAP规范
Generic Access Profile,通用访问规范。
参考链接:https://www.bluetooth.com/specifications/specs/core-specification-5-0/
下载V5.0的pdf文档后,GAP规范的章节在Vol 3 → Part C。
GAP规范的用于定义以下内容:
- 角色分类。
- 发现模式和发现过程。
- 连接模式和连接过程。
- 安全相关的模式和过程。
GAP定义了以下几种角色:
- 广播者(Broadcaster)
- 观察者(Observer)
- 外围设备(Peripheral)
- 中心设备(Central)
典型的可扫描、可连接蓝牙设备建立连接的过程如下:
有些设备只需要发送即可,比如Apple Beacon,有些设备只需要接收即可,比如BLE Sniffer。不同的设备对应不同的角色,比如Apple Beacon对应广播者,BLE Sniffer对应观察者。一些低功耗的蓝牙传感器,比如心律监测计,是外围设备,而负责接收的设备,比如手机,则是中心设备。
对于外围设备和中心设备,在连接建立后,需要区分Slave Role和Master Role。
GATT规范
Generic Attribute Profile,通用属性规范。
GATT区分客户端和服务端,客户端通过command, request, confirmation向服务端发送消息,服务端通过resonpse, notification, indication向客户端返回数据。
数据存储在服务端,通过Profile来表示,其格式如下:
Profile包含一个或多个Service,每个Service包含一个Service Declaration(服务声明,用于说明这个服务是干啥的),Service Include(服务引用,引用了其他哪些服务),以及多个特征值,每个特征值表示一个有效数据。
UUID用于表示当前服务的类型,这些类型是预分配好的,基本上所有的知名服务,比如血压计,心律计,定时器等,都有对应好的UUID,具体的UUID可以查看蓝牙规范文档,参考链接:https://www.bluetooth.com/specifications/assigned-numbers/。
Include表示包含了哪些其他服务及对应的UUID。
特征值结构,首先是特征声明,包含特征的属性,句柄,UUID。
接下来是值的声明。
接下来是可选的补充信息。
所有的属性数据都遵循以下格式:
ATT负责存储数据,GATT为ATT赋予类型属性,根据类型属性就可以对ATT的格式和内容进行解析。
GATT不仅使用ATT来存储和发送数据,还使用ATT来发送命令。
GATT服务端工作流程
- 初始化:初始化蓝牙控制器→ 使能蓝牙控制器→ 使能蓝牙协议栈。
- 注册GATT callback:gatts_event_handler,注册GATT回调事件。
- 注册GAP callback:gap_event_handler,注册GAP回调事件。
- 注册GATT APP ID:APP ID用于协议栈区分不同的profile。
- 设置MTU:参考Core spec V5.0,搜索MTU。
- 处理各种回调事件,包括GAP的回调事件和GATT的回调事件。
GAP事件包括以下几种:
- 广播数据设置成功。
- 开始广播成功,此时可以用BLE调试助手搜索到对应的广播热点。
- 停止广播成功。
- 更新连接参数事件。
GATT事件包括以下几种:
- GATTS注册事件,表示注册GATT APP ID成功,此时可以拿到这个profile的句柄。
- 调用profile的回调函数,继续处理GATT事件,比如特征值读写事件。
GATT服务端广播流程
下载V5.0的pdf文档后,GAP规范的章节在Vol 6 → Part D → 3 Advertising State。
以非定向广播为例,其广播流程如下:
接收端负责扫描广播信息,以第4小节中的被动扫描为例,其流程如下:
客户端也可以进行主动扫描,其流程如下:
GATT服务端广播流程:
- 注册GATT APP ID,触发注册APP ID成功事件,此时可以设置GAP广播数据,以及广播扫描应答数据。
- 触发GAP广播数据设置完成事件和广播扫描应用数据设置成功事件。
- 检测到广播数据设置成功后,使能GAP广播。
- 触发GAP开始广播成功事件,表示已经开始广播了。
- 主动停止广播,触发停止广播成功事件。
GATT广播数据解析
参考Core spec V5.0,Vol3 → Part C → 11小节。
关于AD Type,在上面的Assigned Numbers文档有描述,在Common Data Types章节,以下是一个广播数据示例。
以第一行0x02, 0x01, 0x06为例,0x02表示后面的数据长度为2,0x01表示这是一个标志数据,后面的0x06可以参考Core spec的补充文档查找其含义。
关于device name,广播数据中的device name是用于显示在扫描后的local name中的,而在程序中设置的name是用于在BLE调试助手上显示的。比如XM的所有蓝牙配网设备用BLE调试助手搜索出来的名字都是XM,但由于每个设备广播数据中的device name都不一样,所以在APP上还是可以区分出设备类型。
关于广播数据的长度,可参考Core spec V5.0,Vol6 → Part B → 2.3.1小节。广播数据区分legacy pdu和extended pdu,对应传统蓝牙(4.0, 4.2)和蓝牙5.0(2.3.4小节)。蓝牙5.0通过fragmentation技术,可以发送最大1650字节的广播数据。在设置广播参数时可以指定广播类型,从而决定广播数据包长度。
GATT客户端工作流程
GATT服务端响应读数据事件
枚举值示例:ESP_GATTS_READ_EVT。
场景示例:蓝牙定时器从手机APP上获取定时时间。
GATT客户端响应读数据事件
枚举值示例:ESP_GATTC_READ_CHAR_EVT。
场景示例:手机APP从血压计传感器上读取血压值。
GATT服务端接收数据
枚举值示例:ESP_GATTS_WRITE_EVT。
场景示例:血压计传感器主动向手机APP发送血压值。
触发ESP_GATTS_WRITE_EVT后,先判断客户端写的是哪个句柄,再提取对应的数据长度和数据内容即可。
GATT客户端接收数据
枚举值示例:ESP_GATTC_WRITE_DESCR_EVT。
场景示例:蓝牙定时器将当前定时值写入到手机APP。
参数:连接id,特征值句柄(通过UUID查找),数据长度,数据内容,是否需要应答,是否需要授权。
服务端发送通知处理
场景示例:手机APP连接开发板热点,之后开发板定时向手机APP发送notification,手机APP先进入监听状态,再不断显示notification的值。
客户端处理通知
场景示例:服务端发通知给客户端,客户端处理通知。
先register_for_notify_evt,注册通知处理事件,注册的事件从GATTC_SEARCH_COMPLETE事件中提取。
查找时如果发现服务端有通知功能,则写特征值告知对方需要启动通知,以便于本方接收。
- 无标签