ES32中OTA空中升级

打开SDK可视化配置,检查flash大小设定和“partition table”分区表设定。

左下角,点击SDK可视化配置按钮,进入配置。flash大小为4MB,Partition Table选择Factory app, two OTA definitions,分区表烧写偏移地址0x8000,如果默认是这样,则不用修改,直接关闭窗口即可

从 AWS S3 等服务获取映像时,此选项非常有用,其中 mbedTLS Rx 缓冲区大小 (CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN) 可以设置为较低的值,如果不启用此配置,这是不可能的。

http服务器:

1、HFS的http服务器地址 把XXX.bin 固件拖进服务器。

2、在终端bin目录执行:python -m http.server 8070 通过url访问

应用程序版本

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

若需手动设置版本,需要在项目的 文件中设置 变量,即在 文件中,在包含 之前添加 。CMakeLists.txtPROJECT_VERCMakeLists.txtproject.cmakeset(PROJECT_VER "0.1.0.1")

如果设置了 CONFIG_APP_PROJECT_VER_FROM_CONFIG 选项,则将使用 CONFIG_APP_PROJECT_VER 的值。 否则,如果在项目中未设置 变量,则该变量将从 文件(若有)中检索,或使用 git 命令 检索。 如果两者都不可用,则 将被设置为 “1”。 应用程序可通过调用 esp_app_get_description() 或 esp_ota_get_partition_description() 函数来获取应用程序的版本信息。PROJECT_VER$(PROJECT_PATH)/version.txtgit describePROJECT_VER

ES32中OTA空中升级_第1张图片

ES32中OTA空中升级_第2张图片

一、API函数

esp_ota_begin    //开始写入指定分区的 OTA 更新,指定的分区被擦除到指定的图像大小。
esp_ota_write    //将 OTA 更新数据写入分区。数据按顺序写入分区。
esp_ota_write_with_offset    //将 OTA 更新数据写入分区。可以以非连续方式写入数据。
esp_ota_end    //完成 OTA 更新并验证新编写的应用映像。
esp_ota_abort    //中止 OTA 更新,释放与之关联的句柄和内存。
esp_ota_set_boot_partition    //为新的引导分区配置 OTA 数据。
esp_ota_get_boot_partition    //获取当前配置的启动应用程序的分区信息。
esp_ota_get_running_partition    //获取当前运行的应用程序的分区信息。
esp_ota_get_next_update_partition    //返回下一个应使用新固件写入的 OTA 应用程序分区。
esp_ota_get_partition_description    //返回应用分区的 esp_app_desc 结构。此结构包括应用程序版本。
esp_ota_mark_app_valid_cancel_rollback    //调用此函数以指示正在运行的应用程序运行良好。
esp_ota_mark_app_invalid_rollback_and_reboot    //调用此函数以通过重启回滚到以前可用的应用程序。
esp_ota_get_last_invalid_partition    //返回最后一个状态无效的分区(ESP_OTA_IMG_INVALID 或 ESP_OTA_IMG_ABORTED)
esp_ota_get_state_partition    //返回给定分区的状态。
esp_ota_erase_last_boot_app_partition    //擦除以前的启动应用程序分区和此分区的相应 otadata 选择。
esp_ota_check_rollback_is_possible    //检查可以在回滚的情况下启动的插槽上的应用程序。

详细介绍:

const esp_app_desc_t*esp_ota_get_app_description(void)

返回esp_app_desc结构。此结构包括应用版本。正在运行的应用的返回说明。备注此 API 的存在是出于向后兼容性的原因。具有相同功能的替代功能是esp_app_get_description

返回指向esp_app_desc结构的指针。

int esp_ota_get_app_elf_sha256(char*dst,size_t size)

用 ELF 文件的 SHA256 填充提供的缓冲区,格式为十六进制,以 null 结尾。如果缓冲区大小不足以容纳十六进制加上空终止符的整个 SHA256,则将写入最大可能的字节数,后跟一个空。备注此 API 的存在是出于向后兼容性的原因。具有相同功能的替代功能是esp_app_get_elf_sha256

参数 dst – 目标缓冲区大小 size– 缓冲区的大小

返回写入 dst 的字节数(包括空终止符)

esp_err_t esp_ota_begin(常量esp_partition_t*分区,size_t image_size,esp_ota_handle_t* out_处理)

开始写入指定分区的 OTA 更新。指定的分区将擦除为指定的映像大小。如果图像大小尚未知,请传递OTA_SIZE_UNKNOWN这将导致整个分区被擦除。成功后,此函数将分配仍在使用的内存,直到使用返回的句柄调用 esp_ota_end()。注意:如果启用了回滚选项,并且正在运行的应用程序具有ESP_OTA_IMG_PENDING_VERIFY状态,则会导致ESP_ERR_OTA_ROLLBACK_INVALID_STATE错误。在运行下载新应用程序之前确认正在运行的应用程序,请使用 esp_ota_mark_app_valid_cancel_rollback() 函数(这应该在您首次下载新应用程序时尽早完成)。

参数分区 – 指向将接收 OTA 更新的分区信息的指针。必填。

image_size– 新 OTA 应用程序图像的大小。分区将被擦除以接收此大小的图像。如果为 0 或 OTA_SIZE_UNKNOWN,则擦除整个分区。

out_handle– 成功后,返回一个句柄,该句柄应用于后续的 esp_ota_write() 和 esp_ota_end() 调用。

返回ESP_OK:OTA运营成功。ESP_ERR_INVALID_ARG:分区或out_handle参数为 NULL,或者分区不指向 OTA 应用分区。ESP_ERR_NO_MEM:无法为 OTA 操作分配内存。ESP_ERR_OTA_PARTITION_CONFLICT:分区保存当前正在运行的固件,无法就地更新。ESP_ERR_NOT_FOUND:在分区表中找不到分区参数。ESP_ERR_OTA_SELECT_INFO_INVALID:OTA数据分区包含无效数据。ESP_ERR_INVALID_SIZE:分区不适合配置的闪存大小。ESP_ERR_FLASH_OP_TIMEOUT或ESP_ERR_FLASH_OP_FAIL:闪存写入失败。ESP_ERR_OTA_ROLLBACK_INVALID_STATE:如果正在运行的应用尚未确认状态。在执行更新之前,应用程序必须有效。

esp_err_t esp_ota_write(esp_ota_handle_t 句柄,常量空* 数据,size_t 大小)

将 OTA 更新数据写入分区。在 OTA 操作期间接收数据时,可以多次调用此函数。数据按顺序写入分区。

参数句柄 – 从esp_ota_begin获取的句柄

data– 要写入的数据缓冲区

size– 数据缓冲区的大小(以字节为单位)。

返回ESP_OK:数据已成功写入刷机。ESP_ERR_INVALID_ARG:句柄无效。ESP_ERR_OTA_VALIDATE_FAILED:图像的第一个字节包含无效的应用图像魔术字节。ESP_ERR_FLASH_OP_TIMEOUT或ESP_ERR_FLASH_OP_FAIL:闪存写入失败。ESP_ERR_OTA_SELECT_INFO_INVALID:OTA数据分区包含无效内容

esp_err_t esp_ota_write_with_offset(esp_ota_handle_t句柄,常量空*数据,size_t大小,uint32_t抵消)

将 OTA 更新数据写入偏移分区。此函数可以以非连续的方式写入数据。如果启用了 Flash 加密,则数据应对齐 16 个字节。备注在执行 OTA 时,如果数据包无序到达,可以使用 esp_ota_write_with_offset() 以非连续方式写入数据。不建议将 esp_ota_write_with_offset() 与 esp_ota_write() 结合使用。

参数句柄 – 从esp_ota_begin获取的句柄

data– 要写入的数据缓冲区

size– 数据缓冲区的大小(以字节为单位)

偏移 – 闪存分区中的偏移

返回ESP_OK:数据已成功写入刷机。ESP_ERR_INVALID_ARG:句柄无效。ESP_ERR_OTA_VALIDATE_FAILED:图像的第一个字节包含无效的应用图像魔术字节。ESP_ERR_FLASH_OP_TIMEOUT或ESP_ERR_FLASH_OP_FAIL:闪存写入失败。ESP_ERR_OTA_SELECT_INFO_INVALID:OTA数据分区包含无效内容

esp_err_t esp_ota_end(esp_ota_handle_t 手柄)

完成 OTA 更新并验证新编写的应用映像。备注调用 esp_ota_end() 后,句柄不再有效,并且释放与其关联的任何内存(无论结果如何)。参数handle– 从 esp_ota_begin() 获取的句柄。返回ESP_OK:新写入的 OTA 应用镜像有效。ESP_ERR_NOT_FOUND:找不到 OTA 句柄。ESP_ERR_INVALID_ARG:句柄从未被写过。ESP_ERR_OTA_VALIDATE_FAILED:OTA 映像无效(不是有效的应用映像,或者 - 如果启用了安全启动 - 签名验证失败。ESP_ERR_INVALID_STATE:如果启用了 flash 加密,则此结果表示将最终加密字节写入闪存时出现内部错误。

esp_err_t esp_ota_abort(esp_ota_handle_t 手柄))

中止 OTA 更新,释放与其关联的句柄和内存。参数句柄 – 从 esp_ota_begin() 获得。返回ESP_OK:句柄及其关联的内存已成功释放。ESP_ERR_NOT_FOUND:找不到 OTA 句柄。

esp_err_t esp_ota_set_boot_partition(常量esp_partition_t*分区))

为新的引导分区配置 OTA 数据。备注如果此函数返回 ESP_OK,则调用 esp_restart() 将引导新配置的应用程序分区。参数分区 – 指向包含要启动的应用映像的分区信息的指针。返回ESP_OK:OTA数据已更新,下次重启将使用指定的分区。ESP_ERR_INVALID_ARG:分区参数为 NULL 或未指向类型为“app”的有效 OTA 分区。ESP_ERR_OTA_VALIDATE_FAILED:分区包含无效的应用映像。如果启用了安全启动且签名验证失败,则也会返回。ESP_ERR_NOT_FOUND:找不到 OTA 数据分区。ESP_ERR_FLASH_OP_TIMEOUT或ESP_ERR_FLASH_OP_FAIL:闪存擦除或写入失败。

常量 esp_partition_t*esp_ota_get_boot_partition(void)

获取当前配置的启动应用的分区信息。如果调用了 esp_ota_set_boot_partition(),则将返回该函数设置的分区。如果未调用 esp_ota_set_boot_partition(),则结果通常与 esp_ota_get_running_partition() 相同。如果配置的引导分区不包含有效的应用(这意味着正在运行的分区将是引导加载程序通过回退选择的应用),则这两个结果不相等。如果 OTA 数据分区不存在或无效,则结果是在分区表中找到的第一个应用分区。按优先级顺序,这意味着:工厂应用、第一个 OTA 应用槽或测试应用分区。请注意,不能保证返回的分区是有效的应用。使用 esp_image_verify(ESP_IMAGE_VERIFY, ...) 验证返回的分区是否包含可引导映像。返回指向分区结构信息的指针,如果分区表无效或闪存读取操作失败,则为 NULL。任何返回的指针在应用程序的生存期内都有效。

常量 esp_partition_t*esp_ota_get_running_partition(无效)

获取当前正在运行的应用程序的分区信息。此函数与 esp_ota_get_boot_partition() 的不同之处在于它忽略由 esp_ota_set_boot_partition() 引起的所选引导分区的任何更改。只有代码当前正在运行的应用才会返回其分区信息。如果配置的引导分区以某种方式无效,并且引导加载程序在引导时回退到不同的应用分区,则此函数返回的分区也可能与 esp_ota_get_boot_partition() 不同。返回指向分区结构信息的指针,如果未找到分区或闪存读取操作失败,则为 NULL。返回的指针在应用程序的生存期内有效。

const esp_partition_t*esp_ota_get_next_update_partition(constesp_partition_t*start_from)

返回应使用新固件写入的下一个 OTA 应用程序分区。调用此函数以查找可以传递给 esp_ota_begin() 的 OTA 应用分区。查找下一个分区轮循机制,从当前正在运行的分区开始。参数start_from– 如果设置,请将此分区信息视为描述当前正在运行的分区。可以为 NULL,在这种情况下,esp_ota_get_running_partition() 用于查找当前正在运行的分区。此函数的结果永远不会与此参数相同。返回指向接下来应更新的分区信息的指针。NULL 结果表示 OTA 数据分区无效,或者未找到符合条件的 OTA 应用槽分区。

esp_err_t esp_ota_get_partition_description(常量esp_partition_t*分区,esp_app_desc_t*app_desc)

返回应用分区esp_app_desc结构。此结构包括应用版本。返回所请求的应用程序分区的说明。

参数分区–

[输入]指向应用分区的指针。(仅限应用分区)

app_desc–[输出]有关应用的信息结构。

返回ESP_OK成功。找不到ESP_ERR_NOT_FOUND app_desc结构。魔术词不正确。ESP_ERR_NOT_SUPPORTED分区不是应用程序。ESP_ERR_INVALID_ARG 参数为 NULL 或分区的偏移量超过分区大小。ESP_ERR_INVALID_SIZE读取将超出分区的范围。或来自较低级别的闪存驱动程序的错误代码之一。

uint8_t esp_ota_get_app_partition_count(无效)

返回分区表中提供的 ota 分区数。

返回OTA 分区数

esp_err_t esp_ota_mark_app_valid_cancel_rollback(无效)

调用此函数以指示正在运行的应用运行良好。

返回ESP_OK:如果成功。

esp_err_t esp_ota_mark_app_invalid_rollback_and_reboot(无效)

调用此函数以在重新启动时回滚到以前可用的应用程序。如果回滚成功,则设备将重置,否则 API 将返回错误代码。检查闪存驱动器上的应用程序,以便在回滚时启动。如果闪存没有至少一个应用程序(正在运行的应用程序除外),则无法回滚。

返回ESP_FAIL:如果不成功。ESP_ERR_OTA_ROLLBACK_FAILED:由于闪存没有任何应用程序,因此无法回滚。

常量 esp_partition_t*esp_ota_get_last_invalid_partition(void)

返回状态无效的最后一个分区(ESP_OTA_IMG_INVALID 或 ESP_OTA_IMG_ABORTED)。

返回分区。

esp_err_t esp_ota_get_state_partition(constesp_partition_t*partition,esp_ota_img_states_t*ota_state)

返回给定分区的状态。

参数分区–

[输入]指向分区的指针。

分区的ota_state–[out]状态(如果此分区在 OTADATA 中有记录)。

返回ESP_OK:成功。ESP_ERR_INVALID_ARG:分区或ota_state参数为 NULL。ESP_ERR_NOT_SUPPORTED:分区不是太田。ESP_ERR_NOT_FOUND:分区表没有 otadata,或者找不到给定分区的状态。

esp_err_t esp_ota_erase_last_boot_app_partition(无效)

擦除以前的启动应用程序分区以及为此分区选择的相应 otadata。当当前应用程序标记为有效时,您可以擦除以前的应用程序分区。

返回ESP_OK:成功,否则ESP_ERR。

布尔 esp_ota_check_rollback_is_possible(无效)

检查插槽上的应用程序,以便在回滚时引导。这些应用程序应该是有效的(在 otadata 中标记为未定义、无效或中止且 crc 良好)并且能够启动,并且应用程序> = secure_version 的 efuse(如果启用了反回滚)secure_version。

返回True:如果槽至少有一个应用(正在运行的应用除外),则返回 true。错误:无法回滚。

二、ESP HTTPS OTA

esp_err_t esp_https_ota(const esp_https_ota_config_t *ota_config)

HTTPS OTA 固件升级。该函数分配HTTPS OTA固件升级上下文,建立HTTPS连接,从HTTP流中读取镜像数据并将其写入OTA分区,完成HTTPS OTA固件升级操作。此 API 支持 URL 重定向,但如果 URL 的 CA 证书不同,则应将其追加到成员。cert_pemota_config->http_config备注此 API 处理整个 OTA 操作,因此如果使用此 API,则不应调用来自组件的其他 API。如果在HTTPS OTA过程中需要更多信息和控制,则可以使用后续API。如果此 API 成功返回,则必须调用 esp_restart() 才能从新固件映像启动。esp_https_otaesp_https_ota_begin

参数ota_config – 指向esp_https_ota_config_t结构的指针。

返回ESP_OK:OTA数据已更新,下次重启将使用指定的分区。ESP_FAIL:用于一般故障。ESP_ERR_INVALID_ARG:参数无效ESP_ERR_OTA_VALIDATE_FAILED:应用图像无效ESP_ERR_NO_MEM:无法为 OTA 操作分配内存。ESP_ERR_FLASH_OP_TIMEOUT或ESP_ERR_FLASH_OP_FAIL:闪存写入失败。有关其他返回码,请参阅 esp-idf app_update组件中的 OTA 文档。

esp_err_t esp_https_ota_begin(const esp_https_ota_config_t *ota_config, esp_https_ota_handle_t *handle)

启动 HTTPS OTA 固件升级。此函数初始化 ESP HTTPS OTA 上下文并建立 HTTPS 连接。必须先调用此函数。如果此函数成功返回,则应调用该函数以继续执行 OTA 进程,并且应该调用 toon 完成 OTA 操作或后续操作失败。此 API 支持 URL 重定向,但如果 URL 的 CA 证书不同,则应将其附加到成员,这是其中的一部分。如果出现错误,此 API 显式设置为 NULL。esp_https_ota_performesp_https_ota_finishcert_pemhttp_configota_confighandle备注此 API 正在阻塞,因此设置结构成员将导致错误。is_asynchttp_config

参数ota_config 指向esp_https_ota_config_t结构的指针handle–[out]指向已分配数据类型的指针将在此函数中初始化esp_https_ota_handle_t

返回ESP_OK:初始化 HTTPS OTA 固件升级上下文并建立 HTTPS 连接ESP_FAIL:用于一般故障。ESP_ERR_INVALID_ARG:参数无效(缺少/不正确的配置、证书等)有关其他返回码,请参阅 esp-idf 中app_update组件和esp_http_client组件中的文档。

esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle)

从HTTP流中读取图像数据并将其写入OTA分区。此函数从 HTTP 流中读取图像数据并将其写入 OTA 分区。仅当 esp_https_ota_begin() 成功返回时,才必须调用此函数。此函数必须在循环中调用,因为它在每个 HTTP 读取操作后返回,从而使您能够灵活地在中途停止 OTA 操作。参数https_ota_handle [in]指向esp_https_ota_handle_t结构的指针返回ESP_ERR_HTTPS_OTA_IN_PROGRESS:正在进行OTA更新,请再次调用此接口继续。ESP_OK:OTA更新成功ESP_FAIL:OTA 更新失败ESP_ERR_INVALID_ARG:参数无效ESP_ERR_INVALID_VERSION:映像标头中的芯片修订无效ESP_ERR_OTA_VALIDATE_FAILED:应用图像无效ESP_ERR_NO_MEM:无法为 OTA 操作分配内存。ESP_ERR_FLASH_OP_TIMEOUT或ESP_ERR_FLASH_OP_FAIL:闪存写入失败。有关其他返回码,请参阅 esp-idf app_update组件中的 OTA 文档。

bool esp_https_ota_is_complete_data_received(esp_https_ota_handle_t https_ota_handle)

检查是否收到完整的数据。备注可以在 esp_https_ota_finish() 之前调用此 API,以验证是否确实收到了完整的映像。

参数https_ota_handle [in]指向esp_https_ota_handle_t结构的指针

返回假真

esp_err_t esp_https_ota_finish(esp_https_ota_handle_t https_ota_handle)

清理 HTTPS OTA 固件升级并关闭 HTTPS 连接。此函数关闭 HTTP 连接并释放 ESP HTTPS OTA 上下文。此函数将引导分区切换到包含新固件映像的 OTA 分区。备注如果此 API 成功返回,则必须调用 esp_restart() 才能从新固件映像启动,esp_https_ota_finish调用后不应调用esp_https_ota_abort

参数https_ota_handle [in]指向esp_https_ota_handle_t结构的指针

返回ESP_OK:清理成功ESP_ERR_INVALID_STATEESP_ERR_INVALID_ARG:参数无效ESP_ERR_OTA_VALIDATE_FAILED:应用图像无效

esp_err_t esp_https_ota_abort(esp_https_ota_handle_t https_ota_handle)

清理 HTTPS OTA 固件升级并关闭 HTTPS 连接。此函数关闭 HTTP 连接并释放 ESP HTTPS OTA 上下文。备注esp_https_ota_abort不应在调用esp_https_ota_finish后调用

参数https_ota_handle [in]指向esp_https_ota_handle_t结构的指针

返回ESP_OK:清理成功ESP_ERR_INVALID_STATE:无效的 ESP HTTPS OTA 状态ESP_FAIL:OTA 未启动ESP_ERR_NOT_FOUND:找不到 OTA 句柄ESP_ERR_INVALID_ARG:参数无效

esp_err_t esp_https_ota_get_img_desc(esp_https_ota_handle_t https_ota_handle, esp_app_desc_t *new_app_info)

从图像标头读取应用说明。应用说明提供了映像的“固件版本”等信息。备注只能在 esp_https_ota_begin() 之后和 esp_https_ota_perform() 之前调用此 API。调用此 API 不是强制性的。

参数https_ota_handle [in]指向esp_https_ota_handle_t结构的指针new_app_info–[out]指向已分配esp_app_desc_t结构的指针

返回ESP_ERR_INVALID_ARG:参数无效ESP_ERR_INVALID_STATE:调用此 API 的状态无效。esp_https_ota_begin() 尚未调用。ESP_FAIL:无法读取图像描述符ESP_OK:成功读取图像描述符

int esp_https_ota_get_image_len_read(esp_https_ota_handle_t https_ota_handle)

此函数返回到目前为止读取的 OTA 图像数据。备注仅当至少调用过一次或之前调用过 if 时,才应调用此 API。esp_https_ota_perform()esp_https_ota_get_img_desc

参数https_ota_handle [in]指向esp_https_ota_handle_t结构的指针

返回-1 失败时到目前为止读取的总字节数

int esp_https_ota_get_image_size(esp_https_ota_handle_t https_ota_handle)

此函数返回 OTA 图像总大小。备注此 API 应在调用 esp_https_ota_begin() 后调用。这可用于创建某种进度指示(与 esp_https_ota_get_image_len_read()结合使用)

参数https_ota_handle [in]指向esp_https_ota_handle_t结构的指针

返回-1 失败或分块编码时图像的总字节数

const esp_partition_t *esp_ota_get_next_update_partition(const esp_partition_t *start_from)

返回应使用新固件写入的下一个 OTA 应用程序分区。调用此函数以查找可以传递给 esp_ota_begin() 的 OTA 应用分区。查找下一个分区轮循机制,从当前正在运行的分区开始。

参数:start_from – 如果设置,请将此分区信息视为描述当前正在运行的分区。可以为 NULL,在这种情况下,esp_ota_get_running_partition() 用于查找当前正在运行的分区。此函数的结果永远不会与此参数相同。

返回:指向接下来应更新的分区信息的指针。NULL 结果表示 OTA 数据分区无效,或者未找到符合条件的 OTA 应用槽分区。

应用实测(采用HTTP OTA)

使用示例:

#include "sit_lib_ota_internal.h"

static const char *TAG = "https_ota";
extern const uint8_t server_cert_pem_start[] asm("_binary_ca_cert_pem_start");
extern const uint8_t server_cert_pem_end[] asm("_binary_ca_cert_pem_end");


#define OTA_URL_SIZE 256

static esp_err_t validate_image_header(esp_app_desc_t *new_app_info)
{
    if (new_app_info == NULL) {
        return ESP_ERR_INVALID_ARG;
    }

    const esp_partition_t *running = esp_ota_get_running_partition(); //获取当前运行的分区
    esp_app_desc_t running_app_info;
    if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK) {
        ESP_LOGI(TAG, "Running firmware version: %s", running_app_info.version);
        vTaskDelay(20 / portTICK_PERIOD_MS);//加延时 防止出现socket通讯错误问题 
    }

    //  检测是否为同一版本 
    if (memcmp(new_app_info->version, running_app_info.version, sizeof(new_app_info->version)) == 0) {
        ESP_LOGW(TAG, "Current running version is the same as a new. We will not continue the update.");
        return ESP_FAIL;
    }

    /**
     * 从固件映像头进行安全版本检查,防止后续下载和flash写入整个固件映像。(版本检测)
     * 然而,这是可选的,因为它也在OTA更新过程末尾的API esp_https_ota_finish中被注意到了。
     */
    const uint32_t hw_sec_version = esp_efuse_read_secure_version();
    if (new_app_info->secure_version < hw_sec_version) {
        ESP_LOGW(TAG, "New firmware security version is less than eFuse programmed, %lu < %lu", new_app_info->secure_version, hw_sec_version);
        return ESP_FAIL;
    }

    return ESP_OK;
}

static esp_err_t _http_client_init_cb(esp_http_client_handle_t http_client)
{
    esp_err_t err = ESP_OK;
    return err;
}

void advanced_ota_example_task(void *pvParameter)
{
    ESP_LOGI(TAG, "Starting Advanced OTA example");
    vTaskDelay(20 / portTICK_PERIOD_MS);
    esp_err_t ota_finish_err = ESP_OK;
    if(strlen(G_UpdateInfo.OtaUrl) == 0)
    {
        // ESP_LOGI(TAG, "Get Url is null OTA Failed");
    }
    esp_http_client_config_t config = {
        .url = G_UpdateInfo.OtaUrl,//CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL, //G_UpdateInfo.OtaUrl, 
        .cert_pem = (char *)server_cert_pem_start,
        .timeout_ms = CONFIG_EXAMPLE_OTA_RECV_TIMEOUT, //设置网络超时时间为毫秒
        .keep_alive_enable = true,
        // .buffer_size = 1024,
    };

    esp_https_ota_config_t ota_config = {
        .http_config = &config,
        .http_client_init_cb = _http_client_init_cb, // Register a callback to be invoked after esp_http_client is initialized
    };

    esp_https_ota_handle_t https_ota_handle = NULL;
    esp_err_t err = esp_https_ota_begin(&ota_config, &https_ota_handle); //启动 HTTPS OTA 固件升级
    if (err != ESP_OK) {
        if (GET_BIT(G_Device_Data.RuningFlag, 0) == 1)
        {
            CLEAR_BIT(G_Device_Data.RuningFlag, 0); // 清除bit0
            SET_BIT(G_Device_Data.RuningFlag, 1);   // 正在升级 则设置为升级失败:2
        }
        ESP_LOGE(TAG, "ESP HTTPS OTA Begin failed");
        // vTaskDelete(NULL);
        save_flash_restart();
    }

    esp_app_desc_t app_desc;
    err = esp_https_ota_get_img_desc(https_ota_handle, &app_desc);//从图像标头读取应用说明,应用说明提供了映像的“固件版本”等信息
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "esp_https_ota_read_img_desc failed");
        goto ota_end;
    }
    err = validate_image_header(&app_desc); //根据固件头信息 确定是否可以升级
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "image header verification failed");
        goto ota_end;
    }

    while (1) {
        err = esp_https_ota_perform(https_ota_handle); //从HTTP流中读取图像数据并将其写入OTA分区
        if (err != ESP_ERR_HTTPS_OTA_IN_PROGRESS) {
            break;
        }
        // Esp_https_ota_perform在每次读取操作之后返回,这使用户能够通过调用esp_https_ota_get_image_len_read来监视OTA升级的状态,它给出了到目前为止读取的图像数据的长度。
        ESP_LOGD(TAG, "Image bytes read: %d", esp_https_ota_get_image_len_read(https_ota_handle));
        // mqtt获取到下载固件大小 计算出下载进度上报
    }

    if (esp_https_ota_is_complete_data_received(https_ota_handle) != true) { //完整获取bin数据
        // the OTA image was not completely received and user can customise the response to this situation.
        ESP_LOGE(TAG, "Complete data was not received.");
    } else {
        ota_finish_err = esp_https_ota_finish(https_ota_handle);    //引导分区切换到包含新固件映像的 OTA 分区。
        if ((err == ESP_OK) && (ota_finish_err == ESP_OK)) { //远程升级完成 开始重启
            ESP_LOGI(TAG, "ESP_HTTPS_OTA upgrade successful. Rebooting ...");

            if(GET_BIT(G_Device_Data.RuningFlag,0) == 1) 
            {
                
                SET_BIT(G_Device_Data.RuningFlag,1);//正在升级 则设置为升级完成:3
            }

            vTaskDelay(1000 / portTICK_PERIOD_MS);
            save_flash_restart();
        } else {
            if (ota_finish_err == ESP_ERR_OTA_VALIDATE_FAILED) {
                ESP_LOGE(TAG, "Image validation failed, image is corrupted");
            }
            ESP_LOGE(TAG, "ESP_HTTPS_OTA upgrade failed 0x%x", ota_finish_err);
            if (GET_BIT(G_Device_Data.RuningFlag, 0) == 1)
            {
                CLEAR_BIT(G_Device_Data.RuningFlag, 0); // 清除bit0
                SET_BIT(G_Device_Data.RuningFlag, 1);   // 正在升级 则设置为升级失败:2
            }
            // vTaskDelete(NULL);
            save_flash_restart();
        }
    }

ota_end:
    if (GET_BIT(G_Device_Data.RuningFlag, 0) == 1)
    {
        CLEAR_BIT(G_Device_Data.RuningFlag,0); //清除bit0
        SET_BIT(G_Device_Data.RuningFlag, 1); // 正在升级 则设置为升级失败:2
    }
    esp_https_ota_abort(https_ota_handle); // 清理 HTTPS OTA 固件升级并关闭 HTTPS 连接
    ESP_LOGE(TAG, "ESP_HTTPS_OTA upgrade failed");
    // vTaskDelete(NULL);
    save_flash_restart();
}

void Ota_TaskStart(void)
{
    printf("-- OTA example  start --\r\n");
    vTaskDelay(20 / portTICK_PERIOD_MS);
    /**
     * 我们将把成功的WiFi连接作为一个检查点来取消回滚过程,并将最新更新的固件映像标记为活动的。
     * 对于生产案例,请根据终端应用程序需求调优检查点行为。
     */
    const esp_partition_t *running = esp_ota_get_running_partition();
    esp_ota_img_states_t ota_state;
    if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
        if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
            if (esp_ota_mark_app_valid_cancel_rollback() == ESP_OK) {
                ESP_LOGI(TAG, "App is valid, rollback cancelled successfully");
            } else {
                ESP_LOGE(TAG, "Failed to cancel rollback");
            }
        }
    }
    
    /* *
     * 确保禁用任何WiFi省电模式,这样可以实现最佳吞吐量,从而为整体OTA操作计时。
     */
    esp_wifi_set_ps(WIFI_PS_NONE);

    xTaskCreate(&advanced_ota_example_task, "advanced_ota_task", 4096 , NULL, 5, NULL);
}

menuconfig 配置:

ES32中OTA空中升级_第3张图片

ES32中OTA空中升级_第4张图片

ES32中OTA空中升级_第5张图片

分区设置表(根据自己需要设计)

Name

Type

SubType

offset

Size

flag

nvs

,data

,nvs

,

0x4000

,

otadata

,data

,ota

,

0x2000

,

pth_init

,data

,phy

,

0x1000

,

my_data

,data

,nvs

,

12K

,

ota_1

,app

,ota_1

,

1500K

,

ota_2

,app

,ota_2

,

1500K

,

错误记录:

1、因为http服务被中断 无法连接,使用上面服务器2的方法进行固件下载。或换端口重新尝试。

ES32中OTA空中升级_第6张图片

2、固件不完整。

ES32中OTA空中升级_第7张图片

3、连接超时,http连接未完成下载。

ES32中OTA空中升级_第8张图片

4、http服务器验证出错。结构体添加参数并添加验证文件。

ES32中OTA空中升级_第9张图片

ES32中OTA空中升级_第10张图片

5、https证书添加

EMBED_TXTFILES ${project_dir}/server_certs/ca_cert.pem //cmakelists.txt中添加 证书路径

组件添加:

REQUIRES "bt"
#"nvs_flash" "driver" "esp_timer" "esp_event" "app_update" "esp_http_client" "esp_https_ota" "esp_wifi" "efuse"
#"bt" "esp_wifi" "freertos" "json" "esp_http_client"  "lwip" "esp_netif" "mbedtls" "esp_https_ota"

6、如何支持HTTPS连接,但不做证书校验?参数开始时候,请把 cert_set 设置为 OTA_CERT_SSL_VERIFY_OPTIONAL ,把

.cert_set = OTA_CERT_SSL_VERIFY_OPTIONAL,
.skip_ssl_cert_set = false,

填坑

ESP32做为客户端进行HTTPS请求时,如果不需要验证服务器证书也就是想跳过证书验证,

改constesp_http_client_config_t结构体中skip_cert_common_name_check成员是没有效果的。

他只会跳过检查证书的CN而不是CA,不会跳过整个证书验证。

所以如果想跳过证书则需要在menuconfig里面修改ESP-TLS选项,改为默认跳过服务器证书如下图

ES32中OTA空中升级_第11张图片

华为IOT升级 SSL握手失败

7、启动mqtt后开始OTA报错(建议关闭aws相关服务,但依然内存不足)

单纯删除线程并不能释放内存。需要单独调用mqtt断开连接的函数。

I (16116) advanced_https_ota_example: Connected to server
I (16116) esp_https_ota: Starting OTA...
I (16116) esp_https_ota: Writing to partition subtype 17 at offset 0x1a0000
I (16126) advanced_https_ota_example: Reading Image Description
E (16136) Dynamic Impl: alloc(16749 bytes) failed
E (16136) esp-tls-mbedtls: read error :-0x7F00:
E (16146) transport_base: esp_tls_conn_read error, errno=Success
E (16156) HTTP_CLIENT: transport_read: error - -1 | ESP_FAIL
E (16166) esp_https_ota: Connection closed, errno = 0
E (16176) esp_https_ota: Complete headers were not received
E (16186) advanced_https_ota_example: esp_https_ota_read_img_desc failed
I (16196) advanced_https_ota_example: OTA abort
E (16206) advanced_https_ota_example: ESP_HTTPS_OTA upgrade failed

8、连接WiFi后单独运行OTA功能报错如下:

E (22295) esp-tls-mbedtls: read error :-0x004C:
E (22305) transport_base: esp_tls_conn_read error, errno=Software caused connection abort
W (22325) HTTP_CLIENT: esp_transport_read returned:-76 and errno:113 
E (22335) HTTP_CLIENT: transport_read: error - -1 | ESP_FAIL
E (22465) transport_base: poll_read select error 113, errno = Software caused connection abort, fd = 54
E (22475) HTTP_CLIENT: transport_read: error - 57347 | ERROR
E (22475) esp_https_ota: data read -1, errno 0
E (22485) https_ota: Complete data was not received.
E (22495) https_ota: ESP_HTTPS_OTA upgrade failed

剩余内存不足

ES32中OTA空中升级_第12张图片

9、关闭mqtt连接并按照如下设置可以完成ota

ES32中OTA空中升级_第13张图片

10、修改为短URL后无权限下载固件

E (1074267) esp_https_ota: File not found(403)
E (1074267) esp_https_ota: Failed to establish HTTP connection
E (1074267) https_ota: ESP HTTPS OTA Begin failed //错误后需要处理

11、URL过长

ES32中OTA空中升级_第14张图片

设置1536后实际URL满足存储长度,但是依然报错,最后使用不加密的短URL

ES32中OTA空中升级_第15张图片

12、下载很长时间后报错内存剩余很少,减少OTA任务申请的堆栈并开始前少许延时等待内存分配

ES32中OTA空中升级_第16张图片

/** Reading information from the socket failed. */ #define MBEDTLS_ERR_NET_RECV_FAILED -0x004C

你可能感兴趣的:(ESP32学习,c++,ESP32)