ESP-IDF的OTA流程剥离

一、概述

  • 最近做了一下ESP32的IAP升级(基于Ymodem),所以需要剥离一下ESP32的OTA

二、SDK准备工作

  1. SDK版本:esp-idf-4.4.x

  2. 修改分区表,我这里采用OTA0+OTA1,各1.5M,无Factory区域

    # Name,   Type, SubType, Offset,   Size, Flags
    # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
    nvs,      data, nvs,     ,        0x4000,
    otadata,  data, ota,     ,        0x2000,
    phy_init, data, phy,     ,        0x1000,
    ota_0,    app,  ota_0,   ,        0x180000,
    ota_1,    app,  ota_1,   ,        0x180000,
    
  3. 设置板子的FLASH为4M(这里需要根据硬件和分区表在menuconfig进行调整)

    # CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
    # CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set
    CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
    # CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
    # CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
    

三、整体流程

  1. 需要用到的变量

    volatile esp_ota_handle_t update_handle = 0 ;//update的hdl,用于识别当前是哪个OTA,这里应该允许多个OTA同时进行?
    volatile const esp_partition_t *update_partition = NULL;//拿分区的指针
    volatile int binary_file_length = 0;//文件长度
    volatile bool image_header_was_checked = false;//是否检测到头了
    
  2. 初始化时需要调用(准备开始OTA了)

    ///>ESP32 需要处理的逻辑
    update_partition = esp_ota_get_next_update_partition(NULL);//获取下一个更新的分区
    assert(update_partition != NULL);
    ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x",
    		update_partition->subtype, update_partition->address);
    binary_file_length = 0;//清空写入总长度
    image_header_was_checked = false;//获取到头标志清空
    
  3. 每接收到一包数据,进行调用

    esp_err_t err;
    if (image_header_was_checked == false) {//固件第一包数据 头检查
    	esp_app_desc_t new_app_info;
    	if (dat_len > sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t)) {
    		// check current version with downloading
    		memcpy(&new_app_info, &dat[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)], sizeof(esp_app_desc_t));
    		ESP_LOGI(TAG, "New firmware version: %s", new_app_info.version);
    
    		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);
    		}
    
    		const esp_partition_t* last_invalid_app = esp_ota_get_last_invalid_partition();
    		esp_app_desc_t invalid_app_info;
    		if (esp_ota_get_partition_description(last_invalid_app, &invalid_app_info) == ESP_OK) {
    			ESP_LOGI(TAG, "Last invalid firmware version: %s", invalid_app_info.version);
    		}
    
    		// check current version with last invalid partition
    		// 这部分可以不需要管,通常我们不用理这个版本。。。。。。
    		if (last_invalid_app != NULL) {
    			if (memcmp(invalid_app_info.version, new_app_info.version, sizeof(new_app_info.version)) == 0) {
    				ESP_LOGW(TAG, "New version is the same as invalid version.");
    				ESP_LOGW(TAG, "Previously, there was an attempt to launch the firmware with %s version, but it failed.", invalid_app_info.version);
    				ESP_LOGW(TAG, "The firmware has been rolled back to the previous version.");
    			}
    		}
    		image_header_was_checked = true;//表示已经收到头包数据了,并且检查正常
    
    		err = esp_ota_begin(update_partition, OTA_WITH_SEQUENTIAL_WRITES, &update_handle);//开始OTA
    		if (err != ESP_OK) {
    			ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
    			//http_cleanup(client);
    			esp_ota_abort(update_handle);
    			return COM_ERROR;
    		}
    		ESP_LOGI(TAG, "esp_ota_begin succeeded");
    	} else {
    		ESP_LOGE(TAG, "received package is not fit len");
    		//http_cleanup(client);
    		esp_ota_abort(update_handle);
    		return COM_ERROR;
    	}
    }
    
    //开始写入数据,注意头包检查成功后,esp_ota_begin后, 也要通过下面esp_ota_write进行写入
    //之后每一包都会进行写入
    err = esp_ota_write( update_handle, (const void *)dat, dat_len);
    if (err != ESP_OK) {
    	// http_cleanup(client);
    	esp_ota_abort(update_handle);
    }
    binary_file_length += dat_len;
    ESP_LOGI(TAG, "Written image length %d|%d", binary_file_length);
    
  4. OTA结束后调用

    	///>esp32
    	esp_err_t err;
    	ESP_LOGI(TAG, "Total Write binary data length: %d", binary_file_length);
        err = esp_ota_end(update_handle);//结束调用
        if (err != ESP_OK) {
            if (err == ESP_ERR_OTA_VALIDATE_FAILED) {
                ESP_LOGE(TAG, "Image validation failed, image is corrupted");
            } else {
                ESP_LOGE(TAG, "esp_ota_end failed (%s)!", esp_err_to_name(err));
            }
           // http_cleanup(client);
          //  task_fatal_error();
        }
    	///>下面进行设置启动分区
        err = esp_ota_set_boot_partition(update_partition);
        if (err != ESP_OK) {
            ESP_LOGE(TAG, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err));
           //http_cleanup(client);
           //task_fatal_error();
        }
        ESP_LOGI(TAG, "Prepare to restart system!");
    	///>成功复位
        esp_restart();
    

四、注意事项

  1. 获取头包时,注意适当增加长度,通常1K字节是没问题的,否则上面的实现中,检查头包长度时,会不过,若是收数据单包比较少,建议组包后才调用上面函数进行处理
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值