2. CRC24Q 校验算法实现

任务说明

RTCM 3.x 报文以 8 位十六进制前缀 D3 开头,随后是 6 位保留位与 10 位报文长度,最后附加 3 字节 CRC24Q 校验值。本案例实现 CRC24Q 的完整计算与验证函数,并给出可直接运行的测试入口,确保任意 RTCM 3.x 报文(含前缀与长度字段)能够正确生成和校验 CRC。

CRC24Q 算法定义

CRC24Q 采用生成多项式 0x1864CFB(即 x^24 + x^23 + x^18 + x^17 + x^14 + x^11 + x^10 + x^7 + x^6 + x^5 + x^4 + x^3 + x + 1),初始值为 0x000000,输入数据按位处理,不进行反射,输出不异或。RTCM 标准规定 CRC 覆盖从报文前缀 D3 开始到长度字段结束的所有字节,校验值以大端序追加在报文末尾。

核心代码实现


#include <stdint.h>
#include <stddef.h>
#include <stdio.h>

#define CRC24Q_INIT  0x000000u
#define CRC24Q_POLY  0x1864CFBu
#define CRC24Q_MASK  0xFFFFFFu

/* 计算 CRC24Q:data 指向报文起始字节(含 0xD3 前缀),len 为参与校验的字节数 */
uint32_t crc24q_compute(const uint8_t *data, size_t len) {
    uint32_t crc = CRC24Q_INIT;
    for (size_t i = 0; i < len; i++) {
        crc ^= ((uint32_t)data[i]) << 16;
        for (int bit = 0; bit < 8; bit++) {
            crc <<= 1;
            if (crc & 0x1000000u) {
                crc ^= CRC24Q_POLY;
            }
        }
    }
    return crc & CRC24Q_MASK;
}

/* 验证 CRC:data 指向含 CRC 的完整报文,payload_len 为不含 CRC 的字节数 */
int crc24q_verify(const uint8_t *data, size_t payload_len) {
    uint32_t calc = crc24q_compute(data, payload_len);
    uint32_t recv = ((uint32_t)data[payload_len] << 16) |
                    ((uint32_t)data[payload_len + 1] << 8) |
                    ((uint32_t)data[payload_len + 2]);
    return (calc == recv) ? 1 : 0;
}

/* 测试用例:RTCM 3.x 标准示例帧(来自 RTCM 标准文档) */
int main(void) {
    /* 帧内容:D3 00 06 44 6B 01 9C 3C 0F,其中前 6 字节为报文头+长度,后 3 字节为 CRC */
    uint8_t frame[] = {0xD3, 0x00, 0x06, 0x44, 0x6B, 0x01, 0x9C, 0x3C, 0x0F};
    size_t header_len = 6;  /* 前缀(1) + 保留/长度(2) + 消息体(3) = 6 字节参与 CRC */

    uint32_t crc = crc24q_compute(frame, header_len);
    printf("计算 CRC: %06X\n", crc);
    printf("预期 CRC: 9C3C0F\n");

    if (crc == 0x9C3C0F) {
        printf("CRC 计算正确\n");
    } else {
        printf("CRC 计算错误\n");
        return 1;
    }

    if (crc24q_verify(frame, header_len)) {
        printf("CRC 校验通过\n");
    } else {
        printf("CRC 校验失败\n");
        return 1;
    }
    return 0;
}

代码说明

crc24q_compute 函数逐字节处理输入数据,每字节通过 8 次移位与异或完成位级运算。CRC 寄存器为 32 位,但仅低 24 位有效,溢出位 0x1000000 用于判断是否需要与生成多项式异或。最终返回值掩去高 8 位,得到标准 24 位 CRC。crc24q_verify 函数先对不含 CRC 的报文部分重新计算,再与报文末尾 3 字节(大端序)比较,返回 1 表示匹配。

编译与运行


gcc -o crc24q crc24q.c
./crc24q

验证方法

测试帧 D3 00 06 44 6B 01 9C 3C 0F 取自 RTCM 标准参考数据,其中前 6 字节参与 CRC 计算,后 3 字节为已知正确校验值。程序输出应显示计算 CRC 为 9C3C0F,与预期一致,并打印“CRC 计算正确”与“CRC 校验通过”。若输出不符,说明实现存在位序或多项式错误。

RTCM 3.x 帧结构(CRC 覆盖范围) D3 保留(6bit)+长度(10bit) 消息体(可变长度) CRC24Q CRC 计算覆盖区域(含前缀与长度字段) CRC 校验流程 接收完整帧 提取长度字段 对前(3+len)字节计算CRC 与帧尾3字节比较 不匹配 → 丢弃帧 匹配 → 解析消息体

判定标准

程序退出码为 0 且控制台输出包含“CRC 计算正确”和“CRC 校验通过”即视为实现正确。该测试向量覆盖了前缀字节 D3、长度字段与消息体组合的 CRC 计算,可验证位处理顺序与多项式是否正确。