From b9f8e8a648bd37a3685720f03e339a1384dc107d Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 10 Mar 2016 15:59:36 +1100 Subject: [PATCH 01/13] spi_flash.h: Add note that pointers need to be word-aligned --- include/espressif/spi_flash.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/espressif/spi_flash.h b/include/espressif/spi_flash.h index df21f34..44c8677 100644 --- a/include/espressif/spi_flash.h +++ b/include/espressif/spi_flash.h @@ -31,7 +31,7 @@ sdk_SpiFlashOpResult sdk_spi_flash_erase_sector(uint16_t sec); /* Write data to flash. des_addr is byte offset to write to. Should be 4-byte aligned. - src is pointer to a buffer to read bytes from. + src is pointer to a buffer to read bytes from. Should be 4-byte aligned. size is length of buffer in bytes. Should be a multiple of 4. */ sdk_SpiFlashOpResult sdk_spi_flash_write(uint32_t des_addr, const void *src, uint32_t size); @@ -39,7 +39,7 @@ sdk_SpiFlashOpResult sdk_spi_flash_write(uint32_t des_addr, const void *src, uin /* Read data from flash. src_addr is byte offset to read from. Should be 4-byte aligned. - des is pointer to a buffer to read bytes into. + des is pointer to a buffer to read bytes into. Should be 4-byte aligned. size is number of bytes to read. Should be a multiple of 4. */ sdk_SpiFlashOpResult sdk_spi_flash_read(uint32_t src_addr, void *des, uint32_t size); From f38bb7459375f6b5c8da9cdb446482c7088307d9 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 23 Mar 2016 11:12:20 +1100 Subject: [PATCH 02/13] OTA Images: Use esptool.py elf2image --version=2 instead of requiring esptool2 --- .travis.yml | 6 +----- common.mk | 26 +++++++------------------- utils/travis_build/install_esptool2.sh | 15 --------------- 3 files changed, 8 insertions(+), 39 deletions(-) delete mode 100755 utils/travis_build/install_esptool2.sh diff --git a/.travis.yml b/.travis.yml index bb04286..0e1b62e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,15 +5,12 @@ env: OPENSDK_COMMIT=a48b12f CROSS_ROOT="${HOME}/toolchain-${OPENSDK_COMMIT}" CROSS_BINDIR="${CROSS_ROOT}/bin" - ESPTOOL2_COMMIT=ec0e2c7 - ESPTOOL2_DIR="${HOME}/esptool2-${ESPTOOL2_COMMIT}" - PATH=${PATH}:${CROSS_BINDIR}:${ESPTOOL2_DIR} CROSS="ccache xtensa-lx106-elf-" MAKE_CMD="make WARNINGS_AS_ERRORS=1 -C examples/ build-examples" + PATH=${PATH}:${CROSS_BINDIR} cache: directories: - ${CROSS_ROOT} - - ${ESPTOOL2_DIR} addons: apt: packages: @@ -37,7 +34,6 @@ addons: - git before_install: - - utils/travis_build/install_esptool2.sh - travis_wait 30 utils/travis_build/install_toolchain.sh script: diff --git a/common.mk b/common.mk index c8fee7a..0141a3a 100644 --- a/common.mk +++ b/common.mk @@ -57,15 +57,11 @@ PRINTF_SCANF_FLOAT_SUPPORT ?= 1 # Set OTA to 1 to build an image that supports rBoot OTA bootloader # -# Currently only works with 16mbit or more flash sizes, with 8mbit -# images for each "slot" +# Requires 16mbit or higher flash sizes, with 8mbit +# images for each OTA "slot" OTA ?= 0 ifeq ($(OTA),1) -# for OTA, we build a "SDK v1.2 bootloader" compatible image where everything is in -# one file (should work with the v1.2 binary bootloader, and the FOSS rBoot bootloader). -IMGTOOL ?= esptool2 - # Tell C preprocessor that we're building for OTA CPPFLAGS = -DOTA endif @@ -188,6 +184,9 @@ LIB_ARGS = $(addprefix -l,$(LIBS)) PROGRAM_OUT = $(BUILD_DIR)$(PROGRAM).out LDFLAGS += $(addprefix -T,$(LINKER_SCRIPTS)) +# firmware tool arguments +ESPTOOL_ARGS=-fs $(FLASH_SIZE)m -fm $(FLASH_MODE) -ff $(FLASH_SPEED)m + ifeq ($(OTA),0) # for non-OTA, we create two different files for uploading into the flash # these are the names and options to generate them @@ -197,20 +196,9 @@ FW_FILE_1 = $(addprefix $(FIRMWARE_DIR),$(FW_ADDR_1).bin) FW_FILE_2 = $(addprefix $(FIRMWARE_DIR),$(FW_ADDR_2).bin) else # for OTA, it's a single monolithic image -FW_FILE = $(addprefix $(FIRMWARE_DIR),$(PROGRAM).bin) +FW_FILE = $(addprefix $(FIRMWARE_DIR),$(PROGRAM)-ota.bin) endif -# firmware tool arguments -ESPTOOL_ARGS=-fs $(FLASH_SIZE)m -fm $(FLASH_MODE) -ff $(FLASH_SPEED)m - -IMGTOOL_FLASH_SIZE_2=256 -IMGTOOL_FLASH_SIZE_4=512 -IMGTOOL_FLASH_SIZE_8=1024 -IMGTOOL_FLASH_SIZE_16=2048 -IMGTOOL_FLASH_SIZE_32=4096 -IMGTOOL_FLASH_SIZE=$(value IMGTOOL_FLASH_SIZE_$(FLASH_SIZE)) -IMGTOOL_ARGS=-$(IMGTOOL_FLASH_SIZE) -$(FLASH_MODE) -$(FLASH_SPEED) - # Common include directories, shared across all "components" # components will add their include directories to this argument # @@ -373,7 +361,7 @@ $(FW_FILE_1) $(FW_FILE_2): $(PROGRAM_OUT) $(FIRMWARE_DIR) $(Q) $(ESPTOOL) elf2image $(ESPTOOL_ARGS) $< -o $(FIRMWARE_DIR) $(FW_FILE): $(PROGRAM_OUT) $(FIRMWARE_DIR) - $(Q) $(IMGTOOL) $(IMGTOOL_ARGS) -bin -boot2 $(PROGRAM_OUT) $(FW_FILE) .text .data .rodata + $(Q) $(ESPTOOL) elf2image --version=2 $(ESPTOOL_ARGS) $< -o $(FW_FILE) ifeq ($(OTA),0) flash: $(FW_FILE_1) $(FW_FILE_2) diff --git a/utils/travis_build/install_esptool2.sh b/utils/travis_build/install_esptool2.sh deleted file mode 100755 index 102fd6f..0000000 --- a/utils/travis_build/install_esptool2.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -set -uv - -# Called by Travis to install esptool2 to generate OTA-compatible build -# images - -if test -f ${ESPTOOL2_DIR}/esptool2; then - echo "Using cached esptool2" - exit 0 -fi - -git clone https://github.com/raburton/esptool2 ${ESPTOOL2_DIR} -cd ${ESPTOOL2_DIR} -git reset --hard ${ESPTOOL2_COMMIT} -make From a3956af4ca72685ded1142879d32c61fabb993c7 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 23 Mar 2016 14:59:19 +1100 Subject: [PATCH 03/13] Bootloader: Integrate rboot directly as 'bootloader' component Currently using unpatched upstream rboot, but modified to build without esptool2. --- .gitmodules | 4 +++ bootloader/Makefile | 71 ++++++++++++++++++++++++++++++++++++++++++++ bootloader/README.md | 11 +++++++ bootloader/rboot | 1 + common.mk | 11 +++++-- 5 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 bootloader/Makefile create mode 100644 bootloader/README.md create mode 160000 bootloader/rboot diff --git a/.gitmodules b/.gitmodules index 52708f8..7a3370e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,7 @@ [submodule "extras/jsmn/jsmn"] path = extras/jsmn/jsmn url = https://github.com/zserge/jsmn.git +[submodule "bootloader/rboot"] + path = bootloader/rboot + url = https://github.com/raburton/rboot.git + diff --git a/bootloader/Makefile b/bootloader/Makefile new file mode 100644 index 0000000..64a0ebc --- /dev/null +++ b/bootloader/Makefile @@ -0,0 +1,71 @@ +# This is a wrapper around the rboot makefile, which gives us the parameters +# we need to use rboot with esp-open-rtos +# +# The wrapper means we don't require esptool2 in the build process, so we can just use +# esptool.py (still need xxd, grep, sed to generate the header - see below.) + +BUILD_DIR ?= build +FIRMWARE_DIR ?= firmware + +# RBOOT configuration parameters. +# RBOOT_BIG_FLASH is required for esp-open-rtos. +export RBOOT_BIG_FLASH = 1 + +export RBOOT_BUILD_BASE=$(abspath $(BUILD_DIR)) + +# Default ESPTOOL params, all the same as when using normal esp-open-rtos makefiles +ESPTOOL ?= esptool.py +ESPPORT ?= /dev/ttyUSB0 +ESPBAUD ?= 115200 + +FLASH_SIZE ?= 16 +FLASH_MODE ?= qio +FLASH_SPEED ?= 40 + +ESPTOOL_ARGS=-fs $(FLASH_SIZE)m -fm $(FLASH_MODE) -ff $(FLASH_SPEED)m + +ifeq ("$(V)","1") +Q := +else +Q := @ +endif + +all: $(FIRMWARE_DIR)/rboot.bin + +rboot/Makefile: + $(error rboot git submodule is not checkedo out. Try running 'git submodule update --init --recursive') + +$(FIRMWARE_DIR)/rboot.bin: $(BUILD_DIR)/rboot.elf $(FIRMWARE_DIR) + @echo "FW rboot.bin" + $(Q) $(ESPTOOL) elf2image $(ESPTOOL_ARGS) $< -o $(BUILD_DIR)/ + $(Q) mv $(BUILD_DIR)/0x00000.bin $@ + +# rboot generates this header using the 'esptool2 -header' option. To try and avoid +# esptool2 as a dependency, we try it here using grep, sed, xxd (all fairly common Unix tools) +$(BUILD_DIR)/rboot-hex2a.h: $(BUILD_DIR)/rboot-stage2a.elf $(BUILD_DIR) + @echo "Extracting stub image header..." + $(Q) xtensa-lx106-elf-objcopy $< --only-section .text -Obinary $(BUILD_DIR)/rboot-hex2a.bin + $(Q) xxd -i $(BUILD_DIR)/rboot-hex2a.bin > $@.in + $(Q) sed -i "s/unsigned char .\+\[\]/const uint8 _text_data[]/" $@.in + $(Q) sed -i "s/unsigned int .\+_len/const uint32 _text_len/" $@.in + $(Q) echo "const uint32 entry_addr = $$(xtensa-lx106-elf-objdump -f $< | grep 'start address' | grep -o '0x.\+');" >> $@.in + $(Q) echo "const uint32 _text_addr = 0x$$(xtensa-lx106-elf-objdump -h -j .text $< | grep ".text" | grep -o '401.....' | head -n1);" >> $@.in + $(Q) mv $@.in $@ + +$(BUILD_DIR)/rboot-stage2a.elf: $(BUILD_DIR) + $(Q) $(MAKE) -C rboot $(RBOOT_BUILD_BASE)/rboot-stage2a.elf + +$(BUILD_DIR)/rboot.elf: $(BUILD_DIR)/rboot-hex2a.h + $(Q) $(MAKE) -C rboot $(RBOOT_BUILD_BASE)/rboot.elf + +$(BUILD_DIR) $(FIRMWARE_DIR): + $(Q) mkdir -p "$@" + +flash: $(FIRMWARE_DIR)/rboot.bin + $(Q) $(ESPTOOL) -p $(ESPPORT) -b $(ESPBAUD) write_flash $(ESPTOOL_ARGS) 0x0 $< + +clean: + $(Q) rm -rf $(BUILD_DIR) + $(Q) rm -rf $(FIRMWARE_DIR) + +.PHONY: all clean flash erase_config diff --git a/bootloader/README.md b/bootloader/README.md new file mode 100644 index 0000000..6527dba --- /dev/null +++ b/bootloader/README.md @@ -0,0 +1,11 @@ +OTA Bootloader (rboot) source module and support files. + +Can be used to build an esp-open-rtos compatible rboot bootloader, for use when OTA=1. + +It is also possible to use the upstream rboot verbatim, but *ensure that the `RBOOT_BIG_FLASH` option is enabled or images in slots other than 0 won't work correctly. + +rboot is an open source bootloader by Richard Burton: +https://github.com/raburton/rboot + +See the contents of the 'rboot' directory for more information. + diff --git a/bootloader/rboot b/bootloader/rboot new file mode 160000 index 0000000..4cf6132 --- /dev/null +++ b/bootloader/rboot @@ -0,0 +1 @@ +Subproject commit 4cf6132f6ee624318c04b2a8d9e37da64b7c283c diff --git a/common.mk b/common.mk index 0141a3a..73a998d 100644 --- a/common.mk +++ b/common.mk @@ -165,7 +165,7 @@ LINKER_SCRIPTS += $(ROOT)ld/common.ld $(ROOT)ld/rom.ld #### ifndef PROGRAM - $(error "Set the PROGRAM environment variable in your Makefile before including common.mk" +$(error "Set the PROGRAM environment variable in your Makefile before including common.mk") endif # hacky way to get a single space value @@ -223,7 +223,7 @@ Q := @ vecho := @echo endif -.PHONY: all clean debug_print +.PHONY: all clean debug_print flash flash_bootloader erase_flash all: $(PROGRAM_OUT) $(FW_FILE_1) $(FW_FILE_2) $(FW_FILE) @@ -361,6 +361,7 @@ $(FW_FILE_1) $(FW_FILE_2): $(PROGRAM_OUT) $(FIRMWARE_DIR) $(Q) $(ESPTOOL) elf2image $(ESPTOOL_ARGS) $< -o $(FIRMWARE_DIR) $(FW_FILE): $(PROGRAM_OUT) $(FIRMWARE_DIR) + $(vecho) "FW $@" $(Q) $(ESPTOOL) elf2image --version=2 $(ESPTOOL_ARGS) $< -o $(FW_FILE) ifeq ($(OTA),0) @@ -372,6 +373,12 @@ flash: $(FW_FILE) $(ESPTOOL) -p $(ESPPORT) --baud $(ESPBAUD) write_flash $(ESPTOOL_ARGS) 0x2000 $(FW_FILE) endif +flash_bootloader: + $(MAKE) -C $(ROOT)/bootloader flash + +erase_flash: + $(ESPTOOL) -p $(ESPPORT) --baud $(ESPBAUD) erase_flash + size: $(PROGRAM_OUT) $(Q) $(CROSS)size --format=sysv $(PROGRAM_OUT) From e671927bd0c9467d636d14a7297c1bc54a95e8e9 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 23 Mar 2016 17:33:08 +1100 Subject: [PATCH 04/13] OTA: Add TFTP client mode, expand ota_basic example. --- examples/ota_basic/ota_basic.c | 40 ++++++++++++ extras/rboot-ota/ota-tftp.c | 114 +++++++++++++++++++++++++++++++-- extras/rboot-ota/ota-tftp.h | 14 ++++ 3 files changed, 162 insertions(+), 6 deletions(-) diff --git a/examples/ota_basic/ota_basic.c b/examples/ota_basic/ota_basic.c index d55c03a..ea4eedd 100644 --- a/examples/ota_basic/ota_basic.c +++ b/examples/ota_basic/ota_basic.c @@ -18,6 +18,45 @@ #include "rboot.h" #include "rboot-api.h" +#define TFTP_IMAGE_SERVER "192.168.1.23" +#define TFTP_IMAGE_FILENAME1 "firmware1.bin" +#define TFTP_IMAGE_FILENAME2 "firmware2.bin" + +void tftp_client_task(void *pvParameters) +{ + printf("TFTP client task starting...\n"); + rboot_config conf; + conf = rboot_get_config(); + int slot = (conf.current_rom + 1) % conf.count; + printf("Image will be saved in OTA slot %d.\n", slot); + if(slot == conf.current_rom) { + printf("FATAL ERROR: Only one OTA slot is configured!\n"); + while(1) {} + } + + /* Alternate between trying two different filenames. Probalby want to change this if making a practical + example! + + Note: example will reboot into FILENAME1 if it is successfully downloaded, but FILENAME2 is ignored. + */ + while(1) { + printf("Downloading %s to slot %d...\n", TFTP_IMAGE_FILENAME1, slot); + int res = ota_tftp_download(TFTP_IMAGE_SERVER, TFTP_PORT, TFTP_IMAGE_FILENAME1, 1000, slot); + printf("ota_tftp_download %s result %d\n", TFTP_IMAGE_FILENAME1, res); + if(res == 0) { + printf("Rebooting into slot %d...\n", slot); + rboot_set_current_rom(slot); + sdk_system_restart(); + } + vTaskDelay(5000 / portTICK_RATE_MS); + + printf("Downloading %s to slot %d...\n", TFTP_IMAGE_FILENAME2, slot); + res = ota_tftp_download(TFTP_IMAGE_SERVER, TFTP_PORT, TFTP_IMAGE_FILENAME2, 1000, slot); + printf("ota_tftp_download %s result %d\n", TFTP_IMAGE_FILENAME2, res); + vTaskDelay(5000 / portTICK_RATE_MS); + } +} + void user_init(void) { uart_set_baud(0, 115200); @@ -39,4 +78,5 @@ void user_init(void) sdk_wifi_station_set_config(&config); ota_tftp_init_server(TFTP_PORT); + xTaskCreate(&tftp_client_task, (signed char *)"tftp_client", 1024, NULL, 2, NULL); } diff --git a/extras/rboot-ota/ota-tftp.c b/extras/rboot-ota/ota-tftp.c index d772927..0f4360a 100644 --- a/extras/rboot-ota/ota-tftp.c +++ b/extras/rboot-ota/ota-tftp.c @@ -28,6 +28,7 @@ #define TFTP_FIRMWARE_FILE "firmware.bin" #define TFTP_OCTET_MODE "octet" /* non-case-sensitive */ +#define TFTP_OP_RRQ 1 #define TFTP_OP_WRQ 2 #define TFTP_OP_DATA 3 #define TFTP_OP_ACK 4 @@ -43,8 +44,9 @@ static void tftp_task(void *port_p); static char *tftp_get_field(int field, struct netbuf *netbuf); -static err_t tftp_receive_data(struct netconn *nc, size_t write_offs, size_t limit_offs, size_t *received_len); +static err_t tftp_receive_data(struct netconn *nc, size_t write_offs, size_t limit_offs, size_t *received_len, ip_addr_t *peer_addr, int peer_port); static err_t tftp_send_ack(struct netconn *nc, int block); +static err_t tftp_send_rrq(struct netconn *nc, const char *filename); static void tftp_send_error(struct netconn *nc, int err_code, const char *err_msg); void ota_tftp_init_server(int listen_port) @@ -52,6 +54,60 @@ void ota_tftp_init_server(int listen_port) xTaskCreate(tftp_task, (signed char *)"tftpOTATask", 512, (void *)listen_port, 2, NULL); } +err_t ota_tftp_download(const char *server, int port, const char *filename, int timeout, int ota_slot) +{ + rboot_config rboot_config = rboot_get_config(); + /* Validate the OTA slot parameter */ + if(rboot_config.current_rom == ota_slot || rboot_config.count <= ota_slot) + { + return ERR_VAL; + } + /* This is all we need to know from the rboot config - where we need + to write data to. + */ + uint32_t flash_offset = rboot_config.roms[ota_slot]; + + struct netconn *nc = netconn_new (NETCONN_UDP); + err_t err; + if(!nc) { + return ERR_IF; + } + + netconn_set_recvtimeout(nc, timeout); + + /* try to bind our client port as our local port, + or keep trying the next 10 ports after it */ + int local_port = port-1; + do { + err = netconn_bind(nc, IP_ADDR_ANY, ++local_port); + } while(err == ERR_USE && local_port < port + 10); + if(err) { + netconn_delete(nc); + return err; + } + + ip_addr_t addr; + err = netconn_gethostbyname(server, &addr); + if(err) { + netconn_delete(nc); + return err; + } + + netconn_connect(nc, &addr, port); + + err = tftp_send_rrq(nc, filename); + if(err) { + netconn_delete(nc); + return err; + } + + size_t received_len; + err = tftp_receive_data(nc, flash_offset, flash_offset+MAX_IMAGE_SIZE, &received_len, &addr, port); + netconn_delete(nc); + return err; +} + + static void tftp_task(void *listen_port) { struct netconn *nc = netconn_new (NETCONN_UDP); @@ -100,7 +156,7 @@ static void tftp_task(void *listen_port) /* check mode */ char *mode = tftp_get_field(1, netbuf); - if(!mode || strcmp("octet", mode)) { + if(!mode || strcmp(TFTP_OCTET_MODE, mode)) { tftp_send_error(nc, TFTP_ERR_ILLEGAL, "Mode must be octet/binary"); free(mode); netbuf_delete(netbuf); @@ -133,7 +189,8 @@ static void tftp_task(void *listen_port) /* Finished WRQ phase, start TFTP data transfer */ size_t received_len; - int recv_err = tftp_receive_data(nc, conf.roms[slot], conf.roms[slot]+MAX_IMAGE_SIZE, &received_len); + netconn_set_recvtimeout(nc, 10000); + int recv_err = tftp_receive_data(nc, conf.roms[slot], conf.roms[slot]+MAX_IMAGE_SIZE, &received_len, NULL, 0); netconn_disconnect(nc); printf("OTA TFTP receive data result %d bytes %d\r\n", recv_err, received_len); @@ -182,20 +239,48 @@ static char *tftp_get_field(int field, struct netbuf *netbuf) return result; } -static err_t tftp_receive_data(struct netconn *nc, size_t write_offs, size_t limit_offs, size_t *received_len) +#define TFTP_TIMEOUT_RETRANSMITS 10 + +static err_t tftp_receive_data(struct netconn *nc, size_t write_offs, size_t limit_offs, size_t *received_len, ip_addr_t *peer_addr, int peer_port) { *received_len = 0; const int DATA_PACKET_SZ = 512 + 4; /*( packet size plus header */ uint32_t start_offs = write_offs; int block = 1; - struct netbuf *netbuf; + struct netbuf *netbuf = 0; + int retries = TFTP_TIMEOUT_RETRANSMITS; while(1) { - netconn_set_recvtimeout(nc, 10000); + if(peer_addr) { + netconn_disconnect(nc); + } + err_t err = netconn_recv(nc, &netbuf); + + if(peer_addr) { + if(netbuf) { + /* For TFTP server, the UDP connection is already established. But for client, + we don't know what port the server is using until we see the first data + packet - so we connect here. + */ + netconn_connect(nc, netbuf_fromaddr(netbuf), netbuf_fromport(netbuf)); + peer_addr = 0; + } else { + /* Otherwise, temporarily re-connect so we can send errors */ + netconn_connect(nc, peer_addr, peer_port); + } + } + if(err == ERR_TIMEOUT) { + if(retries-- > 0 && block > 1) { + /* Retransmit the last ACK, wait for repeat data block. + + This doesn't work for the first block, have to time out and start again. */ + tftp_send_ack(nc, block-1); + continue; + } tftp_send_error(nc, TFTP_ERR_ILLEGAL, "Timeout"); return ERR_TIMEOUT; } @@ -225,6 +310,9 @@ static err_t tftp_receive_data(struct netconn *nc, size_t write_offs, size_t lim } } + /* Reset retry count if we got valid data */ + retries = TFTP_TIMEOUT_RETRANSMITS; + if(write_offs % SECTOR_SIZE == 0) { sdk_spi_flash_erase_sector(write_offs / SECTOR_SIZE); } @@ -325,3 +413,17 @@ static void tftp_send_error(struct netconn *nc, int err_code, const char *err_ms netconn_send(nc, err); netbuf_delete(err); } + +static err_t tftp_send_rrq(struct netconn *nc, const char *filename) +{ + struct netbuf *rrqbuf = netbuf_new(); + uint16_t *rrqdata = (uint16_t *)netbuf_alloc(rrqbuf, 4 + strlen(filename) + strlen(TFTP_OCTET_MODE)); + rrqdata[0] = htons(TFTP_OP_RRQ); + char *rrq_filename = (char *)&rrqdata[1]; + strcpy(rrq_filename, filename); + strcpy(rrq_filename + strlen(filename) + 1, TFTP_OCTET_MODE); + + err_t err = netconn_send(nc, rrqbuf); + netbuf_delete(rrqbuf); + return err; +} diff --git a/extras/rboot-ota/ota-tftp.h b/extras/rboot-ota/ota-tftp.h index f08b28c..cccac2a 100644 --- a/extras/rboot-ota/ota-tftp.h +++ b/extras/rboot-ota/ota-tftp.h @@ -1,5 +1,8 @@ #ifndef _OTA_TFTP_H #define _OTA_TFTP_H + +#include "lwip/err.h" + /* TFTP Server OTA Support * * To use, call ota_tftp_init_server() which will start the TFTP server task @@ -30,6 +33,17 @@ */ void ota_tftp_init_server(int listen_port); +/* Attempt to make a TFTP client connection and download the specified filename. + + 'timeout' is in milliseconds, and is timeout for any UDP exchange + _not_ the entire download. + + Returns 0 on success, LWIP err.h values for errors. + + Does not change the current firmware slot, or reboot. + */ +err_t ota_tftp_download(const char *server, int port, const char *filename, int timeout, int ota_slot); + #define TFTP_PORT 69 #endif From 6eceb5843cd9b2cacec083d8554ab40a246a5cab Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 23 Mar 2016 18:01:09 +1100 Subject: [PATCH 05/13] OTA: Move OTA-aware Cache_Read_Enable to core Otherwise images built with OTA=1 are only OTA-suitable if they also link rboot-ota. --- extras/rboot-ota/rboot-cache.S => core/spiflash-cache-enable.S | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename extras/rboot-ota/rboot-cache.S => core/spiflash-cache-enable.S (100%) diff --git a/extras/rboot-ota/rboot-cache.S b/core/spiflash-cache-enable.S similarity index 100% rename from extras/rboot-ota/rboot-cache.S rename to core/spiflash-cache-enable.S From 03559de5cba418ec43bbca22ed9c0a7db663c740 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 3 May 2016 11:07:10 +1000 Subject: [PATCH 06/13] Move rboot_verify_image to rboot-api Removes rboot-integration.c, removes need for clients to include rboot-integration.h --- examples/ota_basic/ota_basic.c | 1 - extras/rboot-ota/rboot-api.c | 146 +++++++++++++++++++++++++++ extras/rboot-ota/rboot-api.h | 16 +++ extras/rboot-ota/rboot-integration.c | 132 ------------------------ extras/rboot-ota/rboot-integration.h | 3 - 5 files changed, 162 insertions(+), 136 deletions(-) delete mode 100644 extras/rboot-ota/rboot-integration.c diff --git a/examples/ota_basic/ota_basic.c b/examples/ota_basic/ota_basic.c index ea4eedd..1a2d826 100644 --- a/examples/ota_basic/ota_basic.c +++ b/examples/ota_basic/ota_basic.c @@ -14,7 +14,6 @@ #include "ssid_config.h" #include "ota-tftp.h" -#include "rboot-integration.h" #include "rboot.h" #include "rboot-api.h" diff --git a/extras/rboot-ota/rboot-api.c b/extras/rboot-ota/rboot-api.c index 7fe5340..9283acb 100644 --- a/extras/rboot-ota/rboot-api.c +++ b/extras/rboot-ota/rboot-api.c @@ -4,6 +4,8 @@ // richardaburton@gmail.com // See license.txt for license terms. // OTA code based on SDK sample from Espressif. +// +// esp-open-rtos additions Copyright 2016 Angus Gratton ////////////////////////////////////////////////// #include @@ -209,6 +211,150 @@ bool ICACHE_FLASH_ATTR rboot_get_last_boot_mode(uint8 *mode) { } #endif +/* NOTE: Functions below here were added for esp-open-rtos only */ + +uint32_t rboot_get_slot_offset(uint8_t slot) { + rboot_config conf; + conf = rboot_get_config(); + if (slot >= conf.count) return (uint32_t)-1; + return conf.roms[slot]; +} + +/* Structures for parsing the rboot OTA image format */ +typedef struct __attribute__((packed)) { + uint8_t magic; + uint8_t section_count; + uint8_t val[2]; /* flash size & speed when placed @ offset 0, I thik ignored otherwise */ + uint32_t entrypoint; +} image_header_t; + +typedef struct __attribute__((packed)) { + uint32_t load_addr; + uint32_t length; +} section_header_t; + +#define ROM_MAGIC_OLD 0xe9 +#define ROM_MAGIC_NEW 0xea + +bool rboot_verify_image(uint32_t initial_offset, uint32_t *image_length, const char **error_message) +{ + uint32_t offset = initial_offset; + char *error = NULL; + RBOOT_DEBUG("rboot_verify_image: verifying image at 0x%08x\n", initial_offset); + if(offset % 4) { + error = "Unaligned flash offset"; + goto fail; + } + + /* sanity limit on how far we can read */ + uint32_t end_limit = offset + 0x100000; + image_header_t image_header __attribute__((aligned(4))); + if(sdk_spi_flash_read(offset, &image_header, sizeof(image_header_t))) { + error = "Flash fail"; + goto fail; + } + + offset += sizeof(image_header_t); + + if(image_header.magic != ROM_MAGIC_OLD && image_header.magic != ROM_MAGIC_NEW) { + error = "Missing initial magic"; + goto fail; + } + + bool is_new_header = (image_header.magic == ROM_MAGIC_NEW); /* a v1.2/rboot header, so expect a v1.1 header after the initial section */ + + int remaining_sections = image_header.section_count; + + uint8_t checksum = CHKSUM_INIT; + + while(remaining_sections > 0 && offset < end_limit) + { + /* read section header */ + section_header_t header __attribute__((aligned(4))); + if(sdk_spi_flash_read(offset, &header, sizeof(section_header_t))) { + error = "Flash fail"; + goto fail; + } + + RBOOT_DEBUG("Found section @ 0x%08x (abs 0x%08x) length %d load 0x%08x\n", offset-initial_offset, offset, header.length, header.load_addr); + offset += sizeof(section_header_t); + + if(header.length+offset > end_limit) { + break; /* sanity check: will reading section take us off end of expected flashregion? */ + } + + if(header.length % 4) { + error = "Header length not modulo 4"; + goto fail; + } + + if(!is_new_header) { + /* Add individual data of the section to the checksum. */ + char chunk[16] __attribute__((aligned(4))); + for(int i = 0; i < header.length; i++) { + if(i % sizeof(chunk) == 0) + sdk_spi_flash_read(offset+i, (uint32_t *)chunk, sizeof(chunk)); + checksum ^= chunk[i % sizeof(chunk)]; + } + } + + offset += header.length; + /* pad section to 4 byte align */ + offset = (offset+3) & ~3; + + remaining_sections--; + + if(is_new_header) { + /* pad to a 16 byte offset */ + offset = (offset+15) & ~15; + + /* expect a v1.1 header here at start of "real" sections */ + sdk_spi_flash_read(offset, (uint32_t *)&image_header, sizeof(image_header_t)); + offset += sizeof(image_header_t); + if(image_header.magic != ROM_MAGIC_OLD) { + error = "Bad second magic"; + goto fail; + } + remaining_sections = image_header.section_count; + is_new_header = false; + } + } + + if(remaining_sections > 0) { + error = "Image truncated"; + goto fail; + } + + /* add a byte for the image checksum (actually comes after the padding) */ + offset++; + /* pad the image length to a 16 byte boundary */ + offset = (offset+15) & ~15; + + uint32_t read_checksum; + sdk_spi_flash_read(offset-1, &read_checksum, 1); + if((uint8_t)read_checksum != checksum) { + error = "Invalid checksum"; + goto fail; + } + + RBOOT_DEBUG("rboot_verify_image: verified expected 0x%08x bytes.\n", offset - initial_offset); + + if(image_length) + *image_length = offset - initial_offset; + + return true; + + fail: + if(error_message) + *error_message = error; + if(error) { + printf("%s: %s\n", __func__, error); + } + if(image_length) + *image_length = offset - initial_offset; + return false; +} + #ifdef __cplusplus } #endif diff --git a/extras/rboot-ota/rboot-api.h b/extras/rboot-ota/rboot-api.h index 5a39b4d..5968827 100644 --- a/extras/rboot-ota/rboot-api.h +++ b/extras/rboot-ota/rboot-api.h @@ -128,6 +128,22 @@ bool ICACHE_FLASH_ATTR rboot_get_last_boot_rom(uint8 *rom); bool ICACHE_FLASH_ATTR rboot_get_last_boot_mode(uint8 *mode); #endif +/* ADDITIONS TO RBOOT-API FOR ESP-OPEN-RTOS FOLLOW */ + +/* Returns offset of given rboot slot, or (uint32_t)-1 if slot is invalid. + */ +uint32_t rboot_get_slot_offset(uint8_t slot); + +/** @description Verify basic image parameters - headers, CRC8 checksum. + + @param Offset of image to verify. Can use rboot_get_slot_offset() to find. + @param Optional pointer will return the total valid length of the image. + @param Optional pointer to a static human-readable error message if fails. + + @return True for valid, False for invalid. +**/ +bool rboot_verify_image(uint32_t offset, uint32_t *image_length, const char **error_message); + #ifdef __cplusplus } #endif diff --git a/extras/rboot-ota/rboot-integration.c b/extras/rboot-ota/rboot-integration.c deleted file mode 100644 index 266d566..0000000 --- a/extras/rboot-ota/rboot-integration.c +++ /dev/null @@ -1,132 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include - -#define ROM_MAGIC_OLD 0xe9 -#define ROM_MAGIC_NEW 0xea - -typedef struct __attribute__((packed)) { - uint8_t magic; - uint8_t section_count; - uint8_t val[2]; /* flash size & speed when placed @ offset 0, I think ignored otherwise */ - uint32_t entrypoint; -} image_header_t; - -typedef struct __attribute__((packed)) { - uint32_t load_addr; - uint32_t length; -} section_header_t; - - -// Check that a valid-looking rboot image is found at this offset on the flash, and -// takes up 'expected_length' bytes. -bool rboot_verify_image(uint32_t offset, uint32_t expected_length, const char **error_message) -{ - char *error = NULL; - if(offset % 4) { - error = "Unaligned flash offset"; - goto fail; - } - - uint32_t end_offset = offset + expected_length; - image_header_t image_header; - sdk_spi_flash_read(offset, (uint32_t *)&image_header, sizeof(image_header_t)); - offset += sizeof(image_header_t); - - if(image_header.magic != ROM_MAGIC_OLD && image_header.magic != ROM_MAGIC_NEW) { - error = "Missing initial magic"; - goto fail; - } - - bool is_new_header = (image_header.magic == ROM_MAGIC_NEW); /* a v1.2/rboot header, so expect a v1.1 header after the initial section */ - - int remaining_sections = image_header.section_count; - - uint8_t checksum = CHKSUM_INIT; - - while(remaining_sections > 0 && offset < end_offset) - { - /* read section header */ - section_header_t header; - sdk_spi_flash_read(offset, (uint32_t *)&header, sizeof(section_header_t)); - RBOOT_DEBUG("Found section @ 0x%08lx length 0x%08lx load 0x%08lx padded 0x%08lx\r\n", offset, header.length, header.load_addr, header.length); - offset += sizeof(section_header_t); - - - if(header.length+offset > end_offset) { - break; /* sanity check: will reading section take us off end of expected flashregion? */ - } - - if(!is_new_header) { - /* Add individual data of the section to the checksum. */ - char chunk[16]; - for(int i = 0; i < header.length; i++) { - if(i % sizeof(chunk) == 0) - sdk_spi_flash_read(offset+i, (uint32_t *)chunk, sizeof(chunk)); - checksum ^= chunk[i % sizeof(chunk)]; - } - } - - offset += header.length; - /* pad section to 4 byte align */ - offset = (offset+3) & ~3; - - remaining_sections--; - - if(is_new_header) { - /* pad to a 16 byte offset */ - offset = (offset+15) & ~15; - - /* expect a v1.1 header here at start of "real" sections */ - sdk_spi_flash_read(offset, (uint32_t *)&image_header, sizeof(image_header_t)); - offset += sizeof(image_header_t); - if(image_header.magic != ROM_MAGIC_OLD) { - error = "Bad second magic"; - goto fail; - } - remaining_sections = image_header.section_count; - is_new_header = false; - } - } - - if(remaining_sections > 0) { - error = "Image truncated"; - goto fail; - } - - /* add a byte for the image checksum (actually comes after the padding) */ - offset++; - /* pad the image length to a 16 byte boundary */ - offset = (offset+15) & ~15; - - uint8_t read_checksum; - sdk_spi_flash_read(offset-1, (uint32_t *)&read_checksum, 1); /* not sure if this will work */ - if(read_checksum != checksum) { - error = "Invalid checksum"; - goto fail; - } - - if(offset != end_offset) { - error = "Wrong length"; - goto fail; - } - - RBOOT_DEBUG("rboot_verify_image: verified expected 0x%08lx bytes.\r\n", expected_length); - return true; - - fail: - if(error_message) - *error_message = error; - printf("%s: %s\r\n", __func__, error); - return false; -} diff --git a/extras/rboot-ota/rboot-integration.h b/extras/rboot-ota/rboot-integration.h index 00c1bcb..199d7a2 100644 --- a/extras/rboot-ota/rboot-integration.h +++ b/extras/rboot-ota/rboot-integration.h @@ -28,7 +28,4 @@ #define RBOOT_DEBUG(f_, ...) #endif -// Check that a valid-looking rboot image is found at this offset on the flash, and -// takes up 'expected_length' bytes. -bool rboot_verify_image(uint32_t offset, uint32_t expected_length, const char **error_message); #endif // __RBOOT_INTEGRATION_H__ From 53b2b50241ee691285d2e44295f429d3d0883614 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 23 Mar 2016 19:44:27 +1100 Subject: [PATCH 07/13] rboot: Add cryptographic digest support for OTA images & SHA256 example --- examples/ota_basic/Makefile | 2 +- examples/ota_basic/ota_basic.c | 47 +++++++++++++++++++++++++++++++--- extras/rboot-ota/ota-tftp.c | 4 ++- extras/rboot-ota/rboot-api.c | 14 ++++++++++ extras/rboot-ota/rboot-api.h | 27 +++++++++++++++++++ 5 files changed, 88 insertions(+), 6 deletions(-) diff --git a/examples/ota_basic/Makefile b/examples/ota_basic/Makefile index 84649c1..aafb05a 100644 --- a/examples/ota_basic/Makefile +++ b/examples/ota_basic/Makefile @@ -1,5 +1,5 @@ PROGRAM=ota_basic OTA=1 -EXTRA_COMPONENTS=extras/rboot-ota +EXTRA_COMPONENTS=extras/rboot-ota extras/mbedtls include ../../common.mk diff --git a/examples/ota_basic/ota_basic.c b/examples/ota_basic/ota_basic.c index 1a2d826..68e6c71 100644 --- a/examples/ota_basic/ota_basic.c +++ b/examples/ota_basic/ota_basic.c @@ -6,12 +6,14 @@ * * NOT SUITABLE TO PUT ON THE INTERNET OR INTO A PRODUCTION ENVIRONMENT!!!! */ +#include #include "espressif/esp_common.h" #include "esp/uart.h" #include "FreeRTOS.h" #include "task.h" #include "esp8266.h" #include "ssid_config.h" +#include "mbedtls/sha256.h" #include "ota-tftp.h" #include "rboot.h" @@ -21,6 +23,9 @@ #define TFTP_IMAGE_FILENAME1 "firmware1.bin" #define TFTP_IMAGE_FILENAME2 "firmware2.bin" +/* Output of the command 'sha256sum firmware1.bin' */ +static const char *FIRMWARE1_SHA256 = "88199daff8b9e76975f685ec7f95bc1df3c61bd942a33a54a40707d2a41e5488"; + void tftp_client_task(void *pvParameters) { printf("TFTP client task starting...\n"); @@ -43,9 +48,43 @@ void tftp_client_task(void *pvParameters) int res = ota_tftp_download(TFTP_IMAGE_SERVER, TFTP_PORT, TFTP_IMAGE_FILENAME1, 1000, slot); printf("ota_tftp_download %s result %d\n", TFTP_IMAGE_FILENAME1, res); if(res == 0) { - printf("Rebooting into slot %d...\n", slot); - rboot_set_current_rom(slot); - sdk_system_restart(); + printf("Looks valid, calculating SHA256...\n"); + uint32_t length; + bool valid = rboot_verify_image(conf.roms[slot], &length, NULL); + static mbedtls_sha256_context ctx; + mbedtls_sha256_init(&ctx); + mbedtls_sha256_starts(&ctx, 0); + valid = valid && rboot_digest_image(conf.roms[slot], length, (rboot_digest_update_fn)mbedtls_sha256_update, &ctx); + static uint8_t hash_result[32]; + mbedtls_sha256_finish(&ctx, hash_result); + mbedtls_sha256_free(&ctx); + + if(!valid) + { + printf("Not valid after all :(\n"); + } + else + { + printf("Image SHA256 = "); + bool valid = true; + for(int i = 0; i < sizeof(hash_result); i++) { + char hexbuf[3]; + snprintf(hexbuf, 3, "%02x", hash_result[i]); + printf(hexbuf); + if(strncmp(hexbuf, FIRMWARE1_SHA256+i*2, 2)) + valid = false; + + } + printf("\n"); + if (valid) { + printf("SHA256 Matches. Rebooting into slot %d...\n", slot); + rboot_set_current_rom(slot); + sdk_system_restart(); + } + else { + printf("Downloaded image SHA256 didn't match expected '%s'\n", FIRMWARE1_SHA256); + } + } } vTaskDelay(5000 / portTICK_RATE_MS); @@ -77,5 +116,5 @@ void user_init(void) sdk_wifi_station_set_config(&config); ota_tftp_init_server(TFTP_PORT); - xTaskCreate(&tftp_client_task, (signed char *)"tftp_client", 1024, NULL, 2, NULL); + xTaskCreate(&tftp_client_task, (signed char *)"tftp_client", 2048, NULL, 2, NULL); } diff --git a/extras/rboot-ota/ota-tftp.c b/extras/rboot-ota/ota-tftp.c index 0f4360a..1dee8cd 100644 --- a/extras/rboot-ota/ota-tftp.c +++ b/extras/rboot-ota/ota-tftp.c @@ -369,7 +369,9 @@ static err_t tftp_receive_data(struct netconn *nc, size_t write_offs, size_t lim it so the client gets an indication if things were successful. */ const char *err = "Unknown validation error"; - if(!rboot_verify_image(start_offs, *received_len, &err)) { + uint32_t image_length; + if(!rboot_verify_image(start_offs, &image_length, &err) + || image_length != *received_len) { tftp_send_error(nc, TFTP_ERR_ILLEGAL, err); return ERR_VAL; } diff --git a/extras/rboot-ota/rboot-api.c b/extras/rboot-ota/rboot-api.c index 9283acb..b3faac2 100644 --- a/extras/rboot-ota/rboot-api.c +++ b/extras/rboot-ota/rboot-api.c @@ -355,6 +355,20 @@ bool rboot_verify_image(uint32_t initial_offset, uint32_t *image_length, const c return false; } +bool rboot_digest_image(uint32_t offset, uint32_t image_length, rboot_digest_update_fn update_fn, void *update_ctx) +{ + uint8_t buf[32] __attribute__((aligned(4))); + for(int i = 0; i < image_length; i += sizeof(buf)) { + if(sdk_spi_flash_read(offset+i, buf, sizeof(buf))) + return false; + uint32_t digest_len = sizeof(buf); + if(i + digest_len > image_length) + digest_len = image_length - i; + update_fn(update_ctx, buf, digest_len); + } + return true; +} + #ifdef __cplusplus } #endif diff --git a/extras/rboot-ota/rboot-api.h b/extras/rboot-ota/rboot-api.h index 5968827..a74eeb2 100644 --- a/extras/rboot-ota/rboot-api.h +++ b/extras/rboot-ota/rboot-api.h @@ -144,6 +144,33 @@ uint32_t rboot_get_slot_offset(uint8_t slot); **/ bool rboot_verify_image(uint32_t offset, uint32_t *image_length, const char **error_message); + +/* @description Digest callback prototype, designed to be compatible with + mbedtls digest functions (SHA, MD5, etc.) + + See the ota_basic example to see an example of calculating the + SHA256 digest of an OTA image. +*/ +typedef void (*rboot_digest_update_fn)(void * ctx, void *data, size_t data_len); + +/** @description Calculate a digest over the image at the offset specified + + @note This function is actually a generic function that hashes SPI + flash contents, doesn't know anything about rboot image format. Use + rboot_verify_image to ensure a well-formed OTA image. + + @param offset - Starting offset of image to hash (should be 4 byte aligned.) + + @param image_length - Length of image to hash (should be 4 byte aligned.) + + @param update_fn - Function to update digest (see rboot_digest_update_fn for details) + + @param update_ctx - Context argument for digest update function. + + @return True if digest completes successfully, false if digest function failed part way through +**/ +bool rboot_digest_image(uint32_t offset, uint32_t image_length, rboot_digest_update_fn update_fn, void *update_ctx); + #ifdef __cplusplus } #endif From 1f1881a45237c0c030a89bf225c4e3396207fa12 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 24 Mar 2016 15:35:23 +1100 Subject: [PATCH 08/13] rboot-ota: Always put a checksum in rboot config Means bootloader will still work if configured to verify the checksum --- extras/rboot-ota/rboot-config.h | 14 -------------- extras/rboot-ota/rboot-integration.h | 7 +++++++ extras/rboot-ota/rboot.h | 9 +++++++-- 3 files changed, 14 insertions(+), 16 deletions(-) delete mode 100644 extras/rboot-ota/rboot-config.h diff --git a/extras/rboot-ota/rboot-config.h b/extras/rboot-ota/rboot-config.h deleted file mode 100644 index 5ca80a6..0000000 --- a/extras/rboot-ota/rboot-config.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _RBOOT_CONFIG_H -/* rboot configuration parameters. - - Must match the config in the compiler bootloader rboot.h. Values below are the rboot.h defaults. - - Override rboot parameters by editing this file, or (much better - alternative) copy rboot-config.h to your program directory or - program/include/ directory, then edit it to override these values. -*/ - -#define RBOOT_MAX_ROMS 4 -//#define RBOOT_CONFIG_CHECKSUM - -#endif diff --git a/extras/rboot-ota/rboot-integration.h b/extras/rboot-ota/rboot-integration.h index 199d7a2..064217b 100644 --- a/extras/rboot-ota/rboot-integration.h +++ b/extras/rboot-ota/rboot-integration.h @@ -28,4 +28,11 @@ #define RBOOT_DEBUG(f_, ...) #endif +/* Enable checksumming when writing out the config, + so if the bootloader is built with checksumming then + it will still work. +*/ +#define BOOT_CONFIG_CHKSUM + + #endif // __RBOOT_INTEGRATION_H__ diff --git a/extras/rboot-ota/rboot.h b/extras/rboot-ota/rboot.h index e09aa7e..750c4d7 100644 --- a/extras/rboot-ota/rboot.h +++ b/extras/rboot-ota/rboot.h @@ -18,8 +18,13 @@ extern "C" { // 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 +// Note: enabling RBOOT_CONFIG_CHECKSUM here means the config sector +// is always written by esp-open-rtos with a checksum. +// +// This means it will work whether the bootloader has config +// checksumming enabled or not. + +#define BOOT_CONFIG_CHKSUM // uncomment to enable big flash support (>1MB) #define BOOT_BIG_FLASH From d9202af2aab2a692c32772ac7772267701a527e8 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Sat, 7 May 2016 17:25:28 +1000 Subject: [PATCH 09/13] Use latest upstream rboot, always build with OTA - use prebuilt rboot if none is compiled locally. --- bootloader/Makefile | 48 ++--- bootloader/README.md | 11 +- bootloader/firmware_prebuilt/blank_config.bin | Bin 0 -> 2048 bytes bootloader/firmware_prebuilt/rboot.bin | Bin 0 -> 3104 bytes bootloader/rboot | 2 +- bootloader/rboot.h | 23 +++ common.mk | 172 +----------------- core/spiflash-cache-enable.S | 4 - examples/ota_basic/Makefile | 1 - examples/ota_basic/ota_basic.c | 1 - extras/rboot-ota/component.mk | 5 +- extras/rboot-ota/ota-tftp.c | 1 - extras/rboot-ota/rboot-api.c | 2 +- extras/rboot-ota/rboot-api.h | 1 + extras/rboot-ota/rboot-integration.h | 4 + extras/rboot-ota/rboot.h | 116 ------------ ld/nonota.ld | 15 -- ld/ota.ld | 15 -- ld/{common.ld => program.ld} | 18 +- parameters.mk | 141 ++++++++++++++ 20 files changed, 216 insertions(+), 364 deletions(-) create mode 100644 bootloader/firmware_prebuilt/blank_config.bin create mode 100644 bootloader/firmware_prebuilt/rboot.bin create mode 100644 bootloader/rboot.h delete mode 100644 extras/rboot-ota/rboot.h delete mode 100644 ld/nonota.ld delete mode 100644 ld/ota.ld rename ld/{common.ld => program.ld} (93%) create mode 100644 parameters.mk diff --git a/bootloader/Makefile b/bootloader/Makefile index 64a0ebc..1928d01 100644 --- a/bootloader/Makefile +++ b/bootloader/Makefile @@ -1,34 +1,17 @@ # This is a wrapper around the rboot makefile, which gives us the parameters -# we need to use rboot with esp-open-rtos +# we need to use rboot with esp-open-rtos. +# +# Use 'make bootloader' to build a custom bootloader. +# +# 'make flash' for any esp-open-rtos program will use the compiled +# bootloader if it exists, or a prebuilt bootloader if no custom +# bootloader was compiled. # # The wrapper means we don't require esptool2 in the build process, so we can just use # esptool.py (still need xxd, grep, sed to generate the header - see below.) +BOOTLOADER_DIR:=$(dir $(abspath $(lastword $(MAKEFILE_LIST)))) -BUILD_DIR ?= build -FIRMWARE_DIR ?= firmware - -# RBOOT configuration parameters. -# RBOOT_BIG_FLASH is required for esp-open-rtos. -export RBOOT_BIG_FLASH = 1 - -export RBOOT_BUILD_BASE=$(abspath $(BUILD_DIR)) - -# Default ESPTOOL params, all the same as when using normal esp-open-rtos makefiles -ESPTOOL ?= esptool.py -ESPPORT ?= /dev/ttyUSB0 -ESPBAUD ?= 115200 - -FLASH_SIZE ?= 16 -FLASH_MODE ?= qio -FLASH_SPEED ?= 40 - -ESPTOOL_ARGS=-fs $(FLASH_SIZE)m -fm $(FLASH_MODE) -ff $(FLASH_SPEED)m - -ifeq ("$(V)","1") -Q := -else -Q := @ -endif +include ../parameters.mk all: $(FIRMWARE_DIR)/rboot.bin @@ -52,14 +35,19 @@ $(BUILD_DIR)/rboot-hex2a.h: $(BUILD_DIR)/rboot-stage2a.elf $(BUILD_DIR) $(Q) echo "const uint32 _text_addr = 0x$$(xtensa-lx106-elf-objdump -h -j .text $< | grep ".text" | grep -o '401.....' | head -n1);" >> $@.in $(Q) mv $@.in $@ + +RBOOT_BUILD_BASE="$(abspath $(BUILD_DIR))" +RBOOT_FW_BASE="$(abspath $(FIRMWARE_DIR))" +MAKE_VARS=RBOOT_EXTRA_INCDIR=$(BOOTLOADER_DIR) RBOOT_BUILD_BASE=$(RBOOT_BUILD_BASE) RBOOT_FW_BASE=$(RBOOT_FW_BASE) + $(BUILD_DIR)/rboot-stage2a.elf: $(BUILD_DIR) - $(Q) $(MAKE) -C rboot $(RBOOT_BUILD_BASE)/rboot-stage2a.elf + $(Q) $(MAKE) -C rboot $(RBOOT_BUILD_BASE)/rboot-stage2a.elf $(MAKE_VARS) $(BUILD_DIR)/rboot.elf: $(BUILD_DIR)/rboot-hex2a.h - $(Q) $(MAKE) -C rboot $(RBOOT_BUILD_BASE)/rboot.elf + $(Q) $(MAKE) -C rboot $(RBOOT_BUILD_BASE)/rboot.elf $(MAKE_VARS) $(BUILD_DIR) $(FIRMWARE_DIR): - $(Q) mkdir -p "$@" + mkdir -p $@ flash: $(FIRMWARE_DIR)/rboot.bin $(Q) $(ESPTOOL) -p $(ESPPORT) -b $(ESPBAUD) write_flash $(ESPTOOL_ARGS) 0x0 $< @@ -68,4 +56,4 @@ clean: $(Q) rm -rf $(BUILD_DIR) $(Q) rm -rf $(FIRMWARE_DIR) -.PHONY: all clean flash erase_config +.PHONY: all diff --git a/bootloader/README.md b/bootloader/README.md index 6527dba..710205b 100644 --- a/bootloader/README.md +++ b/bootloader/README.md @@ -1,11 +1,12 @@ OTA Bootloader (rboot) source module and support files. -Can be used to build an esp-open-rtos compatible rboot bootloader, for use when OTA=1. - -It is also possible to use the upstream rboot verbatim, but *ensure that the `RBOOT_BIG_FLASH` option is enabled or images in slots other than 0 won't work correctly. - rboot is an open source bootloader by Richard Burton: https://github.com/raburton/rboot -See the contents of the 'rboot' directory for more information. +Can be used to build an esp-open-rtos compatible rboot bootloader. Run 'make bootloader' in this directory to compile a new bootloader. +Compiling a new bootloader is optional, there's a prebuilt one in the "firmware_prebuilt" directory that will be used if no new bootloader was compiled. + +It is also possible to use rboot from upstream verbatim, but *ensure that the `RBOOT_BIG_FLASH` option is enabled or images in slots other than 0 won't work correctly. + +See the contents of the 'rboot' directory for more information on rboot. diff --git a/bootloader/firmware_prebuilt/blank_config.bin b/bootloader/firmware_prebuilt/blank_config.bin new file mode 100644 index 0000000000000000000000000000000000000000..e9784eb4c8849062d374dd2058af8814b024f3bd GIT binary patch literal 2048 ccmZQz7zLvtFd71*Aut*OqaiRF0wXO100;m80RR91 literal 0 HcmV?d00001 diff --git a/bootloader/firmware_prebuilt/rboot.bin b/bootloader/firmware_prebuilt/rboot.bin new file mode 100644 index 0000000000000000000000000000000000000000..6cc646c3bae7c7b7fb7d3930d4f9b4a36d2f1f55 GIT binary patch literal 3104 zcmb7G4Nw%<9e;1{0|Lu=cPL@NOy4eXK+Tc8ClaR_kJP9!X~tU2*lE%n*AzeI%(T>|NvEb)rkSYqgTYiK;=TUg9;T#| znND`*x9|UZ@Bjbrd%t~OmpLT;E!CPohoK_vxR*h*Z z$F-_Sty0t!e1}F5+AZ^3#rKhnkr=+5zt1KLii~mpxU6{`1~U&|m2F5obR~b^N6>V} z>Bi@xV$7P?Ad{K8(r`FlVKTOS< zml6K~xn>fF(0R+}C-8aBk>bWRe5bY?|A{$v3dFV{Lb#ur?JC0Xv!@g5T)w1t*)D-K18ZQ$_i=X3yCOQN}WUsx|B(2*FNj$gJ`K! zG$2AH^E`xj!%{)zP;Q<=rPC+M7csJ!k%@`W=@TxUFH1J&>!dnKa&+=kl4L9rL=MTn zGegqTMF$&eZ(d801vNL1kdQ2RL`^NWb2}rHpCp9@#y=OonjHUS5u@97ZuB(@QgT8y z{GF(ukll?QAY6QDPxv<%r$Q<)KE8*k8qiYgqQ8+i9I?MvElmu{Y--}62r zYEv}6*7i)xDzT|3(jkUB)<+@)RdI`!K(W#wMyH?Ldu=C=HeaO;*Qs_Dg0_i3AZS~c zBKC9?MViEL)AGn77X*~B04PiC5XIXwChQ{<4>%vc&71R&e5W;YzSJ?db$^z^-qy}= zgmg#Z-L}enZ62)f#nD9ip~qO1Vm0w{phfOP;L zpaakY=mQJ@1_5EfalpHPGk^<#IA9v!>P?g(NS)0}f=~&R>i}(lLBJ_M46xyCSKcKk z(X>_Jp$}GwnajEah&_yyL)l0{tB|r9FbwvdFR6VbE?l4wY(A@f(s0=`<%G3^|IPj# zo5ehb7c*NpPw@mZL~I}rdtzh4S&FZ+ijfE%ornB(t1wEFOJn3cT46&7`9+HmrFdNT z`ZcZKkzck5zoqz7z2+nxO+kLuD*T4xPxP7-w88*!!YPXXtXI52g?A_(W44I7#wZeg zMe&D>R#+gvofnQ%d`{uN6k1mQpMhVdjem|`@`YvKEPR8Rb;HlE`%2lBSVI_S?0Dp%^fx5is7|Vby1~!v%VlyuY^dsB!_QEE~%b$kvyrsq>B_u2MYHOT456r zIWw?PI|3JnrI$nfwYlD&BB}CZX)jC>W=c}1^5o)Pj$4*&AibQSI%&@9<%~}y&9q+5 zv{5%7J0`57Jf9<;<%;)Lix%U9&2HI}B4Sg1kyWUocnuqygCBhx!6TGYem<^aRnBTU zX-UZ`I%^m;BCV31=W_fD&7+w4>0Dh5vvzHP@#8{!Pkr z<|Z^Um3aQ5dya$0hz%p1!kqu84mD#_`Ymf&`1W3lFqyzpY)XRv8iWe+(&b`z?8Sc2 zB}<(KSz|R5kzMY- zL~m_sj{i9`TUiKJm>5=8yiA27iHS0T-_pnbdct`)p@!pM(H!wvINV_lWzD}d+D`Wj zB@Wn9H=ofyZn)&RtNsR?xVxf)<*v>3*8o3g~pRtN77aJeF2d8}cH>N7=M_9QD>xes=;80Y;_j83MJwooq_cmv`(Ma+|?Nhwkxfhv_M1ZP`G+8`##el)zDoT%@Ks5P}AH8D2iaXZq36(&B@TKtCi>Q?+fTA4>|0?=yK;eaS34IpVsG zP$1a8l&FDL;%6h%6MVhRyJk7@X(26{`^nBgDA3+Yd@X*ht1U#DnQ-fa?fyV(A@f+- zzEx`r_(-T_QwQk`ZX#P++FI6!T6}sd95mq1;_tV!>iaRX-5HGFq?!0NEU*4i z=3TJBw~z$3kY??EelOH6@O{0mHb`27L7(0oZ7cjst+}n`fBM6+EtpA?x;;_G!2ap1 GC;dN{7~$*y literal 0 HcmV?d00001 diff --git a/bootloader/rboot b/bootloader/rboot index 4cf6132..30afbaa 160000 --- a/bootloader/rboot +++ b/bootloader/rboot @@ -1 +1 @@ -Subproject commit 4cf6132f6ee624318c04b2a8d9e37da64b7c283c +Subproject commit 30afbaa777e00abf9d7d469fb3345f118c4975c1 diff --git a/bootloader/rboot.h b/bootloader/rboot.h new file mode 100644 index 0000000..9260a64 --- /dev/null +++ b/bootloader/rboot.h @@ -0,0 +1,23 @@ +/* rboot header overrides + + This "wrapper" header contains default values for building rboot + on/for esp-open-rtos. It gets included both when building the + bootloader and when building extras/rboot-ota support. It includes + the default bootloader/rboot/rboot.h header via the gcc + include_next mechanism. +*/ +#ifndef __RBOOT_H__ + +// Big flash support is required for esp-open-rtos (we use 8Mbit +// "slots" only.) +#define BOOT_BIG_FLASH + +// enable 2 way communication between +// rBoot and the user app via the esp rtc data area +#define BOOT_RTC_ENABLED + +// Call 'main' rboot.h to pick up defaults for other parameters +#include_next "rboot.h" + +#endif + diff --git a/common.mk b/common.mk index 73a998d..172fbe2 100644 --- a/common.mk +++ b/common.mk @@ -20,149 +20,7 @@ # assume the 'root' directory (ie top of the tree) is the directory common.mk is in ROOT := $(dir $(lastword $(MAKEFILE_LIST))) -# include optional local overrides at the root level, then in program directory -# -# Create either of these files for local system overrides if possible, -# instead of editing this makefile directly. --include $(ROOT)local.mk --include local.mk - -# Flash size in megabits -# Valid values are same as for esptool.py - 2,4,8,16,32 -FLASH_SIZE ?= 16 - -# Flash mode, valid values are same as for esptool.py - qio,qout,dio.dout -FLASH_MODE ?= qio - -# Flash speed in MHz, valid values are same as for esptool.py - 80, 40, 26, 20 -FLASH_SPEED ?= 40 - -# Output directories to store intermediate compiled files -# relative to the program directory -BUILD_DIR ?= $(PROGRAM_DIR)build/ -FIRMWARE_DIR ?= $(PROGRAM_DIR)firmware/ - -# esptool.py from https://github.com/themadinventor/esptool -ESPTOOL ?= esptool.py -# serial port settings for esptool.py -ESPPORT ?= /dev/ttyUSB0 -ESPBAUD ?= 115200 - -# set this to 0 if you don't need floating point support in printf/scanf -# this will save approx 14.5KB flash space and 448 bytes of statically allocated -# data RAM -# -# NB: Setting the value to 0 requires a recent esptool.py (Feb 2016 / commit ebf02c9) -PRINTF_SCANF_FLOAT_SUPPORT ?= 1 - -# Set OTA to 1 to build an image that supports rBoot OTA bootloader -# -# Requires 16mbit or higher flash sizes, with 8mbit -# images for each OTA "slot" -OTA ?= 0 - -ifeq ($(OTA),1) -# Tell C preprocessor that we're building for OTA -CPPFLAGS = -DOTA -endif - -FLAVOR ?= release # or debug - -# Compiler names, etc. assume gdb -CROSS ?= xtensa-lx106-elf- - -# Path to the filteroutput.py tool -FILTEROUTPUT ?= $(ROOT)/utils/filteroutput.py - -AR = $(CROSS)ar -CC = $(CROSS)gcc -CPP = $(CROSS)cpp -LD = $(CROSS)gcc -NM = $(CROSS)nm -C++ = $(CROSS)g++ -SIZE = $(CROSS)size -OBJCOPY = $(CROSS)objcopy -OBJDUMP = $(CROSS)objdump - -# Source components to compile and link. Each of these are subdirectories -# of the root, with a 'component.mk' file. -COMPONENTS ?= $(EXTRA_COMPONENTS) FreeRTOS lwip core - -# binary esp-iot-rtos SDK libraries to link. These are pre-processed prior to linking. -SDK_LIBS ?= main net80211 phy pp wpa - -# open source libraries linked in -LIBS ?= hal gcc c - -# set to 0 if you want to use the toolchain libc instead of esp-open-rtos newlib -OWN_LIBC ?= 1 - -# Note: you will need a recent esp -ENTRY_SYMBOL ?= call_user_start - -# Set this to zero if you don't want individual function & data sections -# (some code may be slightly slower, linking will be slighty slower, -# but compiled code size will come down a small amount.) -SPLIT_SECTIONS ?= 1 - -# Set this to 1 to have all compiler warnings treated as errors (and stop the -# build). This is recommended whenever you are working on code which will be -# submitted back to the main project, as all submitted code will be expected to -# compile without warnings to be accepted. -WARNINGS_AS_ERRORS ?= 0 - -# Common flags for both C & C++_ -C_CXX_FLAGS ?= -Wall -Wl,-EL -nostdlib $(EXTRA_C_CXX_FLAGS) -# Flags for C only -CFLAGS ?= $(C_CXX_FLAGS) -std=gnu99 $(EXTRA_CFLAGS) -# Flags for C++ only -CXXFLAGS ?= $(C_CXX_FLAGS) -fno-exceptions -fno-rtti $(EXTRA_CXXFLAGS) - -# these aren't technically preprocesor args, but used by all 3 of C, C++, assembler -CPPFLAGS += -mlongcalls -mtext-section-literals - -LDFLAGS = -nostdlib -Wl,--no-check-sections -L$(BUILD_DIR)sdklib -L$(ROOT)lib -u $(ENTRY_SYMBOL) -Wl,-static -Wl,-Map=$(BUILD_DIR)$(PROGRAM).map $(EXTRA_LDFLAGS) - -ifeq ($(WARNINGS_AS_ERRORS),1) - C_CXX_FLAGS += -Werror -endif - -ifeq ($(SPLIT_SECTIONS),1) - C_CXX_FLAGS += -ffunction-sections -fdata-sections - LDFLAGS += -Wl,-gc-sections -endif - -ifeq ($(FLAVOR),debug) - C_CXX_FLAGS += -g -O0 - LDFLAGS += -g -O0 -else ifeq ($(FLAVOR),sdklike) - # These are flags intended to produce object code as similar as possible to - # the output of the compiler used to build the SDK libs (for comparison of - # disassemblies when coding replacement routines). It is not normally - # intended to be used otherwise. - CFLAGS += -O2 -Os -fno-inline -fno-ipa-cp -fno-toplevel-reorder - LDFLAGS += -O2 -else - C_CXX_FLAGS += -g -O2 - LDFLAGS += -g -O2 -endif - -GITSHORTREV=\"$(shell cd $(ROOT); git rev-parse --short -q HEAD 2> /dev/null)\" -ifeq ($(GITSHORTREV),\"\") - GITSHORTREV="\"(nogit)\"" # (same length as a short git hash) -endif -CPPFLAGS += -DGITSHORTREV=$(GITSHORTREV) - -ifeq ($(OTA),0) -LINKER_SCRIPTS = $(ROOT)ld/nonota.ld -else -LINKER_SCRIPTS = $(ROOT)ld/ota.ld -endif -LINKER_SCRIPTS += $(ROOT)ld/common.ld $(ROOT)ld/rom.ld - -#### -#### no user configurable options below here -#### +include $(ROOT)parameters.mk ifndef PROGRAM $(error "Set the PROGRAM environment variable in your Makefile before including common.mk") @@ -184,20 +42,7 @@ LIB_ARGS = $(addprefix -l,$(LIBS)) PROGRAM_OUT = $(BUILD_DIR)$(PROGRAM).out LDFLAGS += $(addprefix -T,$(LINKER_SCRIPTS)) -# firmware tool arguments -ESPTOOL_ARGS=-fs $(FLASH_SIZE)m -fm $(FLASH_MODE) -ff $(FLASH_SPEED)m - -ifeq ($(OTA),0) -# for non-OTA, we create two different files for uploading into the flash -# these are the names and options to generate them -FW_ADDR_1 = 0x00000 -FW_ADDR_2 = 0x20000 -FW_FILE_1 = $(addprefix $(FIRMWARE_DIR),$(FW_ADDR_1).bin) -FW_FILE_2 = $(addprefix $(FIRMWARE_DIR),$(FW_ADDR_2).bin) -else -# for OTA, it's a single monolithic image -FW_FILE = $(addprefix $(FIRMWARE_DIR),$(PROGRAM)-ota.bin) -endif +FW_FILE = $(addprefix $(FIRMWARE_DIR),$(PROGRAM).bin) # Common include directories, shared across all "components" # components will add their include directories to this argument @@ -223,7 +68,7 @@ Q := @ vecho := @echo endif -.PHONY: all clean debug_print flash flash_bootloader erase_flash +.PHONY: all clean flash erase_flash all: $(PROGRAM_OUT) $(FW_FILE_1) $(FW_FILE_2) $(FW_FILE) @@ -364,17 +209,8 @@ $(FW_FILE): $(PROGRAM_OUT) $(FIRMWARE_DIR) $(vecho) "FW $@" $(Q) $(ESPTOOL) elf2image --version=2 $(ESPTOOL_ARGS) $< -o $(FW_FILE) -ifeq ($(OTA),0) -flash: $(FW_FILE_1) $(FW_FILE_2) - $(ESPTOOL) -p $(ESPPORT) --baud $(ESPBAUD) write_flash $(ESPTOOL_ARGS) $(FW_ADDR_2) $(FW_FILE_2) $(FW_ADDR_1) $(FW_FILE_1) -else flash: $(FW_FILE) - $(vecho) "Flashing OTA image slot 0 (bootloader not updated)" - $(ESPTOOL) -p $(ESPPORT) --baud $(ESPBAUD) write_flash $(ESPTOOL_ARGS) 0x2000 $(FW_FILE) -endif - -flash_bootloader: - $(MAKE) -C $(ROOT)/bootloader flash + $(ESPTOOL) -p $(ESPPORT) --baud $(ESPBAUD) write_flash $(ESPTOOL_ARGS) 0x0 $(RBOOT_BIN) 0x1000 $(RBOOT_CONF) 0x2000 $(FW_FILE) erase_flash: $(ESPTOOL) -p $(ESPPORT) --baud $(ESPBAUD) erase_flash diff --git a/core/spiflash-cache-enable.S b/core/spiflash-cache-enable.S index 2363a98..3e06f4a 100644 --- a/core/spiflash-cache-enable.S +++ b/core/spiflash-cache-enable.S @@ -12,8 +12,6 @@ * Copyright (C) 2015 Superhouse Automation Pty Ltd * BSD Licensed as described in the file LICENSE */ -#ifdef OTA - #define RBOOT_CONFIG_BASE (0x40200000 + 0x1000) #define RBOOT_ROMS_OFFS 0x8 /* offset of rboot_config_t.roms array in config */ @@ -74,5 +72,3 @@ Cache_Read_Enable: movi a0, cache_return_save /* restore a0 return address */ l32i a0, a0, 0 ret.n - -#endif diff --git a/examples/ota_basic/Makefile b/examples/ota_basic/Makefile index aafb05a..3f2ea5a 100644 --- a/examples/ota_basic/Makefile +++ b/examples/ota_basic/Makefile @@ -1,5 +1,4 @@ PROGRAM=ota_basic -OTA=1 EXTRA_COMPONENTS=extras/rboot-ota extras/mbedtls include ../../common.mk diff --git a/examples/ota_basic/ota_basic.c b/examples/ota_basic/ota_basic.c index 68e6c71..9ab3f20 100644 --- a/examples/ota_basic/ota_basic.c +++ b/examples/ota_basic/ota_basic.c @@ -16,7 +16,6 @@ #include "mbedtls/sha256.h" #include "ota-tftp.h" -#include "rboot.h" #include "rboot-api.h" #define TFTP_IMAGE_SERVER "192.168.1.23" diff --git a/extras/rboot-ota/component.mk b/extras/rboot-ota/component.mk index 690b7bc..62cf14f 100644 --- a/extras/rboot-ota/component.mk +++ b/extras/rboot-ota/component.mk @@ -1,8 +1,9 @@ # Component makefile for extras/rboot-ota -INC_DIRS += $(rboot-ota_ROOT) +# global include directories need to find rboot.h for integration, even +# when just including rboot-api.h :( +INC_DIRS += $(rboot-ota_ROOT) $(ROOT)bootloader $(ROOT)bootloader/rboot -# args for passing into compile rule generation rboot-ota_SRC_DIR = $(rboot-ota_ROOT) $(eval $(call component_compile_rules,rboot-ota)) diff --git a/extras/rboot-ota/ota-tftp.c b/extras/rboot-ota/ota-tftp.c index 1dee8cd..b6472a3 100644 --- a/extras/rboot-ota/ota-tftp.c +++ b/extras/rboot-ota/ota-tftp.c @@ -22,7 +22,6 @@ #include #include "ota-tftp.h" -#include "rboot.h" #include "rboot-api.h" #define TFTP_FIRMWARE_FILE "firmware.bin" diff --git a/extras/rboot-ota/rboot-api.c b/extras/rboot-ota/rboot-api.c index b3faac2..b9a5e57 100644 --- a/extras/rboot-ota/rboot-api.c +++ b/extras/rboot-ota/rboot-api.c @@ -8,7 +8,7 @@ // esp-open-rtos additions Copyright 2016 Angus Gratton ////////////////////////////////////////////////// -#include +#include #include //#include //#include diff --git a/extras/rboot-ota/rboot-api.h b/extras/rboot-ota/rboot-api.h index a74eeb2..29c11bd 100644 --- a/extras/rboot-ota/rboot-api.h +++ b/extras/rboot-ota/rboot-api.h @@ -12,6 +12,7 @@ * @{ */ +#include #include #ifdef __cplusplus diff --git a/extras/rboot-ota/rboot-integration.h b/extras/rboot-ota/rboot-integration.h index 064217b..005e9ea 100644 --- a/extras/rboot-ota/rboot-integration.h +++ b/extras/rboot-ota/rboot-integration.h @@ -9,6 +9,10 @@ #include #include +/*************************************************** + * Platform configuration definitions * + ***************************************************/ + #define uint8 uint8_t #define uint16 uint16_t #define uint32 uint32_t diff --git a/extras/rboot-ota/rboot.h b/extras/rboot-ota/rboot.h deleted file mode 100644 index 750c4d7..0000000 --- a/extras/rboot-ota/rboot.h +++ /dev/null @@ -1,116 +0,0 @@ -#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 - -#define RBOOT_INTEGRATION - -// uncomment to use only c code -// if you aren't using gcc you may need to do this -//#define BOOT_NO_ASM - -// Note: enabling RBOOT_CONFIG_CHECKSUM here means the config sector -// is always written by esp-open-rtos with a checksum. -// -// This means it will work whether the bootloader has config -// checksumming enabled or not. - -#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 -//#define BOOT_GPIO_ENABLED - -// 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 - -// increase if required -#define MAX_ROMS 4 - -#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 RBOOT_RTC_MAGIC 0x2334ae68 -#define RBOOT_RTC_READ 1 -#define RBOOT_RTC_WRITE 0 -#define RBOOT_RTC_ADDR 64 - -#ifdef RBOOT_INTEGRATION -#include -#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) - 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 - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/ld/nonota.ld b/ld/nonota.ld deleted file mode 100644 index 97054e6..0000000 --- a/ld/nonota.ld +++ /dev/null @@ -1,15 +0,0 @@ -/* Memory layout for esp-open-rtos when not using OTA - (ie ROM bootloader only, no second stage rboot) - */ -MEMORY -{ - dport0_0_seg : org = 0x3FF00000, len = 0x10 - dram0_0_seg : org = 0x3FFE8000, len = 0x14000 - iram1_0_seg : org = 0x40100000, len = 0x08000 -/* irom0 section, mapped from SPI flash - - Origin is offset by 0x20000 to leave space for bootloader RAM sections. - - - Length is max 8Mbit of mappable flash, minus start offset -*/ - irom0_0_seg : org = 0x40220000, len = (1M - 0x20000) -} diff --git a/ld/ota.ld b/ld/ota.ld deleted file mode 100644 index da32ce1..0000000 --- a/ld/ota.ld +++ /dev/null @@ -1,15 +0,0 @@ -/* Memory layout for esp-open-rtos when using OTA second stage bootloader */ - -MEMORY -{ - dport0_0_seg : org = 0x3FF00000, len = 0x10 - dram0_0_seg : org = 0x3FFE8000, len = 0x14000 - iram1_0_seg : org = 0x40100000, len = 0x08000 -/* irom0 section, mapped from SPI flash - - Origin is offset by 0x2010 to create spacer for second stage bootloader image, - header. - - - Length is max 8Mbit of mappable flash, minus start offset -*/ - irom0_0_seg : org = 0x40202010, len = (1M - 0x2010) -} diff --git a/ld/common.ld b/ld/program.ld similarity index 93% rename from ld/common.ld rename to ld/program.ld index 444c8e7..88fa0f4 100644 --- a/ld/common.ld +++ b/ld/program.ld @@ -1,7 +1,17 @@ -/* - * Common (OTA and non-OTA) parts for the esp-open-rtos Linker Script - * - */ +/* Memory layout for esp-open-rtos when using OTA second stage bootloader */ +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x08000 +/* irom0 section, mapped from SPI flash + - Origin is offset by 0x2010 to create spacer for second stage bootloader image, + header. + + - Length is max 8Mbit of mappable flash, minus start offset +*/ + irom0_0_seg : org = 0x40202010, len = (1M - 0x2010) +} /* FreeRTOS memory management functions diff --git a/parameters.mk b/parameters.mk new file mode 100644 index 0000000..e750e83 --- /dev/null +++ b/parameters.mk @@ -0,0 +1,141 @@ +# Parameters for the esp-open-rtos make process +# +# You can edit this file to change parameters, but a better option is +# to create a local.mk file and add overrides there. The local.mk file +# can be in the root directory, or the program directory alongside the +# Makefile, or both. +# +-include $(ROOT)local.mk +-include local.mk + +# Flash size in megabits +# Valid values are same as for esptool.py - 2,4,8,16,32 +FLASH_SIZE ?= 16 + +# Flash mode, valid values are same as for esptool.py - qio,qout,dio.dout +FLASH_MODE ?= qio + +# Flash speed in MHz, valid values are same as for esptool.py - 80, 40, 26, 20 +FLASH_SPEED ?= 40 + +# Output directories to store intermediate compiled files +# relative to the program directory +BUILD_DIR ?= $(PROGRAM_DIR)build/ +FIRMWARE_DIR ?= $(PROGRAM_DIR)firmware/ + +# esptool.py from https://github.com/themadinventor/esptool +ESPTOOL ?= esptool.py +# serial port settings for esptool.py +ESPPORT ?= /dev/ttyUSB0 +ESPBAUD ?= 115200 + +# firmware tool arguments +ESPTOOL_ARGS=-fs $(FLASH_SIZE)m -fm $(FLASH_MODE) -ff $(FLASH_SPEED)m + + +# set this to 0 if you don't need floating point support in printf/scanf +# this will save approx 14.5KB flash space and 448 bytes of statically allocated +# data RAM +# +# NB: Setting the value to 0 requires a recent esptool.py (Feb 2016 / commit ebf02c9) +PRINTF_SCANF_FLOAT_SUPPORT ?= 1 + +FLAVOR ?= release # or debug + +# Compiler names, etc. assume gdb +CROSS ?= xtensa-lx106-elf- + +# Path to the filteroutput.py tool +FILTEROUTPUT ?= $(ROOT)/utils/filteroutput.py + +AR = $(CROSS)ar +CC = $(CROSS)gcc +CPP = $(CROSS)cpp +LD = $(CROSS)gcc +NM = $(CROSS)nm +C++ = $(CROSS)g++ +SIZE = $(CROSS)size +OBJCOPY = $(CROSS)objcopy +OBJDUMP = $(CROSS)objdump + +# Source components to compile and link. Each of these are subdirectories +# of the root, with a 'component.mk' file. +COMPONENTS ?= $(EXTRA_COMPONENTS) FreeRTOS lwip core + +# binary esp-iot-rtos SDK libraries to link. These are pre-processed prior to linking. +SDK_LIBS ?= main net80211 phy pp wpa + +# open source libraries linked in +LIBS ?= hal gcc c + +# set to 0 if you want to use the toolchain libc instead of esp-open-rtos newlib +OWN_LIBC ?= 1 + +# Note: you will need a recent esp +ENTRY_SYMBOL ?= call_user_start + +# Set this to zero if you don't want individual function & data sections +# (some code may be slightly slower, linking will be slighty slower, +# but compiled code size will come down a small amount.) +SPLIT_SECTIONS ?= 1 + +# Set this to 1 to have all compiler warnings treated as errors (and stop the +# build). This is recommended whenever you are working on code which will be +# submitted back to the main project, as all submitted code will be expected to +# compile without warnings to be accepted. +WARNINGS_AS_ERRORS ?= 0 + +# Common flags for both C & C++_ +C_CXX_FLAGS ?= -Wall -Wl,-EL -nostdlib $(EXTRA_C_CXX_FLAGS) +# Flags for C only +CFLAGS ?= $(C_CXX_FLAGS) -std=gnu99 $(EXTRA_CFLAGS) +# Flags for C++ only +CXXFLAGS ?= $(C_CXX_FLAGS) -fno-exceptions -fno-rtti $(EXTRA_CXXFLAGS) + +# these aren't all technically preprocesor args, but used by all 3 of C, C++, assembler +CPPFLAGS += -mlongcalls -mtext-section-literals + +LDFLAGS = -nostdlib -Wl,--no-check-sections -L$(BUILD_DIR)sdklib -L$(ROOT)lib -u $(ENTRY_SYMBOL) -Wl,-static -Wl,-Map=$(BUILD_DIR)$(PROGRAM).map $(EXTRA_LDFLAGS) + +ifeq ($(WARNINGS_AS_ERRORS),1) + C_CXX_FLAGS += -Werror +endif + +ifeq ($(SPLIT_SECTIONS),1) + C_CXX_FLAGS += -ffunction-sections -fdata-sections + LDFLAGS += -Wl,-gc-sections +endif + +ifeq ($(FLAVOR),debug) + C_CXX_FLAGS += -g -O0 + LDFLAGS += -g -O0 +else ifeq ($(FLAVOR),sdklike) + # These are flags intended to produce object code as similar as possible to + # the output of the compiler used to build the SDK libs (for comparison of + # disassemblies when coding replacement routines). It is not normally + # intended to be used otherwise. + CFLAGS += -O2 -Os -fno-inline -fno-ipa-cp -fno-toplevel-reorder + LDFLAGS += -O2 +else + C_CXX_FLAGS += -g -O2 + LDFLAGS += -g -O2 +endif + +GITSHORTREV=\"$(shell cd $(ROOT); git rev-parse --short -q HEAD 2> /dev/null)\" +ifeq ($(GITSHORTREV),\"\") + GITSHORTREV="\"(nogit)\"" # (same length as a short git hash) +endif +CPPFLAGS += -DGITSHORTREV=$(GITSHORTREV) + +LINKER_SCRIPTS += $(ROOT)ld/program.ld $(ROOT)ld/rom.ld + +# rboot firmware binary paths for flashing +RBOOT_BIN = $(ROOT)bootloader/firmware/rboot.bin +RBOOT_PREBUILT_BIN = $(ROOT)bootloader/firmware_prebuilt/rboot.bin +RBOOT_CONF = $(ROOT)bootloader/firmware_prebuilt/blank_config.bin + +# if a custom bootloader hasn't been compiled, use the +# prebuilt binary from the source tree +ifeq (,$(wildcard $(RBOOT_BIN))) +RBOOT_BIN=$(RBOOT_PREBUILT_BIN) +endif From d62fd4899a8e61fd2a27a9b1f3b5d5705b0a8e9c Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 23 May 2016 12:23:04 +1000 Subject: [PATCH 10/13] ota_basic example cleanup --- examples/ota_basic/ota_basic.c | 115 ++++++++++++++++++++------------- 1 file changed, 69 insertions(+), 46 deletions(-) diff --git a/examples/ota_basic/ota_basic.c b/examples/ota_basic/ota_basic.c index 9ab3f20..61b50b1 100644 --- a/examples/ota_basic/ota_basic.c +++ b/examples/ota_basic/ota_basic.c @@ -1,6 +1,8 @@ /* A very simple OTA example * - * Binds a TCP socket, reads an image from it over TFTP and then flashes live. + * Tries to run both a TFTP client and a TFTP server simultaneously, either will accept a TTP firmware and update it. + * + * Not a realistic OTA setup, this needs adapting (choose either client or server) before you'd want to use it. * * For more information about esp-open-rtos OTA see https://github.com/SuperHouse/esp-open-rtos/wiki/OTA-Update-Configuration * @@ -18,6 +20,7 @@ #include "ota-tftp.h" #include "rboot-api.h" +/* TFTP client will request this image filenames from this server */ #define TFTP_IMAGE_SERVER "192.168.1.23" #define TFTP_IMAGE_FILENAME1 "firmware1.bin" #define TFTP_IMAGE_FILENAME2 "firmware2.bin" @@ -25,6 +28,68 @@ /* Output of the command 'sha256sum firmware1.bin' */ static const char *FIRMWARE1_SHA256 = "88199daff8b9e76975f685ec7f95bc1df3c61bd942a33a54a40707d2a41e5488"; +/* Example function to TFTP download a firmware file and verify its SHA256 before + booting into it. +*/ +static void tftpclient_download_and_verify_file1(int slot, rboot_config *conf) +{ + printf("Downloading %s to slot %d...\n", TFTP_IMAGE_FILENAME1, slot); + int res = ota_tftp_download(TFTP_IMAGE_SERVER, TFTP_PORT+1, TFTP_IMAGE_FILENAME1, 1000, slot); + printf("ota_tftp_download %s result %d\n", TFTP_IMAGE_FILENAME1, res); + + if (res != 0) { + return; + } + + printf("Looks valid, calculating SHA256...\n"); + uint32_t length; + bool valid = rboot_verify_image(conf->roms[slot], &length, NULL); + static mbedtls_sha256_context ctx; + mbedtls_sha256_init(&ctx); + mbedtls_sha256_starts(&ctx, 0); + valid = valid && rboot_digest_image(conf->roms[slot], length, (rboot_digest_update_fn)mbedtls_sha256_update, &ctx); + static uint8_t hash_result[32]; + mbedtls_sha256_finish(&ctx, hash_result); + mbedtls_sha256_free(&ctx); + + if(!valid) + { + printf("Not valid after all :(\n"); + return; + } + + printf("Image SHA256 = "); + valid = true; + for(int i = 0; i < sizeof(hash_result); i++) { + char hexbuf[3]; + snprintf(hexbuf, 3, "%02x", hash_result[i]); + printf(hexbuf); + if(strncmp(hexbuf, FIRMWARE1_SHA256+i*2, 2)) + valid = false; + } + printf("\n"); + + if(!valid) { + printf("Downloaded image SHA256 didn't match expected '%s'\n", FIRMWARE1_SHA256); + return; + } + + printf("SHA256 Matches. Rebooting into slot %d...\n", slot); + rboot_set_current_rom(slot); + sdk_system_restart(); +} + +/* Much simpler function that just downloads a file via TFTP into an rboot slot. + + ( + */ +static void tftpclient_download_file2(int slot) +{ + printf("Downloading %s to slot %d...\n", TFTP_IMAGE_FILENAME2, slot); + int res = ota_tftp_download(TFTP_IMAGE_SERVER, TFTP_PORT+1, TFTP_IMAGE_FILENAME2, 1000, slot); + printf("ota_tftp_download %s result %d\n", TFTP_IMAGE_FILENAME2, res); +} + void tftp_client_task(void *pvParameters) { printf("TFTP client task starting...\n"); @@ -43,53 +108,10 @@ void tftp_client_task(void *pvParameters) Note: example will reboot into FILENAME1 if it is successfully downloaded, but FILENAME2 is ignored. */ while(1) { - printf("Downloading %s to slot %d...\n", TFTP_IMAGE_FILENAME1, slot); - int res = ota_tftp_download(TFTP_IMAGE_SERVER, TFTP_PORT, TFTP_IMAGE_FILENAME1, 1000, slot); - printf("ota_tftp_download %s result %d\n", TFTP_IMAGE_FILENAME1, res); - if(res == 0) { - printf("Looks valid, calculating SHA256...\n"); - uint32_t length; - bool valid = rboot_verify_image(conf.roms[slot], &length, NULL); - static mbedtls_sha256_context ctx; - mbedtls_sha256_init(&ctx); - mbedtls_sha256_starts(&ctx, 0); - valid = valid && rboot_digest_image(conf.roms[slot], length, (rboot_digest_update_fn)mbedtls_sha256_update, &ctx); - static uint8_t hash_result[32]; - mbedtls_sha256_finish(&ctx, hash_result); - mbedtls_sha256_free(&ctx); - - if(!valid) - { - printf("Not valid after all :(\n"); - } - else - { - printf("Image SHA256 = "); - bool valid = true; - for(int i = 0; i < sizeof(hash_result); i++) { - char hexbuf[3]; - snprintf(hexbuf, 3, "%02x", hash_result[i]); - printf(hexbuf); - if(strncmp(hexbuf, FIRMWARE1_SHA256+i*2, 2)) - valid = false; - - } - printf("\n"); - if (valid) { - printf("SHA256 Matches. Rebooting into slot %d...\n", slot); - rboot_set_current_rom(slot); - sdk_system_restart(); - } - else { - printf("Downloaded image SHA256 didn't match expected '%s'\n", FIRMWARE1_SHA256); - } - } - } + tftpclient_download_and_verify_file1(slot, &conf); vTaskDelay(5000 / portTICK_RATE_MS); - printf("Downloading %s to slot %d...\n", TFTP_IMAGE_FILENAME2, slot); - res = ota_tftp_download(TFTP_IMAGE_SERVER, TFTP_PORT, TFTP_IMAGE_FILENAME2, 1000, slot); - printf("ota_tftp_download %s result %d\n", TFTP_IMAGE_FILENAME2, res); + tftpclient_download_file2(slot); vTaskDelay(5000 / portTICK_RATE_MS); } } @@ -114,6 +136,7 @@ void user_init(void) sdk_wifi_set_opmode(STATION_MODE); sdk_wifi_station_set_config(&config); + printf("Starting TFTP server..."); ota_tftp_init_server(TFTP_PORT); xTaskCreate(&tftp_client_task, (signed char *)"tftp_client", 2048, NULL, 2, NULL); } From 84856f80a9c31a12814168330e7865c3ce39fd32 Mon Sep 17 00:00:00 2001 From: Kenshi Kawaguchi Date: Wed, 25 May 2016 00:07:13 -0700 Subject: [PATCH 11/13] ota_tftp_download takes an optional receive_cb that will report on the status of the TFTP transfer --- extras/rboot-ota/ota-tftp.c | 17 ++++++++++++----- extras/rboot-ota/ota-tftp.h | 8 +++++++- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/extras/rboot-ota/ota-tftp.c b/extras/rboot-ota/ota-tftp.c index b6472a3..99ebdf7 100644 --- a/extras/rboot-ota/ota-tftp.c +++ b/extras/rboot-ota/ota-tftp.c @@ -43,7 +43,7 @@ static void tftp_task(void *port_p); static char *tftp_get_field(int field, struct netbuf *netbuf); -static err_t tftp_receive_data(struct netconn *nc, size_t write_offs, size_t limit_offs, size_t *received_len, ip_addr_t *peer_addr, int peer_port); +static err_t tftp_receive_data(struct netconn *nc, size_t write_offs, size_t limit_offs, size_t *received_len, ip_addr_t *peer_addr, int peer_port, tftp_receive_cb receive_cb); static err_t tftp_send_ack(struct netconn *nc, int block); static err_t tftp_send_rrq(struct netconn *nc, const char *filename); static void tftp_send_error(struct netconn *nc, int err_code, const char *err_msg); @@ -53,7 +53,8 @@ void ota_tftp_init_server(int listen_port) xTaskCreate(tftp_task, (signed char *)"tftpOTATask", 512, (void *)listen_port, 2, NULL); } -err_t ota_tftp_download(const char *server, int port, const char *filename, int timeout, int ota_slot) +err_t ota_tftp_download(const char *server, int port, const char *filename, + int timeout, int ota_slot, tftp_receive_cb receive_cb) { rboot_config rboot_config = rboot_get_config(); /* Validate the OTA slot parameter */ @@ -101,7 +102,8 @@ err_t ota_tftp_download(const char *server, int port, const char *filename, int } size_t received_len; - err = tftp_receive_data(nc, flash_offset, flash_offset+MAX_IMAGE_SIZE, &received_len, &addr, port); + err = tftp_receive_data(nc, flash_offset, flash_offset+MAX_IMAGE_SIZE, + &received_len, &addr, port, receive_cb); netconn_delete(nc); return err; } @@ -189,7 +191,7 @@ static void tftp_task(void *listen_port) /* Finished WRQ phase, start TFTP data transfer */ size_t received_len; netconn_set_recvtimeout(nc, 10000); - int recv_err = tftp_receive_data(nc, conf.roms[slot], conf.roms[slot]+MAX_IMAGE_SIZE, &received_len, NULL, 0); + int recv_err = tftp_receive_data(nc, conf.roms[slot], conf.roms[slot]+MAX_IMAGE_SIZE, &received_len, NULL, 0, NULL); netconn_disconnect(nc); printf("OTA TFTP receive data result %d bytes %d\r\n", recv_err, received_len); @@ -240,7 +242,7 @@ static char *tftp_get_field(int field, struct netbuf *netbuf) #define TFTP_TIMEOUT_RETRANSMITS 10 -static err_t tftp_receive_data(struct netconn *nc, size_t write_offs, size_t limit_offs, size_t *received_len, ip_addr_t *peer_addr, int peer_port) +static err_t tftp_receive_data(struct netconn *nc, size_t write_offs, size_t limit_offs, size_t *received_len, ip_addr_t *peer_addr, int peer_port, tftp_receive_cb receive_cb) { *received_len = 0; const int DATA_PACKET_SZ = 512 + 4; /*( packet size plus header */ @@ -382,6 +384,11 @@ static err_t tftp_receive_data(struct netconn *nc, size_t write_offs, size_t lim return ack_err; } + // Make sure ack was successful before calling callback. + if(receive_cb) { + receive_cb(*received_len); + } + if(len < DATA_PACKET_SZ) { return ERR_OK; } diff --git a/extras/rboot-ota/ota-tftp.h b/extras/rboot-ota/ota-tftp.h index cccac2a..6be63aa 100644 --- a/extras/rboot-ota/ota-tftp.h +++ b/extras/rboot-ota/ota-tftp.h @@ -3,6 +3,8 @@ #include "lwip/err.h" +typedef void (*tftp_receive_cb)(size_t bytes_received); + /* TFTP Server OTA Support * * To use, call ota_tftp_init_server() which will start the TFTP server task @@ -41,8 +43,12 @@ void ota_tftp_init_server(int listen_port); Returns 0 on success, LWIP err.h values for errors. Does not change the current firmware slot, or reboot. + + receive_cb: called repeatedly after each successful packet that + has been written to flash and ACKed. Can pass NULL to omit. */ -err_t ota_tftp_download(const char *server, int port, const char *filename, int timeout, int ota_slot); +err_t ota_tftp_download(const char *server, int port, const char *filename, + int timeout, int ota_slot, tftp_receive_cb receive_cb); #define TFTP_PORT 69 From 7fe2020785dfa360a3f49946f426ec385327dbf4 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 26 May 2016 09:19:40 +1000 Subject: [PATCH 12/13] ota_basic example: Update TFTP client calls --- examples/ota_basic/ota_basic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/ota_basic/ota_basic.c b/examples/ota_basic/ota_basic.c index 61b50b1..c2050d5 100644 --- a/examples/ota_basic/ota_basic.c +++ b/examples/ota_basic/ota_basic.c @@ -34,7 +34,7 @@ static const char *FIRMWARE1_SHA256 = "88199daff8b9e76975f685ec7f95bc1df3c61bd94 static void tftpclient_download_and_verify_file1(int slot, rboot_config *conf) { printf("Downloading %s to slot %d...\n", TFTP_IMAGE_FILENAME1, slot); - int res = ota_tftp_download(TFTP_IMAGE_SERVER, TFTP_PORT+1, TFTP_IMAGE_FILENAME1, 1000, slot); + int res = ota_tftp_download(TFTP_IMAGE_SERVER, TFTP_PORT+1, TFTP_IMAGE_FILENAME1, 1000, slot, NULL); printf("ota_tftp_download %s result %d\n", TFTP_IMAGE_FILENAME1, res); if (res != 0) { @@ -86,7 +86,7 @@ static void tftpclient_download_and_verify_file1(int slot, rboot_config *conf) static void tftpclient_download_file2(int slot) { printf("Downloading %s to slot %d...\n", TFTP_IMAGE_FILENAME2, slot); - int res = ota_tftp_download(TFTP_IMAGE_SERVER, TFTP_PORT+1, TFTP_IMAGE_FILENAME2, 1000, slot); + int res = ota_tftp_download(TFTP_IMAGE_SERVER, TFTP_PORT+1, TFTP_IMAGE_FILENAME2, 1000, slot, NULL); printf("ota_tftp_download %s result %d\n", TFTP_IMAGE_FILENAME2, res); } From 34094d233c9a4497621f3cf23edfd1fcb6e1209d Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Sat, 28 May 2016 11:31:29 +1000 Subject: [PATCH 13/13] Travis: build rboot bootloader as part of automated build --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0e1b62e..4bd0884 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,6 +32,7 @@ addons: - python-serial - sed - git + - vim-common before_install: - travis_wait 30 utils/travis_build/install_toolchain.sh @@ -42,3 +43,5 @@ script: - sed -i "s%#error%//#error%" include/ssid_config.h # Don't verbose-build all examples (too much output), only verbose-build errors - ( ${MAKE_CMD} ) || ( ${MAKE_CMD} V=1 ) + # build bootloader + - make -C bootloader/