ESP32 OTA升级之https ota详解

ESP32 OTA升级之 https ota详解

1. 前言

本文以 ESP32 官方demo例程 native_ota_example 为例,详细阐述如何采用https实现esp32的ota升级。

  • 第一章节,为本文的前言部分,对文章内容进行大体概述;
  • 第二章节,主要描述了如何在本地将demo例程跑起来,并附带了关于使用demo例程中遇到的相关报错的具体解决措施;
  • 第三章节,主要描述了ESP32的 flash 扇区布局;
  • 第四章节,主要描述了OTA下载的镜像文件的头部数据结构,并对其进行详细分析,镜像文件的头部与OTA息息相关;
  • 第五、六章节,详细描述了OTA升级过程中应用程序的状态切换逻辑以及相关软件版本的使用;

接下来,让我们一起研究ESP32的 OTA 升级是如何实现的吧!相信你一定有所收获!

2. 例程体验

例程目录:esp-idf/examples/system/ota/native_ota_example/
工程地址:https://github.com/espressif/esp-idf/tree/release/v5.1/examples/system/ota/native_ota_example
IDF版本: v5.1

2.1 采用直接跳过ca根证书验证方案

  1. 进入 native_ota_example 工程

  2. 运行 idf.py menuconfig 配置wifi及服务器地址

  3. 配置 wifi
    在这里插入图片描述
    在这里插入图片描述

  4. 配置https服务器地址
    如果没有https服务器,填写http服务器地址也可以,http服务器搭建参考:ESP32 OTA升级之HTTP OTA
    https服务器,大家可以尝试把升级文件往github、gitee上发布也可以啦,免费的https测试服务器对吧
    在这里插入图片描述在这里插入图片描述

  5. 运行 idf.py build 编译工程

  6. 运行 idf.py flash monitor 下载工程并开启监控

  7. 网络连接成功之后https下载时会报错,提示 mbdtls ssl 握手失败,错误码 -0x2700

    I (5888) native_ota_example: Starting OTA example task
    I (5888) native_ota_example: Running partition type 0 subtype 0 (offset 0x00010000)
    E (6808) esp-tls-mbedtls: mbedtls_ssl_handshake returned -0x2700
    I (6808) esp-tls-mbedtls: Failed to verify peer certificate!
    E (6808) esp-tls: Failed to open new connection
    E (6818) transport_base: Failed to open a new connection
    E (6828) HTTP_CLIENT: Connection failed, sock < 0
    E (6828) native_ota_example: Failed to open HTTP connection: ESP_ERR_HTTP_CONNECT
    E (6838) native_ota_example: Exiting task due to fatal error...
    

    在这里插入图片描述

  8. 打开 native_ota_example.c 文件,屏蔽 .cert_pem 配置
    在这里插入图片描述

  9. 运行 idf.py build 编译工程,之后运行 idf.py flash monitor 开启监控

  10. 网络连接成功之后https下载时会报错,提示 mbdtls 服务器验证选项 esp_tls_cfg_t 结构体配置失败

    I (5888) native_ota_example: Starting OTA example task
    I (5888) native_ota_example: Running partition type 0 subtype 0 (offset 0x00010000)
    E (6368) esp-tls-mbedtls: No server verification option set in esp_tls_cfg_t structure. Check esp_tls API reference
    E (6368) esp-tls-mbedtls: Failed to set client configurations, returned [0x8017] (ESP_ERR_MBEDTLS_SSL_SETUP_FAILED)
    E (6378) esp-tls: create_ssl_handle failed
    E (6388) esp-tls: Failed to open new connection
    E (6388) transport_base: Failed to open a new connection
    E (6398) HTTP_CLIENT: Connection failed, sock < 0
    E (6398) native_ota_example: Failed to open HTTP connection: ESP_ERR_HTTP_CONNECT
    E (6408) native_ota_example: Exiting task due to fatal error...
    

    在这里插入图片描述

  11. 修改 menuconfig ,跳过服务器证书验证
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  12. 运行 idf.py build 编译工程,之后运行 idf.py flash monitor 开启监控

  13. 网络连接成功之后https下载成功
    在这里插入图片描述

2.2 采用mbedtls内自带的ca根证书方案

  1. 修改 native_ota_example.c 文件中.cert_pem 配置
   esp_http_client_config_t config = {
       .url = CONFIG_EXAMPLE_FIRMWARE_UPG_URL,
       // .cert_pem = (char *)server_cert_pem_start,
       .crt_bundle_attach = esp_crt_bundle_attach,
       .timeout_ms = CONFIG_EXAMPLE_OTA_RECV_TIMEOUT,
       .keep_alive_enable = true,
   };

在这里插入图片描述

2.3 采用对应服务器的根证书文件

此方案,首先需要下载对应服务器的证书文件才可以,下载服务器的证书可以采用以下方案:

首先使用浏览器打开对应的服务器,之后浏览器的地址栏旁边有一个🔒,点击它
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
按照上述方式,导出对应服务器的证书文件 .pem,之后替换掉工程目录下 server_certs 目录下的ca_cert.pem 文件里面的内容即可

采用此方案有一个需要特别注意的地方是:通过此方案下载的证书为此网站的证书,通常有效期为1年,过了一年之后就无效了!!!

这个时间在我们下载证书的时候其实就可以看到:在这里插入图片描述
因此使用此方案时,需要注意特别处理,推荐两种解决方案:

1)采用升级的手段,定期更新设备端证书文件;

2)使用发证机构(注意选择大品牌的)的根证书文件,通常此类证书的有效期会比较长,我们上一小节中 mbedtls里面的证书其实就是存的一部分发证机构的ca跟证书

参考文档:ESP32空中升级 OTA

3. ESP32 flash分区结构

OTA是基于 Flash 进行的,想要弄清楚 ESP32 的 OTA,首先肯定得了解 ESP32 的 flash 布局结构,关于此部分内容我整理在了另外一篇博客,请查阅:ESP32 分区表(点击跳转),对 ESP32 的 flash 分区布局有所了解的可以直接跳过。

4. 应用程序镜像段结构

应用程序镜像段结构如下,运行命令 esptool.py --chip esp32 image_info build/app.bin

esptool.py v2.3.1
Image version: 1
Entry point: 40080ea4
13 segments

Segment 1: len 0x13ce0 load 0x3f400020 file_offs 0x00000018 SOC_DROM
Segment 2: len 0x00000 load 0x3ff80000 file_offs 0x00013d00 SOC_RTC_DRAM
Segment 3: len 0x00000 load 0x3ff80000 file_offs 0x00013d08 SOC_RTC_DRAM
Segment 4: len 0x028e0 load 0x3ffb0000 file_offs 0x00013d10 DRAM
Segment 5: len 0x00000 load 0x3ffb28e0 file_offs 0x000165f8 DRAM
Segment 6: len 0x00400 load 0x40080000 file_offs 0x00016600 SOC_IRAM
Segment 7: len 0x09600 load 0x40080400 file_offs 0x00016a08 SOC_IRAM
Segment 8: len 0x62e4c load 0x400d0018 file_offs 0x00020010 SOC_IROM
Segment 9: len 0x06cec load 0x40089a00 file_offs 0x00082e64 SOC_IROM
Segment 10: len 0x00000 load 0x400c0000 file_offs 0x00089b58 SOC_RTC_IRAM
Segment 11: len 0x00004 load 0x50000000 file_offs 0x00089b60 SOC_RTC_DATA
Segment 12: len 0x00000 load 0x50000004 file_offs 0x00089b6c SOC_RTC_DATA
Segment 13: len 0x00000 load 0x50000004 file_offs 0x00089b74 SOC_RTC_DATA
Checksum: e8 (valid)
Validation Hash: 407089ca0eae2bbf83b4120979d3354b1c938a49cb7a0c997f240474ef2ec76b (valid)

4.1 镜像文件头格式

  1. 镜像在最后一段之后有一个校验和字节(如上述中的 Checksum: e8 (valid) )。此字节写入十六字节填充边界,因此应用程序镜像可能需要填充。
  2. 如果esp_image_header_t 结构体(见下图)的hash_appended字段被设置,则将附加 SHA256 校验和。SHA256 哈希的值是在从第一个字节到该字段的范围内计算的,该字段的长度为 32 个字节。

应用程序映像由以下结构组成:

  1. 首先是 镜像头 esp_image_header_t 结构数据,描述了 SPI 闪存的模式和内存段的数量。
    在这里插入图片描述

  2. 之后是 数据段头 esp_image_segment_header_t 结构数据,此结构数据描述了每个段、其长度及其在 ESP32 内存中的位置,后跟长度为data_len,图像中每个片段的数据偏移量按以下方式计算:

    • 第 0 段的偏移量 = sizeof( esp_image_header_t) + sizeof( esp_image_segment_header_t))。
    • 第 1 Segment 的偏移量 = 0 Segment 的偏移量 + 0 Segment 的长度 + sizeof( esp_image_segment_header_t)。
    • 第 2 Segment 的偏移量 = 1 Segment 的偏移量 + 1 Segment 的长度 + sizeof( esp_image_segment_header_t)。
      在这里插入图片描述
  3. 之后是 应用头 esp_app_desc_t 结构数据:
    在这里插入图片描述

    • 此数据结构位于DORM 段起始位置
    • 当前应用程序可以通过调用esp_app_get_description() 获取应用头结构
    • 其他应用程序可通过调用esp_ota_get_partition_description() 获取其他OTA分区应用头结构
    • 此结构的偏移地址计算为:offset = sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)
  4. 再往后是 用户自定义的应用结构头,如有需要可自行查阅 Adding a Custom Structure to an Application


综上,一个应用程序镜像的头部结构为:

  • 首先是 esp_image_header_t
  • 其次是 esp_image_segment_header_t
  • 之后是 esp_app_desc_t
  • 如果有用户自定义的结构custom_app_desc 则之后是用户自定义结构 custom_app_desc
  • 之后就是实际的程序了

参考文档:App Image Format

5. 应用程序状态切换

应用程序通过一个OTA状态对齐进行维护,通过此状态决定应用程序是否运行。

应用程序可通过调用 esp_err_t esp_ota_get_state_partition(const esp_partition_t *partition, esp_ota_img_states_t *ota_state) 获取对应扇区应用的状态。

应用程序的状态有以下几大类:

状态引导加载程序选取启动应用程序的限制
ESP_OTA_IMG_VALID没有限制,可以选取。
ESP_OTA_IMG_UNDEFINED没有限制,可以选取。
ESP_OTA_IMG_INVALID不会选取。
ESP_OTA_IMG_ABORTED不会选取。
ESP_OTA_IMG_NEW如使能 CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE, 则仅会选取一次。在引导加载程序中,状态立即变为 ESP_OTA_IMG_PENDING_VERIFY
ESP_OTA_IMG_PENDING_VERIFY如使能 CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE, 则不会选取,状态变为ESP_OTA_IMG_ABORTED

关于状态的使用,需要注意一个配置项: CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE

  • CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE 未使能时,应用程序状态通常只会使用 ESP_OTA_IMG_UNDEFINED 这一个状态
    • (官方IDF文档只是说ESP_OTA_IMG_NEWESP_OTA_IMG_PENDING_VERIFY 不会使用,但实测发现基本只会使用 ESP_OTA_IMG_UNDEFINED
  • CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE 使能时,应用程序状态通常会使用除 ESP_OTA_IMG_UNDEFINED 状态之外的其他所有状态

CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE 配置项可通过 menuconfig 配置:

在这里插入图片描述

CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE 未使能时:

在这里插入图片描述

CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE 使能时:

在这里插入图片描述

Pass: 程序分析小技巧,可以通过python在工程目录下搭建本地http服务器,配置升级地址为服务器地址,这样可以循环升级,并在例程中添加我们需要的打印信息,即可快速分析ota程序!

参考文档:Over The Air Updates (OTA)

6. 应用程序版本修改

应用程序版本存储在 esp_app_desc_t 结构体中。该结构体位于 DROM 扇区,有一个从二进制文件头部计算的固定偏移值。该结构体位于 esp_image_header_t esp_image_segment_header_t 结构体之后。字段 Version 类型为字符串,最大长度为 32 字节。

关于应用程序的版本设置,总共有以下几种方案:

  1. menuconfig 中设置对应配置项(Application manager选项内)

在这里插入图片描述

  1. CMakeLists.txt 文件中设置 PROJECT_VER 变量,注意需要在 包含project.cmake 之前添加,格式如 set(PROJECT_VER "0.1.0.1")

在这里插入图片描述

  1. 在工程目录下新建 version.txt 文档,在此文档中输入对应版本信息

在这里插入图片描述

  1. 使用 git describe 检索(实测命令无效)

  2. 若以上均未有设置,则会将版本变量 PROJECT_VER 默认设置为 1

7. 总结

以上就是关于 ESP32 使用 https 进行 OTA 升级的全部内容了,欢迎大家一同探讨关于ESP32的更多知识!


创作不易,转载请注明出处!

关注、点赞+收藏,可快速查收博主有关分享!


8. 补充学习

  
强烈推荐:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱出名的狗腿子

你的鼓励就是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值