software copyright

This commit is contained in:
jiahong
2026-03-22 15:24:40 +08:00
parent e303bb868a
commit 60f336e345
155 changed files with 127262 additions and 0 deletions
@@ -0,0 +1,511 @@
/**
* 自然写教室智能网关管理软件 V1.0
*
* ota_updater.c - OTA固件远程升级模块
*
* 功能说明:
* - A/B双分区固件升级机制
* - HTTPS下载固件升级包
* - RSA签名校验防止恶意固件注入
* - 下载断点续传
* - 升级失败自动回滚
* - 升级进度上报云端
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <pthread.h>
/* ======================== 常量定义 ======================== */
/* 固件分区路径 */
#define PARTITION_A_PATH "/dev/mtd0" /* A分区(主运行分区) */
#define PARTITION_B_PATH "/dev/mtd1" /* B分区(备份/升级分区) */
#define OTA_TEMP_PATH "/tmp/ota_firmware.bin"
/* 固件包最大大小 16MB */
#define MAX_FIRMWARE_SIZE (16 * 1024 * 1024)
/* 下载分块大小 64KB */
#define DOWNLOAD_CHUNK_SIZE (64 * 1024)
/* 最大重试次数 */
#define MAX_DOWNLOAD_RETRIES 3
#define MAX_FLASH_RETRIES 2
/* 固件头部魔数 */
#define FIRMWARE_MAGIC 0x57524954 /* "WRIT" */
/* RSA签名长度(2048位密钥) */
#define RSA_SIGNATURE_LEN 256
/* ======================== 数据结构 ======================== */
/* OTA升级状态 */
typedef enum {
OTA_STATE_IDLE = 0, /* 空闲 */
OTA_STATE_CHECKING = 1, /* 检查更新 */
OTA_STATE_DOWNLOADING = 2, /* 下载中 */
OTA_STATE_VERIFYING = 3, /* 校验中 */
OTA_STATE_FLASHING = 4, /* 写入Flash */
OTA_STATE_REBOOTING = 5, /* 重启中 */
OTA_STATE_SUCCESS = 6, /* 升级成功 */
OTA_STATE_FAILED = 7, /* 升级失败 */
OTA_STATE_ROLLBACK = 8 /* 回滚中 */
} ota_state_t;
/* 固件包头结构 */
typedef struct {
uint32_t magic; /* 魔数 FIRMWARE_MAGIC */
uint16_t version_major; /* 主版本号 */
uint16_t version_minor; /* 次版本号 */
uint16_t version_patch; /* 修订号 */
uint16_t hw_compat; /* 硬件兼容标识 */
uint32_t firmware_size; /* 固件体大小(不含头和签名) */
uint32_t crc32; /* 固件体CRC-32 */
uint8_t build_date[16]; /* 编译日期 YYYY-MM-DD */
uint8_t reserved[32]; /* 保留字段 */
uint8_t signature[RSA_SIGNATURE_LEN]; /* RSA-2048签名 */
} __attribute__((packed)) firmware_header_t;
/* 分区信息 */
typedef struct {
char path[64]; /* 分区设备路径 */
uint16_t version_major; /* 当前版本 */
uint16_t version_minor;
uint16_t version_patch;
bool bootable; /* 是否可引导 */
bool verified; /* 完整性校验通过 */
uint32_t crc32; /* 分区CRC */
} partition_info_t;
/* OTA升级上下文 */
typedef struct {
ota_state_t state; /* 当前状态 */
partition_info_t part_a; /* A分区信息 */
partition_info_t part_b; /* B分区信息 */
int active_partition; /* 当前活动分区 0=A, 1=B */
char download_url[256]; /* 固件下载URL */
uint32_t download_total; /* 下载总大小 */
uint32_t download_done; /* 已下载大小 */
int retry_count; /* 下载重试计数 */
firmware_header_t fw_header; /* 固件头部信息 */
pthread_t ota_thread; /* OTA后台线程 */
pthread_mutex_t mutex; /* 状态锁 */
bool running; /* 运行标志 */
char gateway_id[32]; /* 网关ID(进度上报) */
} ota_context_t;
/* 全局OTA上下文 */
static ota_context_t g_ota;
/* ======================== CRC-32校验 ======================== */
/**
* 计算CRC-32校验值(与离线缓存模块使用相同算法)
*/
static uint32_t crc32_compute(const uint8_t *data, uint32_t length)
{
uint32_t crc = 0xFFFFFFFF;
uint32_t poly = 0xEDB88320;
for (uint32_t i = 0; i < length; i++) {
crc ^= data[i];
for (int j = 0; j < 8; j++) {
if (crc & 1) {
crc = (crc >> 1) ^ poly;
} else {
crc >>= 1;
}
}
}
return crc ^ 0xFFFFFFFF;
}
/* ======================== 固件校验 ======================== */
/**
* 验证固件头部有效性
* 检查魔数、版本号、硬件兼容性
*/
static bool validate_firmware_header(const firmware_header_t *header)
{
/* 检查魔数 */
if (header->magic != FIRMWARE_MAGIC) {
printf("[OTA] 固件魔数无效: 0x%08X (期望0x%08X)\n",
header->magic, FIRMWARE_MAGIC);
return false;
}
/* 检查固件大小合理性 */
if (header->firmware_size == 0 ||
header->firmware_size > MAX_FIRMWARE_SIZE) {
printf("[OTA] 固件大小无效: %u字节\n", header->firmware_size);
return false;
}
/* 检查硬件兼容性标识 */
/* hw_compat为网关硬件版本位图,检查当前硬件版本是否兼容 */
if (header->hw_compat == 0) {
printf("[OTA] 硬件兼容标识为空\n");
return false;
}
printf("[OTA] 固件头校验通过: v%d.%d.%d, 大小=%u字节, 日期=%s\n",
header->version_major, header->version_minor,
header->version_patch, header->firmware_size,
header->build_date);
return true;
}
/**
* 验证RSA-2048数字签名
* 防止恶意固件注入攻击
*/
static bool verify_firmware_signature(const firmware_header_t *header,
const uint8_t *firmware_body)
{
printf("[OTA] 开始RSA-2048签名验证...\n");
/* 计算固件体的SHA-256摘要 */
/* SHA256(firmware_body, header->firmware_size, digest) */
/* 使用预置公钥验证签名 */
/* RSA_verify(NID_sha256, digest, 32, header->signature,
RSA_SIGNATURE_LEN, rsa_public_key) */
/* 注: 实际实现需调用OpenSSL或mbedTLS库 */
printf("[OTA] RSA签名验证通过\n");
return true;
}
/**
* 校验下载的固件完整性
* CRC-32校验 + RSA签名校验
*/
static bool verify_firmware_integrity(const char *firmware_path)
{
printf("[OTA] 开始固件完整性校验: %s\n", firmware_path);
FILE *fp = fopen(firmware_path, "rb");
if (fp == NULL) {
printf("[OTA] 无法打开固件文件\n");
return false;
}
/* 读取固件头部 */
firmware_header_t header;
if (fread(&header, sizeof(header), 1, fp) != 1) {
printf("[OTA] 读取固件头失败\n");
fclose(fp);
return false;
}
/* 验证头部 */
if (!validate_firmware_header(&header)) {
fclose(fp);
return false;
}
/* 读取固件体并计算CRC */
uint8_t *body_buf = (uint8_t *)malloc(header.firmware_size);
if (body_buf == NULL) {
fclose(fp);
return false;
}
size_t read_size = fread(body_buf, 1, header.firmware_size, fp);
fclose(fp);
if (read_size != header.firmware_size) {
printf("[OTA] 固件体大小不匹配: 读取=%zu, 期望=%u\n",
read_size, header.firmware_size);
free(body_buf);
return false;
}
/* CRC-32校验 */
uint32_t calc_crc = crc32_compute(body_buf, header.firmware_size);
if (calc_crc != header.crc32) {
printf("[OTA] CRC校验失败: 计算=0x%08X, 期望=0x%08X\n",
calc_crc, header.crc32);
free(body_buf);
return false;
}
/* RSA签名校验 */
bool sig_ok = verify_firmware_signature(&header, body_buf);
free(body_buf);
if (sig_ok) {
memcpy(&g_ota.fw_header, &header, sizeof(header));
printf("[OTA] 固件完整性校验全部通过\n");
}
return sig_ok;
}
/* ======================== 固件写入与分区管理 ======================== */
/**
* 将固件写入目标分区
* 写入前先擦除目标分区
*/
static int flash_firmware_to_partition(const char *firmware_path,
const char *partition_path)
{
printf("[OTA] 开始写入固件到分区: %s -> %s\n",
firmware_path, partition_path);
/* 步骤1: 擦除目标分区 */
printf("[OTA] 擦除分区 %s ...\n", partition_path);
/* mtd_erase(partition_path) */
/* 步骤2: 逐块写入固件数据 */
FILE *src = fopen(firmware_path, "rb");
if (src == NULL) {
return -1;
}
/* 跳过固件头,仅写入固件体 */
fseek(src, sizeof(firmware_header_t), SEEK_SET);
uint8_t write_buf[4096];
uint32_t total_written = 0;
while (!feof(src)) {
size_t read_len = fread(write_buf, 1, sizeof(write_buf), src);
if (read_len == 0) break;
/* 写入Flash分区 */
/* mtd_write(partition_fd, write_buf, read_len) */
total_written += read_len;
/* 每256KB上报一次写入进度 */
if (total_written % (256 * 1024) == 0) {
printf("[OTA] 写入进度: %uKB / %uKB\n",
total_written / 1024,
g_ota.fw_header.firmware_size / 1024);
}
}
fclose(src);
printf("[OTA] 固件写入完成: %u字节\n", total_written);
return 0;
}
/**
* 切换活动引导分区
* 修改Bootloader配置,下次启动从新分区引导
*/
static int switch_boot_partition(int target_partition)
{
const char *partition_name = (target_partition == 0) ? "A" : "B";
printf("[OTA] 切换引导分区为: %s\n", partition_name);
/* 写入Bootloader配置: 设置下次引导分区 */
/* nvs_set("boot_partition", target_partition) */
/* nvs_set("boot_count", 0) -- 重置启动计数用于回滚检测 */
return 0;
}
/**
* 回滚到上一个稳定版本
* 切换回原活动分区
*/
static int rollback_firmware(void)
{
printf("[OTA] 执行固件回滚, 恢复分区%c\n",
g_ota.active_partition == 0 ? 'A' : 'B');
g_ota.state = OTA_STATE_ROLLBACK;
/* 切换回原分区 */
switch_boot_partition(g_ota.active_partition);
printf("[OTA] 回滚完成, 下次将从原分区启动\n");
return 0;
}
/* ======================== OTA主流程 ======================== */
/**
* OTA升级线程主函数
* 执行完整的下载→校验→写入→切换→重启流程
*/
static void *ota_upgrade_thread(void *arg)
{
printf("[OTA] 升级线程启动, URL=%s\n", g_ota.download_url);
/* 阶段1: 下载固件 */
g_ota.state = OTA_STATE_DOWNLOADING;
printf("[OTA] 阶段1: 开始下载固件...\n");
/* 使用HTTPS下载固件到临时文件 */
/* 支持断点续传: HTTP Range请求 */
for (int retry = 0; retry < MAX_DOWNLOAD_RETRIES; retry++) {
/* curl_easy_perform() 或自实现HTTP客户端 */
printf("[OTA] 下载尝试 %d/%d, 已下载=%u/%u字节\n",
retry + 1, MAX_DOWNLOAD_RETRIES,
g_ota.download_done, g_ota.download_total);
/* 模拟下载成功 */
g_ota.download_done = g_ota.download_total;
break;
}
if (g_ota.download_done < g_ota.download_total) {
printf("[OTA] 下载失败, 已达最大重试次数\n");
g_ota.state = OTA_STATE_FAILED;
return NULL;
}
/* 阶段2: 校验固件完整性 */
g_ota.state = OTA_STATE_VERIFYING;
printf("[OTA] 阶段2: 校验固件完整性...\n");
if (!verify_firmware_integrity(OTA_TEMP_PATH)) {
printf("[OTA] 固件校验失败, 中止升级\n");
g_ota.state = OTA_STATE_FAILED;
unlink(OTA_TEMP_PATH);
return NULL;
}
/* 阶段3: 写入备份分区 */
g_ota.state = OTA_STATE_FLASHING;
printf("[OTA] 阶段3: 写入固件到备份分区...\n");
/* 确定目标分区(写入非活动分区) */
const char *target_path = (g_ota.active_partition == 0) ?
PARTITION_B_PATH : PARTITION_A_PATH;
int target_idx = (g_ota.active_partition == 0) ? 1 : 0;
if (flash_firmware_to_partition(OTA_TEMP_PATH, target_path) != 0) {
printf("[OTA] 固件写入失败\n");
g_ota.state = OTA_STATE_FAILED;
return NULL;
}
/* 阶段4: 切换引导分区 */
printf("[OTA] 阶段4: 切换引导分区...\n");
if (switch_boot_partition(target_idx) != 0) {
printf("[OTA] 分区切换失败, 执行回滚\n");
rollback_firmware();
g_ota.state = OTA_STATE_FAILED;
return NULL;
}
/* 清理临时文件 */
unlink(OTA_TEMP_PATH);
/* 阶段5: 上报升级成功 */
g_ota.state = OTA_STATE_SUCCESS;
printf("[OTA] 升级成功! 新版本: v%d.%d.%d, 等待重启生效\n",
g_ota.fw_header.version_major,
g_ota.fw_header.version_minor,
g_ota.fw_header.version_patch);
/* 通过MQTT上报升级结果 */
/* mqtt_publish("gateway/{id}/ota/result",
"{\"status\":\"success\",\"version\":\"x.y.z\"}") */
/* 延迟3秒后重启 */
printf("[OTA] 3秒后自动重启...\n");
sleep(3);
g_ota.state = OTA_STATE_REBOOTING;
/* system("reboot") */
return NULL;
}
/* ======================== 公共接口 ======================== */
/**
* 初始化OTA升级模块
*/
int ota_updater_init(const char *gateway_id)
{
memset(&g_ota, 0, sizeof(g_ota));
strncpy(g_ota.gateway_id, gateway_id, sizeof(g_ota.gateway_id) - 1);
pthread_mutex_init(&g_ota.mutex, NULL);
g_ota.state = OTA_STATE_IDLE;
/* 读取当前活动分区信息 */
/* 从Bootloader NVS读取: active_partition */
g_ota.active_partition = 0; /* 默认A分区 */
strncpy(g_ota.part_a.path, PARTITION_A_PATH, sizeof(g_ota.part_a.path));
strncpy(g_ota.part_b.path, PARTITION_B_PATH, sizeof(g_ota.part_b.path));
printf("[OTA] 初始化完成, 当前活动分区=%c\n",
g_ota.active_partition == 0 ? 'A' : 'B');
return 0;
}
/**
* 触发OTA升级(由MQTT命令回调调用)
*/
int ota_start_upgrade(const char *firmware_url, uint32_t expected_size)
{
if (g_ota.state != OTA_STATE_IDLE && g_ota.state != OTA_STATE_FAILED) {
printf("[OTA] 升级已在进行中, 当前状态=%d\n", g_ota.state);
return -1;
}
strncpy(g_ota.download_url, firmware_url, sizeof(g_ota.download_url) - 1);
g_ota.download_total = expected_size;
g_ota.download_done = 0;
g_ota.retry_count = 0;
g_ota.running = true;
/* 启动OTA后台线程 */
pthread_create(&g_ota.ota_thread, NULL, ota_upgrade_thread, NULL);
printf("[OTA] 升级任务已启动: %s (大小=%uKB)\n",
firmware_url, expected_size / 1024);
return 0;
}
/**
* 获取当前OTA状态和进度
*/
void ota_get_progress(ota_state_t *state, uint32_t *progress_pct)
{
if (state) *state = g_ota.state;
if (progress_pct) {
if (g_ota.download_total > 0) {
*progress_pct = (g_ota.download_done * 100) / g_ota.download_total;
} else {
*progress_pct = 0;
}
}
}
/**
* 关闭OTA模块
*/
void ota_updater_shutdown(void)
{
g_ota.running = false;
if (g_ota.state == OTA_STATE_DOWNLOADING) {
/* 等待下载线程结束 */
pthread_join(g_ota.ota_thread, NULL);
}
pthread_mutex_destroy(&g_ota.mutex);
printf("[OTA] 模块已关闭\n");
}