main/updates.c

Fri, 08 Nov 2019 22:40:15 +0100

author
Michiel Broek <mbroek@mbse.eu>
date
Fri, 08 Nov 2019 22:40:15 +0100
changeset 26
8a3696620c0a
parent 0
88d965579617
child 27
8bb63daa7b46
permissions
-rw-r--r--

Increaded stacksize for the user process. Implemented the network update using the proven brewboard code. Reverted the lock release and display sendbuffer lines to the previous code. The networks status screen uses the wifi lock.

/**
 * @file updates.c
 * @brief Updates management. It can download and install new firmware
 *        downloaded from the internet.
 */

#include "config.h"


#define BUFFSIZE 1024					///< Download buffer size
static char ota_write_data[BUFFSIZE + 1] = { 0 };
static const char               *TAG = "update";
int				update_running = 0;	///< Not zero if update is running.

extern u8g2_t			u8g2;			///< Structure for the display.
extern int			Main_Loop1;


static void http_cleanup(esp_http_client_handle_t client)
{
    esp_http_client_close(client);
    esp_http_client_cleanup(client);
}



/**
 * @brief Run binary update procedure
 */
void bin_update(void)
{
    char                        temp[64];
    esp_err_t                   err;
    const esp_partition_t       *update_partition = NULL;
    esp_ota_handle_t            update_handle = 0;

    ESP_LOGI(TAG, "Update begin");
    update_running = 1;
    screen_updating("Stop tests", NULL);
    requestWiFi_user(true);

    for (;;) {
	vTaskDelay(50 / portTICK_PERIOD_MS);
	if (ready_WiFi() && Main_Loop1 == ML1_DONE)
	    break;
    }
    ESP_LOGI(TAG, "System is ready for update");
    screen_updating("Prepare update", NULL);

    const esp_partition_t       *running = esp_ota_get_running_partition();

    /*
     * Don't use https because it costs more then 100K memory.
     */
    esp_http_client_config_t update = {
	.url = "http://update.mbse.eu/ap2/fw/co2meter.bin",
    };

    esp_http_client_handle_t client = esp_http_client_init(&update);
    if (client == NULL) {
	ESP_LOGI(TAG, "Failed to init HTTP connection");
	goto updateerr;
    }

    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);
	goto updateerr;
    }

    int content_length = esp_http_client_fetch_headers(client);
    int status_code = esp_http_client_get_status_code(client);
    if (status_code != 200) {
	ESP_LOGE(TAG, "GET %s error %d", update.url, status_code);
	esp_http_client_cleanup(client);
	goto updateerr;
    }
    update_partition = esp_ota_get_next_update_partition(NULL);
    if (update_partition == NULL) {
	ESP_LOGE(TAG, "No update partition");
	esp_http_client_cleanup(client);
	goto updateerr;
    }
    ESP_LOGI(TAG, "Update to partition subtype %d at offset 0x%x", update_partition->subtype, update_partition->address);

    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));
	http_cleanup(client);
	goto updateerr;
    }

    screen_updating("Begin download", NULL);
    ESP_LOGI(TAG, "Download update %s size %d", update.url, content_length);
    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, ota_write_data, BUFFSIZE);
	if (data_read < 0) {
	    ESP_LOGE(TAG, "Error: data read error");
	    http_cleanup(client);
	    goto updateerr;;
	} 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)) {
                    // 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_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, %s %s", running_app_info.version, running_app_info.date, running_app_info.time);
                    }

                    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 sha256 with last invalid partition
                    if (last_invalid_app != NULL) {
                        if (memcmp(invalid_app_info.app_elf_sha256, new_app_info.app_elf_sha256, 32) == 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);
			    goto updateok;
                        }
                    }

		    if (memcmp(new_app_info.app_elf_sha256, running_app_info.app_elf_sha256, 32) == 0) {
			screen_updating("No new update", NULL);
                        ESP_LOGI(TAG, "Current running version is the same as a new.");
                        http_cleanup(client);
			goto updateok;
                    }

                    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));
                        http_cleanup(client);
			goto updateerr;
                    }
                    ESP_LOGI(TAG, "Continue upgrade application");
                } else {
                    ESP_LOGE(TAG, "Received package is not fit len");
                    http_cleanup(client);
		    goto updateerr;
                }
	    }
	    err = esp_ota_write( update_handle, (const void *)ota_write_data, data_read);
	    if (err != ESP_OK) {
		http_cleanup(client);
		goto updateerr;;
	    }
	    binary_file_length += data_read;
	    ESP_LOGD(TAG, "Written image length %d", binary_file_length);
	} else if (data_read == 0) {
	    break;
	}
    }

    ESP_LOGI(TAG, "Download complete, binary data length: %d", binary_file_length);
    http_cleanup(client);

    if (binary_file_length != content_length) {
	ESP_LOGE(TAG, "Incomplete file");
	goto updateerr;
    }
    if (esp_ota_end(update_handle) != ESP_OK) {
	ESP_LOGE(TAG, "esp_ota_end failed!");
	goto updateerr;
    }
    snprintf(temp, 63, "Ok %d bytes", binary_file_length);
    screen_updating("Begin download", temp);

    /*
     * Here we have new version, install and boot it.
     */
    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));
	goto updateerr;
    }

    ESP_LOGI(TAG, "Prepare to restart system!");
    screen_updating("Reboot...", "...Reboot");
    vTaskDelay(1000 / portTICK_PERIOD_MS);
    update_running = 0;
    esp_restart();
    return;

updateerr:
    screen_updating("** ERROR **", "Update failed");

updateok:
    update_running = 0;
    requestWiFi_user(false);
    vTaskDelay(3000 / portTICK_PERIOD_MS);
}

mercurial