当前位置: 首页 > news >正文

ESP32的OTA升级详解:2. OTA低层组件app_update介绍

一、app_update,esp_https_ota组件关系和区别

在ESP-IDF 框架中,app_update 和 esp_https_ota 都是与固件更新相关的组件。

1. app_update:底层分区操作和固件切换 API

  • 定位: 这是 最底层、最核心 的 OTA 功能库。

  • 功能:

    • 提供 API 来写入数据到特定的 OTA 应用分区 (esp_ota_write)。
    • 提供 API 来设置下次启动时使用的引导分区 (esp_ota_set_boot_partition)。
    • 提供 API 来获取当前运行的分区信息 (esp_ota_get_running_partition, esp_ota_get_next_update_partition)。
    • 管理 OTA 分区表(查找分区、获取分区信息)。
    • 处理固件校验。
  • 作用: 它是 OTA 更新的基础引擎。无论通过HTTP, HTTPS或自定义协议方式获取到新的固件二进制数据,最终都需要调用 app_update 提供的 API 将这些数据写入到 Flash 的 OTA 分区,并在验证后设置引导分区。

  • 使用场景: 当需要实现自定义的 OTA 传输协议时,例如通过 MQTT、CoAP、私有 TCP/UDP 协议、串口、蓝牙传输固件时,需要在代码中调用 app_update 的 API 来完成最终的固件写入和启动切换。

2. esp_https_ota:基于 HTTPS 的完整 OTA 更新客户端

  • 定位: 这是一个高级别、封装好的 OTA 客户端组件,专门用于通过 HTTPS 协议从远程服务器下载和安装固件更新。
  • 功能:
    • 建立到指定 HTTPS URL 的安全 TLS 连接。
    • 执行 HTTP GET 请求 下载固件。
    • 处理 HTTP 响应状态码、Headers。
    • 分块接收固件数据。
    • 调用 app_update 的 API 将下载到的数据块写入正确的 OTA 分区。
    • 在下载和写入完成后,自动设置新的引导分区。
    • 提供基本的错误处理和状态回调。
  • 优化: 隐藏了 HTTPS 协议处理、网络通信、数据分块接收以及底层 app_update API 调用的所有复杂性。只需要提供一个 HTTPS URL 和必要的配置如证书,调用简单函数就能完成整个 OTA 更新流程。
  • 依赖: 它内部依赖 app_update 组件来完成实际的 Flash 写入操作。esp_https_ota 是构建在 app_update 基础之上的一个应用层组件。
  • 使用场景: 需要从HTTPS 的 Web 服务器进行 OTA 更新时,这是最简单、最推荐的方式。只需几行代码即可实现安全可靠的 OTA。
特性app_updateesp_https_ota
层级底层核心 (操作分区/Flash)高层应用 (完整 HTTPS OTA 客户端)
主要职责写分区、设引导区、管理分区信息通过 HTTPS 下载固件并安装
网络通信完全不处理处理 HTTPS 协议栈 (依赖 esp_http_client, esp_tls)
TLS/SSL 安全不涉及核心功能,处理证书验证等
调用 appupdate提供API给别人调用内部调用 appupdate API 来写 Flash
固件来源无限制仅限于 HTTPS URL
复杂度低 (只做 Flash 操作)高 (封装了网络、协议、安全、Flash 操作)
使用场景实现自定义传输协议的 OTA实现标准 HTTPS 服务器的 OTA
开发者工作需实现所有网络传输、协议解析逻辑只需配置 URL/证书,调用 perform 函数

3. 总结

  • app_update 是“写 Flash 和切分区”的工具箱。
  • esp_https_ota 是一个“从 HTTPS 网址下载更新包并用 app_update 工具箱安装好”的自动化程序。

二、app_update的API解释用法

1. 获取应用描述信息

const esp_app_desc_t *esp_ota_get_app_description(void);
  • 作用:返回当前运行应用的描述信息(如版本号、项目名称等)。
  • 状态:已弃用,建议使用 esp_app_get_description。

2. 获取应用 ELF 文件的 SHA256 值

int esp_ota_get_app_elf_sha256(char* dst, size_t size);
  • 作用:将当前运行应用的 ELF 文件的 SHA256 值(十六进制字符串)写入缓冲区。
  • 状态:已弃用,建议使用 esp_app_get_elf_sha256。

3. 开始 OTA 更新会话

esp_err_t esp_ota_begin(const esp_partition_t* partition, size_t image_size, esp_ota_handle_t* out_handle);
  • 作用:初始化 OTA 更新,擦除目标分区并返回操作句柄。
  • 参数:
    • partition:目标 OTA 分区。
    • image_size:新固件大小(未知时用 OTA_SIZE_UNKNOWN)。
    • out_handle:输出句柄,用于后续写入操作。
  • 返回值:状态码(如 ESP_OK 表示成功)。

4. 持续的写入 OTA 数据

esp_err_t esp_ota_write(esp_ota_handle_t handle, const void* data, size_t size);
  • 作用:将数据顺序写入 OTA 分区,在esp_ota_begin擦除之后调用,写入位置指针会自动增加。
  • 参数:
    • handle:esp_ota_begin 返回的句柄。
    • data:待写入数据的缓冲区。
    • size:数据大小。

5. 偏移量写入 OTA 数据

esp_err_t esp_ota_write_with_offset(esp_ota_handle_t handle, const void *data, size_t size, uint32_t offset);
  • 作用:将数据写入分区的指定偏移位置,支持非连续写入。
  • 参数:
    • offset:分区内的写入偏移量。
    • 适用场景:数据包乱序到达时使用。

6. 结束 OTA 更新并验证

esp_err_t esp_ota_end(esp_ota_handle_t handle);
  • 作用:结束 OTA 会话,验证固件有效性,并释放资源。
  • 注意:无论成功与否,句柄在此后均无效。

7. 中止 OTA 更新

esp_err_t esp_ota_abort(esp_ota_handle_t handle);
  • 作用:中止 OTA 更新,释放句柄及相关资源。
  • 适用场景:更新过程中发生错误需取消时。

8. 设置启动分区

esp_err_t esp_ota_set_boot_partition(const esp_partition_t* partition);
  • 作用:设置下次启动时使用的分区,可以设置新固件所在分区。
  • 注意:成功后需重启 (esp_restart) 生效。

9. 获取当前配置的启动分区

const esp_partition_t* esp_ota_get_boot_partition(void);
  • 作用:返回当前配置的启动分区,不一定是当前运行的分区。
  • 注意:可能与 esp_ota_get_running_partition 结果不同(如回滚时)。

10. 获取当前运行分区

const esp_partition_t* esp_ota_get_running_partition(void);
  • 作用:返回当前正在运行的应用所在的分区。

11. 获取下一个更新分区

const esp_partition_t* esp_ota_get_next_update_partition(const esp_partition_t *start_from);
  • 作用:返回下一个可用于 OTA 更新的分区(轮询逻辑)。
  • 参数:start_from 指定起点分区(通常为当前运行分区)。
  • start_from: 查找的起始分区指针。如果为 NULL,则从第一个 OTA 分区开始查找。

假设有 4 个 OTA 分区:ota0, ota1, ota2, ota3,当前运行在 ota2 分区:

  1. 如果传入 start_from 为 NULL:
    - 从 ota0 开始查找
    - ota0 不是当前运行分区 → 返回 ota0
  2. 如果传入 start_from 为 ota2 分区指针:
    - 从 ota2 开始查找下一个
    - ota3 不是当前运行分区 → 返回 ota3
  3. 如果传入 start_from 为 ota3 分区指针:
    - 从 ota3 开始查找下一个
    - 循环回到 ota0
    - ota0 不是当前运行分区 → 返回 ota0
  • 例子:
// 获取下一个可用的OTA分区
const esp_partition_t *update_partition = esp_ota_get_next_update_partition(NULL);
if (update_partition == NULL) {ESP_LOGE(TAG, "No valid OTA partition found");return ESP_FAIL;
}// 开始OTA更新
esp_ota_handle_t update_handle;
esp_err_t err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle);
if (err != ESP_OK) {ESP_LOGE(TAG, "OTA begin failed");return err;
}

12. 获取分区描述信息

esp_err_t esp_ota_get_partition_description(const esp_partition_t *partition, esp_app_desc_t *app_desc);
  • 作用:读取指定分区的应用描述信息(版本号等)。
  • 参数:partition 必须是应用分区。

13. 获取引导加载程序 (Bootloader) 描述

esp_err_t esp_ota_get_bootloader_description(const esp_partition_t *bootloader_partition, esp_bootloader_desc_t *desc);
  • 作用:读取 Bootloader 的描述信息。
  • 参数:bootloader_partition 可为 NULL(使用默认位置)。

14. 获取 OTA 分区数量

uint8_t esp_ota_get_app_partition_count(void);
  • 作用:返回分区表中 OTA 应用分区的总数。

15. 标记应用为有效

esp_err_t esp_ota_mark_app_valid_cancel_rollback(void);
  • 作用:确认当前应用运行正常,取消回滚标记。
  • 调用时机:启动后首次验证应用正常时调用。

16. 回滚到之前版本并重启

esp_err_t esp_ota_mark_app_invalid_rollback_and_reboot(void);
  • 作用:将当前应用标记为无效,回滚到之前版本并重启。
  • 条件:需存在有效的回滚分区。
  • 流程:
    1. 该函数会将当前运行的应用程序标记为无效
    2. 触发系统重启
    3. 引导加载程序(bootloader)会选择上一个已知良好的OTA分区启动
    4. 如果所有OTA分区都无效,才会回退到factory分区
上一个OTA分区有效
所有OTA分区无效
调用函数
标记当前APP为无效
重启设备
引导加载程序检查
启动上一个OTA分区
启动factory分区

17. 获取最后一个无效分区

const esp_partition_t* esp_ota_get_last_invalid_partition(void);
  • 作用:返回状态为 INVALID 或 ABORTED 的最后一个分区。

18. 获取分区状态

esp_err_t esp_ota_get_state_partition(const esp_partition_t *partition, esp_ota_img_states_t *ota_state);
  • 作用:查询指定分区的 OTA 状态(如 PENDING_VERIFY、VALID 等)。

19. 擦除上一次启动的分区

esp_err_t esp_ota_erase_last_boot_app_partition(void);
  • 作用:擦除上一次启动的应用分区及关联的 OTA 数据。
  • 条件:当前应用必须已被标记为 VALID。

20. 检查回滚可能性

bool esp_ota_check_rollback_is_possible(void);
  • 作用:检查是否存在有效的回滚分区(除当前运行分区外)。
  • 返回值:true 表示可回滚。

三、回滚到factory分区

  • 下列场景时:
    • 新固件启动后检测到严重错误时
    • 安全验证失败时(如签名验证)
    • 需要紧急回退到稳定版本时
  • 使用 esp_ota_set_boot_partition() 直接指定factory分区,或者调用 esp_ota_mark_app_valid_cancel_rollback() 配合其他方法
// 直接指定factory分区
const esp_partition_t *factory = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
if (factory) {esp_ota_set_boot_partition(factory);esp_restart();
}
http://www.dtcms.com/a/270637.html

相关文章:

  • 增强检索知识库系统1
  • 模型内部进行特征提取时,除了“减法”之外,还有哪些技术
  • 线程池与并发工具:优化多线程执行!
  • [特殊字符]【跨数据库支持】SQL 秒转 ArkTS 实体!HarmonyOS 开发者的数据库适配神器 gotool.top
  • Node.Js是什么?
  • AI+智慧园区 | 事件处置自动化——大模型重构园区治理逻辑
  • 【图像处理基石】如何检测到画面中的ppt并对其进行增强?
  • 洛谷 P1104 生日---排序
  • Android Studio 2024,小白入门喂饭级教程
  • 滑动窗口的初步了解
  • 记录一下:成功部署k8s集群(部分)
  • 【音视频】TS协议介绍
  • 搭建商城系统
  • 【Java】【力扣】3.无重复字符的最长字串
  • Flutter基础(前端教程⑧-数据模型)
  • Elasticsearch RESTful API入门:基础搜索与查询DSL
  • C#项目 在Vue/React前端项目中 使用使用wkeWebBrowser引用并且内部使用iframe网页外链 页面部分白屏
  • 数据管理新范式:基于Docker的私有云存储系统构建指南
  • 十一、K8s细粒度权限管理RBAC
  • 异步进阶:C#的Task.WhenAll——如何开启多个异步任务
  • ReactNative【实战系列教程】我的小红书 6 -- 购物(含商品搜索、商品分类、商品列表)
  • 编写产品需求文档:黄历日历小程序
  • [Leetcode] 预处理 | 多叉树bfs | 格雷编码 | static_cast | 矩阵对角线
  • React面试高频考点解析
  • LeetCode Hot 100 搜索二维矩阵 II
  • langchain从入门到精通(四十一)——基于ReACT架构的Agent智能体设计与实现
  • [附源码+数据库+毕业论]基于Spring Boot+mysql+vue结合内容推荐算法的学生咨询系统
  • RedisCommandExecutionException: ERR unknown command ‘LPOS‘
  • 树莓派5-系统 Debian 12 开启VNC远程访问踩坑记录
  • vue3面试题(个人笔记)