Add rboot support: build and memory mapping.

This commit is contained in:
Chris Christensen
2018-08-31 20:40:40 -07:00
parent f3c2990112
commit a5461e5bd8
9 changed files with 1038 additions and 4 deletions

View File

@@ -52,7 +52,9 @@ CFLAGS = -Os -g -O2 -Wpointer-arith -Wundef -Werror -Wl,-EL -fno-inline-functio
LDFLAGS = -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static -L.
# linker script used for the above linkier step
LD_SCRIPT = eagle.app.v6.ld
#LD_SCRIPT = eagle.app.v6.ld
LD_SCRIPT = -Trom0.ld
#LD_SCRIPT = -Trom1.ld
# various paths from the SDK used in this project
SDK_LIBDIR = lib
@@ -86,7 +88,7 @@ LIBS := $(addprefix -l,$(LIBS))
APP_AR := $(addprefix $(BUILD_BASE)/,$(TARGET)_app.a)
TARGET_OUT := $(addprefix $(BUILD_BASE)/,$(TARGET).out)
LD_SCRIPT := $(addprefix -T$(SDK_BASE)/$(SDK_LDDIR)/,$(LD_SCRIPT))
#LD_SCRIPT := $(addprefix -T$(SDK_BASE)/$(SDK_LDDIR)/,$(LD_SCRIPT))
INCDIR := $(addprefix -I,$(SRC_DIR))
EXTRA_INCDIR := $(addprefix -I,$(EXTRA_INCDIR))
@@ -118,7 +120,7 @@ all: checkdirs $(TARGET_OUT) $(FW_FILE_1) $(FW_FILE_2)
$(FW_BASE)/%.bin: $(TARGET_OUT) | $(FW_BASE)
$(vecho) "FW $(FW_BASE)/"
$(Q) $(ESPTOOL) elf2image -o $(FW_BASE)/ $(TARGET_OUT)
$(Q) $(ESPTOOL) elf2image --version=2 $(TARGET_OUT)
$(TARGET_OUT): $(APP_AR)
$(vecho) "LD $@"

View File

@@ -349,6 +349,7 @@ Now you can configure the new Ethernet interface:
- set eth_netmask _netmask_: sets a static netmask for the ETH interface
- set eth_gw _gw-addr_: sets a static gateway address for the ETH interface
# Building and Flashing
To build this binary you download and install the esp-open-sdk (https://github.com/pfalcon/esp-open-sdk). Make sure, you can compile and download the included "blinky" example.
@@ -364,6 +365,46 @@ On Windows you can flash it using the "ESP8266 Download Tool" available at https
If "QIO" mode fails on your device, try "DIO" instead. Also have a look at the "Detected Info" to check size and mode of the flash chip. If your downloaded firmware still doesn't start properly, please check with the enclosed checksums whether the binary files are possibly corrupted.
# OTA (Over the air) update support
Based on using the rboot lib: https://github.com/raburton/rboot
User flash location `FLASH_BLOCK_NO` was updated as `0x0c` -> `0x1aee` conflicted with the rboot memory locations.
Memory mapping updates:
Example flashing update based on new bin files: `$ esptool.py write_flash 0x00000 rboot.bin 0x02000 app-0x02000.bin 0x82000 app-0x82000.bin`
`rboot.bin` is from raburton/rboot "Building" and "Installation" instructions.
Note: "Linking user code" from rboot documentation:
`rom0.ld`
```diff
$ diff -u ../esp-open-sdk/sdk/ld/eagle.app.v6.ld rom0.ld
--- ../esp-open-sdk/sdk/ld/eagle.app.v6.ld 2018-08-19 10:32:30.932083233 -0700
+++ rom0.ld 2018-08-21 20:39:36.838230232 -0700
@@ -5,7 +5,7 @@
dport0_0_seg : org = 0x3FF00000, len = 0x10
dram0_0_seg : org = 0x3FFE8000, len = 0x14000
iram1_0_seg : org = 0x40100000, len = 0x8000
- irom0_0_seg : org = 0x40210000, len = 0x5C000
+ irom0_0_seg : org = 0x40202010, len = 0x5C000
}
PHDRS
@@ -227,4 +227,4 @@
}
/* get ROM code address */
-INCLUDE "../ld/eagle.rom.addr.v6.ld"
+INCLUDE "eagle.rom.addr.v6.ld"
```
`rom1.ld`
```diff
- irom0_0_seg : org = 0x40210000, len = 0x5C000
+ irom0_0_seg : org = 0x40282010, len = 0x5C000
```
# Known Issues
- Due to the limitations of the ESP's SoftAP implementation, there is a maximum of 8 simultaniously connected stations.
- The ESP8266 requires a good power supply as it produces current spikes of up to 170 mA during transmit (typical average consumption is around 70 mA when WiFi is on). Check the power supply first, if your ESP runs unstable and reboots from time to time. A large capacitor between Vdd and Gnd can help if you experience problems here.

230
rom0.ld Normal file
View File

@@ -0,0 +1,230 @@
/* This linker script generated from xt-genldscripts.tpp for LSP . */
/* Linker Script for ld -N */
MEMORY
{
dport0_0_seg : org = 0x3FF00000, len = 0x10
dram0_0_seg : org = 0x3FFE8000, len = 0x14000
iram1_0_seg : org = 0x40100000, len = 0x8000
irom0_0_seg : org = 0x40202010, len = 0x5C000
}
PHDRS
{
dport0_0_phdr PT_LOAD;
dram0_0_phdr PT_LOAD;
dram0_0_bss_phdr PT_LOAD;
iram1_0_phdr PT_LOAD;
irom0_0_phdr PT_LOAD;
}
/* Default entry point: */
ENTRY(call_user_start)
EXTERN(_DebugExceptionVector)
EXTERN(_DoubleExceptionVector)
EXTERN(_KernelExceptionVector)
EXTERN(_NMIExceptionVector)
EXTERN(_UserExceptionVector)
PROVIDE(_memmap_vecbase_reset = 0x40000000);
/* Various memory-map dependent cache attribute settings: */
_memmap_cacheattr_wb_base = 0x00000110;
_memmap_cacheattr_wt_base = 0x00000110;
_memmap_cacheattr_bp_base = 0x00000220;
_memmap_cacheattr_unused_mask = 0xFFFFF00F;
_memmap_cacheattr_wb_trapnull = 0x2222211F;
_memmap_cacheattr_wba_trapnull = 0x2222211F;
_memmap_cacheattr_wbna_trapnull = 0x2222211F;
_memmap_cacheattr_wt_trapnull = 0x2222211F;
_memmap_cacheattr_bp_trapnull = 0x2222222F;
_memmap_cacheattr_wb_strict = 0xFFFFF11F;
_memmap_cacheattr_wt_strict = 0xFFFFF11F;
_memmap_cacheattr_bp_strict = 0xFFFFF22F;
_memmap_cacheattr_wb_allvalid = 0x22222112;
_memmap_cacheattr_wt_allvalid = 0x22222112;
_memmap_cacheattr_bp_allvalid = 0x22222222;
PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull);
SECTIONS
{
.dport0.rodata : ALIGN(4)
{
_dport0_rodata_start = ABSOLUTE(.);
*(.dport0.rodata)
*(.dport.rodata)
_dport0_rodata_end = ABSOLUTE(.);
} >dport0_0_seg :dport0_0_phdr
.dport0.literal : ALIGN(4)
{
_dport0_literal_start = ABSOLUTE(.);
*(.dport0.literal)
*(.dport.literal)
_dport0_literal_end = ABSOLUTE(.);
} >dport0_0_seg :dport0_0_phdr
.dport0.data : ALIGN(4)
{
_dport0_data_start = ABSOLUTE(.);
*(.dport0.data)
*(.dport.data)
_dport0_data_end = ABSOLUTE(.);
} >dport0_0_seg :dport0_0_phdr
.data : ALIGN(4)
{
_data_start = ABSOLUTE(.);
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
*(.data1)
*(.sdata)
*(.sdata.*)
*(.gnu.linkonce.s.*)
*(.sdata2)
*(.sdata2.*)
*(.gnu.linkonce.s2.*)
*(.jcr)
_data_end = ABSOLUTE(.);
} >dram0_0_seg :dram0_0_phdr
.rodata : ALIGN(4)
{
_rodata_start = ABSOLUTE(.);
*(.sdk.version)
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
*(.rodata1)
__XT_EXCEPTION_TABLE__ = ABSOLUTE(.);
*(.xt_except_table)
*(.gcc_except_table)
*(.gnu.linkonce.e.*)
*(.gnu.version_r)
*(.eh_frame)
/* C++ constructor and destructor tables, properly ordered: */
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
/* C++ exception handlers table: */
__XT_EXCEPTION_DESCS__ = ABSOLUTE(.);
*(.xt_except_desc)
*(.gnu.linkonce.h.*)
__XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.);
*(.xt_except_desc_end)
*(.dynamic)
*(.gnu.version_d)
. = ALIGN(4); /* this table MUST be 4-byte aligned */
_bss_table_start = ABSOLUTE(.);
LONG(_bss_start)
LONG(_bss_end)
_bss_table_end = ABSOLUTE(.);
_rodata_end = ABSOLUTE(.);
} >dram0_0_seg :dram0_0_phdr
.bss ALIGN(8) (NOLOAD) : ALIGN(4)
{
. = ALIGN (8);
_bss_start = ABSOLUTE(.);
*(.dynsbss)
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
*(.scommon)
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
*(.dynbss)
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN (8);
_bss_end = ABSOLUTE(.);
_heap_start = ABSOLUTE(.);
/* _stack_sentry = ALIGN(0x8); */
} >dram0_0_seg :dram0_0_bss_phdr
/* __stack = 0x3ffc8000; */
.irom0.text : ALIGN(4)
{
_irom0_text_start = ABSOLUTE(.);
*libat.a:(.literal.* .text.*)
*libcrypto.a:(.literal.* .text.*)
*libespnow.a:(.literal.* .text.*)
*libjson.a:(.literal.* .text.*)
*liblwip.a:(.literal.* .text.*)
*libmesh.a:(.literal.* .text.*)
*libnet80211.a:(.literal.* .text.*)
*libsmartconfig.a:(.literal.* .text.*)
*libssl.a:(.literal.* .text.*)
*libupgrade.a:(.literal.* .text.*)
*libwpa.a:(.literal.* .text.*)
*libwpa2.a:(.literal.* .text.*)
*libwps.a:(.literal.* .text.*)
*libmbedtls.a:(.literal.* .text.*)
*libm.a:(.literal .text .literal.* .text.*)
*(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text)
_irom0_text_end = ABSOLUTE(.);
} >irom0_0_seg :irom0_0_phdr
.text : ALIGN(4)
{
_stext = .;
_text_start = ABSOLUTE(.);
*(.UserEnter.text)
. = ALIGN(16);
*(.DebugExceptionVector.text)
. = ALIGN(16);
*(.NMIExceptionVector.text)
. = ALIGN(16);
*(.KernelExceptionVector.text)
LONG(0)
LONG(0)
LONG(0)
LONG(0)
. = ALIGN(16);
*(.UserExceptionVector.text)
LONG(0)
LONG(0)
LONG(0)
LONG(0)
. = ALIGN(16);
*(.DoubleExceptionVector.text)
LONG(0)
LONG(0)
LONG(0)
LONG(0)
. = ALIGN (16);
*(.entry.text)
*(.init.literal)
*(.init)
*(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
*(.fini.literal)
*(.fini)
*(.gnu.version)
_text_end = ABSOLUTE(.);
_etext = .;
} >iram1_0_seg :iram1_0_phdr
.lit4 : ALIGN(4)
{
_lit4_start = ABSOLUTE(.);
*(*.lit4)
*(.lit4.*)
*(.gnu.linkonce.lit4.*)
_lit4_end = ABSOLUTE(.);
} >iram1_0_seg :iram1_0_phdr
}
/* get ROM code address */
INCLUDE "eagle.rom.addr.v6.ld"

230
rom1.ld Normal file
View File

@@ -0,0 +1,230 @@
/* This linker script generated from xt-genldscripts.tpp for LSP . */
/* Linker Script for ld -N */
MEMORY
{
dport0_0_seg : org = 0x3FF00000, len = 0x10
dram0_0_seg : org = 0x3FFE8000, len = 0x14000
iram1_0_seg : org = 0x40100000, len = 0x8000
irom0_0_seg : org = 0x40282010, len = 0x5C000
}
PHDRS
{
dport0_0_phdr PT_LOAD;
dram0_0_phdr PT_LOAD;
dram0_0_bss_phdr PT_LOAD;
iram1_0_phdr PT_LOAD;
irom0_0_phdr PT_LOAD;
}
/* Default entry point: */
ENTRY(call_user_start)
EXTERN(_DebugExceptionVector)
EXTERN(_DoubleExceptionVector)
EXTERN(_KernelExceptionVector)
EXTERN(_NMIExceptionVector)
EXTERN(_UserExceptionVector)
PROVIDE(_memmap_vecbase_reset = 0x40000000);
/* Various memory-map dependent cache attribute settings: */
_memmap_cacheattr_wb_base = 0x00000110;
_memmap_cacheattr_wt_base = 0x00000110;
_memmap_cacheattr_bp_base = 0x00000220;
_memmap_cacheattr_unused_mask = 0xFFFFF00F;
_memmap_cacheattr_wb_trapnull = 0x2222211F;
_memmap_cacheattr_wba_trapnull = 0x2222211F;
_memmap_cacheattr_wbna_trapnull = 0x2222211F;
_memmap_cacheattr_wt_trapnull = 0x2222211F;
_memmap_cacheattr_bp_trapnull = 0x2222222F;
_memmap_cacheattr_wb_strict = 0xFFFFF11F;
_memmap_cacheattr_wt_strict = 0xFFFFF11F;
_memmap_cacheattr_bp_strict = 0xFFFFF22F;
_memmap_cacheattr_wb_allvalid = 0x22222112;
_memmap_cacheattr_wt_allvalid = 0x22222112;
_memmap_cacheattr_bp_allvalid = 0x22222222;
PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull);
SECTIONS
{
.dport0.rodata : ALIGN(4)
{
_dport0_rodata_start = ABSOLUTE(.);
*(.dport0.rodata)
*(.dport.rodata)
_dport0_rodata_end = ABSOLUTE(.);
} >dport0_0_seg :dport0_0_phdr
.dport0.literal : ALIGN(4)
{
_dport0_literal_start = ABSOLUTE(.);
*(.dport0.literal)
*(.dport.literal)
_dport0_literal_end = ABSOLUTE(.);
} >dport0_0_seg :dport0_0_phdr
.dport0.data : ALIGN(4)
{
_dport0_data_start = ABSOLUTE(.);
*(.dport0.data)
*(.dport.data)
_dport0_data_end = ABSOLUTE(.);
} >dport0_0_seg :dport0_0_phdr
.data : ALIGN(4)
{
_data_start = ABSOLUTE(.);
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
*(.data1)
*(.sdata)
*(.sdata.*)
*(.gnu.linkonce.s.*)
*(.sdata2)
*(.sdata2.*)
*(.gnu.linkonce.s2.*)
*(.jcr)
_data_end = ABSOLUTE(.);
} >dram0_0_seg :dram0_0_phdr
.rodata : ALIGN(4)
{
_rodata_start = ABSOLUTE(.);
*(.sdk.version)
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
*(.rodata1)
__XT_EXCEPTION_TABLE__ = ABSOLUTE(.);
*(.xt_except_table)
*(.gcc_except_table)
*(.gnu.linkonce.e.*)
*(.gnu.version_r)
*(.eh_frame)
/* C++ constructor and destructor tables, properly ordered: */
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
/* C++ exception handlers table: */
__XT_EXCEPTION_DESCS__ = ABSOLUTE(.);
*(.xt_except_desc)
*(.gnu.linkonce.h.*)
__XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.);
*(.xt_except_desc_end)
*(.dynamic)
*(.gnu.version_d)
. = ALIGN(4); /* this table MUST be 4-byte aligned */
_bss_table_start = ABSOLUTE(.);
LONG(_bss_start)
LONG(_bss_end)
_bss_table_end = ABSOLUTE(.);
_rodata_end = ABSOLUTE(.);
} >dram0_0_seg :dram0_0_phdr
.bss ALIGN(8) (NOLOAD) : ALIGN(4)
{
. = ALIGN (8);
_bss_start = ABSOLUTE(.);
*(.dynsbss)
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
*(.scommon)
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
*(.dynbss)
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN (8);
_bss_end = ABSOLUTE(.);
_heap_start = ABSOLUTE(.);
/* _stack_sentry = ALIGN(0x8); */
} >dram0_0_seg :dram0_0_bss_phdr
/* __stack = 0x3ffc8000; */
.irom0.text : ALIGN(4)
{
_irom0_text_start = ABSOLUTE(.);
*libat.a:(.literal.* .text.*)
*libcrypto.a:(.literal.* .text.*)
*libespnow.a:(.literal.* .text.*)
*libjson.a:(.literal.* .text.*)
*liblwip.a:(.literal.* .text.*)
*libmesh.a:(.literal.* .text.*)
*libnet80211.a:(.literal.* .text.*)
*libsmartconfig.a:(.literal.* .text.*)
*libssl.a:(.literal.* .text.*)
*libupgrade.a:(.literal.* .text.*)
*libwpa.a:(.literal.* .text.*)
*libwpa2.a:(.literal.* .text.*)
*libwps.a:(.literal.* .text.*)
*libmbedtls.a:(.literal.* .text.*)
*libm.a:(.literal .text .literal.* .text.*)
*(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text)
_irom0_text_end = ABSOLUTE(.);
} >irom0_0_seg :irom0_0_phdr
.text : ALIGN(4)
{
_stext = .;
_text_start = ABSOLUTE(.);
*(.UserEnter.text)
. = ALIGN(16);
*(.DebugExceptionVector.text)
. = ALIGN(16);
*(.NMIExceptionVector.text)
. = ALIGN(16);
*(.KernelExceptionVector.text)
LONG(0)
LONG(0)
LONG(0)
LONG(0)
. = ALIGN(16);
*(.UserExceptionVector.text)
LONG(0)
LONG(0)
LONG(0)
LONG(0)
. = ALIGN(16);
*(.DoubleExceptionVector.text)
LONG(0)
LONG(0)
LONG(0)
LONG(0)
. = ALIGN (16);
*(.entry.text)
*(.init.literal)
*(.init)
*(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
*(.fini.literal)
*(.fini)
*(.gnu.version)
_text_end = ABSOLUTE(.);
_etext = .;
} >iram1_0_seg :iram1_0_phdr
.lit4 : ALIGN(4)
{
_lit4_start = ABSOLUTE(.);
*(*.lit4)
*(.lit4.*)
*(.gnu.linkonce.lit4.*)
_lit4_end = ABSOLUTE(.);
} >iram1_0_seg :iram1_0_phdr
}
/* get ROM code address */
INCLUDE "eagle.rom.addr.v6.ld"

View File

@@ -14,7 +14,7 @@
#include "user_config.h"
#include "acl.h"
#define FLASH_BLOCK_NO 0xc
#define FLASH_BLOCK_NO 0x1aee
#define MAGIC_NUMBER 0x152435fc

219
user/rboot-api.c Normal file
View File

@@ -0,0 +1,219 @@
//////////////////////////////////////////////////
// rBoot OTA and config API for ESP8266.
// Copyright 2015 Richard A Burton
// richardaburton@gmail.com
// See license.txt for license terms.
// OTA code based on SDK sample from Espressif.
//////////////////////////////////////////////////
#include <string.h>
#include <c_types.h>
#include "osapi.h"
#include <spi_flash.h>
// detect rtos sdk (not ideal method!)
#ifdef IRAM_ATTR
#define os_free(s) vPortFree(s)
#define os_malloc(s) pvPortMalloc(s)
#else
#include <mem.h>
#endif
#include "rboot-api.h"
#ifdef __cplusplus
extern "C" {
#endif
#if defined(BOOT_CONFIG_CHKSUM) || defined(BOOT_RTC_ENABLED)
// calculate checksum for block of data
// from start up to (but excluding) end
static uint8 calc_chksum(uint8 *start, uint8 *end) {
uint8 chksum = CHKSUM_INIT;
while(start < end) {
chksum ^= *start;
start++;
}
return chksum;
}
#endif
// get the rboot config
rboot_config ICACHE_FLASH_ATTR rboot_get_config(void) {
rboot_config conf;
spi_flash_read(BOOT_CONFIG_SECTOR * SECTOR_SIZE, (uint32*)&conf, sizeof(rboot_config));
return conf;
}
// write the rboot config
// preserves the contents of the rest of the sector,
// so the rest of the sector can be used to store user data
// updates checksum automatically (if enabled)
bool ICACHE_FLASH_ATTR rboot_set_config(rboot_config *conf) {
uint8 *buffer;
buffer = (uint8*)os_malloc(SECTOR_SIZE);
if (!buffer) {
//os_printf("No ram!\r\n");
return false;
}
#ifdef BOOT_CONFIG_CHKSUM
conf->chksum = calc_chksum((uint8*)conf, (uint8*)&conf->chksum);
#endif
spi_flash_read(BOOT_CONFIG_SECTOR * SECTOR_SIZE, (uint32*)((void*)buffer), SECTOR_SIZE);
os_memcpy(buffer, conf, sizeof(rboot_config));
spi_flash_erase_sector(BOOT_CONFIG_SECTOR);
//spi_flash_write(BOOT_CONFIG_SECTOR * SECTOR_SIZE, (uint32*)((void*)buffer), SECTOR_SIZE);
spi_flash_write(BOOT_CONFIG_SECTOR * SECTOR_SIZE, (uint32*)((void*)buffer), SECTOR_SIZE);
os_free(buffer);
return true;
}
// get current boot rom
uint8 ICACHE_FLASH_ATTR rboot_get_current_rom(void) {
rboot_config conf;
conf = rboot_get_config();
return conf.current_rom;
}
// set current boot rom
bool ICACHE_FLASH_ATTR rboot_set_current_rom(uint8 rom) {
rboot_config conf;
conf = rboot_get_config();
if (rom >= conf.count) return false;
conf.current_rom = rom;
return rboot_set_config(&conf);
}
// create the write status struct, based on supplied start address
rboot_write_status ICACHE_FLASH_ATTR rboot_write_init(uint32 start_addr) {
rboot_write_status status = {0};
status.start_addr = start_addr;
status.start_sector = start_addr / SECTOR_SIZE;
status.last_sector_erased = status.start_sector - 1;
//status.max_sector_count = 200;
//os_printf("init addr: 0x%08x\r\n", start_addr);
return status;
}
// ensure any remaning bytes get written (needed for files not a multiple of 4 bytes)
bool ICACHE_FLASH_ATTR rboot_write_end(rboot_write_status *status) {
uint8 i;
if (status->extra_count != 0) {
for (i = status->extra_count; i < 4; i++) {
status->extra_bytes[i] = 0xff;
}
return rboot_write_flash(status, status->extra_bytes, 4);
}
return true;
}
// function to do the actual writing to flash
// call repeatedly with more data (max len per write is the flash sector size (4k))
bool ICACHE_FLASH_ATTR rboot_write_flash(rboot_write_status *status, uint8 *data, uint16 len) {
bool ret = false;
uint8 *buffer;
int32 lastsect;
if (data == NULL || len == 0) {
return true;
}
// get a buffer
buffer = (uint8 *)os_malloc(len + status->extra_count);
if (!buffer) {
//os_printf("No ram!\r\n");
return false;
}
// copy in any remaining bytes from last chunk
if (status->extra_count != 0) {
os_memcpy(buffer, status->extra_bytes, status->extra_count);
}
// copy in new data
os_memcpy(buffer + status->extra_count, data, len);
// calculate length, must be multiple of 4
// save any remaining bytes for next go
len += status->extra_count;
status->extra_count = len % 4;
len -= status->extra_count;
os_memcpy(status->extra_bytes, buffer + len, status->extra_count);
// check data will fit
//if (status->start_addr + len < (status->start_sector + status->max_sector_count) * SECTOR_SIZE) {
// erase any additional sectors needed by this chunk
lastsect = ((status->start_addr + len) - 1) / SECTOR_SIZE;
while (lastsect > status->last_sector_erased) {
status->last_sector_erased++;
spi_flash_erase_sector(status->last_sector_erased);
}
// write current chunk
//os_printf("write addr: 0x%08x, len: 0x%04x\r\n", status->start_addr, len);
if (spi_flash_write(status->start_addr, (uint32 *)((void*)buffer), len) == SPI_FLASH_RESULT_OK) {
ret = true;
status->start_addr += len;
}
//}
os_free(buffer);
return ret;
}
#ifdef BOOT_RTC_ENABLED
bool ICACHE_FLASH_ATTR rboot_get_rtc_data(rboot_rtc_data *rtc) {
if (system_rtc_mem_read(RBOOT_RTC_ADDR, rtc, sizeof(rboot_rtc_data))) {
return (rtc->chksum == calc_chksum((uint8*)rtc, (uint8*)&rtc->chksum));
}
return false;
}
bool ICACHE_FLASH_ATTR rboot_set_rtc_data(rboot_rtc_data *rtc) {
// calculate checksum
rtc->chksum = calc_chksum((uint8*)rtc, (uint8*)&rtc->chksum);
return system_rtc_mem_write(RBOOT_RTC_ADDR, rtc, sizeof(rboot_rtc_data));
}
bool ICACHE_FLASH_ATTR rboot_set_temp_rom(uint8 rom) {
rboot_rtc_data rtc;
// invalid data in rtc?
if (!rboot_get_rtc_data(&rtc)) {
// set basics
rtc.magic = RBOOT_RTC_MAGIC;
rtc.last_mode = MODE_STANDARD;
rtc.last_rom = 0;
}
// set next boot to temp mode with specified rom
rtc.next_mode = MODE_TEMP_ROM;
rtc.temp_rom = rom;
return rboot_set_rtc_data(&rtc);
}
bool ICACHE_FLASH_ATTR rboot_get_last_boot_rom(uint8 *rom) {
rboot_rtc_data rtc;
if (rboot_get_rtc_data(&rtc)) {
*rom = rtc.last_rom;
return true;
}
return false;
}
bool ICACHE_FLASH_ATTR rboot_get_last_boot_mode(uint8 *mode) {
rboot_rtc_data rtc;
if (rboot_get_rtc_data(&rtc)) {
*mode = rtc.last_mode;
return true;
}
return false;
}
#endif
#ifdef __cplusplus
}
#endif

145
user/rboot-api.h Normal file
View File

@@ -0,0 +1,145 @@
#ifndef __RBOOT_API_H__
#define __RBOOT_API_H__
/** @defgroup rboot rBoot API
* @brief rBoot for ESP8266 API allows runtime code to access the rBoot configuration.
* Configuration may be read to use within the main firmware or updated to
* affect next boot behavior.
* @copyright 2015 Richard A Burton
* @author richardaburton@gmail.com
* @author OTA code based on SDK sample from Espressif
* @license See licence.txt for license terms.
* @{
*/
#include "rboot.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Structure defining flash write status
* @note The user application should not modify the contents of this
* structure.
* @see rboot_write_flash
*/
typedef struct {
uint32 start_addr;
uint32 start_sector;
//uint32 max_sector_count;
int32 last_sector_erased;
uint8 extra_count;
uint8 extra_bytes[4];
} rboot_write_status;
/** @brief Read rBoot configuration from flash
* @retval rboot_config Copy of the rBoot configuration
* @note Returns rboot_config (defined in rboot.h) allowing you to modify any values
* in it, including the ROM layout.
*/
rboot_config ICACHE_FLASH_ATTR rboot_get_config(void);
/** @brief Write rBoot configuration to flash memory
* @param conf pointer to a rboot_config structure containing configuration to save
* @retval bool True on success
* @note Saves the rboot_config structure back to configuration sector (BOOT_CONFIG_SECTOR)
* of the flash, while maintaining the contents of the rest of the sector.
* You can use the rest of this sector for your app settings, as long as you
* protect this structure when you do so.
*/
bool ICACHE_FLASH_ATTR rboot_set_config(rboot_config *conf);
/** @brief Get index of current ROM
* @retval uint8 Index of the current ROM
* @note Get the currently selected boot ROM (this will be the currently
* running ROM, as long as you haven't changed it since boot or rBoot
* booted the rom in temporary boot mode, see rboot_get_last_boot_rom).
*/
uint8 ICACHE_FLASH_ATTR rboot_get_current_rom(void);
/** @brief Set the index of current ROM
* @param rom The index of the ROM to use on next boot
* @retval bool True on success
* @note Set the current boot ROM, which will be used when next restarted.
* @note This function re-writes the whole configuration to flash memory (not just the current ROM index)
*/
bool ICACHE_FLASH_ATTR rboot_set_current_rom(uint8 rom);
/** @brief Initialise flash write process
* @param start_addr Address on the SPI flash to begin write to
* @note Call once before starting to pass data to write to flash memory with rboot_write_flash function.
* start_addr is the address on the SPI flash to write from. Returns a status structure which
* must be passed back on each write. The contents of the structure should not
* be modified by the calling code.
*/
rboot_write_status ICACHE_FLASH_ATTR rboot_write_init(uint32 start_addr);
/** @brief Complete flash write process
* @param status Pointer to rboot_write_status structure defining the write status
* @note Call at the completion of flash writing. This ensures any
* outstanding bytes are written (if data so far hasn't been a multiple
* of 4 bytes there will be a few bytes unwritten, until you call
* this function).
*/
bool ICACHE_FLASH_ATTR rboot_write_end(rboot_write_status *status);
/** @brief Write data to flash memory
* @param status Pointer to rboot_write_status structure defining the write status
* @param data Pointer to a block of uint8 data elements to be written to flash
* @param len Quantity of uint8 data elements to write to flash
* @note Call repeatedly to write data to the flash, starting at the address
* specified on the prior call to rboot_write_init. Current write position is
* tracked automatically. This method is likely to be called each time a packet
* of OTA data is received over the network.
* @note Call rboot_write_init before calling this function to get the rboot_write_status structure
*/
bool ICACHE_FLASH_ATTR rboot_write_flash(rboot_write_status *status, uint8 *data, uint16 len);
#ifdef BOOT_RTC_ENABLED
/** @brief Get rBoot status/control data from RTC data area
* @param rtc Pointer to a rboot_rtc_data structure to be populated
* @retval bool True on success, false if no data/invalid checksum (in which
* case do not use the contents of the structure)
*/
bool ICACHE_FLASH_ATTR rboot_get_rtc_data(rboot_rtc_data *rtc);
/** @brief Set rBoot status/control data in RTC data area
* @param rtc pointer to a rboot_rtc_data structure
* @retval bool True on success
* @note The checksum will be calculated automatically for you.
*/
bool ICACHE_FLASH_ATTR rboot_set_rtc_data(rboot_rtc_data *rtc);
/** @brief Set temporary rom for next boot
* @param rom Rom slot number for next boot
* @retval bool True on success
* @note This call will tell rBoot to temporarily boot the specified rom on
* the next boot. This is does not update the stored rBoot config on
* the flash, so after another reset it will boot back to the original
* rom.
*/
bool ICACHE_FLASH_ATTR rboot_set_temp_rom(uint8 rom);
/** @brief Get the last booted rom slot number
* @param rom Pointer to rom slot number variable to populate
* @retval bool True on success, false if no data/invalid checksum
* @note This will find the currently running rom, even if booted as a
* temporary rom.
*/
bool ICACHE_FLASH_ATTR rboot_get_last_boot_rom(uint8 *rom);
/** @brief Get the last boot mode
* @param mode Pointer to mode variable to populate
* @retval bool True on success, false if no data/invalid checksum
* @note This will indicate the type of boot: MODE_STANDARD, MODE_GPIO_ROM or
* MODE_TEMP_ROM.
*/
bool ICACHE_FLASH_ATTR rboot_get_last_boot_mode(uint8 *mode);
#endif
#ifdef __cplusplus
}
#endif
/** @} */
#endif

159
user/rboot.h Normal file
View File

@@ -0,0 +1,159 @@
#ifndef __RBOOT_H__
#define __RBOOT_H__
//////////////////////////////////////////////////
// rBoot open source boot loader for ESP8266.
// Copyright 2015 Richard A Burton
// richardaburton@gmail.com
// See license.txt for license terms.
//////////////////////////////////////////////////
#ifdef __cplusplus
extern "C" {
#endif
#include <c_types.h> // uint* types
#ifdef RBOOT_INTEGRATION
#include <rboot-integration.h>
#endif
// uncomment to use only c code
// if you aren't using gcc you may need to do this
//#define BOOT_NO_ASM
// uncomment to have a checksum on the boot config
//#define BOOT_CONFIG_CHKSUM
// uncomment to enable big flash support (>1MB)
//#define BOOT_BIG_FLASH
// uncomment to enable 2 way communication between
// rBoot and the user app via the esp rtc data area
//#define BOOT_RTC_ENABLED
// uncomment to enable GPIO booting of specific rom
// (specified in rBoot config block)
// cannot be used at same time as BOOT_GPIO_SKIP_ENABLED
//#define BOOT_GPIO_ENABLED
// uncomment to enable GPIO rom skip mode, trigger
// GPIO at boot time to skip to next rom
// cannot be used at same time as BOOT_GPIO_ENABLED
//#define BOOT_GPIO_SKIP_ENABLED
// set the GPIO pin used by GPIO modes above (will default
// to 16 if not manually set), only applicable when
// BOOT_GPIO_ENABLED or BOOT_GPIO_SKIP_ENABLED is enabled
//#define BOOT_GPIO_NUM 16
// uncomment to include .irom0.text section in the checksum
// roms must be built with esptool2 using -iromchksum option
//#define BOOT_IROM_CHKSUM
// uncomment to add a boot delay, allows you time to connect
// a terminal before rBoot starts to run and output messages
// value is in microseconds
//#define BOOT_DELAY_MICROS 2000000
// define your own default custom rBoot config, used on
// first boot and in case of corruption, standard fields
// (magic, version and chksum (if applicable) are included
// for you automatically), see example at end of this file
// and customise as required
//#define BOOT_CUSTOM_DEFAULT_CONFIG
// max number of roms in the config (defaults to 4), higher
// values will use more ram at run time
//#define MAX_ROMS 4
// you should not need to modify anything below this line,
// except default_config() right at the bottom of the file
#define CHKSUM_INIT 0xef
#define SECTOR_SIZE 0x1000
#define BOOT_CONFIG_SECTOR 1
#define BOOT_CONFIG_MAGIC 0xe1
#define BOOT_CONFIG_VERSION 0x01
#define MODE_STANDARD 0x00
#define MODE_GPIO_ROM 0x01
#define MODE_TEMP_ROM 0x02
#define MODE_GPIO_ERASES_SDKCONFIG 0x04
#define MODE_GPIO_SKIP 0x08
#define RBOOT_RTC_MAGIC 0x2334ae68
#define RBOOT_RTC_READ 1
#define RBOOT_RTC_WRITE 0
#define RBOOT_RTC_ADDR 64
// defaults for unset user options
#ifndef BOOT_GPIO_NUM
#define BOOT_GPIO_NUM 16
#endif
#ifndef MAX_ROMS
#define MAX_ROMS 4
#endif
/** @brief Structure containing rBoot configuration
* @note ROM addresses must be multiples of 0x1000 (flash sector aligned).
* Without BOOT_BIG_FLASH only the first 8Mbit (1MB) of the chip will
* be memory mapped so ROM slots containing .irom0.text sections must
* remain below 0x100000. Slots beyond this will only be accessible via
* spi read calls, so use these for stored resources, not code. With
* BOOT_BIG_FLASH the flash will be mapped in chunks of 8MBit (1MB), so
* ROMs can be anywhere, but must not straddle two 8MBit (1MB) blocks.
* @ingroup rboot
*/
typedef struct {
uint8 magic; ///< Our magic, identifies rBoot configuration - should be BOOT_CONFIG_MAGIC
uint8 version; ///< Version of configuration structure - should be BOOT_CONFIG_VERSION
uint8 mode; ///< Boot loader mode (MODE_STANDARD | MODE_GPIO_ROM | MODE_GPIO_SKIP)
uint8 current_rom; ///< Currently selected ROM (will be used for next standard boot)
uint8 gpio_rom; ///< ROM to use for GPIO boot (hardware switch) with mode set to MODE_GPIO_ROM
uint8 count; ///< Quantity of ROMs available to boot
uint8 unused[2]; ///< Padding (not used)
uint32 roms[MAX_ROMS]; ///< Flash addresses of each ROM
#ifdef BOOT_CONFIG_CHKSUM
uint8 chksum; ///< Checksum of this configuration structure (if BOOT_CONFIG_CHKSUM defined)
#endif
} rboot_config;
#ifdef BOOT_RTC_ENABLED
/** @brief Structure containing rBoot status/control data
* @note This structure is used to, optionally, communicate between rBoot and
* the user app. It is stored in the ESP RTC data area.
* @ingroup rboot
*/
typedef struct {
uint32 magic; ///< Magic, identifies rBoot RTC data - should be RBOOT_RTC_MAGIC
uint8 next_mode; ///< The next boot mode, defaults to MODE_STANDARD - can be set to MODE_TEMP_ROM
uint8 last_mode; ///< The last (this) boot mode - can be MODE_STANDARD, MODE_GPIO_ROM or MODE_TEMP_ROM
uint8 last_rom; ///< The last (this) boot rom number
uint8 temp_rom; ///< The next boot rom number when next_mode set to MODE_TEMP_ROM
uint8 chksum; ///< Checksum of this structure this will be updated for you passed to the API
} rboot_rtc_data;
#endif
// override function to create default config, must be placed after type
// and constant defines as it uses some of them, flashsize is the used size
// (may be smaller than actual flash size if big flash mode is not enabled,
// or just plain wrong if the device has not been programmed correctly!)
#ifdef BOOT_CUSTOM_DEFAULT_CONFIG
static uint8 default_config(rboot_config *romconf, uint32 flashsize) {
romconf->count = 2;
romconf->roms[0] = SECTOR_SIZE * (BOOT_CONFIG_SECTOR + 1);
romconf->roms[1] = (flashsize / 2) + (SECTOR_SIZE * (BOOT_CONFIG_SECTOR + 1));
}
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -12,6 +12,9 @@
#include "lwip/app/dhcpserver.h"
#include "lwip/app/espconn.h"
#include "lwip/app/espconn_tcp.h"
#include "rboot-api.h"
#ifdef ALLOW_PING
#include "lwip/app/ping.h"
#endif
@@ -3539,6 +3542,11 @@ struct espconn *pCon;
sntp_init();
#endif
// Flip boot to rom0
//rboot_set_current_rom(0);
// Flip boot to rom1
rboot_set_current_rom(0);
// Start the timer
os_timer_setfn(&ptimer, timer_func, 0);
os_timer_arm(&ptimer, 500, 0);