4、RTCM 3.x消息帧结构:同步码、保留位、消息长度、CRC校验,帧解析流程
RTCM 3.x(Radio Technical Commission for Maritime Services,国际海运事业无线电技术委员会)协议是GNSS差分改正数传输的事实标准,广泛应用于RTK(实时动态载波相位差分)测量、PPP-RTK、网络RTK(如VRS、FKP、MAC)以及精密农业、自动驾驶、无人机定位等场景。与RTCM 2.x的变长、无强校验、面向字符的帧格式不同,RTCM 3.x采用固定8位同步码、12位消息长度、24位CRC-24Q校验的二进制帧结构,具有极高的抗误码能力和解析效率。本章将深入拆解RTCM 3.x帧的每一个比特位,给出严谨的帧解析流程,并结合实际抓包数据演示从字节流到消息内容的完整解码过程。
上图展示了RTCM 3.x帧的完整结构以及从字节流中提取一帧数据的核心状态机流程。下面我们将从帧结构各字段的位级定义开始,逐步深入到CRC校验算法和实际解析代码实现。
4.1 帧结构各字段位级定义
核心原理:RTCM 3.x帧采用大端(Big-Endian)字节序,所有多字节字段均按高位在前的方式传输。帧总长度 = 1字节同步码 + 2字节长度字段 + N字节消息数据 + 3字节CRC,其中N由长度字段的10个比特决定,取值范围为0~1023字节。整个帧的最小长度为6字节(N=0时),最大长度为1029字节。
| 字段名称 | 比特数 | 字节偏移 | 取值/含义 | 备注 |
|---|---|---|---|---|
| 同步码(Preamble) | 8 | 0 | 固定0xD3(二进制1101 0011) | 用于帧边界识别,不可与其他字段混淆 |
| 保留位(Reserved) | 6 | 1(高6位) | 固定为0 | 协议预留,未来扩展使用,当前必须为0 |
| 消息长度(Message Length) | 10 | 1(低2位)+2(全部8位) | 0~1023,表示消息数据(不含同步码、长度字段和CRC)的字节数 | 长度字段共16位,但高6位为保留位,实际有效长度仅10位 |
| 消息数据(Message Data) | 可变 | 3 ~ 3+N-1 | 包含消息头(12位消息类型)+ 消息体 + 填充位 | 填充位用于将消息体对齐到字节边界,填充位值无意义 |
| CRC校验(CRC-24Q) | 24 | 3+N ~ 3+N+2 | 对同步码之后的所有字节(即长度字段+消息数据)进行CRC-24Q计算 | 多项式0x1864CFB,初始值0x000000 |
判断方法:解析时,首先读取第一个字节,若等于0xD3则初步认为找到同步码。但仅凭一个字节不能完全确认帧边界,因为消息数据中也可能出现0xD3。因此必须结合长度字段和CRC校验来最终确认。读取第2、3字节后,提取低10位作为消息长度N,然后连续读取N+3字节(消息数据+CRC),对长度字段和消息数据计算CRC-24Q,与接收到的CRC比对。若一致,则确认这是一个完整且正确的RTCM 3.x帧。
实战经验:在串口或网络流中,0xD3可能出现在任何位置。高效的解析器应使用状态机而非逐字节搜索。当处于“搜索同步码”状态时,每收到一个字节就与0xD3比较;一旦匹配,立即切换到“读取长度”状态,并启动超时计时器。若在超时时间内未收到足够字节,则回到搜索状态,避免因数据流中断导致解析卡死。
4.2 CRC-24Q校验算法详解
核心原理:CRC-24Q是RTCM 3.x专用的循环冗余校验算法,其生成多项式为0x1864CFB(二进制:1 1000 0110 0100 1100 1111 1011),初始值为0x000000,输入数据按位处理,不进行反射(即MSB-first),输出结果直接附加在消息末尾。该算法能检测出所有长度≤24比特的突发错误,以及绝大多数更长的错误模式,非常适合无线和串行链路。
操作流程:CRC计算的输入范围是从长度字段的第一个字节开始,一直到消息数据的最后一个字节,不包含同步码和CRC本身。具体步骤如下:
- 初始化CRC寄存器为0x000000。
- 对输入字节流中的每一位(从最高位MSB开始),执行以下操作:
a. 将CRC寄存器左移1位,最低位补0;
b. 若移出的最高位(原CRC第23位)与当前输入位异或结果为1,则CRC寄存器与多项式0x1864CFB进行异或。 - 处理完所有字节后,CRC寄存器中的24位值即为校验码。
// C语言实现CRC-24Q(RTCM 3.x)
uint32_t crc24q(const uint8_t *data, size_t len) {
uint32_t crc = 0;
for (size_t i = 0; i < len; i++) {
crc ^= ((uint32_t)data[i]) << 16; // 将字节放入CRC最高字节
for (int j = 0; j < 8; j++) {
crc <<= 1;
if (crc & 0x1000000) { // 检查第24位
crc ^= 0x1864CFB; // 异或多项式
}
}
}
return crc & 0xFFFFFF; // 取低24位
}
案例拆解:假设收到一帧RTCM 3.x数据,十六进制为:D3 00 06 10 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00