跳转至

MSP v1、v2与DisplayPort

多旋翼飞行器串行协议(MSP,MultiWii Serial Protocol)常用于飞控配置、状态查询、命令、外设桥接和屏幕叠加显示。MSP历史长、实现多,兼容性必须绑定具体固件和应用程序编程接口(API,Application Programming Interface)版本。

MSP v1与v2帧结构

MSP不是单一功能

同一MSP传输可以包含:

  • 固件和API身份;
  • 状态与传感器数据;
  • 配置读取与写入;
  • 重启或进入引导加载器;
  • OSD配置;
  • DisplayPort字符和绘制命令;
  • 厂商或项目扩展。

能够解析只读状态,不代表可以安全发送写配置或重启命令。工具必须先识别API、飞控类型和能力,再开放对应功能。

MSP v1

请求帧概念结构:

'$' 'M' '<' [size8] [command8] [payload] [xor]

响应方向通常使用>,错误响应可使用!。其中:

  • size8是载荷字节数;
  • command8是8位命令;
  • 校验是size8command8和全部载荷字节的逐字节异或;
  • 三字节前导符不进入异或;
  • 载荷最大长度受8位长度及实现缓冲区共同限制。

异或校验只能发现部分错误,不能提供密码学完整性。

原生MSP v2

原生v2请求概念结构:

'$' 'X' '<'
[flags8]
[command16 little-endian]
[size16 little-endian]
[payload]
[crc8]

关键点:

  • 命令和长度扩展为16位;
  • 多字节字段低字节先传;
  • CRC采用CRC-8/DVB-S2;
  • CRC覆盖flags、命令、长度和载荷;
  • $X<前导符不进入CRC;
  • 接收端仍必须把协议长度与本地缓冲上限比较。

响应方向和错误方向与v1采用相同概念,但第二个标识字节为X

v2-over-v1

为了穿过只识别MSP v1外框的传输路径,MSP v2还可以封装在v1帧中:

MSP v1外层
└── 保留的v2封装命令
    └── flags + command16 + size16 + payload + v2 CRC

这类帧同时存在:

  • v1外层长度和异或校验;
  • v1外层命令固定为255
  • v2内层字段和CRC-8/DVB-S2。

外层异或覆盖v1长度、命令255、全部封装内容和内层CRC。新实现和网关应验证两层长度与两层校验,不能因外层通过就跳过内层。

Betaflight 2026.6.2接收状态机会验证外层异或和内层CRC,但不会额外强制外层长度等于5 + 内层载荷长度 + 1。这是一项固定实现边界,不是推荐的新解析器行为。差分测试必须覆盖“外层可容纳、内外声明不一致”的帧,防止桥接器和飞控对同一输入得出不同结论。

长度与缓冲区

安全解析顺序:

  1. 识别$M$X
  2. 验证方向字符;
  3. 收集固定头;
  4. 解码声明长度;
  5. 比较协议上限和本地缓冲上限;
  6. 等待完整载荷;
  7. 校验;
  8. 若为v2-over-v1,再验证内层;
  9. 分派已知命令。

协议字段上限不等于固定固件实例的输入能力。Betaflight 2026.6.2串口MSP输入缓冲为192字节,接收状态机不解析Jumbo输入。发送边界要按线格式分开:

发送格式 进入Jumbo的条件 固定源码的线上位置
MSP v1 应用数据载荷长度>=255 size=255、8位命令之后紧跟16位小端应用数据长度
v2-over-v1 外层封装载荷5 + dataLen + 1 >= 255,即应用数据dataLen >= 249 size=255、命令255、5字节v2头之后,紧跟16位小端外层封装载荷长度
Native MSP v2 不使用v1 Jumbo 原生16位小端size直接表示应用数据长度

Jumbo额外长度字节进入v1外层异或校验;v2-over-v1的内层v2 CRC仍只覆盖v2头和应用数据,不覆盖位于v2头后的Jumbo长度,外层异或则覆盖全部头、应用数据和v2 CRC。Jumbo在该固定实现中是发送侧特殊路径,不存在通用的线上容量协商。客户端必须按命令和固定接收上限选择请求,不能只根据v1长度字段推导“双方都能收255字节”,也不能假定可以自动分块。

必须测试:

  • v1长度255附近;
  • v2长度大于本地缓冲;
  • 内外层长度矛盾;
  • 截断帧;
  • 载荷包含$M<$X<
  • 连续无间隔帧;
  • 错误帧后的重同步。

API版本和飞控身份

Betaflight的MSP API约定要求客户端先读取API版本和飞控标识。工具至少记录:

  • MSP协议版本;
  • API主、次版本;
  • 飞控标识;
  • 固件版本;
  • 板卡或目标标识;
  • 能力和可用命令。

MSP线格式版本与MSP API版本不是同一概念。Betaflight 2026.6.2可以使用MSP_V1MSP_V2_OVER_V1MSP_V2_NATIVE线格式,而MSP_API_VERSION返回协议版本字节、API主版本1和次版本48。使用v2帧不等于“API v2”。

API主版本不兼容时,客户端不应继续通信和写配置。对更高次版本,应在已知命令范围内尝试兼容,并对未知或失败命令优雅降级,只关闭依赖该命令的功能。派生固件若API不完全一致,应使用不同飞控标识,不能伪装成相同标识和API。

未知命令应返回协议定义的错误或被安全拒绝,不能造成解析器失步、重启或部分写入。

读、写和执行命令

建议按风险分级:

级别 示例 最低门禁
只读 身份、状态、传感器、配置读取 版本和长度验证
配置写入 端口、接收机、OSD、模式 API兼容、范围、状态和回读
持久化 保存非易失配置 事务、结果和重启恢复
执行动作 重启、引导加载器、电机测试 物理安全、权限和当前状态

收到合法帧不能绕过飞控内部解锁和安全状态机。客户端也不能在不知道命令结果时自动重复高风险操作。

请求和响应匹配

MSP通常在串行会话中按请求和响应工作,但实现仍需处理:

  • 超时;
  • 上一次迟到响应;
  • 异步状态数据;
  • 错误方向;
  • 重连;
  • 多客户端共享同一桥接链路;
  • 请求并发。

串行链路没有天然事务ID时,最保守的方法是限制同一会话只有一个未完成请求,并按命令、长度和当前状态匹配响应。

DisplayPort

MSP DisplayPort让飞控向显示设备发送屏幕叠加显示(OSD,On-Screen Display)的字符网格和绘制控制。常见操作包括:

  • 心跳;
  • 释放或停止会话;
  • 清屏;
  • 写入字符串或字符属性;
  • 提交绘制;
  • 设置显示选项或画布信息。

具体子命令和字段必须以固定版本API文档与源码为准。

它传输什么

DisplayPort传输的是OSD绘制语义,例如在某行某列写字符,再提交一帧显示。它不是:

  • 模拟视频波形;
  • 压缩数字视频码流;
  • 摄像头图像;
  • 射频图传本身。

典型路径是:

飞控OSD状态
→ MSP DisplayPort字符/绘制命令
→ 数字图传设备
→ 图传系统把OSD叠加到视频
→ 视频编码与射频路径

DisplayPort正常而视频黑屏,问题可能在摄像头、编码、射频或显示端;视频正常而OSD不更新,问题可能在MSP路径、画布能力或字体映射。

画布与字符

双方需要协商或约定:

  • 行列数;
  • 字符集和字体页;
  • 坐标原点;
  • 字符属性;
  • 扩展字符;
  • 清屏和提交时序;
  • 心跳和超时;
  • 设备重连后的重绘。

发送端不能根据一个固定分辨率假定所有设备具有同一画布。文本越界应裁剪或拒绝,不能写出缓冲区。

帧更新

OSD刷新可能产生突发数据。实现应:

  • 合并同一显示周期的更新;
  • 避免每个字符单独产生不必要请求;
  • 保留关键告警优先级;
  • 监测队列和丢弃;
  • 在链路恢复后执行明确清屏或全量重绘;
  • 避免旧字符长期残留。

显示一帧成功不代表长期带宽足够。

安全边界

MSP传统链路通常不提供认证或加密。风险控制依赖:

  • 限制物理和网络可达范围;
  • 区分只读与写入入口;
  • 禁止从不受信网络直接桥接;
  • 飞控状态门禁;
  • 工具侧确认和审计;
  • 固件更新与协议解析器安全。

USB不是天然可信边界;连接到被攻陷的计算机仍可能收到恶意命令。

固定版本核验

Betaflight 2026.6.2至少核对:

  • src/main/msp/msp_serial.c中的v1、v2和封装解析;
  • src/main/msp/msp_protocol.h中的API与命令;
  • DisplayPort实现和当前文档;
  • 端口共享、最大载荷和命令状态门禁。

INAV与Betaflight有共同历史,但命令、字段和API版本不能直接互换。其他平台或设备实现MSP子集时,应建立独立能力表。

测试矩阵

执行写参数、重启、引导加载器或DisplayPort主动输出前,必须先完成协议审查与测试卡第0节,并按抓包、解码、一致性与版本迁移保存请求、响应和最终状态。

类别 用例 通过标准
身份 v1/v2读取API与飞控身份 版本与固定固件一致
正常、截断、超长、错误校验 安全拒绝并能重新同步
兼容 未知命令、旧工具、新工具 明确错误,不执行错误写入
写入 合法值、越界值、错误状态 仅合法写入,回读一致
重启 应用前断线、应用后断线 最终状态可判定
DisplayPort 不同画布、越界、突发更新 无越界、无长期残留
资源 最大持续流量 队列和任务时延不越门限

异常帧和写入测试仅在SITL、HITL或拆桨且动力级断开的隔离台架执行。

常见误判

  • 把MSP API版本等同于飞控产品版本;
  • 只按命令ID解析,不先读取飞控身份;
  • 把v1异或校验称为CRC;
  • 忘记v2多字节字段是小端;
  • 对v2-over-v1只验证一层校验;
  • 把未知命令当作成功空响应;
  • 把DisplayPort当作视频传输协议;
  • 用一次OSD显示成功证明持续链路容量;
  • 允许网络桥接客户端无门禁地发送写入或电机命令。

检查理解

  1. MSP v1和原生v2的前导符有什么不同?
  2. v2-over-v1为什么需要两层校验?
  3. 工具为什么要先读取API版本和飞控身份?
  4. DisplayPort和视频码流分别承载什么?
  5. MSP帧校验正确为什么仍不能直接执行高风险命令?

主要参考