2. BLE协议栈基础回顾:GAP与GATT角色、Service与Characteristic、MTU与PDU

好,咱们进入第二章。在做OTA升级之前,有些基础概念必须得捋清楚。说实话,我见过太多开发者在OTA上栽跟头,根子就是没搞懂这几个协议栈的基本概念。今天咱们就一次性把它们说透。

2.1 GAP与GATT角色——谁在说话,谁在听?

BLE协议栈分两层,GAP和GATT。很多人搞混,我简单解释一下。

GAP(Generic Access Profile),负责设备怎么被发现、怎么建立连接。说白了,就是管“广播”和“连接”的。

GAP定义了四种角色:

  • Broadcaster:只发广播,不连。比如蓝牙信标。
  • Observer:只收广播,不连。比如扫描器。
  • Peripheral:从设备,发广播,等别人来连。比如手环。
  • Central:主设备,主动扫描并发起连接。比如手机。

做OTA升级时,手机是Central,设备是Peripheral。这个关系要记牢。

GATT(Generic Attribute Profile),负责连接建立之后的数据交互。它定义了谁是Server,谁是Client。

  • GATT Server:提供数据的一方。设备端通常是Server。
  • GATT Client:读写数据的一方。手机端通常是Client。

关键点:GAP管“能不能连”,GATT管“连上后怎么传数据”。OTA升级中,设备既是GAP的Peripheral,又是GATT的Server。手机既是Central,又是Client。

我记得有一次,一个同事把GAP角色和GATT角色搞混了,在代码里把设备配成了GATT Client,结果手机死活读不到数据。排查了半天才发现是角色配反了。嗯,这种低级错误,犯一次就记住了。

2.2 Service与Characteristic——数据怎么组织?

GATT的数据模型,说白了就是一个树形结构。最顶层是Profile,下面挂Service,Service下面挂Characteristic,Characteristic下面还有Descriptor。

我画个简化的结构:

Profile
  └── Service (UUID: 0x180A)
       ├── Characteristic (UUID: 0x2A24, 型号)
       │    └── Descriptor (CCCD)
       ├── Characteristic (UUID: 0x2A25, 序列号)
       └── Characteristic (UUID: 0x2A26, 固件版本)

Service:一组功能的集合。比如“设备信息服务”、“电池服务”。每个Service有唯一的UUID。

Characteristic:具体的数据点。比如“固件版本号”、“电池电量”。每个Characteristic也有UUID,并且有属性(读、写、通知等)。

Descriptor:对Characteristic的描述或配置。最常用的是CCCD(Client Characteristic Configuration Descriptor),用来开关通知。

做OTA升级时,我们通常会自定义一个OTA Service,里面放几个Characteristic:

  • OTA Control Point:写属性,用来发送升级命令(开始、暂停、取消)。
  • OTA Data:写属性,用来传输固件数据包。
  • OTA Status:通知属性,设备用来上报升级进度和状态。

个人经验:我建议把OTA Service的UUID设成自定义的128位UUID,不要用标准UUID。这样可以避免和其他Service冲突。我曾经见过一个产品,因为用了标准UUID,结果手机端同时连了两个设备,数据串了,升级到一半就崩了。

2.3 MTU与PDU——一次能传多少数据?

这是OTA升级中最容易出问题的地方。很多人不理解MTU和PDU的关系,导致传输效率极低,甚至丢包。

MTU(Maximum Transmission Unit),指的是ATT层一次能传输的最大数据包大小。默认是23字节,其中3字节是ATT头,实际有效载荷只有20字节。

但我们可以协商更大的MTU。手机和设备在连接建立后,可以通过MTU Exchange Request把MTU提升到512字节甚至更大。

PDU(Protocol Data Unit),指的是链路层的数据包。一个ATT包可能会被拆成多个PDU来传输。

我直接给个表格,大家看得更清楚:

层级 数据单元 说明
应用层 固件数据 你要传输的.bin文件
ATT层 ATT PDU 受MTU限制,最大MTU-3字节
L2CAP层 L2CAP PDU 加4字节L2CAP头
链路层 LL PDU 实际在空口传输的数据包

做OTA升级时,我建议:

  • 连接建立后,立即协商MTU到最大值(通常247或512)。
  • 每个数据包不要超过MTU-3字节(ATT头开销)。
  • 如果MTU是247,每个包最多传244字节数据。

避坑指南:我曾经在一个项目里,MTU协商到了512,但每次写数据时还是按20字节分包。结果传输速度只有可怜的2KB/s。后来发现是应用层没改分包大小,白白浪费了大MTU的优势。记住:协商了MTU,就要用满它!

还有一个容易忽略的点:PDU的时序。BLE的链路层有严格的时序要求,两个PDU之间必须有150微秒的间隔(T_IFS)。如果你连续发太多包,设备来不及处理,就会丢包。我一般会在每发10-20个包后,加一个小的延时,给设备喘口气。

嗯,这些基础概念看起来简单,但真正做OTA时,每一个细节都可能成为瓶颈。下一章咱们就进入正题,聊聊OTA升级的整体架构设计。