SMP 传输规范
本文档说明了实现服务器端和客户端 SMP 传输所需的信息。
Bluetooth Low Energy (LE)
MCUmgr 客户端在实现 SMP 客户端时需要使用以下 Bluetooth 特征:
服务 UUID:
8D53DC1D-1DB7-4CD3-868B-8A527460AA84特征 UUID:
DA2E7828-FBCE-4E01-AE9E-261174997C48
所有 SMP 通信都使用单个 GATT 特征。SMP 请求通过 GATT Write Without Response 命令发送。SMP 响应以 GATT Notification 的形式发送
如果 SMP 请求或响应太大,无法放入单个 GATT 命令,发送方会将其分片到多个数据包中。对请求或响应进行分片时不会引入额外的帧格式;有效载荷只是被拆分到多个数据包中。由于 GATT 保证数据包按序交付,第一个分片中的 SMP 头包含重组所需的足够信息。
UART/串行和控制台
Zephyr 的 MCUmgr 子系统中的 SMP 协议规范使用基本的数据帧格式,以支持 UART 通道的多路复用。多路复用要求为每个帧添加两个字节的标记作为前缀,并以换行符终止。目前 MCUmgr 对帧大小施加 127 字节的限制,尽管并没有实际的协议约束要求这一限制。该限制包括前缀和换行符,因此允许的有效载荷大小实际上是 124 字节。
尽管 Zephyr 中不存在这样的传输方式,但可以实现不使用任何帧格式、使用硬件串口控制或使用其他帧界定方式的 UART 传输上的 MCUmgr 客户端/服务器。
帧分片
串行链路上的 SMP 协议被分片为 MTU 大小的帧;每个帧由两个字节的起始标记、正文和终止换行符组成。
帧有四种类型:初始帧、部分帧、部分-最终帧和初始-最终帧;每种帧类型通过起始标记和/或正文内容来区分。
帧格式
初始帧后面必须跟随可选的部分帧序列,最后是部分-最终帧。正文始终采用 Base64 编码,因此正文大小(此处描述为 MTU - 3)实际上能够承载 N = (MTU - 3) / 4 * 3 字节的原始数据。
初始帧的正文前面有两个字节的总数据包长度,采用大端序编码,其值等于原始正文大小加上 CRC16 的两个字节;这意味着初始帧中允许的实际正文大小为 N - 2。
如果正文大小小于 N - 4,则可以在单个帧中承载整个正文及其前面的长度和后面的 CRC,此帧称为初始-最终帧;有关初始-最终帧的说明,请参见下文。
初始帧格式:
内容 |
大小 |
描述 |
|---|---|---|
0x06 0x09 |
2 字节 |
帧起始标记 |
<base64-i> |
不超过 MTU - 3 字节 |
Base64 编码的正文 |
0x0a |
1 字节 |
帧终止 |
<base64-i> 是格式如下的 Base64 编码正文:
内容 |
大小 |
描述 |
|---|---|---|
总长度 |
2 字节 |
大端序 16 位值,表示正文总长度加上 CRC16 的 2 字节;请注意,总长度字段本身的大小不会加到总长度值中。 |
正文 |
不超过 MTU - 5 |
原始正文数据片段 |
初始-最终帧格式与初始帧格式类似,但 <base64-i> 的定义不同。
初始-最终帧的 <base64-i> 是格式如下的 Base64 编码数据:
内容 |
大小 |
描述 |
|---|---|---|
总长度 |
2 字节 |
大端序 16 位值,表示正文总长度加上 CRC16 的 2 字节;请注意,总长度字段本身的大小不会加到总长度值中。 |
正文 |
不超过 MTU - 7 |
原始正文数据片段 |
crc16 |
2 字节 |
整个数据包正文的 CRC16,不包括前面的长度字段。 |
部分帧是前一个初始帧或其他部分帧的延续。部分帧的形式如下:
内容 |
大小 |
描述 |
|---|---|---|
0x04 0x14 |
2 字节 |
帧起始标记 |
<base64-i> |
不超过 MTU - 3 字节 |
Base64 编码的正文 |
0x0a |
1 字节 |
帧终止 |
部分帧的 <base64-i> 是数据的 Base64 编码,形式如下:
内容 |
大小 |
描述 |
|---|---|---|
正文 |
不超过 MTU - 3 |
原始正文数据片段 |
部分-最终帧的 <base64-i> 是数据的 Base64 编码,形式如下:
内容 |
大小 |
描述 |
|---|---|---|
正文 |
不超过 MTU - 5 |
原始正文数据片段 |
crc16 |
2 字节 |
整个数据包正文的 CRC16,不包括前面的长度字段。 |
CRC 详细信息
最终类型帧中包含的 CRC16 仅对原始数据计算,不包括数据包长度。CRC16 多项式为 0x1021,初始值为 0。
原始 UART/串行(无控制台)
在 Zephyr 中,UART 还有一种替代传输方式,它不像基于控制台的 SMP 传输那样使用 Base64;这可以实现更小的代码体积和更快的传输,但不能用于在同一 UART 上具有 shell 或日志输出的设备,也不能用于连接到显示 ASCII 数据的终端,因为所有通信都使用原始二进制 SMP 协议。
要使用此协议,请使用 CONFIG_MCUMGR_TRANSPORT_RAW_UART,它要求以原始模式启用 MCUmgr UART 控制台驱动。
超时
由于使用此传输方式时没有帧界定,UART 上可能会收到无效数据,导致系统等待例如一个永远也不会到达的超长数据包。为防止这种情况,系统提供了超时机制:如果在特定时间范围内未收到完整数据包,则会清空整个接收缓冲区。建议在 UART 端口上启用此选项;对于 USB CDC 等传输方式,如果它是“虚拟”UART,并且数据在传递前可以被验证,则不需要此选项。可以使用 CONFIG_MCUMGR_TRANSPORT_RAW_UART_INPUT_TIMEOUT 启用该选项,其超时时间可以使用 CONFIG_MCUMGR_TRANSPORT_RAW_UART_INPUT_TIMEOUT_TIME_MS 设置。