2024-05-17 14:34:21 -07:00

250 lines
6.9 KiB
C++

/*
* OTA.cpp
*
* Created on: Apr 23, 2019
* Author: miro
*/
#include "App.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_log.h"
#include "esp_ota_ops.h"
#include "esp_http_client.h"
#include "esp_flash_partitions.h"
#include "esp_partition.h"
#include "string.h"
#include "OTA.h"
#define OTA_URL "http://192.168.1.131/wellhub.bin"
static const char *TAG = "OTA";
#define _FORCE_UPDATE
namespace ota_update
{
OTA::OTA(App & app) : m_app(app)
{
}
void OTA::httpCleanup(esp_http_client_handle_t client)
{
esp_http_client_close(client);
esp_http_client_cleanup(client);
}
void OTA::taskFatalError()
{
ESP_LOGE(TAG, "Exiting task due to fatal error...");
(void) vTaskDelete(NULL);
while (1)
{
;
}
}
void OTA::start()
{
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 check...");
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%08x, but running from offset 0x%08x",
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%08x)", running->type, running->subtype,
running->address);
esp_http_client_config_t config = { };
config.url = OTA_URL;
esp_http_client_handle_t client = esp_http_client_init(&config);
if (client == NULL)
{
ESP_LOGE(TAG, "Failed to initialize HTTP connection");
}
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);
return;
}
esp_http_client_fetch_headers(client);
int remote_len = esp_http_client_get_content_length(client);
ESP_LOGI(TAG,"remote len %d", remote_len);
update_partition = esp_ota_get_next_update_partition(NULL);
ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x", update_partition->subtype,
update_partition->address);
assert(update_partition != NULL);
int binary_file_length = 0;
/*deal with all receive packet*/
bool image_header_was_checked = false;
while (1)
{
int data_read = esp_http_client_read(client, otaWriteData, BUFFSIZE);
if (data_read < 0)
{
ESP_LOGE(TAG, "Error: SSL data read error");
esp_http_client_close(client);
esp_http_client_cleanup(client);
taskFatalError();
}
else if (data_read > 0)
{
//printf(".");
if (image_header_was_checked == false)
{
// this is the first 1k of received image
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,
&otaWriteData[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)],
sizeof(esp_app_desc_t));
ESP_LOGI(TAG, "New firmware");
ESP_LOGI(TAG, "version: %s", new_app_info.version);
ESP_LOGI(TAG, " name: %s", new_app_info.project_name);
ESP_LOGI(TAG, " c time: %s", new_app_info.time);
ESP_LOGI(TAG, " c date: %s", new_app_info.date);
ESP_LOGI(TAG, "idf ver: %s", new_app_info.idf_ver);
//ESP_LOGI(TAG, " sha: %s", new_app_info.app_elf_sha256);
esp_app_desc_t running_app_info;
if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK)
{
ESP_LOGI(TAG, "");
ESP_LOGI(TAG, "Running firmware");
ESP_LOGI(TAG, "version: %s", running_app_info.version);
ESP_LOGI(TAG, " name: %s", running_app_info.project_name);
ESP_LOGI(TAG, " c time: %s", running_app_info.time);
ESP_LOGI(TAG, " c date: %s", running_app_info.date);
ESP_LOGI(TAG, "idf ver: %s", running_app_info.idf_ver);
// ESP_LOGI(TAG, " sha: %s", running_app_info.app_elf_sha256);
}
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) + sizeof(new_app_info.project_name) + sizeof(new_app_info.time)) == 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.");
httpCleanup(client);
return;
}
}
#ifndef FORCE_UPDATE
if (memcmp(new_app_info.version, running_app_info.version, sizeof(new_app_info.version) + sizeof(new_app_info.project_name) + sizeof(new_app_info.time) + sizeof(new_app_info.date)) == 0)
{
ESP_LOGW(TAG, "Current running version is the same as a remote. No need for update.");
httpCleanup(client);
return;
}
#endif
m_app.m_led->setPulse(255, 0, 255);
image_header_was_checked = true;
err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle);
if (err != ESP_OK)
{
ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
httpCleanup(client);
taskFatalError();
}
ESP_LOGI(TAG, "esp_ota_begin succeeded");
}
else
{
ESP_LOGE(TAG, "received package does not fit len");
httpCleanup(client);
taskFatalError();
}
}
err = esp_ota_write(update_handle, (const void *) otaWriteData, data_read);
if (err != ESP_OK)
{
httpCleanup(client);
taskFatalError();
}
binary_file_length += data_read;
int progress = binary_file_length*100/remote_len;
static int last_reported = -1;
if(last_reported != progress)
{
last_reported = progress;
ESP_LOGI(TAG, "%d%%", last_reported);
}
}
else if (data_read == 0)
{
ESP_LOGI(TAG, "Connection closed,all data received");
break;
}
}
printf("\n");
ESP_LOGI(TAG, "Total Write binary data length : %d", binary_file_length);
if (esp_ota_end(update_handle) != ESP_OK)
{
ESP_LOGE(TAG, "esp_ota_end failed!");
httpCleanup(client);
taskFatalError();
}
ESP_LOGI(TAG, "esp_ota_end");
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));
httpCleanup(client);
taskFatalError();
}
ESP_LOGI(TAG, "Prepare to restart system!");
esp_restart();
return;
}
OTA::~OTA()
{
}
}