From 5fa9b4e9eb33beb1fc7b308865c0449a806905e6 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Thu, 24 Jan 2019 14:59:00 +0800 Subject: [PATCH 1/4] feat(ota): Remove raw OTA example --- examples/system/ota/Makefile | 9 - examples/system/ota/OTA_workflow.png | Bin 57443 -> 0 bytes examples/system/ota/README.md | 101 ------- examples/system/ota/main/Kconfig.projbuild | 40 --- examples/system/ota/main/component.mk | 4 - examples/system/ota/main/ota_example_main.c | 310 -------------------- examples/system/ota/sdkconfig.defaults | 4 - 7 files changed, 468 deletions(-) delete mode 100644 examples/system/ota/Makefile delete mode 100644 examples/system/ota/OTA_workflow.png delete mode 100644 examples/system/ota/README.md delete mode 100644 examples/system/ota/main/Kconfig.projbuild delete mode 100644 examples/system/ota/main/component.mk delete mode 100644 examples/system/ota/main/ota_example_main.c delete mode 100644 examples/system/ota/sdkconfig.defaults diff --git a/examples/system/ota/Makefile b/examples/system/ota/Makefile deleted file mode 100644 index 7ffb1023..00000000 --- a/examples/system/ota/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# This is a project Makefile. It is assumed the directory this Makefile resides in is a -# project subdirectory. -# - -PROJECT_NAME := ota - -include $(IDF_PATH)/make/project.mk - diff --git a/examples/system/ota/OTA_workflow.png b/examples/system/ota/OTA_workflow.png deleted file mode 100644 index 5fd4c3e91d728c707c29b9c42a62be3926f7bdf5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 57443 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 -#include -#include -#include - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/event_groups.h" - -#include "esp_system.h" -#include "esp_wifi.h" -#include "esp_event_loop.h" -#include "esp_log.h" -#include "esp_ota_ops.h" - -#include "nvs.h" -#include "nvs_flash.h" - -#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID -#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD -#define EXAMPLE_SERVER_IP CONFIG_SERVER_IP -#define EXAMPLE_SERVER_PORT CONFIG_SERVER_PORT -#define EXAMPLE_FILENAME CONFIG_EXAMPLE_FILENAME -#define BUFFSIZE 1500 -#define TEXT_BUFFSIZE 1024 - -static const char *TAG = "ota"; -/*an ota data write buffer ready to write to the flash*/ -static char ota_write_data[BUFFSIZE + 1] = { 0 }; -/*an packet receive buffer*/ -static char text[BUFFSIZE + 1] = { 0 }; -/* an image total length*/ -static int binary_file_length = 0; -/*socket id*/ -static int socket_id = -1; - -/* FreeRTOS event group to signal when we are connected & ready to make a request */ -static EventGroupHandle_t wifi_event_group; - -/* The event group allows multiple bits for each event, - but we only care about one event - are we connected - to the AP with an IP? */ -const int CONNECTED_BIT = BIT0; - -static esp_err_t event_handler(void *ctx, system_event_t *event) -{ - switch (event->event_id) { - case SYSTEM_EVENT_STA_START: - esp_wifi_connect(); - break; - case SYSTEM_EVENT_STA_GOT_IP: - xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); - break; - case SYSTEM_EVENT_STA_DISCONNECTED: - /* This is a workaround as ESP32 WiFi libs don't currently - auto-reassociate. */ - esp_wifi_connect(); - xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); - break; - default: - break; - } - return ESP_OK; -} - -static void initialise_wifi(void) -{ - tcpip_adapter_init(); - wifi_event_group = xEventGroupCreate(); - ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) ); - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - ESP_ERROR_CHECK( esp_wifi_init(&cfg) ); - ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) ); - wifi_config_t wifi_config = { - .sta = { - .ssid = EXAMPLE_WIFI_SSID, - .password = EXAMPLE_WIFI_PASS, - }, - }; - ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid); - ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); - ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) ); - ESP_ERROR_CHECK( esp_wifi_start() ); -} - -/*read buffer by byte still delim ,return read bytes counts*/ -static int read_until(char *buffer, char delim, int len) -{ -// /*TODO: delim check,buffer check,further: do an buffer length limited*/ - int i = 0; - while (buffer[i] != delim && i < len) { - ++i; - } - return i + 1; -} - -/* resolve a packet from http socket - * return true if packet including \r\n\r\n that means http packet header finished,start to receive packet body - * otherwise return false - * */ -static bool read_past_http_header(char text[], int total_len, esp_ota_handle_t update_handle) -{ - /* i means current position */ - int i = 0, i_read_len = 0; - while (text[i] != 0 && i < total_len) { - i_read_len = read_until(&text[i], '\n', total_len); - // if we resolve \r\n line,we think packet header is finished - if (i_read_len == 2) { - int i_write_len = total_len - (i + 2); - memset(ota_write_data, 0, BUFFSIZE); - /*copy first http packet body to write buffer*/ - memcpy(ota_write_data, &(text[i + 2]), i_write_len); - - esp_err_t err = esp_ota_write( update_handle, (const void *)ota_write_data, i_write_len); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Error: esp_ota_write failed! err=0x%x", err); - return false; - } else { - ESP_LOGI(TAG, "esp_ota_write header OK"); - binary_file_length += i_write_len; - } - return true; - } - i += i_read_len; - } - return false; -} - -static bool connect_to_http_server() -{ - ESP_LOGI(TAG, "Server IP: %s Server Port:%s", EXAMPLE_SERVER_IP, EXAMPLE_SERVER_PORT); - - int http_connect_flag = -1; - struct sockaddr_in sock_info; - - socket_id = socket(AF_INET, SOCK_STREAM, 0); - if (socket_id == -1) { - ESP_LOGE(TAG, "Create socket failed!"); - return false; - } - - // set connect info - memset(&sock_info, 0, sizeof(struct sockaddr_in)); - sock_info.sin_family = AF_INET; - sock_info.sin_addr.s_addr = inet_addr(EXAMPLE_SERVER_IP); - sock_info.sin_port = htons(atoi(EXAMPLE_SERVER_PORT)); - - // connect to http server - http_connect_flag = connect(socket_id, (struct sockaddr *)&sock_info, sizeof(sock_info)); - if (http_connect_flag == -1) { - ESP_LOGE(TAG, "Connect to server failed! errno=%d", errno); - close(socket_id); - return false; - } else { - ESP_LOGI(TAG, "Connected to server"); - return true; - } - return false; -} - -static void __attribute__((noreturn)) task_fatal_error() -{ - ESP_LOGE(TAG, "Exiting task due to fatal error..."); - close(socket_id); - (void)vTaskDelete(NULL); - - while (1) { - ; - } -} - -static void ota_example_task(void *pvParameter) -{ - 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 example..."); - - 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); - - /* Wait for the callback to set the CONNECTED_BIT in the - event group. - */ - xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, - false, true, portMAX_DELAY); - ESP_LOGI(TAG, "Connect to Wifi ! Start to Connect to Server...."); - - /*connect to http server*/ - if (connect_to_http_server()) { - ESP_LOGI(TAG, "Connected to http server"); - } else { - ESP_LOGE(TAG, "Connect to http server failed!"); - task_fatal_error(); - } - - /*send GET request to http server*/ - const char *GET_FORMAT = - "GET %s HTTP/1.0\r\n" - "Host: %s:%s\r\n" - "User-Agent: esp-idf/1.0 esp32\r\n\r\n"; - - char *http_request = NULL; - int get_len = asprintf(&http_request, GET_FORMAT, EXAMPLE_FILENAME, EXAMPLE_SERVER_IP, EXAMPLE_SERVER_PORT); - if (get_len < 0) { - ESP_LOGE(TAG, "Failed to allocate memory for GET request buffer"); - task_fatal_error(); - } - int res = send(socket_id, http_request, get_len, 0); - free(http_request); - - if (res < 0) { - ESP_LOGE(TAG, "Send GET request to server failed"); - task_fatal_error(); - } else { - ESP_LOGI(TAG, "Send GET request to server succeeded"); - } - - 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); - - err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle); - if (err != ESP_OK) { - ESP_LOGE(TAG, "esp_ota_begin failed, error=%d", err); - task_fatal_error(); - } - ESP_LOGI(TAG, "esp_ota_begin succeeded"); - - bool resp_body_start = false, flag = true; - /*deal with all receive packet*/ - while (flag) { - memset(text, 0, TEXT_BUFFSIZE); - memset(ota_write_data, 0, BUFFSIZE); - int buff_len = recv(socket_id, text, TEXT_BUFFSIZE, 0); - if (buff_len < 0) { /*receive error*/ - ESP_LOGE(TAG, "Error: receive data error! errno=%d", errno); - task_fatal_error(); - } else if (buff_len > 0 && !resp_body_start) { /*deal with response header*/ - memcpy(ota_write_data, text, buff_len); - resp_body_start = read_past_http_header(text, buff_len, update_handle); - } else if (buff_len > 0 && resp_body_start) { /*deal with response body*/ - memcpy(ota_write_data, text, buff_len); - err = esp_ota_write( update_handle, (const void *)ota_write_data, buff_len); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Error: esp_ota_write failed! err=0x%x", err); - task_fatal_error(); - } - binary_file_length += buff_len; - ESP_LOGI(TAG, "Have written image length %d", binary_file_length); - } else if (buff_len == 0) { /*packet over*/ - flag = false; - ESP_LOGI(TAG, "Connection closed, all packets received"); - close(socket_id); - } else { - ESP_LOGE(TAG, "Unexpected recv result"); - } - } - - 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!"); - task_fatal_error(); - } - err = esp_ota_set_boot_partition(update_partition); - if (err != ESP_OK) { - ESP_LOGE(TAG, "esp_ota_set_boot_partition failed! err=0x%x", err); - task_fatal_error(); - } - ESP_LOGI(TAG, "Prepare to restart system!"); - esp_restart(); - return ; -} - -void app_main() -{ - // Initialize NVS. - esp_err_t err = nvs_flash_init(); - if (err == ESP_ERR_NVS_NO_FREE_PAGES) { - // OTA app partition table has a smaller NVS partition size than the non-OTA - // partition table. This size mismatch may cause NVS initialization to fail. - // If this happens, we erase NVS partition and initialize NVS again. - ESP_ERROR_CHECK(nvs_flash_erase()); - err = nvs_flash_init(); - } - ESP_ERROR_CHECK( err ); - - initialise_wifi(); - xTaskCreate(&ota_example_task, "ota_example_task", 8192, NULL, 5, NULL); -} diff --git a/examples/system/ota/sdkconfig.defaults b/examples/system/ota/sdkconfig.defaults deleted file mode 100644 index 50f320c6..00000000 --- a/examples/system/ota/sdkconfig.defaults +++ /dev/null @@ -1,4 +0,0 @@ -# Default sdkconfig parameters to use the ESP8266 OTA -CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y -CONFIG_PARTITION_TABLE_TWO_OTA=y -CONFIG_LWIP_SOCKET_MULTITHREAD= From df4c82f39424328c2b743916f38acbbef46965c3 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Thu, 24 Jan 2019 15:02:29 +0800 Subject: [PATCH 2/4] feat(ota): Rename example "universal_ota" to "ota" The "universal_ota" is able to be compatible with ESP8285(ESP8266 + 1MB flash). --- examples/system/{universal_ota => ota}/Makefile | 0 .../system/{universal_ota => ota}/OTA_workflow.png | Bin examples/system/{universal_ota => ota}/README.md | 0 .../{universal_ota => ota}/main/Kconfig.projbuild | 0 .../system/{universal_ota => ota}/main/component.mk | 0 .../{universal_ota => ota}/main/ota_example_main.c | 0 .../partitions_two_ota.1MB.mini.csv | 0 .../partitions_two_ota_v2tov3.1MB.csv | 0 .../{universal_ota => ota}/sdkconfig.defaults | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename examples/system/{universal_ota => ota}/Makefile (100%) rename examples/system/{universal_ota => ota}/OTA_workflow.png (100%) rename examples/system/{universal_ota => ota}/README.md (100%) rename examples/system/{universal_ota => ota}/main/Kconfig.projbuild (100%) rename examples/system/{universal_ota => ota}/main/component.mk (100%) rename examples/system/{universal_ota => ota}/main/ota_example_main.c (100%) rename examples/system/{universal_ota => ota}/partitions_two_ota.1MB.mini.csv (100%) rename examples/system/{universal_ota => ota}/partitions_two_ota_v2tov3.1MB.csv (100%) rename examples/system/{universal_ota => ota}/sdkconfig.defaults (100%) diff --git a/examples/system/universal_ota/Makefile b/examples/system/ota/Makefile similarity index 100% rename from examples/system/universal_ota/Makefile rename to examples/system/ota/Makefile diff --git a/examples/system/universal_ota/OTA_workflow.png b/examples/system/ota/OTA_workflow.png similarity index 100% rename from examples/system/universal_ota/OTA_workflow.png rename to examples/system/ota/OTA_workflow.png diff --git a/examples/system/universal_ota/README.md b/examples/system/ota/README.md similarity index 100% rename from examples/system/universal_ota/README.md rename to examples/system/ota/README.md diff --git a/examples/system/universal_ota/main/Kconfig.projbuild b/examples/system/ota/main/Kconfig.projbuild similarity index 100% rename from examples/system/universal_ota/main/Kconfig.projbuild rename to examples/system/ota/main/Kconfig.projbuild diff --git a/examples/system/universal_ota/main/component.mk b/examples/system/ota/main/component.mk similarity index 100% rename from examples/system/universal_ota/main/component.mk rename to examples/system/ota/main/component.mk diff --git a/examples/system/universal_ota/main/ota_example_main.c b/examples/system/ota/main/ota_example_main.c similarity index 100% rename from examples/system/universal_ota/main/ota_example_main.c rename to examples/system/ota/main/ota_example_main.c diff --git a/examples/system/universal_ota/partitions_two_ota.1MB.mini.csv b/examples/system/ota/partitions_two_ota.1MB.mini.csv similarity index 100% rename from examples/system/universal_ota/partitions_two_ota.1MB.mini.csv rename to examples/system/ota/partitions_two_ota.1MB.mini.csv diff --git a/examples/system/universal_ota/partitions_two_ota_v2tov3.1MB.csv b/examples/system/ota/partitions_two_ota_v2tov3.1MB.csv similarity index 100% rename from examples/system/universal_ota/partitions_two_ota_v2tov3.1MB.csv rename to examples/system/ota/partitions_two_ota_v2tov3.1MB.csv diff --git a/examples/system/universal_ota/sdkconfig.defaults b/examples/system/ota/sdkconfig.defaults similarity index 100% rename from examples/system/universal_ota/sdkconfig.defaults rename to examples/system/ota/sdkconfig.defaults From 2e9cb80033069ec2dc04f278eff79c56ff05611c Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Thu, 24 Jan 2019 15:32:24 +0800 Subject: [PATCH 3/4] feat(ota): Add OTA binary link address verify of ESP8285 or ESP8266 + 1MB flash --- components/app_update/esp_ota_ops.c | 29 +++++++++++++++++++++ components/esp8266/Makefile.projbuild | 10 +++---- examples/system/ota/main/ota_example_main.c | 2 +- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/components/app_update/esp_ota_ops.c b/components/app_update/esp_ota_ops.c index 9f41cda7..b9072340 100644 --- a/components/app_update/esp_ota_ops.c +++ b/components/app_update/esp_ota_ops.c @@ -69,6 +69,28 @@ static ota_select s_ota_select[2]; const static char *TAG = "esp_ota_ops"; +#ifndef CONFIG_ESP8266_BOOT_COPY_APP +static inline int esp_ota_verify_binary(const esp_partition_pos_t *pos, esp_image_header_t *image) +{ + const int32_t entry = image->entry_addr - 0x40200010; + + ESP_LOGD(TAG, "OTA binary start entry 0x%x, partition start from 0x%x to 0x%x\n", entry, pos->offset, + pos->offset + pos->size); + + if (pos->offset + pos->size <= 0x100000) { + if (entry <= 0 || entry <= pos->offset || entry >= pos->offset + pos->size) { + const char *doc_str = "<>"; + + ESP_LOGE(TAG, "**Important**: The OTA binary link data is error, " + "please refer to document %s for how to generate OTA binaries", doc_str); + return ESP_ERR_INVALID_ARG; + } + } + + return ESP_OK; +} +#endif + /* Return true if this is an OTA app partition */ static bool is_ota_partition(const esp_partition_t *p) { @@ -244,6 +266,13 @@ esp_err_t esp_ota_end(esp_ota_handle_t handle) goto cleanup; } +#ifndef CONFIG_ESP8266_BOOT_COPY_APP + if (esp_ota_verify_binary(&part_pos, &data.image) != ESP_OK) { + ret = ESP_ERR_OTA_VALIDATE_FAILED; + goto cleanup; + } +#endif + #ifdef CONFIG_SECURE_BOOT_ENABLED ret = esp_secure_boot_verify_signature(it->part->address, data.image_len); if (ret != ESP_OK) { diff --git a/components/esp8266/Makefile.projbuild b/components/esp8266/Makefile.projbuild index 735d0ae9..d90d587b 100644 --- a/components/esp8266/Makefile.projbuild +++ b/components/esp8266/Makefile.projbuild @@ -94,7 +94,7 @@ OTA_V2_TO_V3_BIN := ./build/$(PROJECT_NAME).v2_to_v3.ota.bin CONFIG_APP2_OFFSET ?= $(CONFIG_APP1_OFFSET) CONFIG_APP2_SIZE ?= $(CONFIG_APP1_SIZE) -OTA1_OFFSET := CONFIG_APP1_OFFSET +OTA1_OFFSET := $(CONFIG_APP1_OFFSET) ifdef CONFIG_ESP8266_BOOT_COPY_APP OTA2_LINK_OFFSET := $(CONFIG_APP1_OFFSET) else @@ -102,7 +102,7 @@ OTA2_LINK_OFFSET := $(CONFIG_APP2_OFFSET) endif $(OTA2_BIN): all_binaries -ifeq ($(CONFIG_ESPTOOLPY_FLASHSIZE), "1MB") +ifneq ($(OTA1_OFFSET), $(OTA2_LINK_OFFSET)) @rm -f ./build/esp8266/esp8266_out.ld @make APP_OFFSET=$(OTA2_LINK_OFFSET) APP_SIZE=$(CONFIG_APP2_SIZE) CFLAGS= CXXFLAGS= endif @@ -110,16 +110,16 @@ endif @echo [GEN] $(OTA2_BIN) $(OTA1_BIN): all_binaries -ifeq ($(CONFIG_ESPTOOLPY_FLASHSIZE), "1MB") +ifneq ($(OTA1_OFFSET), $(OTA2_LINK_OFFSET)) @rm -f ./build/esp8266/esp8266_out.ld endif - @make APP_OFFSET=$(CONFIG_APP1_OFFSET) APP_SIZE=$(CONFIG_APP1_SIZE) CFLAGS= CXXFLAGS= + @make APP_OFFSET=$(OTA1_OFFSET) APP_SIZE=$(CONFIG_APP1_SIZE) CFLAGS= CXXFLAGS= @cp $(RAW_BIN) $(OTA1_BIN) @echo [GEN] $(OTA1_BIN) $(OTA_BIN): $(OTA1_BIN) $(OTA2_BIN) @cp $(OTA1_BIN) $(OTA_BIN) -ifeq ($(CONFIG_ESPTOOLPY_FLASHSIZE), "1MB") +ifneq ($(OTA1_OFFSET), $(OTA2_LINK_OFFSET)) @cat $(OTA2_BIN) >> $(OTA_BIN) endif @cp $(OTA1_BIN) $(RAW_BIN) diff --git a/examples/system/ota/main/ota_example_main.c b/examples/system/ota/main/ota_example_main.c index b5137287..27e58646 100644 --- a/examples/system/ota/main/ota_example_main.c +++ b/examples/system/ota/main/ota_example_main.c @@ -185,7 +185,7 @@ bool _esp_ota_firm_parse_http(esp_ota_firm_t *ota_firm, const char *text, size_t memset(length_str, 0, sizeof(length_str)); memcpy(length_str, ptr, ptr2 - ptr); ota_firm->content_len = atoi(length_str); -#ifdef CONFIG_ESPTOOLPY_FLASHSIZE_1MB +#if defined(CONFIG_ESPTOOLPY_FLASHSIZE_1MB) && !defined(CONFIG_ESP8266_BOOT_COPY_APP) ota_firm->ota_size = ota_firm->content_len / ota_firm->ota_num; ota_firm->ota_offset = ota_firm->ota_size * ota_firm->update_ota_num; #else From d36793c00fc5765b45783e337bd8b451b54dd470 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Thu, 24 Jan 2019 15:17:31 +0800 Subject: [PATCH 4/4] docs(ota): Add important description for OTA of ESP8285 or ESP8266 + 1MB flash --- examples/system/ota/README.md | 41 +++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/examples/system/ota/README.md b/examples/system/ota/README.md index d0d2a61c..2086a4f9 100644 --- a/examples/system/ota/README.md +++ b/examples/system/ota/README.md @@ -1,4 +1,10 @@ +# Important + +If your development board is based on **ESP8285** or **ESP8266 + 1MB flash**, you should read this document carefully, especially the Chapter **"Principle"**. + +--- + # Simple OTA Demo This example demonstrates a working OTA (over the air) firmware update workflow. @@ -13,8 +19,7 @@ An app running on ESP8266 can upgrade itself by downloading a new app "image" bi In this example, the ESP8266 has 2 images in flash: OTA_0, OTA_1. Each of these is a self-contained partition. The number of OTA image partition is determined by the partition table layout. -Flashing the example over serial with "make flash" updates the OTA_0 app image. On first boot, the bootloader loads this OTA_0 app image which then performs an OTA update (triggered in the example code). The update downloads a new image from an http server and saves it into the OTA_1 partition. At this point the example code updates the ota_data partition to indicate the new app partition, and reboots. The bootloader reads ota_data, determines the new OTA image has been selected, and runs it. - +Flash the example through serial port with command "make flash" to update the OTA_0 app image. In first boot, the bootloader loads this OTA_0 app image which then will execute an OTA update (triggered in the example code). The OTA update will download a new image from an http server and save it into the OTA_1 partition. After that, the example code will update the ota_data partition to indicate the new app partition, and then reboot, which leads to the second boot. During the second boot, the bootloader will read the ota_data, and select to run the new OTA image. # Custom partition configuration @@ -93,7 +98,7 @@ For our upgrade example OTA file, we're going to use the `get-started/project_te Open a new terminal to run the HTTP server, then run these commands to build the example and start the server, if your board's flash size is "1 MB", you should firstly configure flash size to be "1 MB"(default is "2 MB") at "menuconfig" and then build project: -Configure 1MB flash if need: +Configure 1MB flash if it is needed: ``` Serial flasher config ---> @@ -119,10 +124,6 @@ While the server is running, the contents of the build directory can be browsed NB: On some systems, the command may be `python2 -m SimpleHTTPServer`. -NB: Command "make ota" will generate 3 binaries: "xxx(project name).app1.bin", "xxx(project name).app2.bin" and "xxx(project name).ota.bin". You should only upload the "xxx(project name).ota.bin" to your OTA server and let the app download it by the example. - -NB: "xxx.app1.bin" is for downloading to OTA_0 partition, and "xxx.app2.bin" is for downloading to OTA_1 partition. If your board's flash size is larger than "1 MB", then "xxx.app1.bin" = "xxx.app2.bin" = "xxx.ota.bin". Otherwise "xxx.ota.bin" = "xxx.app1.bin" + "xxx.app2.bin". So the flash size configuration is very important. The example will select the binary it needs and store it to flash. - If you have any firewall software running that will block incoming access to port 8070, configure it to allow access while running the example. ## Step 3: Build OTA Example @@ -143,7 +144,7 @@ Serial flasher config ---> (X) 1 MB ``` -Configurate the application location information and it must be same as the OTA example's information, how to do refer to **Step 3: Configurate application location** of **Custom partition configuration**. +Configurate the application location information and it must be the same as the OTA example's information, you can refer to the **Step 3: Configurate application location** of **Custom partition configuration**. Save your changes, and type `make` to build the example. @@ -166,11 +167,29 @@ When the example starts up, it will print "ota: Starting OTA example..." then: 3. Write the image to flash, and configure the next boot from this image. 4. Reboot +# Principle + +Command "make ota" will generate 3 binaries: "xxx(project name).app1.bin", "xxx(project name).app2.bin" and "xxx(project name).ota.bin". You should only upload the "xxx(project name).ota.bin" to your OTA server and let the app download it as the example. + +"xxx.app1.bin" is for downloading to OTA_0 partition, and "xxx.app2.bin" is for downloading to OTA_1 partition. If your board's flash size is larger than "1 MB" or you select "Copy OTA" function, then "xxx.app1.bin" = "xxx.app2.bin" = "xxx.ota.bin". Otherwise If your board's flash size is "1 MB" and you don't select "Copy OTA" function, "xxx.app1.bin" != "xxx.app2.bin" != "xxx.ota.bin", "xxx.ota.bin" = "xxx.app1.bin" + "xxx.app2.bin". So the flash size configuration is very important. Otherwise if and at the last The example will select the binary it needs and download it into flash. + +Based on the above theory, we can see that for ESP8266 + 2MB flash(or larger size), app1 and app2 are the same, you can download it directly without any distinction. But for ESP8285 (ESP8266 + 1MB flash), the ota0 (app1) and ota1 (app2) are different, you need to distinguish which one should be downloaded, and to what location, during FOTA. Now, the way in the example code is to synthesize app1 and app2 into an "xxxx (project name).ota.bin". And only write the target app (app1 or app2) into the flash, according to the location of download, when FOTA; the other part will be discarded. + +On the other hand, if you want to use ESP8285(ESP8266 + 1MB flash) and don't want to upload 2 binaries for OTA, you can enable the "Copy OTA" function in menuconfig. + +``` +Component config ---> + ESP8266-specific ---> + [*] (**Expected**)Boot copy app +``` + +After enabling "Copy OTA" mode, the system will always download the app bin into ota_1 partition and then re-boot. After reboot, the bootloader will unpack the app bin and copy it to the ota_0 partition, then run the application in ota_0 partition. + # Troubleshooting -* Check your PC can ping the ESP8266 at its IP, and that the IP, AP and other configuration settings are correct in menuconfig. -* Check if any firewall software is preventing incoming connections on the PC. -* Check you can see the configured file (default project_template.ota.bin) if you browse the file listing at http://127.0.0.1/ +* Check whether your PC can ping the ESP8266 at its IP, and make sure that the IP, AP and other configuration settings are correct in menuconfig. +* Check if there is any firewall software on the PC that prevents incoming connections. +* Check whether you can see the configured file (default project_template.ota.bin) when browsing the file listing at http://127.0.0.1/ * If you have another PC or a phone, try viewing the file listing from the separate host. ## Error "ota_begin error err=0x104"