main/updates.c

Sat, 14 Mar 2020 13:07:02 +0100

author
Michiel Broek <mbroek@mbse.eu>
date
Sat, 14 Mar 2020 13:07:02 +0100
changeset 47
1ab1f4a8c328
parent 41
d327e0aff62f
child 53
20c14b06f255
permissions
-rw-r--r--

Version 0.2.2 Changed to use a permanent network and WiFi connection. Removed three mainloop stages. Removed MQTT sequence counter that was not used. Update WiFi rssi status during eacht measure cycle. Changed FreeRTOS schedulng to 500 Hz.

/**
 * @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)
{
    esp_err_t                   err;
    const esp_partition_t       *update_partition = NULL;
    esp_ota_handle_t            update_handle = 0;
    int				timeout = 600;

    ESP_LOGI(TAG, "Update begin");
    update_running = 1;
    screen_updating("Stop meten", NULL);

    for (;;) {
	vTaskDelay(100 / portTICK_PERIOD_MS);
	if (Main_Loop1 == ML1_DONE)
	    break;
	if (timeout)
	    timeout--;
	else {
	    ESP_LOGE(TAG, "Timout request stop");
	    goto updateerr;
	}
    }

    screen_updating("Stop meten", "Start WiFi");
    timeout = 600;
    for (;;) {
        vTaskDelay(100 / portTICK_PERIOD_MS);
        if (ready_WiFi())
            break;
	if (timeout)
            timeout--;
        else {
            ESP_LOGE(TAG, "Timout request WiFi");
            goto updateerr;
        }
    }
    ESP_LOGI(TAG, "System is ready for update");
    screen_updating("Verbonden", 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("Start 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("Geen nieuwe versie", 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");
		    screen_updating("Start download", "Nieuwe versie!");
                } 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;
    }

    /*
     * 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("Herstart ...", "... Herstart");
    vTaskDelay(1000 / portTICK_PERIOD_MS);
    update_running = 0;
    esp_restart();
    return;

updateerr:
    screen_updating("** FOUT **", "Update mislukt");

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

mercurial