4. Bootloader中实现固件版本检查
任务说明
在Bootloader中实现固件版本检查:解析待升级固件的头部信息,提取版本号,与Bootloader当前运行的版本号比较,根据比较结果决定是否执行升级流程。本案例聚焦版本比较逻辑本身,不涉及具体通信协议或存储驱动。
固件头部格式定义
偏移量 字段 大小 说明
0x00 magic 4字节 固定为0xAA55AA55,用于校验固件有效性
0x04 version 4字节 版本号,高2字节为主版本,低2字节为次版本
0x08 length 4字节 固件数据总长度(含头部)
0x0C crc32 4字节 固件数据CRC32校验值(不含头部)
0x10 payload N字节 实际固件数据
关键完整代码
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#define FW_HEADER_MAGIC 0xAA55AA55u
#define FW_HEADER_SIZE 16u
#define FW_VERSION_MAJOR(v) (((v) >> 16) & 0xFFFF)
#define FW_VERSION_MINOR(v) ((v) & 0xFFFF)
typedef struct {
uint32_t magic;
uint32_t version;
uint32_t length;
uint32_t crc32;
} fw_header_t;
/* 当前Bootloader版本号 */
#define BOOTLOADER_VERSION 0x00010002u /* v1.2 */
/* 模拟从存储介质读取固件头部(实际工程中替换为Flash/通信读取) */
static bool read_fw_header(const uint8_t *fw_addr, fw_header_t *hdr)
{
if (fw_addr == NULL || hdr == NULL) {
return false;
}
memcpy(hdr, fw_addr, sizeof(fw_header_t));
return true;
}
/* 版本比较:返回true表示新固件版本高于当前版本 */
static bool is_newer_version(uint32_t new_ver, uint32_t cur_ver)
{
uint32_t new_major = FW_VERSION_MAJOR(new_ver);
uint32_t new_minor = FW_VERSION_MINOR(new_ver);
uint32_t cur_major = FW_VERSION_MAJOR(cur_ver);
uint32_t cur_minor = FW_VERSION_MINOR(cur_ver);
if (new_major != cur_major) {
return new_major > cur_major;
}
return new_minor > cur_minor;
}
/* 固件版本检查主函数 */
int check_firmware_version(const uint8_t *fw_addr)
{
fw_header_t hdr;
if (fw_addr == NULL) {
return -1; /* 参数错误 */
}
if (!read_fw_header(fw_addr, &hdr)) {
return -2; /* 头部读取失败 */
}
if (hdr.magic != FW_HEADER_MAGIC) {
return -3; /* 固件magic错误,非法固件 */
}
if (hdr.length < FW_HEADER_SIZE) {
return -4; /* 固件长度字段非法 */
}
if (is_newer_version(hdr.version, BOOTLOADER_VERSION)) {
return 1; /* 新固件版本更高,允许升级 */
} else if (hdr.version == BOOTLOADER_VERSION) {
return 0; /* 版本相同,无需升级 */
} else {
return -5; /* 新固件版本更低,拒绝降级 */
}
}
/* 测试用例 */
#include <stdio.h>
int main(void)
{
/* 构造测试固件:v2.0,高于当前v1.2 */
uint8_t fw_new[] = {
0x55, 0xAA, 0x55, 0xAA, /* magic */
0x00, 0x02, 0x00, 0x00, /* version = 0x00020000 (v2.0) */
0x10, 0x00, 0x00, 0x00, /* length = 16 */
0x00, 0x00, 0x00, 0x00 /* crc32占位 */
};
/* 构造测试固件:v1.0,低于当前v1.2 */
uint8_t fw_old[] = {
0x55, 0xAA, 0x55, 0xAA, /* magic */
0x00, 0x01, 0x00, 0x00, /* version = 0x00010000 (v1.0) */
0x10, 0x00, 0x00, 0x00, /* length = 16 */
0x00, 0x00, 0x00, 0x00 /* crc32占位 */
};
/* 构造测试固件:v1.2,与当前相同 */
uint8_t fw_same[] = {
0x55, 0xAA, 0x55, 0xAA, /* magic */
0x00, 0x01, 0x00, 0x02, /* version = 0x00010002 (v1.2) */
0x10, 0x00, 0x00, 0x00, /* length = 16 */
0x00, 0x00, 0x00, 0x00 /* crc32占位 */
};
printf("测试v2.0 (高于当前): %d (预期1)\n", check_firmware_version(fw_new));
printf("测试v1.0 (低于当前): %d (预期-5)\n", check_firmware_version(fw_old));
printf("测试v1.2 (等于当前): %d (预期0)\n", check_firmware_version(fw_same));
return 0;
}
编译与运行
gcc -o fw_check fw_version_check.c
./fw_check
验证方法
程序输出以下三行即表示逻辑正确:
测试v2.0 (高于当前): 1 (预期1)
测试v1.0 (低于当前): -5 (预期-5)
测试v1.2 (等于当前): 0 (预期0)
返回码含义:1允许升级,0版本相同无需升级,-5拒绝降级,-1~-4为参数或头部校验错误。
集成说明
在实际Bootloader工程中,fw_addr指向接收缓冲区或Flash映射地址,read_fw_header替换为对应存储介质的读取函数。版本比较通过后,再执行CRC32校验和固件搬运,本案例不涉及这些后续步骤。