4、Mesh协议栈架构:协议栈分层
好,咱们今天聊聊Mesh协议栈的分层结构。说实话,我刚接触蓝牙Mesh那会儿,看着这五层协议栈,心里直犯嘀咕——这不就是套了个Mesh壳子的BLE吗?后来踩了几个坑才明白,每一层都有它存在的道理。
我个人习惯把协议栈比作一个快递系统。你想想看,从寄件人到收件人,中间要经过打包、分拣、运输、派送好几个环节。Mesh协议栈也是这么回事。咱们一层层往下看。
5.1 Bearer Layer(承载层)
承载层是协议栈的最底层。说白了,它负责把数据变成能在物理介质上传输的信号。在Mesh里,主要有两种承载方式:
- Advertising Bearer(广播承载):利用BLE的广播通道发数据。这是Mesh最常用的方式。
- GATT Bearer(GATT承载):通过GATT连接传输。主要用于手机App配网场景。
关键点:广播承载用的是BLE的37、38、39三个广播通道。这三个通道避开了Wi-Fi的干扰频段,所以抗干扰能力还不错。
我在项目中遇到过一个问题:设备在金属机箱里,广播信号衰减得厉害。后来发现是天线匹配没做好。嗯,这里要注意,承载层的物理性能直接影响整个网络的可靠性。
5.2 Network Layer(网络层)
网络层负责消息的转发和中继。这是Mesh网络的核心能力所在。它主要干三件事:
- 消息中继:收到消息后,判断要不要转发给邻居节点。
- 地址处理:识别源地址、目的地址,决定消息流向。
- 安全校验:检查网络层加密和完整性校验。
网络层的数据包格式是这样的:
Network PDU:
| IVI | NID | CTL | TTL | SEQ | SRC | DST | Transport PDU | NetMIC |
| 1b | 7b | 1b | 7b | 24b | 16b | 16b | 可变长度 | 32b/64b |
这里有个坑——TTL字段。我曾经把TTL设得太大,结果消息在网络里到处乱窜,造成广播风暴。后来我学乖了,一般设成3到5就够用了。你想想看,一个消息跳个三五次还到不了目的地,那多半是网络拓扑有问题。
5.3 Transport Layer(传输层)
传输层负责把上层的大数据包拆分成小段,或者把小段重组回去。它分两个子层:
- Lower Transport Layer(低层传输):处理分段和重组,以及端到端的确认重传。
- Upper Transport Layer(高层传输):负责应用数据的加密和解密。
小技巧:分段消息最多可以拆成32个Segment。每个Segment最大12字节。所以一条消息最多能传384字节的应用数据。超过这个数?那就得用扩展模型了。
我记得有一次调试,发现设备收不到长消息。查了半天,原来是分段重组超时时间设得太短。默认是10秒,但我的网络里节点比较多,中继延迟大。改成20秒就好了。
5.4 Access Layer(接入层)
接入层是应用层和传输层之间的桥梁。它负责:
- 应用密钥管理:决定用哪把密钥加密应用数据。
- 消息格式定义:定义Opcode和参数的结构。
- 访问控制:检查设备是否有权限发送或接收某个消息。
接入层的PDU结构很简单:
Access PDU:
| Opcode | Parameters |
| 1-3B | 0-379B |
Opcode的设计很有意思。1字节的Opcode留给最常用的消息,2字节的给次常用的,3字节的给厂商自定义。说白了,就是省带宽。
5.5 Model Layer(模型层)
模型层是最顶层,直接面向应用开发者。它定义了设备的行为和状态。比如:
- Generic OnOff Server:开关服务器模型,控制灯的亮灭。
- Generic OnOff Client:开关客户端模型,发送开关命令。
- Light Lightness Server:亮度服务器模型,调节灯光亮度。
核心概念:模型分为Server Model和Client Model。Server负责维护状态,Client负责发起请求。一个设备可以同时包含多个模型。
我刚开始做智能照明项目时,把所有的逻辑都塞在一个模型里。结果代码耦合严重,改一个功能要动半套代码。后来我学乖了,按功能拆分成多个模型——开关归开关,调光归调光,场景归场景。清爽多了。
数据封装过程
咱们捋一遍数据从上层到底层的封装过程:
| 层级 | 输入 | 输出 | 关键操作 |
|---|---|---|---|
| Model Layer | 应用逻辑 | Model Message | 定义Opcode和参数 |
| Access Layer | Model Message | Access PDU | 添加Opcode,应用密钥加密 |
| Upper Transport | Access PDU | Transport PDU | 应用层加密,添加SeqAuth |
| Lower Transport | Transport PDU | Segment PDU | 分段,添加SeqZero和SegN |
| Network Layer | Segment PDU | Network PDU | 添加网络头,网络层加密 |
| Bearer Layer | Network PDU | 广播包/GATT包 | 封装成BLE协议格式 |
注意:每一层加密用的密钥都不一样。网络层用NetKey,传输层用AppKey。千万别搞混了。我曾经见过有人把AppKey当成NetKey用,结果整个网络都解密失败。
嗯,协议栈分层的好处就在这里——每层只管自己的事,出了问题也好排查。比如消息发不出去,先看承载层有没有广播,再看网络层TTL对不对,一层层往上查,很快就能定位问题。
我个人建议,刚开始学Mesh协议栈的朋友,先别急着看代码。拿张纸,把五层结构画出来,每层的数据格式写清楚。然后找一个实际的Mesh包,用手工一层层解包。这个过程走一遍,比你读十遍协议文档都管用。