|
| 1 | +/* |
| 2 | + * This file is part of the MicroPython project, http://micropython.org/ |
| 3 | + * |
| 4 | + * The MIT License (MIT) |
| 5 | + * |
| 6 | + * Copyright (c) 2020 microDev |
| 7 | + * |
| 8 | + * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 9 | + * of this software and associated documentation files (the "Software"), to deal |
| 10 | + * in the Software without restriction, including without limitation the rights |
| 11 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 12 | + * copies of the Software, and to permit persons to whom the Software is |
| 13 | + * furnished to do so, subject to the following conditions: |
| 14 | + * |
| 15 | + * The above copyright notice and this permission notice shall be included in |
| 16 | + * all copies or substantial portions of the Software. |
| 17 | + * |
| 18 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 19 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 20 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 21 | + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 22 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 23 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 24 | + * THE SOFTWARE. |
| 25 | + */ |
| 26 | + |
| 27 | +#include "common-hal/dualbank/__init__.h" |
| 28 | +#include "shared-bindings/dualbank/__init__.h" |
| 29 | + |
| 30 | +#include <string.h> |
| 31 | + |
| 32 | +#include "esp_log.h" |
| 33 | +#include "esp_ota_ops.h" |
| 34 | + |
| 35 | +static const esp_partition_t *update_partition = NULL; |
| 36 | +static esp_ota_handle_t update_handle = 0; |
| 37 | + |
| 38 | +static const char *TAG = "dualbank"; |
| 39 | + |
| 40 | +void dualbank_reset(void) { |
| 41 | + // should use `abort` instead of `end` |
| 42 | + // but not in idf v4.2 |
| 43 | + // esp_ota_abort(update_handle); |
| 44 | + if (esp_ota_end(update_handle) == ESP_OK) { |
| 45 | + update_handle = 0; |
| 46 | + update_partition = NULL; |
| 47 | + } |
| 48 | +} |
| 49 | + |
| 50 | +static void __attribute__((noreturn)) task_fatal_error(void) { |
| 51 | + ESP_LOGE(TAG, "Exiting task due to fatal error..."); |
| 52 | + mp_raise_RuntimeError(translate("Update Failed")); |
| 53 | +} |
| 54 | + |
| 55 | +void common_hal_dualbank_flash(const void *buf, const size_t len, const size_t offset) { |
| 56 | + esp_err_t err; |
| 57 | + |
| 58 | + const esp_partition_t *running = esp_ota_get_running_partition(); |
| 59 | + const esp_partition_t *last_invalid = esp_ota_get_last_invalid_partition(); |
| 60 | + |
| 61 | + if (update_partition == NULL) { |
| 62 | + update_partition = esp_ota_get_next_update_partition(NULL); |
| 63 | + |
| 64 | + ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08x)", |
| 65 | + running->type, running->subtype, running->address); |
| 66 | + |
| 67 | + ESP_LOGI(TAG, "Writing partition type %d subtype %d (offset 0x%08x)\n", |
| 68 | + update_partition->type, update_partition->subtype, update_partition->address); |
| 69 | + |
| 70 | + assert(update_partition != NULL); |
| 71 | + } |
| 72 | + |
| 73 | + if (update_handle == 0) { |
| 74 | + if (len > sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t)) { |
| 75 | + esp_app_desc_t new_app_info; |
| 76 | + memcpy(&new_app_info, &((char *)buf)[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)], sizeof(esp_app_desc_t)); |
| 77 | + ESP_LOGI(TAG, "New firmware version: %s", new_app_info.version); |
| 78 | + |
| 79 | + esp_app_desc_t running_app_info; |
| 80 | + if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK) { |
| 81 | + ESP_LOGI(TAG, "Running firmware version: %s", running_app_info.version); |
| 82 | + } |
| 83 | + |
| 84 | + esp_app_desc_t invalid_app_info; |
| 85 | + if (esp_ota_get_partition_description(last_invalid, &invalid_app_info) == ESP_OK) { |
| 86 | + ESP_LOGI(TAG, "Last invalid firmware version: %s", invalid_app_info.version); |
| 87 | + } |
| 88 | + |
| 89 | + // check new version with running version |
| 90 | + if (memcmp(new_app_info.version, running_app_info.version, sizeof(new_app_info.version)) == 0) { |
| 91 | + ESP_LOGW(TAG, "New version is the same as running version."); |
| 92 | + task_fatal_error(); |
| 93 | + } |
| 94 | + |
| 95 | + // check new version with last invalid partition |
| 96 | + if (last_invalid != NULL) { |
| 97 | + if (memcmp(new_app_info.version, invalid_app_info.version, sizeof(new_app_info.version)) == 0) { |
| 98 | + ESP_LOGW(TAG, "New version is the same as invalid version."); |
| 99 | + task_fatal_error(); |
| 100 | + } |
| 101 | + } |
| 102 | + |
| 103 | + err = esp_ota_begin(update_partition, OTA_WITH_SEQUENTIAL_WRITES, &update_handle); |
| 104 | + if (err != ESP_OK) { |
| 105 | + ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err)); |
| 106 | + task_fatal_error(); |
| 107 | + } |
| 108 | + } else { |
| 109 | + ESP_LOGE(TAG, "received package is not fit len"); |
| 110 | + task_fatal_error(); |
| 111 | + } |
| 112 | + } |
| 113 | + |
| 114 | + if (offset == 0) { |
| 115 | + err = esp_ota_write(update_handle, buf, len); |
| 116 | + } else { |
| 117 | + err = esp_ota_write_with_offset(update_handle, buf, len, offset); |
| 118 | + } |
| 119 | + if (err != ESP_OK) { |
| 120 | + ESP_LOGE(TAG, "esp_ota_write failed (%s)", esp_err_to_name(err)); |
| 121 | + task_fatal_error(); |
| 122 | + } |
| 123 | +} |
| 124 | + |
| 125 | +void common_hal_dualbank_switch(void) { |
| 126 | + if (esp_ota_end(update_handle) == ESP_OK) { |
| 127 | + update_handle = 0; |
| 128 | + update_partition = NULL; |
| 129 | + } |
| 130 | + esp_err_t err = esp_ota_set_boot_partition(esp_ota_get_next_update_partition(NULL)); |
| 131 | + if (err != ESP_OK) { |
| 132 | + if (err == ESP_ERR_OTA_VALIDATE_FAILED) { |
| 133 | + ESP_LOGE(TAG, "Image validation failed, image is corrupted"); |
| 134 | + mp_raise_RuntimeError(translate("Firmware image is invalid")); |
| 135 | + } |
| 136 | + ESP_LOGE(TAG, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err)); |
| 137 | + task_fatal_error(); |
| 138 | + } |
| 139 | +} |
0 commit comments