Sat, 27 Oct 2018 15:55:16 +0200
Boot now checks got IP status before installing the http and vnc servers.
/** * @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"; extern sButton Buttons[MAXBUTTONS]; extern int Main_Screen; 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; TFT_setFont(DEJAVU18_FONT, NULL); _fg = TFT_CYAN; const esp_partition_t *running = esp_ota_get_running_partition(); snprintf(temp, 63, "Running part.type %d sub %d,\r\nat offset 0x%08x\r\n", running->type, running->subtype, running->address); TFT_print(temp, 0, LASTY); /* * Don't use https because it costs more then 100K memory. */ esp_http_client_config_t update = { .url = "http://update.mbse.eu/ap1/fw/brewboard.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; } TFT_print("Begin download.\r\n", 0, LASTY); ESP_LOGI(TAG, "Download update %s size %d", update.url, content_length); int binary_file_length = 0; /*deal with all receive packet*/ 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) { 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 (esp_ota_end(update_handle) != ESP_OK) { ESP_LOGE(TAG, "esp_ota_end failed!"); goto updateerr; } snprintf(temp, 63, "Received image %d bytes\r\n", binary_file_length); TFT_print(temp, 0, LASTY); if (esp_partition_check_identity(esp_ota_get_running_partition(), update_partition) == true) { ESP_LOGI(TAG, "Already the latest version"); TFT_print("Already the latest version.\r\n", LASTX, LASTY); goto updateok; } /* * Here we have a different and hopefully newer 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!"); TFT_print("Rebooting ...", 0, LASTY); vTaskDelay(1000 / portTICK_PERIOD_MS); esp_restart(); return ; updateerr: _fg = TFT_RED; TFT_print("Error\r\n", 0, LASTY); updateok: vTaskDelay(3000 / portTICK_PERIOD_MS); } /** * @brief Download a file to /spiffs * @param filename The name and path of the file to download. * @return Return 0 if ok, negative if errors. */ int DownloadSpiffs(char *filename) { esp_err_t err; static char theurl[73], thefile[41]; FILE *f; // static char todel[41]; // snprintf(todel, 40, "/spiffs//%s", filename); // unlink(todel); // return 0; snprintf(theurl, 72, "http://update.mbse.eu/ap1/image/%s", filename); snprintf(thefile, 40, "/spiffs/%s", filename); esp_http_client_config_t update = { .url = theurl, }; esp_http_client_handle_t client = esp_http_client_init(&update); if (client == NULL) { ESP_LOGE(TAG, "Failed to init HTTP connection"); return -1; } 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 -1; } 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); return -1; } /* * Remove a possible stale download. */ unlink("/spiffs/tmpfile"); f = fopen("/spiffs/tmpfile", "w"); if (f == NULL) { ESP_LOGE(TAG, "Cannot create /spiffs/tmpfile"); esp_http_client_cleanup(client); return -1; } int read_length = 0; int write_length = 0; 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 %s", theurl); http_cleanup(client); return -1; } else if (data_read > 0) { size_t bytes = fwrite(ota_write_data, 1, data_read, f); if (bytes != data_read) { ESP_LOGE(TAG, "fwrite %s %d/%d at %d", theurl, bytes, data_read, write_length); } write_length += bytes; read_length += data_read; } else if (data_read == 0) { break; } vTaskDelay(5 / portTICK_PERIOD_MS); } fclose(f); if (content_length != write_length) { ESP_LOGE(TAG, "Download %s size %d but got %d bytes", theurl, content_length, write_length); unlink("/spiffs/tmpfile"); return -1; } ESP_LOGI(TAG, "Download %s size %d Ok", theurl, content_length); unlink(thefile); rename("/spiffs/tmpfile", thefile); esp_http_client_cleanup(client); return 0; } /** * @brief Update /spiffs filesystem */ void spiffs_update(void) { int rc; FILE *f; char v1[12], v2[12], fn[41]; TFT_setFont(DEJAVU18_FONT, NULL); _fg = TFT_CYAN; TFT_print("Update /spiffs ", 0, 25); rc = rename("/spiffs/version.txt", "/spiffs/version.old"); if ((rc != 0) && (errno == ENOENT)) { /* No old file. */ ESP_LOGI(TAG, "No old /spiffs/version.txt"); /* Download, install old and new */ DownloadSpiffs("version.txt"); rename("/spiffs/version.txt", "/spiffs/version.old"); DownloadSpiffs("version.txt"); goto spiffs_update; } if (DownloadSpiffs("version.txt") < 0) goto spiffs_error; /* Compare spiffs/version.old and /spiffs/version.txt */ v1[0] = '\0'; v2[0] = '\0'; f = fopen("/spiffs/version.old", "r"); if (f) { fgets(v1, 11, f); fclose(f); } f = fopen("/spiffs/version.txt", "r"); if (f) { fgets(v2, 11, f); fclose(f); } // ESP_LOG_BUFFER_HEXDUMP(TAG, v1, strlen(v1), ESP_LOG_INFO); // ESP_LOG_BUFFER_HEXDUMP(TAG, v2, strlen(v2), ESP_LOG_INFO); if (strcmp(v1, v2) == 0) { ESP_LOGI(TAG, "/spiffs is up to date"); TFT_print("Ok\r\n", LASTX, LASTY); unlink("/spiffs/version.old"); return; } spiffs_update: /* * Run the update, get the filelist. */ ESP_LOGI(TAG, "Full /spiffs update"); rc = DownloadSpiffs("files.list"); if (rc < 0) { unlink("/spiffs/version.txt"); rename("/spiffs/version.old", "/spiffs/version.txt"); // So next time we try again. goto spiffs_error; } f = fopen("/spiffs/files.list", "r"); while (fgets(fn, 40, f)) { fn[strlen(fn)-1] = '\0'; rc = DownloadSpiffs(fn); if (rc < 0) { ESP_LOGE(TAG, "Updates failed"); fclose(f); goto spiffs_error; } // vTaskDelay(10 / portTICK_PERIOD_MS); } fclose(f); unlink("/spiffs/version.old"); TFT_print("updated\r\n", LASTX, LASTY); return; spiffs_error: _fg = TFT_RED; TFT_print("error\r\n", LASTX, LASTY); } /* * Files init function, only runs once a new screen is entered. */ void Updates_Init(void) { switch (Main_Screen) { case MAIN_TOOLS_UPDATES: _bg = TFT_BLACK; TFT_fillScreen(_bg); TopMessage("Update"); break; default: break; } } /* * Updates management loop, non-blocking. */ void Updates_Loop(void) { switch (Main_Screen) { case MAIN_TOOLS_UPDATES: spiffs_update(); bin_update(); Main_Screen = MAIN_TOOLS; break; default: break; } }