mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-09-19 00:21:15 +08:00
Merge branch 'feature/v2_bootloader_load_v3_firmware' into 'master'
Support V2 firmware update to V3 by OTA See merge request sdk/ESP8266_RTOS_SDK!628
This commit is contained in:
@ -539,13 +539,10 @@ const esp_partition_t* esp_ota_get_running_partition(void)
|
|||||||
/* Find the flash address of this exact function. By definition that is part
|
/* Find the flash address of this exact function. By definition that is part
|
||||||
of the currently running firmware. Then find the enclosing partition. */
|
of the currently running firmware. Then find the enclosing partition. */
|
||||||
|
|
||||||
#ifdef CONFIG_TARGET_PLATFORM_ESP32
|
|
||||||
size_t phys_offs = spi_flash_cache2phys(esp_ota_get_running_partition);
|
size_t phys_offs = spi_flash_cache2phys(esp_ota_get_running_partition);
|
||||||
|
|
||||||
assert (phys_offs != SPI_FLASH_CACHE2PHYS_FAIL); /* indicates cache2phys lookup is buggy */
|
assert (phys_offs != SPI_FLASH_CACHE2PHYS_FAIL); /* indicates cache2phys lookup is buggy */
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CONFIG_TARGET_PLATFORM_ESP32
|
|
||||||
esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_APP,
|
esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_APP,
|
||||||
ESP_PARTITION_SUBTYPE_ANY,
|
ESP_PARTITION_SUBTYPE_ANY,
|
||||||
NULL);
|
NULL);
|
||||||
@ -561,9 +558,6 @@ const esp_partition_t* esp_ota_get_running_partition(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
abort(); /* Partition table is invalid or corrupt */
|
abort(); /* Partition table is invalid or corrupt */
|
||||||
#else
|
|
||||||
return esp_ota_get_boot_partition();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "bootloader_common.h"
|
#include "bootloader_common.h"
|
||||||
#include "esp_image_format.h"
|
#include "esp_image_format.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "esp_spi_flash.h"
|
||||||
|
|
||||||
static const char* TAG = "boot";
|
static const char* TAG = "boot";
|
||||||
|
|
||||||
@ -112,6 +113,18 @@ static int selected_boot_partition(const bootloader_state_t *bs)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_ESP8266_BOOT_COPY_APP
|
||||||
|
if (boot_index == 1) {
|
||||||
|
ESP_LOGI(TAG, "Copy application from OAT1 to OTA0, please wait ...");
|
||||||
|
int ret = esp_patition_copy_ota1_to_ota0(bs);
|
||||||
|
if (ret) {
|
||||||
|
ESP_LOGE(TAG, "Fail to initialize OTA0");
|
||||||
|
return INVALID_INDEX;
|
||||||
|
}
|
||||||
|
|
||||||
|
boot_index = 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
// Customer implementation.
|
// Customer implementation.
|
||||||
// if (gpio_pin_1 == true && ...){
|
// if (gpio_pin_1 == true && ...){
|
||||||
|
@ -12,8 +12,8 @@ MEMORY
|
|||||||
{
|
{
|
||||||
dport0_seg : org = 0x3FF00000, len = 0x10
|
dport0_seg : org = 0x3FF00000, len = 0x10
|
||||||
|
|
||||||
/* All .data/.bss/heap are in this segment. */
|
/* All .data/.bss/heap are in this segment. Reserve 1KB for old boot or ROM boot */
|
||||||
dram_seg : org = 0x3FFE8000, len = 0x18000
|
dram_seg : org = 0x3FFE8000, len = 0x18000 - 0x400
|
||||||
|
|
||||||
/* Functions which are critical should be put in this segment. */
|
/* Functions which are critical should be put in this segment. */
|
||||||
iram_seg : org = 0x40100000, len = 0x8000
|
iram_seg : org = 0x40100000, len = 0x8000
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
PROVIDE ( ets_memcpy = 0x400018b4 );
|
PROVIDE ( ets_memcpy = 0x400018b4 );
|
||||||
|
|
||||||
PROVIDE ( SPIRead = 0x40004b1c );
|
PROVIDE ( SPIRead = 0x40004b1c );
|
||||||
|
PROVIDE ( SPIWrite = 0x40004a4c );
|
||||||
|
PROVIDE ( SPIEraseSector = 0x40004a00 );
|
||||||
|
|
||||||
PROVIDE ( gpio_input_get = 0x40004cf0 );
|
PROVIDE ( gpio_input_get = 0x40004cf0 );
|
||||||
|
|
||||||
|
@ -648,6 +648,8 @@ static void update_flash_config(const esp_image_header_t* pfhdr)
|
|||||||
|
|
||||||
ESP_LOGD(TAG, "bootloader initialize SPI flash clock and I/O");
|
ESP_LOGD(TAG, "bootloader initialize SPI flash clock and I/O");
|
||||||
#endif /* CONFIG_BOOTLOADER_INIT_SPI_FLASH */
|
#endif /* CONFIG_BOOTLOADER_INIT_SPI_FLASH */
|
||||||
|
|
||||||
|
Cache_Read_Disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_flash_info(const esp_image_header_t* phdr)
|
static void print_flash_info(const esp_image_header_t* phdr)
|
||||||
|
@ -512,6 +512,13 @@ bool bootloader_utility_load_partition_table(bootloader_state_t* bs)
|
|||||||
esp_err_t err;
|
esp_err_t err;
|
||||||
int num_partitions;
|
int num_partitions;
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP8266_OTA_FROM_OLD
|
||||||
|
if (esp_patition_table_init_location()) {
|
||||||
|
ESP_LOGE(TAG, "Failed to update partition table location");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SECURE_BOOT_ENABLED
|
#ifdef CONFIG_SECURE_BOOT_ENABLED
|
||||||
if(esp_secure_boot_enabled()) {
|
if(esp_secure_boot_enabled()) {
|
||||||
ESP_LOGI(TAG, "Verifying partition table signature...");
|
ESP_LOGI(TAG, "Verifying partition table signature...");
|
||||||
@ -605,6 +612,14 @@ bool bootloader_utility_load_partition_table(bootloader_state_t* bs)
|
|||||||
|
|
||||||
bootloader_munmap(partitions);
|
bootloader_munmap(partitions);
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP8266_OTA_FROM_OLD
|
||||||
|
ESP_LOGI(TAG, "Copy firmware ...");
|
||||||
|
if (esp_patition_table_init_data(bs)) {
|
||||||
|
ESP_LOGE(TAG,"Failed to update partition data");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ESP_LOGI(TAG,"End of partition table");
|
ESP_LOGI(TAG,"End of partition table");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -213,6 +213,28 @@ config CRYSTAL_USED_40MHZ
|
|||||||
bool "40MHz"
|
bool "40MHz"
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
|
config ESP8266_OTA_FROM_OLD
|
||||||
|
bool "(**Expected**)ESP8266 update from old SDK by OTA"
|
||||||
|
default n
|
||||||
|
depends on TARGET_PLATFORM_ESP8266
|
||||||
|
select ESP8266_BOOT_COPY_APP
|
||||||
|
help
|
||||||
|
The function is not released.
|
||||||
|
|
||||||
|
Enable this option, script will generate the complete firmware for both old RTOS SDK(before V3.0)
|
||||||
|
and NonOS SDK to update to v3 by OTA.
|
||||||
|
|
||||||
|
The old RTOS SDK(before V3.0) or NonOS SDK can download the firmware to its partition and run it as it self's application.
|
||||||
|
|
||||||
|
config ESP8266_BOOT_COPY_APP
|
||||||
|
bool "(**Expected**)Boot copy app"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
The function is not released.
|
||||||
|
|
||||||
|
Enable this option, when it is that "OTA1" application is to run after update by OTA,
|
||||||
|
bootloader will copy "OTA1" application to "OTA0" partition and run "OTA0".
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu WIFI
|
menu WIFI
|
||||||
|
@ -89,10 +89,22 @@ OTA_BIN := ./build/$(PROJECT_NAME).ota.bin
|
|||||||
OTA1_BIN := ./build/$(PROJECT_NAME).app1.bin
|
OTA1_BIN := ./build/$(PROJECT_NAME).app1.bin
|
||||||
OTA2_BIN := ./build/$(PROJECT_NAME).app2.bin
|
OTA2_BIN := ./build/$(PROJECT_NAME).app2.bin
|
||||||
|
|
||||||
|
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
|
||||||
|
ifdef CONFIG_ESP8266_BOOT_COPY_APP
|
||||||
|
OTA2_LINK_OFFSET := $(CONFIG_APP1_OFFSET)
|
||||||
|
else
|
||||||
|
OTA2_LINK_OFFSET := $(CONFIG_APP2_OFFSET)
|
||||||
|
endif
|
||||||
|
|
||||||
$(OTA2_BIN): all_binaries
|
$(OTA2_BIN): all_binaries
|
||||||
ifeq ($(CONFIG_ESPTOOLPY_FLASHSIZE), "1MB")
|
ifeq ($(CONFIG_ESPTOOLPY_FLASHSIZE), "1MB")
|
||||||
@rm -f ./build/esp8266/esp8266_out.ld
|
@rm -f ./build/esp8266/esp8266_out.ld
|
||||||
@make APP_OFFSET=$(CONFIG_APP2_OFFSET) APP_SIZE=$(CONFIG_APP2_SIZE) CFLAGS= CXXFLAGS=
|
@make APP_OFFSET=$(OTA2_LINK_OFFSET) APP_SIZE=$(CONFIG_APP2_SIZE) CFLAGS= CXXFLAGS=
|
||||||
endif
|
endif
|
||||||
@cp $(RAW_BIN) $(OTA2_BIN)
|
@cp $(RAW_BIN) $(OTA2_BIN)
|
||||||
@echo [GEN] $(OTA2_BIN)
|
@echo [GEN] $(OTA2_BIN)
|
||||||
@ -113,9 +125,22 @@ endif
|
|||||||
@cp $(OTA1_BIN) $(RAW_BIN)
|
@cp $(OTA1_BIN) $(RAW_BIN)
|
||||||
@echo [GEN] $(OTA_BIN)
|
@echo [GEN] $(OTA_BIN)
|
||||||
|
|
||||||
|
ifdef CONFIG_ESP8266_OTA_FROM_OLD
|
||||||
|
$(OTA_V2_TO_V3_BIN): $(OTA_BIN)
|
||||||
|
@cp $(RAW_BIN) $(RAW_BIN).tmp.bak
|
||||||
|
@cp $(OTA1_BIN) $(RAW_BIN)
|
||||||
|
@python $(IDF_PATH)/tools/pack_fw.py --output $(OTA_V2_TO_V3_BIN) pack3 $(ESPTOOL_ALL_FLASH_ARGS)
|
||||||
|
@cp $(RAW_BIN).tmp.bak $(RAW_BIN)
|
||||||
|
@echo [GEN] $(OTA_V2_TO_V3_BIN)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_ESP8266_OTA_FROM_OLD
|
||||||
|
ota: $(OTA_V2_TO_V3_BIN)
|
||||||
|
else
|
||||||
ota: $(OTA_BIN)
|
ota: $(OTA_BIN)
|
||||||
|
endif
|
||||||
|
|
||||||
ota-clean:
|
ota-clean:
|
||||||
@rm -f $(OTA_BIN) $(OTA1_BIN) $(OTA2_BIN)
|
@rm -f $(OTA_BIN) $(OTA1_BIN) $(OTA2_BIN) $(OTA_V2_TO_V3_BIN)
|
||||||
|
|
||||||
clean: ota-clean
|
clean: ota-clean
|
||||||
|
@ -140,6 +140,12 @@
|
|||||||
#define WDT_CTL_EN_LSB 0
|
#define WDT_CTL_EN_LSB 0
|
||||||
|
|
||||||
#define WDT_FEED_VALUE 0x73
|
#define WDT_FEED_VALUE 0x73
|
||||||
|
|
||||||
|
#define WDT_REG_READ(_reg) REG_READ(PERIPHS_WDT_BASEADDR + _reg)
|
||||||
|
#define WDT_REG_WRITE(_reg, _val) REG_WRITE(PERIPHS_WDT_BASEADDR + _reg, _val)
|
||||||
|
#define CLEAR_WDT_REG_MASK(_reg, _mask) WDT_REG_WRITE(_reg, WDT_REG_READ(_reg) & (~_mask))
|
||||||
|
#define WDT_FEED() WDT_REG_WRITE(WDT_RST_ADDRESS, WDT_FEED_VALUE)
|
||||||
|
|
||||||
//}}
|
//}}
|
||||||
|
|
||||||
//RTC reg {{
|
//RTC reg {{
|
||||||
|
@ -33,6 +33,10 @@ int SPI_write_status(esp_spi_flash_chip_t *chip, uint32_t status);
|
|||||||
int SPI_read_status(esp_spi_flash_chip_t *chip, uint32_t *status);
|
int SPI_read_status(esp_spi_flash_chip_t *chip, uint32_t *status);
|
||||||
int Enable_QMode(esp_spi_flash_chip_t *chip);
|
int Enable_QMode(esp_spi_flash_chip_t *chip);
|
||||||
|
|
||||||
|
int SPIWrite(uint32_t addr, const uint8_t *src, uint32_t size);
|
||||||
|
int SPIRead(uint32_t addr, void *dst, uint32_t size);
|
||||||
|
int SPIEraseSector(uint32_t sector_num);
|
||||||
|
|
||||||
void Cache_Read_Disable();
|
void Cache_Read_Disable();
|
||||||
void Cache_Read_Enable(uint8_t map, uint8_t p, uint8_t v);
|
void Cache_Read_Enable(uint8_t map, uint8_t p, uint8_t v);
|
||||||
|
|
||||||
|
@ -263,6 +263,14 @@ extern "C" {
|
|||||||
|
|
||||||
#define PERIPHS_SPI_FLASH_USRREG (0x60000200 + 0x1c)
|
#define PERIPHS_SPI_FLASH_USRREG (0x60000200 + 0x1c)
|
||||||
|
|
||||||
|
#define CACHE_MAP_1M_HIGH BIT25
|
||||||
|
#define CACHE_MAP_2M BIT24
|
||||||
|
#define CACHE_MAP_SEGMENT_S 16
|
||||||
|
#define CACHE_MAP_SEGMENT_MASK 0x3
|
||||||
|
#define CACHE_BASE_ADDR 0x40200000
|
||||||
|
#define CACHE_2M_SIZE 0x00200000
|
||||||
|
#define CACHE_1M_SIZE 0x00100000
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,11 +21,6 @@
|
|||||||
#include "portmacro.h"
|
#include "portmacro.h"
|
||||||
#include "esp8266/eagle_soc.h"
|
#include "esp8266/eagle_soc.h"
|
||||||
|
|
||||||
#define WDT_REG_READ(_reg) REG_READ(PERIPHS_WDT_BASEADDR + _reg)
|
|
||||||
#define WDT_REG_WRITE(_reg, _val) REG_WRITE(PERIPHS_WDT_BASEADDR + _reg, _val)
|
|
||||||
#define CLEAR_WDT_REG_MASK(_reg, _mask) WDT_REG_WRITE(_reg, WDT_REG_READ(_reg) & (~_mask))
|
|
||||||
#define WDT_FEED() WDT_REG_WRITE(WDT_RST_ADDRESS, WDT_FEED_VALUE)
|
|
||||||
|
|
||||||
static const char *TAG = "wdt";
|
static const char *TAG = "wdt";
|
||||||
|
|
||||||
#ifdef CONFIG_TASK_WDT_PANIC
|
#ifdef CONFIG_TASK_WDT_PANIC
|
||||||
|
@ -9,3 +9,10 @@ COMPONENT_OBJS := src/spi_flash.o src/spi_flash_raw.o
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
CFLAGS += -DPARTITION_QUEUE_HEADER=\"sys/queue.h\"
|
CFLAGS += -DPARTITION_QUEUE_HEADER=\"sys/queue.h\"
|
||||||
|
|
||||||
|
ifdef CONFIG_ESP8266_OTA_FROM_OLD
|
||||||
|
ifdef IS_BOOTLOADER_BUILD
|
||||||
|
COMPONENT_SRCDIRS += port
|
||||||
|
COMPONENT_OBJS += port/port.o
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
@ -32,6 +32,8 @@ extern "C" {
|
|||||||
|
|
||||||
#define SPI_READ_BUF_MAX 64
|
#define SPI_READ_BUF_MAX 64
|
||||||
|
|
||||||
|
#define SPI_FLASH_CACHE2PHYS_FAIL UINT32_MAX /*<! Result from spi_flash_cache2phys() if flash cache address is invalid */
|
||||||
|
|
||||||
#ifdef CONFIG_ENABLE_FLASH_MMAP
|
#ifdef CONFIG_ENABLE_FLASH_MMAP
|
||||||
/**
|
/**
|
||||||
* @brief Enumeration which specifies memory space requested in an mmap call
|
* @brief Enumeration which specifies memory space requested in an mmap call
|
||||||
@ -149,6 +151,50 @@ void spi_flash_munmap(spi_flash_mmap_handle_t handle);
|
|||||||
|
|
||||||
#endif /* CONFIG_ENABLE_FLASH_MMAP */
|
#endif /* CONFIG_ENABLE_FLASH_MMAP */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Given a memory address where flash is mapped, return the corresponding physical flash offset.
|
||||||
|
*
|
||||||
|
* Cache address does not have have been assigned via spi_flash_mmap(), any address in memory mapped flash space can be looked up.
|
||||||
|
*
|
||||||
|
* @param cached Pointer to flashed cached memory.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - SPI_FLASH_CACHE2PHYS_FAIL If cache address is outside flash cache region, or the address is not mapped.
|
||||||
|
* - Otherwise, returns physical offset in flash
|
||||||
|
*/
|
||||||
|
uintptr_t spi_flash_cache2phys(const void *cached);
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP8266_OTA_FROM_OLD
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if current firmware updates from V2 firmware and its location is at "APP2", if so, then V3 bootloader
|
||||||
|
* will copy patition table from "APP2" location to "APP1" location of V2 partition map.
|
||||||
|
*
|
||||||
|
* @return 0 if success or others if failed
|
||||||
|
*/
|
||||||
|
int esp_patition_table_init_location(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if current firmware updates from V2 firmware and its location is at "APP2", if so, then V3 bootloader
|
||||||
|
* will copy firmware from "APP2" location to "APP1" location.
|
||||||
|
*
|
||||||
|
* @note All data which is copied is "ota0" application and all data whose location is before "ota0".
|
||||||
|
*
|
||||||
|
* @return 0 if success or others if failed
|
||||||
|
*/
|
||||||
|
int esp_patition_table_init_data(void *partition_info);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP8266_BOOT_COPY_APP
|
||||||
|
/**
|
||||||
|
* @brief Check if current application which is to run is at "ota1" location, if so, bootloader will copy it to "ota0" location,
|
||||||
|
* and clear OTA data partition.
|
||||||
|
*
|
||||||
|
* @return 0 if success or others if failed
|
||||||
|
*/
|
||||||
|
int esp_patition_copy_ota1_to_ota0(const void *partition_info);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
385
components/spi_flash/port/port.c
Normal file
385
components/spi_flash/port/port.c
Normal file
@ -0,0 +1,385 @@
|
|||||||
|
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
|
#if defined(CONFIG_ESP8266_OTA_FROM_OLD) && defined(BOOTLOADER_BUILD)
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "esp_flash_data_types.h"
|
||||||
|
#include "esp_spi_flash.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_image_format.h"
|
||||||
|
#include "bootloader_config.h"
|
||||||
|
#include "esp_libc.h"
|
||||||
|
#include "esp8266/rom_functions.h"
|
||||||
|
#include "esp8266/eagle_soc.h"
|
||||||
|
|
||||||
|
#define PARTITION_DATA_OFFSET (CONFIG_SPI_FLASH_SIZE / 2)
|
||||||
|
|
||||||
|
typedef struct s_sys_param {
|
||||||
|
uint8_t flag;
|
||||||
|
uint8_t reserved1[3];
|
||||||
|
uint32_t reserved2[7];
|
||||||
|
} sys_param_t;
|
||||||
|
|
||||||
|
typedef union s_boot_param {
|
||||||
|
struct {
|
||||||
|
uint8_t usr_bin : 4;
|
||||||
|
uint8_t flag : 4;
|
||||||
|
} boot_1;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint8_t usr_bin : 4;
|
||||||
|
uint8_t flag : 4;
|
||||||
|
uint8_t version;
|
||||||
|
} boot_2;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint8_t usr_bin : 2;
|
||||||
|
uint8_t boot_statue : 1;
|
||||||
|
uint8_t to_qio : 1;
|
||||||
|
uint8_t reserved1 : 4;
|
||||||
|
|
||||||
|
uint8_t version : 5;
|
||||||
|
uint8_t test_pass_flag : 1;
|
||||||
|
uint8_t test_start_flag : 1;
|
||||||
|
uint8_t enhance_boot_flag : 1;
|
||||||
|
} boot_base;
|
||||||
|
|
||||||
|
uint8_t data[4096];
|
||||||
|
} boot_param_t;
|
||||||
|
|
||||||
|
static const char *TAG = "partition_port";
|
||||||
|
static uint32_t s_partition_offset;
|
||||||
|
static uint8_t s_cache_buf[SPI_FLASH_SEC_SIZE];
|
||||||
|
static sys_param_t s_sys_param;
|
||||||
|
static boot_param_t s_boot_param;
|
||||||
|
static esp_spi_flash_chip_t s_flash_chip = {
|
||||||
|
0x1640ef,
|
||||||
|
CONFIG_SPI_FLASH_SIZE,
|
||||||
|
64 * 1024,
|
||||||
|
4 * 1024,
|
||||||
|
256,
|
||||||
|
0xffff
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void esp_hw_reset(void)
|
||||||
|
{
|
||||||
|
CLEAR_WDT_REG_MASK(WDT_CTL_ADDRESS, BIT0);
|
||||||
|
|
||||||
|
WDT_REG_WRITE(WDT_OP_ADDRESS, 8);
|
||||||
|
WDT_REG_WRITE(WDT_OP_ND_ADDRESS, 8);
|
||||||
|
|
||||||
|
SET_PERI_REG_BITS(PERIPHS_WDT_BASEADDR + WDT_CTL_ADDRESS, WDT_CTL_RSTLEN_MASK, 7 << WDT_CTL_RSTLEN_LSB, 0);
|
||||||
|
// interrupt then reset
|
||||||
|
SET_PERI_REG_BITS(PERIPHS_WDT_BASEADDR + WDT_CTL_ADDRESS, WDT_CTL_RSPMOD_MASK, 0 << WDT_CTL_RSPMOD_LSB, 0);
|
||||||
|
// start task watch dog1
|
||||||
|
SET_PERI_REG_BITS(PERIPHS_WDT_BASEADDR + WDT_CTL_ADDRESS, WDT_CTL_EN_MASK, 1 << WDT_CTL_EN_LSB, 0);
|
||||||
|
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int spi_flash_read_data(uint32_t addr, void *buf, size_t n)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "read buffer %p total %d from 0x%x", buf, n ,addr);
|
||||||
|
|
||||||
|
ret = SPI_read_data(&s_flash_chip, addr, buf, n);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int spi_flash_write_data(uint32_t addr, const void *buf, uint32_t n)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "write buffer %p total %d to 0x%x", buf, n ,addr);
|
||||||
|
|
||||||
|
ret = SPIWrite(addr, (void *)buf, n);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int spi_flash_erase(uint32_t addr)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "erase addr is 0x%x", addr);
|
||||||
|
|
||||||
|
ret = SPIEraseSector(addr / SPI_FLASH_SEC_SIZE);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t esp_get_updated_partition_table_addr(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
size_t offset;
|
||||||
|
uint8_t user_bin;
|
||||||
|
const uint32_t sect = CONFIG_SPI_FLASH_SIZE / SPI_FLASH_SEC_SIZE - 3;
|
||||||
|
|
||||||
|
if (s_partition_offset)
|
||||||
|
return s_partition_offset;
|
||||||
|
|
||||||
|
ret = spi_flash_read_data((sect + 2) * SPI_FLASH_SEC_SIZE, &s_sys_param, sizeof(sys_param_t));
|
||||||
|
if (ret) {
|
||||||
|
ESP_LOGE(TAG, "read V2 system param error %d", ret);
|
||||||
|
return -1UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "V2 system flag is %x", s_sys_param.flag);
|
||||||
|
|
||||||
|
offset = s_sys_param.flag ? 1 : 0;
|
||||||
|
|
||||||
|
ret = spi_flash_read_data((sect + offset) * SPI_FLASH_SEC_SIZE, &s_boot_param, sizeof(boot_param_t));
|
||||||
|
if (ret) {
|
||||||
|
ESP_LOGE(TAG, "read V2 boot param error %d", ret);
|
||||||
|
return -1UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_boot_param.boot_base.usr_bin == 1) {
|
||||||
|
if (s_boot_param.boot_base.boot_statue == 1)
|
||||||
|
user_bin = 1;
|
||||||
|
else
|
||||||
|
user_bin = 0;
|
||||||
|
} else {
|
||||||
|
if (s_boot_param.boot_base.boot_statue == 1)
|
||||||
|
user_bin = 0;
|
||||||
|
else {
|
||||||
|
if (s_boot_param.boot_base.version == 4)
|
||||||
|
user_bin = 0;
|
||||||
|
else
|
||||||
|
user_bin = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_bin)
|
||||||
|
s_partition_offset = CONFIG_PARTITION_TABLE_OFFSET + PARTITION_DATA_OFFSET;
|
||||||
|
else
|
||||||
|
s_partition_offset = CONFIG_PARTITION_TABLE_OFFSET;
|
||||||
|
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "Boot info %x %x %x %x %x", s_boot_param.boot_base.usr_bin, s_boot_param.boot_base.boot_statue,
|
||||||
|
s_boot_param.boot_base.version, user_bin, s_partition_offset);
|
||||||
|
|
||||||
|
return s_partition_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int spi_flash_write_data_safe(uint32_t addr, const void *buf, size_t n)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
static uint8_t check_buf[SPI_FLASH_SEC_SIZE];
|
||||||
|
|
||||||
|
ret = spi_flash_erase(addr);
|
||||||
|
if (ret) {
|
||||||
|
ESP_LOGE(TAG, "erase flash 0x%x error", addr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = spi_flash_write_data(addr, buf, n);
|
||||||
|
if (ret) {
|
||||||
|
ESP_LOGE(TAG, "write flash %d bytes to 0x%x error", n, addr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = spi_flash_read_data(addr, check_buf, n);
|
||||||
|
if (ret) {
|
||||||
|
ESP_LOGE(TAG, "read flash %d bytes from 0x%x error", n, addr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(buf, check_buf, n)) {
|
||||||
|
ESP_LOGE(TAG, "check write flash %d bytes to 0x%x error", n, addr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int esp_flash_sector_copy(uint32_t dest, uint32_t src, uint32_t total_size)
|
||||||
|
{
|
||||||
|
ESP_LOGD(TAG, "Start to copy data from 0x%x to 0x%x total %d", src, dest, total_size);
|
||||||
|
|
||||||
|
for (uint32_t offset = 0; offset < total_size; offset += SPI_FLASH_SEC_SIZE) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = spi_flash_read_data(src + offset, s_cache_buf, SPI_FLASH_SEC_SIZE);
|
||||||
|
if (ret) {
|
||||||
|
ESP_LOGE(TAG, "read flash %d bytes from 0x%x error", SPI_FLASH_SEC_SIZE, src + offset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = spi_flash_write_data_safe(dest + offset, s_cache_buf, SPI_FLASH_SEC_SIZE);
|
||||||
|
if (ret) {
|
||||||
|
ESP_LOGE(TAG, "write flash %d bytes to 0x%x error", SPI_FLASH_SEC_SIZE, dest + offset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int esp_set_v2boot_app1(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
size_t offset = s_sys_param.flag ? 1 : 0;
|
||||||
|
const uint32_t base_addr = CONFIG_SPI_FLASH_SIZE / SPI_FLASH_SEC_SIZE - 3;
|
||||||
|
const uint32_t sys_addr = (base_addr + 2) * SPI_FLASH_SEC_SIZE;
|
||||||
|
const uint32_t to_addr = (base_addr + 1 - offset) * SPI_FLASH_SEC_SIZE;
|
||||||
|
|
||||||
|
if (s_boot_param.boot_base.version == 0x2
|
||||||
|
|| s_boot_param.boot_base.version == 0x1f) {
|
||||||
|
if (s_boot_param.boot_base.usr_bin == 1)
|
||||||
|
s_boot_param.boot_base.usr_bin = 0;
|
||||||
|
else
|
||||||
|
s_boot_param.boot_base.usr_bin = 1;
|
||||||
|
} else {
|
||||||
|
s_boot_param.boot_base.enhance_boot_flag = 1;
|
||||||
|
if (s_boot_param.boot_base.boot_statue != 0) {
|
||||||
|
if (s_boot_param.boot_base.usr_bin == 1)
|
||||||
|
s_boot_param.boot_base.usr_bin = 0;
|
||||||
|
else
|
||||||
|
s_boot_param.boot_base.usr_bin = 1;
|
||||||
|
}
|
||||||
|
s_boot_param.boot_base.boot_statue = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "Boot info %x %x %x", s_boot_param.boot_base.usr_bin, s_boot_param.boot_base.boot_statue, s_boot_param.boot_base.version);
|
||||||
|
|
||||||
|
ret = spi_flash_write_data_safe(to_addr, &s_boot_param, sizeof(boot_param_t));
|
||||||
|
if (ret) {
|
||||||
|
ESP_LOGE(TAG, "write flash %d bytes to 0x%x error", sizeof(boot_param_t), to_addr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_sys_param.flag)
|
||||||
|
s_sys_param.flag = 0;
|
||||||
|
else
|
||||||
|
s_sys_param.flag = 1;
|
||||||
|
|
||||||
|
ret = spi_flash_write_data_safe(sys_addr, &s_sys_param, sizeof(sys_param_t));
|
||||||
|
if (ret) {
|
||||||
|
ESP_LOGE(TAG, "write flash %d bytes to 0x%x error", SPI_FLASH_SEC_SIZE, sys_addr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int esp_sdk_update_from_v2(void)
|
||||||
|
{
|
||||||
|
const int segment_cnt = 3;
|
||||||
|
const size_t v2_max_size = 4096;
|
||||||
|
|
||||||
|
uint32_t segment_base = sizeof(esp_image_header_t);
|
||||||
|
uint32_t segment_size = 0;
|
||||||
|
|
||||||
|
if (s_partition_offset)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
for (int i = 0 ; i < segment_cnt; i++) {
|
||||||
|
int ret;
|
||||||
|
esp_image_segment_header_t segment;
|
||||||
|
|
||||||
|
ret = spi_flash_read_data(segment_base, &segment, sizeof(esp_image_segment_header_t));
|
||||||
|
if (ret) {
|
||||||
|
ESP_LOGE(TAG, "%d read segment @0x%x is %d", i, segment_base, ret);
|
||||||
|
return -1UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "data is %x len is %d", segment.load_addr, segment.data_len);
|
||||||
|
|
||||||
|
segment_size += segment.data_len;
|
||||||
|
|
||||||
|
segment_base += sizeof(esp_image_segment_header_t) + segment.data_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "boot total segment size is %u", segment_size);
|
||||||
|
|
||||||
|
return segment_size <= v2_max_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int esp_patition_table_init_location(void)
|
||||||
|
{
|
||||||
|
uint32_t addr;
|
||||||
|
|
||||||
|
if (!esp_sdk_update_from_v2())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
addr = esp_get_updated_partition_table_addr();
|
||||||
|
if (addr == CONFIG_PARTITION_TABLE_OFFSET)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return esp_flash_sector_copy(CONFIG_PARTITION_TABLE_OFFSET, addr, SPI_FLASH_SEC_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int esp_patition_copy_ota1_to_ota0(const void *partition_info)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
bootloader_state_t *bs = (bootloader_state_t *)partition_info;
|
||||||
|
|
||||||
|
ret = esp_flash_sector_copy(bs->ota[0].offset, bs->ota[1].offset, bs->ota[1].size);
|
||||||
|
if (ret) {
|
||||||
|
ESP_LOGE(TAG, "Fail to copy OTA from 0x%x to 0x%x total %d", bs->ota[1].offset,
|
||||||
|
bs->ota[0].offset, bs->ota[1].size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t offset = 0; offset < bs->ota_info.size; offset += SPI_FLASH_SEC_SIZE) {
|
||||||
|
ret = spi_flash_erase(bs->ota_info.offset + offset);
|
||||||
|
if (ret) {
|
||||||
|
ESP_LOGE(TAG, "Fail to erase OTA data from 0x%x", bs->ota_info.offset + offset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int esp_patition_table_init_data(void *partition_info)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
const uint32_t boot_base = 0x1000;
|
||||||
|
const uint32_t boot_size = CONFIG_SPI_FLASH_SIZE / 2 - boot_base - 4 * SPI_FLASH_SEC_SIZE;
|
||||||
|
|
||||||
|
if (!esp_sdk_update_from_v2())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (esp_get_updated_partition_table_addr() == CONFIG_PARTITION_TABLE_OFFSET)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "Copy firmware1 from %d total %d", boot_base + PARTITION_DATA_OFFSET, boot_size);
|
||||||
|
|
||||||
|
ret = esp_flash_sector_copy(boot_base, boot_base + PARTITION_DATA_OFFSET, boot_size);
|
||||||
|
if (ret) {
|
||||||
|
ESP_LOGE(TAG, "Fail to copy V3 bootloader from 0x%x to 0x%x total %d", boot_base + PARTITION_DATA_OFFSET,
|
||||||
|
boot_base, boot_size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = esp_set_v2boot_app1();
|
||||||
|
if (ret) {
|
||||||
|
ESP_LOGE(TAG, "Fail to update V2 bootloader data");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_hw_reset();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_ESP8266_OTA_FROM_OLD */
|
@ -751,3 +751,29 @@ void esp_spi_flash_init(uint32_t spi_speed, uint32_t spi_mode)
|
|||||||
ESP_EARLY_LOGI("qio_mode", "Enabling default flash chip QIO");
|
ESP_EARLY_LOGI("qio_mode", "Enabling default flash chip QIO");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uintptr_t spi_flash_cache2phys(const void *cached)
|
||||||
|
{
|
||||||
|
uint32_t map_size;
|
||||||
|
uintptr_t addr_offset;
|
||||||
|
uintptr_t addr = (uintptr_t)cached;
|
||||||
|
|
||||||
|
const uint32_t reg = REG_READ(CACHE_FLASH_CTRL_REG);
|
||||||
|
const uint32_t segment = (reg >> CACHE_MAP_SEGMENT_S) & CACHE_MAP_SEGMENT_MASK;
|
||||||
|
|
||||||
|
if (reg & CACHE_MAP_2M) {
|
||||||
|
map_size = CACHE_2M_SIZE;
|
||||||
|
addr_offset = 0;
|
||||||
|
} else {
|
||||||
|
map_size = CACHE_1M_SIZE;
|
||||||
|
if (reg & CACHE_MAP_1M_HIGH)
|
||||||
|
addr_offset = CACHE_1M_SIZE;
|
||||||
|
else
|
||||||
|
addr_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr <= CACHE_BASE_ADDR || addr >= CACHE_BASE_ADDR + map_size)
|
||||||
|
return SPI_FLASH_CACHE2PHYS_FAIL;
|
||||||
|
|
||||||
|
return segment * CACHE_2M_SIZE + (addr + addr_offset - CACHE_BASE_ADDR);
|
||||||
|
}
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
# Name, Type, SubType, Offset, Size, Flags
|
||||||
|
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
|
||||||
|
# Bootloader is at 0x1000 - 0x8000, total 28KB
|
||||||
|
# Partition table is at 0x8000 - 0x9000, total 4KB
|
||||||
|
# Reserve 4 sectors at the end flash address for V2 updating to V3 and system can read V2 parameters.
|
||||||
|
# If you don't need read v2 parameters, don't reserve the 4 sectors.
|
||||||
|
nvs, data, nvs, 0x9000, 0x4000
|
||||||
|
otadata, data, ota, 0xd000, 0x2000
|
||||||
|
phy_init, data, phy, 0xf000, 0x1000
|
||||||
|
ota_0, 0, ota_0, 0x10000, 0x6C000
|
||||||
|
ota_1, 0, ota_1, 0x90000, 0x6C000
|
|
176
tools/pack_fw.py
Normal file
176
tools/pack_fw.py
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
#!/usr/bin/env python2
|
||||||
|
#
|
||||||
|
# Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import inspect
|
||||||
|
import sys
|
||||||
|
import binascii
|
||||||
|
import struct
|
||||||
|
|
||||||
|
__version__ = "1.0.1"
|
||||||
|
|
||||||
|
FLASH_SECTOR_SIZE = 0x1000
|
||||||
|
|
||||||
|
PYTHON2 = sys.version_info[0] < 3
|
||||||
|
|
||||||
|
def esp8266_crc32(data):
|
||||||
|
"""
|
||||||
|
CRC32 algorithm used by 8266 SDK bootloader (and gen_appbin.py).
|
||||||
|
"""
|
||||||
|
crc = binascii.crc32(data, 0) & 0xFFFFFFFF
|
||||||
|
if crc & 0x80000000:
|
||||||
|
return crc ^ 0xFFFFFFFF
|
||||||
|
else:
|
||||||
|
return crc + 1
|
||||||
|
|
||||||
|
def version(args):
|
||||||
|
print(__version__)
|
||||||
|
|
||||||
|
# python pack_fw.py addr1 bin1 addr2 bin2 ......
|
||||||
|
# The address must increase.
|
||||||
|
|
||||||
|
class proc_addr_file(argparse.Action):
|
||||||
|
""" Custom parser class for the address/filename pairs passed as arguments """
|
||||||
|
def __init__(self, option_strings, dest, nargs='+', **kwargs):
|
||||||
|
super(proc_addr_file, self).__init__(option_strings, dest, nargs, **kwargs)
|
||||||
|
|
||||||
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
|
pairs = []
|
||||||
|
for i in range(0, len(values) ,2):
|
||||||
|
try:
|
||||||
|
address = int(values[i], 0)
|
||||||
|
except ValueError:
|
||||||
|
raise argparse.ArgumentError(self, 'Address "%s" must be a number' % values[i])
|
||||||
|
try:
|
||||||
|
argfile = open(values[i + 1], 'rb')
|
||||||
|
except IOError as e:
|
||||||
|
raise argparse.ArgumentError(self, e)
|
||||||
|
pairs.append((address, argfile))
|
||||||
|
|
||||||
|
end = 0
|
||||||
|
pairs = sorted(pairs)
|
||||||
|
for address, argfile in pairs:
|
||||||
|
argfile.seek(0,2) # seek to end
|
||||||
|
size = argfile.tell()
|
||||||
|
argfile.seek(0)
|
||||||
|
sector_start = address & ~(FLASH_SECTOR_SIZE - 1)
|
||||||
|
sector_end = ((address + size + FLASH_SECTOR_SIZE - 1) & ~(FLASH_SECTOR_SIZE - 1)) - 1
|
||||||
|
if sector_start < end:
|
||||||
|
message = 'Detected overlap at address: 0x%x for file: %s' % (address, argfile.name)
|
||||||
|
raise argparse.ArgumentError(self, message)
|
||||||
|
end = sector_end
|
||||||
|
setattr(namespace, self.dest, pairs)
|
||||||
|
|
||||||
|
def pack3(args):
|
||||||
|
fw_data = ''
|
||||||
|
|
||||||
|
try:
|
||||||
|
output_file = open(args.output, "w+")
|
||||||
|
except IOError as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
end_addr = None
|
||||||
|
for address, argfile in args.addr_filename:
|
||||||
|
if address == 0:
|
||||||
|
address = 4096
|
||||||
|
|
||||||
|
if end_addr is not None and address > end_addr:
|
||||||
|
data = (address - end_addr) * ['ff']
|
||||||
|
filled = binascii.a2b_hex(''.join(data))
|
||||||
|
fw_data += filled
|
||||||
|
|
||||||
|
try:
|
||||||
|
argfile.seek(0, 0)
|
||||||
|
data = argfile.read()
|
||||||
|
fw_data += data
|
||||||
|
|
||||||
|
argfile.seek(0, 2)
|
||||||
|
end_addr = address + argfile.tell()
|
||||||
|
except IOError as e:
|
||||||
|
raise e
|
||||||
|
|
||||||
|
crc32 = esp8266_crc32(fw_data)
|
||||||
|
fw_data += struct.pack('<I', crc32)
|
||||||
|
|
||||||
|
try:
|
||||||
|
output_file.write(fw_data)
|
||||||
|
output_file.close()
|
||||||
|
except IOError as e:
|
||||||
|
raise e
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='pack_fw v%s - ESP8266 ROM Bootloader Utility' % __version__, prog='pack_fw')
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'--output', '-o',
|
||||||
|
help='Output file name with full path',
|
||||||
|
default=None)
|
||||||
|
|
||||||
|
subparsers = parser.add_subparsers(
|
||||||
|
dest='operation',
|
||||||
|
help='Run pack_fw {command} -h for additional help')
|
||||||
|
|
||||||
|
parser_pack_fw = subparsers.add_parser(
|
||||||
|
'pack3',
|
||||||
|
help='Pack the V3 firmware')
|
||||||
|
parser_pack_fw.add_argument('addr_filename', metavar='<address> <filename>', help='Address followed by binary filename, separated by space',
|
||||||
|
action=proc_addr_file)
|
||||||
|
|
||||||
|
print('pack_fw.py v%s' % __version__)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.operation is None:
|
||||||
|
parser.print_help()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
operation_func = globals()[args.operation]
|
||||||
|
|
||||||
|
if PYTHON2:
|
||||||
|
# This function is depreciated in Python3
|
||||||
|
operation_args = inspect.getargspec(operation_func).args
|
||||||
|
else:
|
||||||
|
operation_args = inspect.getfullargspec(operation_func).args
|
||||||
|
|
||||||
|
operation_func(args)
|
||||||
|
|
||||||
|
class FatalError(RuntimeError):
|
||||||
|
"""
|
||||||
|
Wrapper class for runtime errors that aren't caused by internal bugs, but by
|
||||||
|
ESP8266 responses or input content.
|
||||||
|
"""
|
||||||
|
def __init__(self, message):
|
||||||
|
RuntimeError.__init__(self, message)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def WithResult(message, result):
|
||||||
|
"""
|
||||||
|
Return a fatal error object that appends the hex values of
|
||||||
|
'result' as a string formatted argument.
|
||||||
|
"""
|
||||||
|
message += " (result was %s)" % hexify(result)
|
||||||
|
return FatalError(message)
|
||||||
|
|
||||||
|
def _main():
|
||||||
|
try:
|
||||||
|
main()
|
||||||
|
except FatalError as e:
|
||||||
|
print('\nA fatal error occurred: %s' % e)
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
_main()
|
Reference in New Issue
Block a user