打开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
一、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 配置:
分区设置表(根据自己需要设计)
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的方法进行固件下载。或换端口重新尝试。
2、固件不完整。
3、连接超时,http连接未完成下载。
4、http服务器验证出错。结构体添加参数并添加验证文件。
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选项,改为默认跳过服务器证书如下图
华为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
剩余内存不足
9、关闭mqtt连接并按照如下设置可以完成ota
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过长
设置1536后实际URL满足存储长度,但是依然报错,最后使用不加密的短URL
12、下载很长时间后报错内存剩余很少,减少OTA任务申请的堆栈并开始前少许延时等待内存分配
/** Reading information from the socket failed. */ #define MBEDTLS_ERR_NET_RECV_FAILED -0x004C