This commit is contained in:
tang1219
2026-06-12 17:03:10 +08:00
parent e488cd3216
commit 9eaffcc9ff
31 changed files with 6829 additions and 0 deletions
+209
View File
@@ -0,0 +1,209 @@
/**
* @file ota_manager.h
* @brief 固件 OTAOver-The-Air)底层管理器
*
* 提供与传输层无关的固件更新基础设施。
* 上层(USB / 串口 / 蓝牙 / SD 卡 / HTTP)只需:
* 1. 调用 ota_begin(total_size) 开始更新
* 2. 循环调用 ota_write(chunk, len) 写入固件数据
* 3. 调用 ota_end() 完成更新(验证 + 切换启动分区)
* 4. 异常时调用 ota_abort() 放弃更新
*
* 回调机制:
* 注册回调后,在 OTA 各阶段自动触发,用于 UI 更新 / 日志 / 错误处理。
*
* 框架: ESP-IDF 5.1.x
* 依赖: hw_led_set()(状态 LED 反馈)
*/
#ifndef OTA_MANAGER_H
#define OTA_MANAGER_H
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "esp_err.h"
#include "esp_partition.h"
#ifdef __cplusplus
extern "C" {
#endif
/* ================================================================
* 类型定义
* ================================================================ */
/** OTA 状态机 */
typedef enum {
OTA_STATE_IDLE, /**< 空闲,等待开始 */
OTA_STATE_IN_PROGRESS, /**< 固件写入中 */
OTA_STATE_VERIFYING, /**< 固件校验中(end 阶段) */
OTA_STATE_COMPLETE, /**< 更新成功,准备重启 */
OTA_STATE_ERROR, /**< 发生错误,需 abort 或重试 */
} ota_state_t;
/** OTA 错误码(扩展 esp_err_t,负值为 ESP-IDF 错误,正值为自定义错误) */
typedef enum {
OTA_ERR_NONE = 0, /**< 无错误 */
OTA_ERR_NOT_INITIALIZED = 1, /**< 未调用 begin */
OTA_ERR_ALREADY_IN_PROGRESS = 2, /**< 已有进行中的 OTA */
OTA_ERR_BEGIN_FAILED = 3, /**< begin 阶段失败 */
OTA_ERR_WRITE_FAILED = 4, /**< 写入 flash 失败 */
OTA_ERR_END_FAILED = 5, /**< end 阶段失败 */
OTA_ERR_ABORT_FAILED = 6, /**< abort 失败 */
OTA_ERR_SIZE_MISMATCH = 7, /**< 写入长度与声明的 total 不符 */
OTA_ERR_NO_OTA_PARTITION = 8, /**< 无可用 OTA 分区 */
OTA_ERR_STATE_ERROR = 9, /**< 当前状态不允许该操作 */
OTA_ERR_VERIFY_FAILED = 10, /**< 固件校验失败 */
} ota_error_t;
/* ================================================================
* 回调函数类型
* ================================================================ */
/**
* @brief 进度回调
* @param percent 完成百分比 (0100)
* @param bytes_written 已写入字节数
* @param total_size 固件总字节数
*
* 调用频率: 每完成一个 ota_write() 调用后触发一次(约 1–4KB 一次)。
* 上层可在此回调中更新进度条或打印日志。
*/
typedef void (*ota_progress_cb_t)(int percent, size_t bytes_written, size_t total_size);
/**
* @brief 完成回调
* @param success true=更新成功, false=更新失败
* @param error_code 失败时的错误码(success 为 true 时无效)
*
* 调用时机: ota_end() 处理完毕后触发。
* 若 success=true,设备应在适当时机重启以加载新固件。
*/
typedef void (*ota_complete_cb_t)(bool success, ota_error_t error_code);
/**
* @brief 状态变化回调
* @param old_state 变化前的状态
* @param new_state 变化后的状态
*
* 每次 OTA 状态机发生转换时触发。
* 上层可在 OTA_STATE_COMPLETE 时自动重启,或在 OTA_STATE_ERROR 时告警。
*/
typedef void (*ota_state_cb_t)(ota_state_t old_state, ota_state_t new_state);
/**
* @brief 错误回调(颗粒度更细)
* @param error_code 错误码
* @param message 可读错误描述
*
* 在 ota_write 失败、end 失败等场景触发,先于状态变化回调。
* 可用于日志记录、错误提示等。
*/
typedef void (*ota_error_cb_t)(ota_error_t error_code, const char *message);
/* ================================================================
* 回调注册
* ================================================================ */
/** 注册进度回调(最多一个,后注册的覆盖前面的) */
void ota_set_progress_callback(ota_progress_cb_t cb);
/** 注册完成回调 */
void ota_set_complete_callback(ota_complete_cb_t cb);
/** 注册状态变化回调 */
void ota_set_state_callback(ota_state_cb_t cb);
/** 注册错误回调 */
void ota_set_error_callback(ota_error_cb_t cb);
/** 一次性注销所有回调 */
void ota_clear_callbacks(void);
/* ================================================================
* 底层 OTA API
*
* 调用顺序:
* 正常流程: ota_begin() → ota_write()×N → ota_end() → 重启设备
* 错误处理: ota_begin() → ota_write()×N → ota_abort()
* ================================================================ */
/**
* @brief 开始 OTA 更新
*
* 内部自动选择下一个可用的 OTA 分区,擦除分区空间。
*
* @param firmware_size 固件总大小(字节)。
* 传入 0 表示大小未知:跳过长度校验,progress 百分比始终为 0。
* @return
* - ESP_OK: 开始成功,可调用 ota_write
* - OTA_ERR_ALREADY_IN_PROGRESS: 上次 OTA 未结束
* - OTA_ERR_NO_OTA_PARTITION: 分区表无可用 OTA 分区
* - OTA_ERR_BEGIN_FAILED: ESP-IDF OTA begin 失败
*/
esp_err_t ota_begin(size_t firmware_size);
/**
* @brief 写入固件数据块
*
* 阻塞调用,写入 flash 前先进行必要的擦除。
* 建议每次写入 1024–4096 字节以获得最佳吞吐量。
*
* @param data 数据指针
* @param len 数据长度(字节)
* @return
* - ESP_OK: 写入成功
* - OTA_ERR_NOT_INITIALIZED: 未调用 ota_begin
* - OTA_ERR_STATE_ERROR: 当前状态不允许写入
* - OTA_ERR_WRITE_FAILED: 写入 flash 失败
*/
esp_err_t ota_write(const uint8_t *data, size_t len);
/**
* @brief 完成 OTA 更新
*
* 校验已写入数据的完整性,验证固件镜像,切换启动分区。
* 成功返回后,设备应在适当时机调用 esp_restart() 重启。
*
* @return
* - ESP_OK: 更新完成,可重启
* - OTA_ERR_END_FAILED: 校验或切换失败
* - OTA_ERR_SIZE_MISMATCH: 实写大小与声明不符
*/
esp_err_t ota_end(void);
/**
* @brief 中止 OTA 更新
*
* 放弃当前写入的固件,恢复状态机到 IDLE。
* 调用后目标 OTA 分区数据不可靠,下次 begin 会重新擦除。
*
* @return ESP_OK 或错误码
*/
esp_err_t ota_abort(void);
/* ================================================================
* 状态查询
* ================================================================ */
/** 获取当前 OTA 状态 */
ota_state_t ota_get_state(void);
/** 获取当前运行的固件分区(const 指针,不可修改) */
const esp_partition_t *ota_get_running_partition(void);
/** 获取正在更新的目标分区(仅在 IN_PROGRESS 或 VERIFYING 时有效) */
const esp_partition_t *ota_get_update_partition(void);
/** 获取已写入字节数 */
size_t ota_get_bytes_written(void);
/** 获取声明的固件总大小 */
size_t ota_get_firmware_size(void);
#ifdef __cplusplus
}
#endif
#endif /* OTA_MANAGER_H */