diff --git a/esp32_device/main/ota.c b/esp32_device/main/ota.c index d76339f..e49311b 100644 --- a/esp32_device/main/ota.c +++ b/esp32_device/main/ota.c @@ -2,15 +2,25 @@ #include "esp_partition.h" #include "esp_ota_ops.h" #include "esp_http_client.h" +#include "esp_app_format.h" #include "constants.h" #include "ota.h" #include "storage.h" +#include "secure_api.h" #include const char *TAG = "ota"; +#define BUFF_SIZE 1024 + +static void http_cleanup(esp_http_client_handle_t client) +{ + esp_http_client_close(client); + esp_http_client_cleanup(client); +} + bool ota_perform_update(const char *version) { const esp_partition_t *configured = esp_ota_get_boot_partition(); @@ -72,5 +82,151 @@ bool ota_perform_update(const char *version) ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%" PRIx32, update_partition->subtype, update_partition->address); - return false; + // OTA update loop + int binary_file_length = 0; + esp_ota_handle_t update_handle = 0; + /*deal with all receive packet*/ + bool image_header_was_checked = false; + char *ota_write_data = calloc(BUFF_SIZE + 1, 1); + while (1) + { + int data_read = esp_http_client_read(client, ota_write_data, BUFF_SIZE); + if (data_read < 0) + { + ESP_LOGE(TAG, "Error: SSL data read error"); + http_cleanup(client); + free(ota_write_data); + return false; + } + + if (data_read == 0) + { + /* + * 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; + } + + // No data received yet + continue; + } + + 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 + 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); + + 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."); + http_cleanup(client); + free(ota_write_data); + secure_api_report_log_message(Error, "New version is the same as last invalid version. Could not perform update!"); + return false; + } + } + + image_header_was_checked = true; + + 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); + free(ota_write_data); + esp_ota_abort(update_handle); + return false; + } + ESP_LOGI(TAG, "esp_ota_begin succeeded"); + } + else + { + ESP_LOGE(TAG, "received package is not fit len"); + http_cleanup(client); + free(ota_write_data); + esp_ota_abort(update_handle); + return false; + } + } + err = esp_ota_write(update_handle, (const void *)ota_write_data, data_read); + if (err != ESP_OK) + { + http_cleanup(client); + free(ota_write_data); + esp_ota_abort(update_handle); + return false; + } + binary_file_length += data_read; + ESP_LOGD(TAG, "Written image length %d", binary_file_length); + } + free(ota_write_data); + + ESP_LOGI(TAG, "Total Write binary data length: %d", binary_file_length); + 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); + return false; + } + + 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); + return false; + } + + 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); + + return false; + } + + ESP_LOGI(TAG, "End of OTA procedure!"); + + return true; } \ No newline at end of file