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字段用于检测存储区数据是否有效,防止读取到未初始化或损坏的版本数据。