1. 固件版本信息管理
任务说明
在OTA固件更新中,版本号是判断是否需要升级、防止回滚攻击的基础。本案例实现固件版本号的存储与读取,提供版本比较接口,为后续OTA流程提供版本管理基础。
实现方案
使用结构体保存版本的主版本号、次版本号、补丁号和构建号,提供版本设置、获取和比较三个核心接口。版本号以文本格式存储在固定内存区域,便于调试和外部工具读取。
完整代码
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#define VERSION_STR_MAX_LEN 32
#define VERSION_MAGIC 0xA5A5A5A5
/* 版本信息结构体 */
typedef struct {
uint32_t magic; /* 校验魔数 */
uint8_t major; /* 主版本号 */
uint8_t minor; /* 次版本号 */
uint8_t patch; /* 补丁号 */
uint8_t build; /* 构建号 */
char reserved[8]; /* 保留字段 */
} firmware_version_t;
/* 版本存储区(模拟Flash固定区域) */
static firmware_version_t version_store;
/* 版本比较结果 */
typedef enum {
VERSION_OLDER = -1, /* 版本较旧 */
VERSION_EQUAL = 0, /* 版本相同 */
VERSION_NEWER = 1 /* 版本较新 */
} version_compare_t;
/* 初始化版本存储区 */
void version_init(void)
{
memset(&version_store, 0, sizeof(version_store));
version_store.magic = VERSION_MAGIC;
version_store.major = 1;
version_store.minor = 0;
version_store.patch = 0;
version_store.build = 1;
}
/* 设置版本号 */
void version_set(uint8_t major, uint8_t minor, uint8_t patch, uint8_t build)
{
version_store.magic = VERSION_MAGIC;
version_store.major = major;
version_store.minor = minor;
version_store.patch = patch;
version_store.build = build;
}
/* 读取版本号到输出参数 */
int version_get(uint8_t *major, uint8_t *minor, uint8_t *patch, uint8_t *build)
{
if (version_store.magic != VERSION_MAGIC) {
return -1; /* 版本区未初始化或数据损坏 */
}
if (major) *major = version_store.major;
if (minor) *minor = version_store.minor;
if (patch) *patch = version_store.patch;
if (build) *build = version_store.build;
return 0;
}
/* 比较两个版本号 */
version_compare_t version_compare(const firmware_version_t *v1,
const firmware_version_t *v2)
{
if (v1->major != v2->major)
return (v1->major > v2->major) ? VERSION_NEWER : VERSION_OLDER;
if (v1->minor != v2->minor)
return (v1->minor > v2->minor) ? VERSION_NEWER : VERSION_OLDER;
if (v1->patch != v2->patch)
return (v1->patch > v2->patch) ? VERSION_NEWER : VERSION_OLDER;
if (v1->build != v2->build)
return (v1->build > v2->build) ? VERSION_NEWER : VERSION_OLDER;
return VERSION_EQUAL;
}
/* 将版本号格式化为字符串 */
void version_to_string(char *buf, size_t buf_size)
{
if (!buf || buf_size == 0) return;
snprintf(buf, buf_size, "%u.%u.%u.%u",
version_store.major, version_store.minor,
version_store.patch, version_store.build);
}
/* 测试入口 */
int main(void)
{
char ver_str[VERSION_STR_MAX_LEN];
firmware_version_t new_ver;
uint8_t maj, min, pat, bld;
/* 初始化并读取当前版本 */
version_init();
version_get(&maj, &min, &pat, &bld);
version_to_string(ver_str, sizeof(ver_str));
printf("当前固件版本: %s\n", ver_str);
/* 模拟OTA下载的新版本 */
new_ver.magic = VERSION_MAGIC;
new_ver.major = 1;
new_ver.minor = 1;
new_ver.patch = 0;
new_ver.build = 2;
/* 比较当前版本与新版本 */
version_compare_t result = version_compare(&version_store, &new_ver);
if (result == VERSION_NEWER) {
printf("新版本可用,需要升级\n");
} else if (result == VERSION_EQUAL) {
printf("版本相同,无需升级\n");
} else {
printf("新版本更旧,拒绝降级\n");
}
/* 更新版本号 */
version_set(new_ver.major, new_ver.minor, new_ver.patch, new_ver.build);
version_to_string(ver_str, sizeof(ver_str));
printf("升级后版本: %s\n", ver_str);
return 0;
}
编译与运行
gcc -o version_demo version_demo.c
./version_demo
验证方法
程序执行后应依次输出:
- 当前固件版本为
1.0.0.1,表明版本初始化与读取正常; - 比较结果提示“新版本可用,需要升级”,说明版本比较逻辑正确识别了更高版本;
- 升级后版本显示为
1.1.0.2,验证版本写入接口生效。
若将new_ver的版本号改为低于当前版本(如0.9.0.0),程序应输出“新版本更旧,拒绝降级”,可用于测试降级防护逻辑。
关键说明
本实现使用内存变量模拟Flash存储区,实际OTA工程中应将version_store映射到专用Flash扇区,并增加写入前的擦除操作和写入后的回读校验。版本比较接口采用逐字段比较方式,避免将版本号拼接为整数后比较可能出现的溢出问题。magic字段用于检测存储区数据是否有效,防止读取到未初始化或损坏的版本数据。