ESP32 OTA(2)

对于ESP32 OTA也是第一次操作,所以就朦朦胧胧一直走呗。加油

ESP32的加密算法说明链接:https://wenku.baidu.com/view/a22671fe7c192279168884868762caaedd33ba34.html

链接:(24条消息) ESP32 的esp_http_client详解_做了不一定能实现但不做一定不会实现的博客-CSDN博客_esp32 http

链接:http://t.zoukankan.com/kerwincui-p-13968497.html

 链接:【玩转ESP32】10、创建用户分区表,数据读写存储 - 腾讯云开发者社区-腾讯云 (tencent.com)

(25条消息) ESP8266 分区表介绍_Dreaming咸鱼的博客-CSDN博客_esp8266分区

OTA

运行OTA机制需要配置设备的分区表。这个分区表至少包括2个OTA应用程序分区(ota_0 和 ota_1)以及一个OTA数据分区。

OTA功能启动后,向当前未用于启动的OTA应用分区写入新的固件镜像。镜像验证后,OTA数据分区更新,指定在下一次启动时使用该镜像。所以说OTA的数据分区用来指定下一次启动时运行的程序。

OTA数据分区是2个0X2000字节大小的flash扇区,防止写入是电源故障引发问题。两个扇区单独擦写、写入匹配数据,若存在不一致,则用计数器字段判定哪个扇区为最新数据。

应用程序回滚

应用程序回滚的主要目的是确保设备更新后正常运转。该功能可使设备在更新新版本后出现严重错误时,回滚到之前正常运行的应用版本。回滚使能,OTA升级,应用程序更新至新版本,之后可能有以下三种情况:

(1)应用程序运行正常esp_ota_mark_app_valid_cancel_rollback()将应用程序标记为ESP_OTA_IMG_VALID,启动无限制。

(2)应用程序出现严重错误,无法继续工作,必须回滚到此前的版本,esp_ota_mark_app_invalid_rollback_and_reboot()将正在运行的版本标记为ESP_OTA_IMG_INVALID然后复位。启动加载器不会选取此版本,而是此前正常运行的版本。

(3)如果CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE使能,则无需调用函数便可复位,回滚到之前的应用版本。

注:应用程序的状态不是写到程序的二进制镜像,而是写到otadata分区。该分区有一个ota_seq计数器,该计数器是OTA应用分区的指针,指向下次启动时选取应用所在的分区(ota_0,ota_1.......)

esp_err_t   esp_ota_mark_app_valid_cancel_rollback(void)

函数功能:该函数被调用表明运行的程序(running app)正常工作

函数返回:ESP_OK:如果成功。

esp_err_t   esp_ota_mark_app_invalid_rollback_and_reboot(void)

函数功能:调用该函数在重启的时候回滚到之前的应用程序。如果回滚成功,设备将复位。否则,API将返回到错误的代码。检查在回滚情况下可以启动的flash驱动器上的应用程序。如果flash没有至少一个app(除了running app),回滚是不可能的。

返回:ESP_FAIL:如果不成功

           ESP_ERR_OTA_ROLLBACK_FAILED:由于flash没有任何app,回滚是不可能的。

 

应用程序OTA状态

状态控制了选取启动应用程序的过程:

 

 如果config_bootloader_app_rollback_enable没有使能(默认情况),则esp_ota_mark_app_valid_cancel_rollback()和esp_ota_mark_app_invalid_rollback_and_reboot()为可选功能,ESP_OTA_IMG_NEW和ESP_OTA_IMG_PENDING_VERIFY不会使用。

Kconfig中的config_bootloader_app_rollback_enable可以帮助用户追踪新版本应用程序的第一次启动。应用程序需调用esp_ota_mark_app_valid_cancel_rollback()函数确认可以运行,否则将在重启时回滚至旧版本。该功能可让用户在启动阶段控制应用程序的可操作性。新版应用程序仅有一次机会尝试是否能成功启动。

 

回滚过程

config_bootloader_app_rollback_enable使能时,回滚过程如下:

(1)新版应用程序下载成功,esp_ota_set_boot_partition()函数将分区设为可启动,状态设为esp_ota_img_new。该状态表示应用程序为新版本,第一次启动需要监测。

(2)重新启动esp_restart()

(3)启动加载器检查新版应用程序,若状态设置为esp_ota_img_pending_verify,则写入eap_ota_img_aborted。

(4)启动加载器选取新版应用程序启动,应用程序状态不设置为esp_ota_img_invalid或esp_ota_img_aborted。

(5)启动加载器检查所选取的新版应用程序,若状态设置为esp_ota_img_new,则写入esp_ota_img_pending_verify。该状态表示,需确认应用程序的可操作性,如不确认,发生重启,则状态会重写为esp_ota_img_aborted(见上文的3),该应用程序不可再启动,将回滚至上一版本。

(6)新版应用程序启动,应进行自测。

(7)若通过自测,则必须调用函数esp_ota_mark_app_valid_cancel_rollback(),因为新版应用程序在等待确认其可操作性(esp_ota_img_pending_verify状态)。

(8)若未通过自测,则调用函数esp_ota_mark_app_invalid_rollback_and_reboot(),回滚至之前的版本,同时无效的新版本设置为eap_ota_img_invalid。

(9)如果新版应用程序可操作性没有确认,则状态一直为esp_ota_img_penfing_verify。下一次启动时,状态变更为esp_ota_img_aborted,阻止其再次启动,之后回滚到之前的版本。

 

意外复位

如果在新版应用第一次启动时发生断电或意外崩溃,则会回滚至之前正常运行的版本。

建议:尽快完成自测,防止因断电回滚。只有OTA分区可以回滚。工厂分区不会回滚。

 

启动无效/中止的应用程序

用户可以启动此前设置为esp_ota_img_invalid或esp_ota_img_aborted的应用程序:

(1)获取最后一个无效应用分区 esp_ota_get_last_invalid_partition()。

(2)将获取的分区传递给esp_ota_set_boot_partition(),更新otadata。

(3)重启esp_restart()。启动加载器会启动指定应用程序。

要确定是否在应用程序启动时进行自测,可以调用eap_ota_get_state_partition()函数。如果结果为esp_ota_img_pending_verify,则需要自测,后续确认应用程序的可操作性。

 

防回滚

防回滚机制可以防止回滚到安全版本号低于芯片eFuse中烧录程序的应用程序版本。

设置config_bootloader_app_anti_rollback,启动防回滚机制。在启动加载器中选取可启动的应用程序,会额外检查芯片和应用程序镜像的安全版本号。可启动固件中的应用安全版本号必须等于或高于芯片中的应用安全版本号。

config_bootloader_app_anti_rollback和config_bootloader_app_rollback_enable一起使用。此时,只有安全版本号等于或高于芯片中的应用安全版本号才会回滚。

注:如果想避免因服务器应用程序的安全版本号低于运行的应用程序,造成不必要的下载和擦除,必须从镜像的第一个包中获取new_app_info.secure_version,和eFuse的安全版本号比较。如果esp_efuse_check_secure_version(new_app_info.secure_version)函数为真,则继续下载,反之则中断。

bool image_header_was_checked = false;
while (1) {
int data_read = esp_http_client_read(client, ota_write_data, BUFFSIZE);
...
if (data_read > 0) {
if (image_header_was_checked == false) {
esp_app_desc_t new_app_info;
if (data_read > sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t)) {
// check current version with downloading
if (esp_efuse_check_secure_version(new_app_info.secure_version) == false) {
ESP_LOGE(TAG, "This a new app can not be downloaded due to a secure version is lower than stored in efuse.");
http_cleanup(client);
task_fatal_error();
}

image_header_was_checked = true;

esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle);
}
}
esp_ota_write( update_handle, (const void *)ota_write_data, data_read);
}
}

注:(1)secure_version字段最多有32位。也就是说,防回滚最多可以做32次。用户可以使用config_bootloader_app_sec_ver_size_efuse_field减少该efuse字段的长度。

(2)防回滚仅在eFuse编码机制设置为NONE时生效。

(3)分区表不应有工厂分区,应仅有两个应用程序分区。

(4)security_version存储在应用程序镜像中的esp_app_desc里。版本号用config_bootloader_app_secure_version设置。

(5)ESP32中版本号存储在efuse的efuse_blk3_rdata4_reg里(若efuse的位烧写为1,则永远无法恢复为0)。寄存器设置了多少位,应用程序的安全版本号就为多少。

 

esp_err_t   esp_ota_begin(const esp_partition_t * partition, size_t  image_size, esp_ota_handle_t  *out_handle)

函数说明:开始一个OTA更新写到指定的分区。这个指定的分区被擦除指定的映像大小。如果这个映像大小还未知道,通过ota_size_unknown将导致整个分区被擦除。如果成功,这个函数将分配的内存一直使用直到esp_ota_end()被返回的句柄调用。

注:如果回滚操作使能,并且running application有ESP_OTA_IMG_PENDING_VERIFY状态。这将到导致esp_err_ota_rollback_invalid_state错误。在运行下载一个新的app之前确认running app使用usp_ota_mark_valid_cancel_rollback()函数(当你第一次下载一个新的application时,应该尽可能早的做这一步)。

返回:ESP_OK:OTA操作成功的开始

           ESP_ERR_INVALID_ARG:分区或者输出的句柄参数为NULL,或者分区不指向一个OTA app分区

           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:分区不适合配置的flash大小。

           ESP_ERR_FLASH_OP_TIMEOUT or  ESP_ERR_FLASH_OP_FAIL:flash写失败。

           ESP_ERR_OTA_ROLLBACK_INVALID_STATE:如果running app没有确认状态。在执行之前,这个application 必须可获得。

参数:partition:指向将要接收OTA更新的分区的信息。

           iamge_size:新的OTA镜像大小。分区将会被擦除为了接收这个大小的镜像。如果为0或者OTA_SIZE_UNKNOWN,全部的镜像会被擦除。

          out_handle:一旦成功,返回一个句柄被esp_ota_write()和esp_ota_end()调用。

 

esp_err_t  esp_ota_end(esp_ota_handle_t handle)

函数说明:完成OTA的更新并验证新编写的app image。

注:在调用esp_ota_end()之后,句柄不再有效,并且释放与之相关的所有内存(无论结果如何)。

返回:ESP_OK:新写入的OTA app图像有效

           ESP_ERR_NOT_FOUND:OTA句柄没有被发现

           ESP_ERR_INVALID_ARG:句柄从未被写入

           ESP_ERR_OTA_VALIDATE_FAILED:OTA图像是无效的(要么不是一个有效的app image,要么启用了安全引导—签名验证失败)

           ESP_ERR_INVALID_STATE:如果使能flash加密,这个结果表明写最终加密字节到falsh是内部的错误。

参数:handle:handle从esp_ota_begin()获取。

 

esp_err_t  eap_ota_write(esp_ota_handle_t  handle,const void *data,size_t size)

函数说明:写OTA更新数据到分区

当OTA操作期间,当接收到数据时,可以多次调用次函数。数据按顺序写入分区。

返回:ESP_OK:数据成功写入到flash中

           ESP_ERR_INVALID_ARG:句柄无效

           ESP_ERR_OTA_VALIDATE_FAILED:第一个字节的图像包含无效的应用图像字节

           ESP_ERR_FLASH_OP_TIMEOUT or  ESP_ERR_FLASH_OP_FAIL:flash写失败

           ESP_ERR_OTA_SELECT_INFO_INVALID:OTA数据分区有无效的内容

参数:handle:句柄从esp_ota_begin获得

           data:写入的数组

           size:写入数组的字节大小。

 

posted @ 2022-07-20 17:55  笙箫涩  阅读(1408)  评论(0编辑  收藏  举报