这里会显示出您选择的修订版和当前版本之间的差别。
cc2640r2f:exchange_mtu [2017/09/28 16:21] long |
cc2640r2f:exchange_mtu [2021/06/22 23:14] |
||
---|---|---|---|
行 1: | 行 1: | ||
- | < | ||
- | # BLE 一次能传多少数据 # | ||
- | BLE 到底一包能够收发多少数据是很多开发者都会关心的。我们知道 BLE 5.0 物理层设计 2Mpbs 的码元率,实际数据传输速率远远到不了这个级别。主要原因是无法直接单次发送 1M 或者 1K 数据,必须按照我们知道的 `ATT_MTU` 作为最大值进行拆包发送,不断拆包的过程中导致整体蓝牙有效数据吞吐量下降。本章节,我们实用性出发研究如何究竟蓝牙一包能够发送多少数据。 | ||
- | |||
- | 以下是 GAPP Client 进行特征值写请求的完整抓包,`AttValue` 表示写入的值,该值的最大长度到底是多少呢?本文将详细研究并且验证。 | ||
- | |||
- | ![](http:// | ||
- | |||
- | 本文的正确打开姿势,我们希望你已经仔细阅读并理解协议栈的 L2CAP,和 BLE4.2/5.0 全新支持的 LE 数据扩展功能。 | ||
- | |||
- | * <a href=" | ||
- | * <a href=" | ||
- | |||
- | ## 术语 ## | ||
- | |||
- | |术语|解释| | ||
- | |---|----| | ||
- | |PDU|Potocal Data Unit 协议数据单元,对于协议栈数据单元我们应该理解为蓝牙协议分层的消息实体的完整封装,例如 LL PDU 表示逻辑链路层的协议消息的完整封装| | ||
- | |MTU|Maximum Transmission Unit 最大传输单元,和本文研究的 BLE 数据包的最大长度意思接近| | ||
- | |LL|Logic Link 逻辑链路层| | ||
- | |PHY| physical layer 物理层 蓝牙协议的最底层| | ||
- | ## 分析 ## | ||
- | |||
- | 在 BLE PHY 包格式由以下组成:排除 前导码、访问地址、CRC 地址 对于 BLE4.0/ | ||
- | |||
- | ![](http:// | ||
- | |||
- | 更新后的 BLE4.2/ | ||
- | |||
- | ![](http:// | ||
- | |||
- | > | ||
- | |||
- | |||
- | 从蓝牙协议分层设计来看,逻辑链路层是最底层,已经正常连接的两个设备之间通信 PDU 主要由 `LL Data PDU` 组成。`LL Playload` 作为上层协议的负载。 | ||
- | |||
- | ![](http:// | ||
- | |||
- | 逻辑链路层再往上就是 L2CAP ——逻辑逻辑链路控制适配协议, | ||
- | |||
- | ![](http:// | ||
- | |||
- | L2CAP 协议再上就是操作特征值的 ATT 层,这一层数据长度被最大传输单元 `ATT_MTU` 限制,ATT_Payload 由 `Attribute OPCode` + `Attribute Parames` + `Authentication Signature`(可选)组成。排除 12 字节可选的认证签名,和一个字节属性操作码。 | ||
- | |||
- | ![](http:// | ||
- | |||
- | 对于写属性值,`Attribute Parameters` = `Attribute Handle`(2) + `Attribute Value` 。 `Attribute Value` 就是操作属性的值,其最大长度= `ATT_MTU` - `Attribute OPCode`(1)- `Attribute Handle`(2) = `ATT_MTU`-3 。 | ||
- | |||
- | ![](http:// | ||
- | |||
- | 同样地,对于读操作属性,主要包含在 ReadResponse 操作码。最大长度 = `ATT_MTU` - `Attribute OPCode`(1) = `ATT_MTU`-1 。 | ||
- | |||
- | ![](http:// | ||
- | |||
- | |||
- | 总之,对于 Host 部分读写属性值最大有效数据长度直接由 `ATT_MTU` 决定的,但根本是受 Controller `LL PDU` 大小限制。 | ||
- | |||
- | > | ||
- | |||
- | ## 更改 simpler_peripheral 配置更大 MTU ## | ||
- | |||
- | ![](http:// | ||
- | 对于 simpler_peripheral 工程我们的< | ||
- | |||
- | simpler_peripheral 默认的 `ATT_MTU` 为 23 ,即实际写属性值最大长度为 20 。GATT 服务端 `ATT_MTU` 由以上宏定义,GATT 客户端可以通过`GATT_ExchangeMTU()` 命令配置。 GATT 服务端根据当前的配置的 ATT_MTU 决定是否生效。例如我们这里的 `simple_peripheral` 作为 GATT 服务端,以更改宏 `L2CAP_MTU_SIZE` 为 150 ,` GATT_ExchangeMTU()` 需要配置到 200,返回 150 表示生效。 | ||
- | |||
- | > | ||
- | |||
- | |||
- | 参考《< | ||
- | |||
- | ### 更改工程 ### | ||
- | |||
- | * 更改配置宏 | ||
- | |||
- | ```C | ||
- | // | ||
- | // Maximum size in bytes of the BLE HCI PDU. Valid range: 27 to 255 | ||
- | // The maximum ATT_MTU is MAX_PDU_SIZE - 4. | ||
- | #ifndef MAX_PDU_SIZE | ||
- | #if defined(BLE_V42_FEATURES) && (BLE_V42_FEATURES & SECURE_CONNS_CFG) | ||
- | #define MAX_PDU_SIZE | ||
- | #else | ||
- | #define MAX_PDU_SIZE | ||
- | #endif // | ||
- | #endif | ||
- | ``` | ||
- | 配置`L2CAP MAX_PDU_SIZE` 为255, `ATT_MTU` 最大 为251 读写特征值最大长度应该`ATT_MTU`-3=248; | ||
- | ```C | ||
- | // | ||
- | #define SIMPLEPROFILE_CHAR5_LEN | ||
- | |||
- | ``` | ||
- | 由于增加了特征值 5 的大小为 248,相应参考特征的栈空间也得增加,它对应着任务栈,否则程序可能会跑飞。 | ||
- | ``` | ||
- | // | ||
- | #ifndef SBP_TASK_STACK_SIZE | ||
- | #define SBP_TASK_STACK_SIZE | ||
- | #endif | ||
- | ``` | ||
- | > | ||
- | |||
- | |||
- | 同时为了更好测试,直接将特征 5 的属性更改为直接读写,不需要配对连接。 | ||
- | |||
- | ```C | ||
- | // | ||
- | // Characteristic Value 5 | ||
- | { | ||
- | { ATT_BT_UUID_SIZE, | ||
- | GATT_PERMIT_READ|GATT_PERMIT_WRITE, | ||
- | 0, | ||
- | simpleProfileChar5 | ||
- | }, | ||
- | ``` | ||
- | 但是 simple_peripheral 默认没有进行 Characteristic Value 5 写操作,所以需要更改。 | ||
- | |||
- | ```C | ||
- | // | ||
- | case SIMPLEPROFILE_CHAR5_UUID: | ||
- | | ||
- | status = ATT_ERR_INVALID_VALUE_SIZE; | ||
- | } | ||
- | | ||
- | // | ||
- | if ( status == SUCCESS ) { | ||
- | uint8 *pCurVal = (uint8 *)pAttr-> | ||
- | | ||
- | *(pCurVal+offset+i)=*(pValue+i); | ||
- | } | ||
- | | ||
- | | ||
- | } | ||
- | } | ||
- | | ||
- | ``` | ||
- | 同时要在应用程序回调处理 Characteristic Value 5 的写入操作,方便打印到串口调试。 | ||
- | |||
- | ```C | ||
- | // | ||
- | case SIMPLEPROFILE_CHAR5: | ||
- | SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR5, | ||
- | | ||
- | sprintf(sprintChar," | ||
- | //!< 大概每 60 个字符要换一行 | ||
- | line=7; | ||
- | index=8; | ||
- | for(uint8_t i=0; | ||
- | sprintf(sprintChar+index, | ||
- | index=index+2; | ||
- | //!< 每60个字符进行换行打印。 | ||
- | if(index%60==0) { | ||
- | index=0; | ||
- | Display_print1(dispHandle, | ||
- | } | ||
- | } | ||
- | if(index> | ||
- | Display_print1(dispHandle, | ||
- | } | ||
- | break; | ||
- | ``` | ||
- | ### 现象 ### | ||
- | * simple_periphearal 打印进入广播状态 | ||
- | |||
- | ![](http:// | ||
- | |||
- | * BTool 扫描连接 | ||
- | |||
- | ![](http:// | ||
- | |||
- | * 配对 | ||
- | |||
- | ![](http:// | ||
- | |||
- | * 交换MTU,设置到 GATT 服务端编译支持的最大 251 。 | ||
- | > | ||
- | |||
- | ![](http:// | ||
- | ```C | ||
- | -------------------------------------------------------------------- | ||
- | [26] : <Rx> - 05: | ||
- | -Type : 0x04 (Event) | ||
- | -EventCode | ||
- | -Data Length | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | Dump(Rx): | ||
- | 0000:04 FF 06 7F 06 00 02 FD 00 ......... | ||
- | -------------------------------------------------------------------- | ||
- | [27] : <Rx> - 05: | ||
- | -Type : 0x04 (Event) | ||
- | -EventCode | ||
- | -Data Length | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | Dump(Rx): | ||
- | 0000:04 FF 08 03 05 00 00 00 02 FB 00 ........... | ||
- | -------------------------------------------------------------------- | ||
- | [28] : <Rx> - 05: | ||
- | -Type : 0x04 (Event) | ||
- | -EventCode | ||
- | -Data Length | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | Dump(Rx): | ||
- | 0000:04 FF 08 7F 05 00 00 00 02 FB 00 ........... | ||
- | -------------------------------------------------------------------- | ||
- | ``` | ||
- | | ||
- | ![](http:// | ||
- | | ||
- | * 读取特征值 | ||
- | |||
- | ![](http:// | ||
- | |||
- | * 成功写入,将读取 Attribute Value 前面和后面都改成 `FFFFFF03` 和 `C6FFFF` 。 | ||
- | |||
- | |||
- | ![](http:// | ||
- | ![](http:// | ||
- | |||
- | ### 总结 ### | ||
- | 尽管通过 GATT 服务端配置更大 MTU ,再通过 GATT Client 交换,成功读取 200 字节的特征值。但在抓包分析中不难发现在 Controller 的链路层还是被拆分为最大长度 27 字节发送。 | ||
- | 通过前面分析已经不难理解:BLE4.2/ | ||
- | |||
- | 为了获取到更大数据吞吐量,我们继续研究 BLE4.2/5.0 新增功能 LE Data Extence。 | ||
- | |||
- | ![](http:// | ||
- | |||
- | ### Troubleshooting ### | ||
- | * 写入数据失败,提示找不到 Attribute Handle。 | ||
- | |||
- | ![](http:// | ||
- | |||
- | 需要添加特征值 5 的写回调处理,否则会直接提示找不到句柄。 | ||
- | |||
- | |||
- | * 读取特征值超时 | ||
- | |||
- | ![](http:// | ||
- | |||
- | 因为更改的 GATT 服务端也就是 simple_peripheral 工程的默认 MTU 大小,正常读写特征值前需要进行 `ATT_Exchange_MTU_Req` 请求,否则会直接失败。 | ||
- | |||
- | ## LE Data Extension ## | ||
- | <a href=" | ||
- | |||
- | BLE4.2/5.0 设备默认支持 TX_PDU 大小,为了兼容 BLE4.1/4.0 设备,默认设置为 27 字节/ | ||
- | |||
- | 所以直接设置 Peripheral/ | ||
- | |||
- | ```C | ||
- | #define APP_SUGGESTED_PDU_SIZE 251 | ||
- | #define APP_SUGGESTED_TX_TIME 2120 | ||
- | |||
- | //This API is documented in hci.h | ||
- | HCI_LE_WriteSuggestedDefaultDataLenCmd(APP_SUGGESTED_PDU_SIZE , | ||
- | ``` | ||
- | |||
- | ### 抓包分析 ### | ||
- | |||
- | * M-> | ||
- | |||
- | ``` | ||
- | +----------------------------------------------------+----------------- - - - | ||
- | | | ||
- | +----+-------------+-------------------------+-------+ | ||
- | |info| Packet nbr. | Time stamp | Length| | ||
- | +----+-------------+-------------------------+-------+----------------- - - - | ||
- | | 01 | E1 00 00 00 | 29 0C 05 0E 02 00 00 00 | 15 00 | 14 BD AA 6D C4 0F 09 **14** ** FB 00 48 08 1B 00 48 01 ** 75 9A 9B 2A 9A | ||
- | +----+-------------+-------------------------+-------+----------------- - - - | ||
- | ``` | ||
- | |||
- | * S-> | ||
- | |||
- | ``` | ||
- | +----------------------------------------------------+----------------- - - - | ||
- | | | ||
- | +----+-------------+-------------------------+-------+ | ||
- | |info| Packet nbr. | Time stamp | Length| | ||
- | +----+-------------+-------------------------+-------+----------------- - - - | ||
- | | 01 | E2 00 00 00 | C2 0A 07 0E 02 00 00 00 | 15 00 | 14 BD AA 6D C4 0B 09 **14** ** FB 00 48 08 1B 00 48 01** B3 1B C9 2E 9A | ||
- | +----+-------------+-------------------------+-------+----------------- - - - | ||
- | ``` | ||
- | |||
- | * S-> | ||
- | |||
- | ``` | ||
- | +----------------------------------------------------+----------------- - - - | ||
- | | | ||
- | +----+-------------+-------------------------+-------+ | ||
- | |info| Packet nbr. | Time stamp | Length| | ||
- | +----+-------------+-------------------------+-------+----------------- - - - | ||
- | | 01 | E3 00 00 00 | 3C 0B 85 10 02 00 00 00 | 15 00 | 14 BD AA 6D C4 03 09 **15** | ||
- | +----+-------------+-------------------------+-------+----------------- - - - | ||
- | |||
- | ``` | ||
- | |||
- | * M-> | ||
- | |||
- | ``` | ||
- | +----------------------------------------------------+----------------- - - - | ||
- | | | ||
- | +----+-------------+-------------------------+-------+ | ||
- | |info| Packet nbr. | Time stamp | Length| | ||
- | +----+-------------+-------------------------+-------+----------------- - - - | ||
- | | 01 | E4 00 00 00 | D7 09 87 10 02 00 00 00 | 15 00 | 14 BD AA 6D C4 07 09 **15** | ||
- | +----+-------------+-------------------------+-------+----------------- - - - | ||
- | |||
- | ``` | ||
- | |||
- | ## 加入我们 ## | ||
- | |||
- | 文章所有代码、工具、文档开源。加入我们[**QQ群 591679055**](http:// | ||
- | <div> | ||
- | <p align=" | ||
- | <a target=" | ||
- | </p> | ||
- | </ | ||
- | |||
- | </ |