ESP32 开发笔记——OTA

//****************************************************************************************************************************//
//****************************************************************************************************************************//
//*****************************************OTA部分****************************************************************************//
//****************************************************************************************************************************//
//****************************************************************************************************************************//
//****************************************************************************************************************************//

/*******************************************************************************
* Function Name  : http_cleanup
* Description  : 关闭http服务
* Input   : None 
* Output  : None 
* Return  : None
*******************************************************************************/
static void http_cleanup(esp_http_client_handle_t client)
{
    esp_http_client_close(client);
    esp_http_client_cleanup(client);
}

// static void __attribute__((noreturn)) task_fatal_error(void)
// {
//     ESP_LOGE(TAG, "Exiting task due to fatal error...");
//     (void)vTaskDelete(NULL);

//     while (1) {
//         ;
//     }
// }

static void print_sha256 (const uint8_t *image_hash, const char *label)
{
    char hash_print[HASH_LEN * 2 + 1];
    hash_print[HASH_LEN * 2] = 0;
    for (int i = 0; i < HASH_LEN; ++i) {
        sprintf(&hash_print[i * 2], "%02x", image_hash[i]);
    }
    ESP_LOGI(TAG, "%s: %s", label, hash_print);
}
/*******************************************************************************
* Function Name  : ota_init
* Description  : ota_init 初始化
* Input   : None 
* Output  : None 
* Return  : None
*******************************************************************************/
void ota_init(void)
{
    uint8_t sha_256[HASH_LEN] = { 0 };
    esp_partition_t partition;

    //分区表sha256
    partition.address   = ESP_PARTITION_TABLE_OFFSET;//CONFIG_PARTITION_TABLE_OFFSET:分区表偏移0x8000
    partition.size      = ESP_PARTITION_TABLE_MAX_LEN;//0xC00=3K 
    partition.type      = ESP_PARTITION_TYPE_DATA;
    esp_partition_get_sha256(&partition, sha_256);
    print_sha256(sha_256, "SHA-256 for the partition table: ");

    //boot sha256
    partition.address   = ESP_BOOTLOADER_OFFSET;//CONFIG_BOOTLOADER_OFFSET_IN_FLASH:boot偏移0x1000
    // partition.size      = ESP_PARTITION_TABLE_OFFSET;//此处官方代码有问题,修改成如下
    partition.size      = ESP_PARTITION_TABLE_OFFSET-ESP_BOOTLOADER_OFFSET;//0x8000-0x1000=0x7000=28K
    partition.type      = ESP_PARTITION_TYPE_APP;
    esp_partition_get_sha256(&partition, sha_256);
    print_sha256(sha_256, "SHA-256 for bootloader: ");

    //应用程序sha256
    esp_partition_get_sha256(esp_ota_get_running_partition(), sha_256);//应用程序
    print_sha256(sha_256, "SHA-256 for current firmware: ");

    ESP_LOGI(TAG, "----------------------------------------------------------------------");

    //获取当前运行APP分区信息
    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) {
            //检查能否运行
            bool diagnostic_is_ok = 1;
            if (diagnostic_is_ok) {
                ESP_LOGI(TAG, "Diagnostics completed successfully! Continuing execution ...");
                //当前APP运行正常,不用回滚
                esp_ota_mark_app_valid_cancel_rollback();
            } else {
                ESP_LOGE(TAG, "Diagnostics failed! Start rollback to the previous version ...");
                //回滚到以前可用的应用程序,重启
                esp_ota_mark_app_invalid_rollback_and_reboot();
            }
        }else{
            ESP_LOGE(TAG, "ota_state != ESP_OTA_IMG_PENDING_VERIFY   : = ota_state = %d",ota_state);    
        }
    }else{
        ESP_LOGE(TAG, "error esp_ota_get_state_partition");    
    }
    
    //读取当前运行app的版本号
    esp_app_desc_t running_app_infor;
    if (esp_ota_get_partition_description(running, &running_app_infor) == ESP_OK) {
        ESP_LOGI(TAG, "Running firmware version: %s", running_app_infor.version);
    }
}
/*******************************************************************************
* Function Name  : ota_example_task
* Description  : 固件升级
* Input   : file_buf:url地址
* Output  : None 
* Return  : None
*******************************************************************************/
void ota_example_task(char * file_buf)//void *pvParameter
{
    esp_err_t err;
    /* update handle : set by esp_ota_begin(), must be freed via esp_ota_end() */
    esp_ota_handle_t update_handle = 0 ;
    const esp_partition_t *update_partition = NULL;

    ESP_LOGI(TAG, "Starting OTA example");

    const esp_partition_t *configured = esp_ota_get_boot_partition();
    const esp_partition_t *running = esp_ota_get_running_partition();

    if (configured != running) {
        ESP_LOGW(TAG, "Configured OTA boot partition at offset 0x%08"PRIx32", but running from offset 0x%08"PRIx32,
                 configured->address, running->address);
        ESP_LOGW(TAG, "(This can happen if either the OTA boot data or preferred boot image become corrupted somehow.)");
    }
    ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08"PRIx32")",
             running->type, running->subtype, running->address);

    esp_http_client_config_t config = {
        .url = file_buf,//"http://192.168.2.53:8070/1.bin"
        // .cert_pem = (char *)server_cert_pem_start,
        // .crt_bundle_attach = esp_crt_bundle_attach,
        .timeout_ms = 5000,
        .keep_alive_enable = true,
    };

#ifdef CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL_FROM_STDIN
    char url_buf[OTA_URL_SIZE];
    if (strcmp(config.url, "FROM_STDIN") == 0) {
        example_configure_stdin_stdout();
        fgets(url_buf, OTA_URL_SIZE, stdin);
        int len = strlen(url_buf);
        url_buf[len - 1] = '\0';
        config.url = url_buf;
    } else {
        ESP_LOGE(TAG, "Configuration mismatch: wrong firmware upgrade image url");
        abort();
    }
#endif

#ifdef CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK
    config.skip_cert_common_name_check = true;
#endif
    esp_http_client_handle_t client = esp_http_client_init(&config);
    if (client == NULL) {
        ESP_LOGE(TAG, "Failed to initialise HTTP connection");
        // task_fatal_error();
        uart_write_bytes(UART_NUM_1, (const char *) "B8.2", strlen("B8.2"));//http连接失败
        return;
    }
    err = esp_http_client_open(client, 0);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
        esp_http_client_cleanup(client);
        // task_fatal_error();
        uart_write_bytes(UART_NUM_1, (const char *) "B8.2", strlen("B8.2"));//http连接失败
        return;
    }
    //获取http头
    esp_http_client_fetch_headers(client);

    //获取下一个可用的OTA分区,用于存储OTA数据
    update_partition = esp_ota_get_next_update_partition(NULL);
    assert(update_partition != NULL);
    ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%"PRIx32,
             update_partition->subtype, update_partition->address);

    int binary_file_length = 0;
    /*deal with all receive packet*/
    bool image_header_was_checked = false;
    while (1) {
        //读取http数据
        int data_read = esp_http_client_read(client, ota_write_data, BUFFSIZE);
        if (data_read < 0) {//异常
            ESP_LOGE(TAG, "Error: SSL data read error");
            http_cleanup(client);
            uart_write_bytes(UART_NUM_1, (const char *) "B8.2", strlen("B8.2"));//升级失败
            return;
            // task_fatal_error();
        } else 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)) {
                    
                    //比较三个版本号,
                    //读取OTA的版本号
                    memcpy(&new_app_info, &ota_write_data[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);

                    //读取当前运行app的版本号
                    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);
                    }
                    //获取无效分区(下一个可用的分区)app的版本号
                    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) {
                        //OTA版本和无效分区版本相同退出,不下载
                        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.");
                            http_cleanup(client);
                            //infinite_loop();
                            return ;
                        }
                    }
#ifndef CONFIG_EXAMPLE_SKIP_VERSION_CHECK
                    //OTA版本和当前版本相同退出,不下载,可以跳过检查版本
                    // 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.");
                    //     http_cleanup(client);
                    //     // infinite_loop();
                    //     uart_write_bytes(UART_NUM_1, (const char *) "B8.1", strlen("B8.1"));//版本一致,不需要升级
                    //     return ;
                    // }
#endif

                    //头结束,准备接受OTA数据包
                    image_header_was_checked = true;
                    //开始OTA保存(先擦除),放在可用的OTA分区
                    err = esp_ota_begin(update_partition, OTA_WITH_SEQUENTIAL_WRITES, &update_handle);
                    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);
                        uart_write_bytes(UART_NUM_1, (const char *) "B8.2", strlen("B8.2"));//升级失败
                        return;
                        // task_fatal_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);
                    uart_write_bytes(UART_NUM_1, (const char *) "B8.2", strlen("B8.2"));//升级失败
                    return;
                    // task_fatal_error();
                }
            }
            //保存OTA数据包
            err = esp_ota_write( update_handle, (const void *)ota_write_data, data_read);
            if (err != ESP_OK) {
                http_cleanup(client);
                esp_ota_abort(update_handle);
                uart_write_bytes(UART_NUM_1, (const char *) "B8.2", strlen("B8.2"));//升级失败
                // task_fatal_error();
                return;
            }
            //总的OTA数据长度
            binary_file_length += data_read;
            ESP_LOGI(TAG, "Written image length %d", binary_file_length);
        } else if (data_read == 0) {//OTA结束,http连接断开
           /*
            * As esp_http_client_read never returns negative error code, we rely on
            * `errno` to check for underlying transport connectivity closure if any
            */
            if (errno == ECONNRESET || errno == ENOTCONN) {
                ESP_LOGE(TAG, "Connection closed, errno = %d", errno);
                break;
            }
            if (esp_http_client_is_complete_data_received(client) == true) {
                ESP_LOGI(TAG, "Connection closed");
                break;
            }
        }
    }
    ESP_LOGI(TAG, "Total Write binary data length: %d", binary_file_length);

    //检查是否读取了http响应中的整个数据而没有任何错误
    if (esp_http_client_is_complete_data_received(client) != true) {
        ESP_LOGE(TAG, "Error in receiving complete file");
        http_cleanup(client);
        esp_ota_abort(update_handle);
        // task_fatal_error();
        uart_write_bytes(UART_NUM_1, (const char *) "B8.2", strlen("B8.2"));//升级失败
        return;
    }
    //OTA保存结束,与esp_ota_begin对应,esp_ota_write居中保存
    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");
        }
        ESP_LOGE(TAG, "esp_ota_end failed (%s)!", esp_err_to_name(err));
        http_cleanup(client);
        // task_fatal_error();
        uart_write_bytes(UART_NUM_1, (const char *) "B8.2", strlen("B8.2"));//升级失败
        return;
    }
    //设置启动新的OTA分区APP
    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();
        uart_write_bytes(UART_NUM_1, (const char *) "B8.2", strlen("B8.2"));//升级失败
        return;
    }
    uart_write_bytes(UART_NUM_1, (const char *) "B8.0", strlen("B8.0"));//升级成功返回
    //重启
    ESP_LOGI(TAG, "Prepare to restart system!");
    esp_restart();
    return ;
}
/*******************************************************************************
* Function Name  : ota_version_read
* Description  : 固件版本读取
* Input   : None 
* Output  : None 
* Return  : None
*******************************************************************************/
void ota_version_read(void)
{
    const esp_partition_t *running = esp_ota_get_running_partition();
     //读取当前运行app的版本号
    esp_app_desc_t running_app_infor;
    if (esp_ota_get_partition_description(running, &running_app_infor) == ESP_OK) {
        ESP_LOGI(TAG, "Running firmware version: %s", running_app_infor.version);
    }
    char device_version_read[50];
    sprintf(device_version_read,"B9=%s",running_app_infor.version);
    uart_write_bytes(UART_NUM_1, (const char *) device_version_read, strlen(device_version_read));

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值