/* 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 esp_err_t ota_download(int socket_id, esp_ota_handle_t ota_handle) { IOT_CHECK(TAG, socket_id != -1, ESP_ERR_INVALID_ARG); bool resp_start = false; uint8_t data_buff[BUFF_SIZE]; int total_len = 0; esp_err_t ret = ESP_OK; for (;;) { memset(data_buff, 0, BUFF_SIZE); int recv_len = recv(socket_id, data_buff, BUFF_SIZE, 0); if (recv_len < 0) { return ESP_FAIL; } if (recv_len > 0 && !resp_start) { int data_len = 0; resp_start = erase_http_header(data_buff, recv_len, &data_len); ret = esp_ota_write(ota_handle, data_buff, data_len); IOT_CHECK(TAG, ret == ESP_OK, ESP_FAIL); total_len += data_len; } else if (recv_len > 0 && resp_start) { ret = esp_ota_write(ota_handle, data_buff, recv_len); IOT_CHECK(TAG, ret == ESP_OK, ESP_FAIL); total_len += recv_len; } else if (recv_len == 0) { if (!g_ota_timeout) { ESP_LOGI(TAG, "all packets received, total length:%d", total_len); } else { return ESP_ERR_TIMEOUT; } break; } else { ESP_LOGE(TAG, "Unexpected recv result"); } ESP_LOGI(TAG, "Have written image length %d", total_len); } return ESP_OK; }
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(); } int res = -1; /*send GET request to http server*/ res = send(socket_id, http_request, strlen(http_request), 0); if (res == -1) { 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 ; }
static int ota_file_upload_cb(void *data, const char *name, const char *filename, char *buf, int len, enum lws_spa_fileupload_states state) { struct per_session_data__esplws_ota *pss = (struct per_session_data__esplws_ota *)data; switch (state) { case LWS_UFS_OPEN: lwsl_notice("LWS_UFS_OPEN Filename %s\n", filename); strncpy(pss->filename, filename, sizeof(pss->filename) - 1); if (strcmp(name, "ota")) return 1; pss->part = ota_choose_part(); if (!pss->part) return 1; if (esp_ota_begin(pss->part, (long)-1, &pss->otahandle) != ESP_OK) { lwsl_err("OTA: Failed to begin\n"); return 1; } pss->file_length = 0; break; case LWS_UFS_FINAL_CONTENT: case LWS_UFS_CONTENT: if (pss->file_length + len > pss->part->size) { lwsl_err("OTA: incoming file too large\n"); return 1; } lwsl_notice("writing 0x%lx... 0x%lx\n", pss->part->address + pss->file_length, pss->part->address + pss->file_length + len); if (esp_ota_write(pss->otahandle, buf, len) != ESP_OK) { lwsl_err("OTA: Failed to write\n"); return 1; } pss->file_length += len; if (state == LWS_UFS_CONTENT) break; lwsl_notice("LWS_UFS_FINAL_CONTENT\n"); if (esp_ota_end(pss->otahandle) != ESP_OK) { lwsl_err("OTA: end failed\n"); return 1; } if (esp_ota_set_boot_partition(pss->part) != ESP_OK) { lwsl_err("OTA: set boot part failed\n"); return 1; } pss->reboot_timer = xTimerCreate("x", pdMS_TO_TICKS(250), 0, NULL, ota_reboot_timer_cb); xTimerStart(pss->reboot_timer, 0); break; } return 0; }
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...."); esp_http_client_config_t config = { .url = EXAMPLE_SERVER_URL, .cert_pem = (char *)server_cert_pem_start, }; esp_http_client_handle_t client = esp_http_client_init(&config); if (client == NULL) { ESP_LOGE(TAG, "Failed to initialise HTTP connection"); task_fatal_error(); } 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); task_fatal_error(); } esp_http_client_fetch_headers(client); 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, ota_write_data, BUFFSIZE); if (data_read < 0) { ESP_LOGE(TAG, "Error: SSL data read error"); http_cleanup(client); task_fatal_error(); } 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_LOGI(TAG, "New firmware version: %s", new_app_info.version); 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", running_app_info.version); } 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)) == 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); infinite_loop(); } } if (memcmp(new_app_info.version, running_app_info.version, sizeof(new_app_info.version)) == 0) { ESP_LOGW(TAG, "Current running version is the same as a new. We will not continue the update."); http_cleanup(client); infinite_loop(); } 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); task_fatal_error(); } ESP_LOGI(TAG, "esp_ota_begin succeeded"); } else { ESP_LOGE(TAG, "received package is not fit len"); http_cleanup(client); task_fatal_error(); } } err = esp_ota_write( update_handle, (const void *)ota_write_data, data_read); if (err != ESP_OK) { http_cleanup(client); task_fatal_error(); } binary_file_length += data_read; ESP_LOGD(TAG, "Written image length %d", binary_file_length); } else if (data_read == 0) { ESP_LOGI(TAG, "Connection closed,all data received"); break; } } 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!"); http_cleanup(client); task_fatal_error(); } 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)); http_cleanup(client); task_fatal_error(); } ESP_LOGI(TAG, "Prepare to restart system!"); esp_restart(); return ; } static bool diagnostic(void) { gpio_config_t io_conf; io_conf.intr_type = GPIO_PIN_INTR_DISABLE; io_conf.mode = GPIO_MODE_INPUT; io_conf.pin_bit_mask = (1ULL << CONFIG_GPIO_DIAGNOSTIC); io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; io_conf.pull_up_en = GPIO_PULLUP_ENABLE; gpio_config(&io_conf); ESP_LOGI(TAG, "Diagnostics (5 sec)..."); vTaskDelay(5000 / portTICK_PERIOD_MS); bool diagnostic_is_ok = gpio_get_level(CONFIG_GPIO_DIAGNOSTIC); gpio_reset_pin(CONFIG_GPIO_DIAGNOSTIC); return diagnostic_is_ok; }