Updated rboot to #75ca33b including the flash write bug.

This commit is contained in:
Johan Kanflo 2016-04-07 20:29:28 +02:00
parent 02c35d8a71
commit 9c49134d61
9 changed files with 505 additions and 130 deletions

View file

@ -14,13 +14,15 @@
#include "ssid_config.h"
#include "ota-tftp.h"
#include "rboot-ota.h"
#include "rboot-integration.h"
#include "rboot.h"
#include "rboot-api.h"
void user_init(void)
{
uart_set_baud(0, 115200);
rboot_config_t conf = rboot_get_config();
rboot_config conf = rboot_get_config();
printf("\r\n\r\nOTA Basic demo.\r\nCurrently running on flash slot %d / %d.\r\n\r\n",
conf.current_rom, conf.count);

View file

@ -22,7 +22,8 @@
#include <espressif/esp_system.h>
#include "ota-tftp.h"
#include "rboot-ota.h"
#include "rboot.h"
#include "rboot-api.h"
#define TFTP_FIRMWARE_FILE "firmware.bin"
#define TFTP_OCTET_MODE "octet" /* non-case-sensitive */
@ -112,7 +113,7 @@ static void tftp_task(void *listen_port)
netbuf_delete(netbuf);
/* Find next free slot - this requires flash unmapping so best done when no packets in flight */
rboot_config_t conf;
rboot_config conf;
conf = rboot_get_config();
int slot = (conf.current_rom + 1) % conf.count;

View file

@ -0,0 +1,214 @@
//////////////////////////////////////////////////
// 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 <rboot.h>
#include <string.h>
//#include <c_types.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
#ifdef RBOOT_INTEGRATION
#include <rboot-integration.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);
memcpy(buffer, conf, sizeof(rboot_config));
vPortEnterCritical();
spi_flash_erase_sector(BOOT_CONFIG_SECTOR);
vPortExitCritical();
taskYIELD();
vPortEnterCritical();
//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);
vPortExitCritical();
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;
}
// 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
memcpy(buffer, status->extra_bytes, status->extra_count);
// copy in new data
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;
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

View file

@ -0,0 +1,136 @@
#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 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

View file

@ -10,17 +10,10 @@
#include <FreeRTOS.h>
#include <task.h>
#include "rboot-ota.h"
#include <rboot.h>
#define ROM_MAGIC_OLD 0xe9
#define ROM_MAGIC_NEW 0xea
#define CHECKSUM_INIT 0xef
#if 0
#define RBOOT_DEBUG(f_, ...) printf((f_), __VA_ARGS__)
#else
#define RBOOT_DEBUG(f_, ...)
#endif
typedef struct __attribute__((packed)) {
uint8_t magic;
@ -35,67 +28,6 @@ typedef struct __attribute__((packed)) {
} section_header_t;
// get the rboot config
rboot_config_t rboot_get_config() {
rboot_config_t conf;
sdk_spi_flash_read(BOOT_CONFIG_SECTOR * SECTOR_SIZE, (uint32_t*)&conf, sizeof(rboot_config_t));
return conf;
}
// write the rboot config
// preserves contents of rest of sector, so rest
// of sector can be used to store user data
// updates checksum automatically, if enabled
bool rboot_set_config(rboot_config_t *conf) {
uint8_t *buffer;
#ifdef RBOOT_CONFIG_CHKSUM
uint8_t chksum;
uint8_t *ptr;
#endif
buffer = (uint8_t*)malloc(SECTOR_SIZE);
if (!buffer) {
printf("rboot_set_config: Failed to allocate sector buffer\r\n");
return false;
}
#ifdef BOOT_CONFIG_CHKSUM
chksum = CHKSUM_INIT;
for (ptr = (uint8_t*)conf; ptr < &conf->chksum; ptr++) {
chksum ^= *ptr;
}
conf->chksum = chksum;
#endif
sdk_spi_flash_read(BOOT_CONFIG_SECTOR * SECTOR_SIZE, (uint32_t*)buffer, SECTOR_SIZE);
memcpy(buffer, conf, sizeof(rboot_config_t));
vPortEnterCritical();
sdk_spi_flash_erase_sector(BOOT_CONFIG_SECTOR);
vPortExitCritical();
taskYIELD();
vPortEnterCritical();
sdk_spi_flash_write(BOOT_CONFIG_SECTOR * SECTOR_SIZE, (uint32_t*)buffer, SECTOR_SIZE);
vPortExitCritical();
free(buffer);
return true;
}
// get current boot rom
uint8_t rboot_get_current_rom() {
rboot_config_t conf;
conf = rboot_get_config();
return conf.current_rom;
}
// set current boot rom
bool rboot_set_current_rom(uint8_t rom) {
rboot_config_t conf;
conf = rboot_get_config();
if (rom >= conf.count) return false;
conf.current_rom = rom;
return rboot_set_config(&conf);
}
// 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)
@ -120,7 +52,7 @@ bool rboot_verify_image(uint32_t offset, uint32_t expected_length, const char **
int remaining_sections = image_header.section_count;
uint8_t checksum = CHECKSUM_INIT;
uint8_t checksum = CHKSUM_INIT;
while(remaining_sections > 0 && offset < end_offset)
{

View file

@ -0,0 +1,34 @@
// The rboot project provides this file for making rboot fit other projects
#ifndef __RBOOT_INTEGRATION_H__
#define __RBOOT_INTEGRATION_H__
#include <stdint.h>
#include <stdbool.h>
#include <espressif/spi_flash.h>
#include <espressif/esp_system.h>
#include <FreeRTOS.h>
#include <task.h>
#define uint8 uint8_t
#define uint16 uint16_t
#define uint32 uint32_t
#define int32 int32_t
#define ICACHE_FLASH_ATTR
#define spi_flash_read sdk_spi_flash_read
#define spi_flash_erase_sector sdk_spi_flash_erase_sector
#define spi_flash_write sdk_spi_flash_write
#define os_malloc malloc
#define os_free free
#define system_rtc_mem_read sdk_system_rtc_mem_read
#define system_rtc_mem_write sdk_system_rtc_mem_write
#if 0
#define RBOOT_DEBUG(f_, ...) printf((f_), __VA_ARGS__)
#else
#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__

View file

@ -1,55 +0,0 @@
#ifndef __RBOOT_OTA_H__
#define __RBOOT_OTA_H__
/* rboot-ota client API
*
* Ported from https://github.com/raburton/esp8266/ to esp-open-rtos
*
* BSD Licensed as per the file LICENSE in the top-level directory.
* Copyright (c) 2015 Richard A Burton & SuperHouse Pty Ltd
*/
#include <stdint.h>
#include <stdbool.h>
#include <rboot-config.h>
/* rboot config block structure (stored in flash offset 0x1000)
*
* Structure taken from rboot.h revision a4724ede22
* The version of rboot you're using has to match this structure
*/
typedef struct {
uint8_t magic; // our magic
uint8_t version; // config struct version
uint8_t mode; // boot loader mode
uint8_t current_rom; // currently selected rom
uint8_t gpio_rom; // rom to use for gpio boot
uint8_t count; // number of roms in use
uint8_t unused[2]; // padding
uint32_t roms[RBOOT_MAX_ROMS]; // flash addresses of the roms
#ifdef RBOOT_CONFIG_CHKSUM
uint8_t chksum; // config chksum
#endif
} rboot_config_t;
#define SECTOR_SIZE 0x1000
#define BOOT_CONFIG_SECTOR 1
// timeout for the initial connect (in ms)
#define OTA_CONNECT_TIMEOUT 10000
// timeout for the download and flash to complete (in ms), once connected
#define OTA_DOWNLOAD_TIMEOUT 20000
#define UPGRADE_FLAG_IDLE 0x00
#define UPGRADE_FLAG_START 0x01
#define UPGRADE_FLAG_FINISH 0x02
#define FLASH_BY_ADDR 0xff
rboot_config_t rboot_get_config();
bool rboot_set_config(rboot_config_t *conf);
uint8_t rboot_get_current_rom();
bool rboot_set_current_rom(uint8_t rom);
bool rboot_verify_image(uint32_t offset, uint32_t expected_length, const char **error_message);
#endif

111
extras/rboot-ota/rboot.h Normal file
View file

@ -0,0 +1,111 @@
#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
// 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
//#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 <rboot-integration.h>
#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

View file

@ -1,4 +1,4 @@
*NOTE: This rboot-ota and the TFTP server ota-tftp.h are specific to esp-open-rtos. The below Makefile is from the upstream rboot-ota project.*
*NOTE: This rboot-ota and the TFTP server ota-tftp.h are specific to esp-open-rtos. The below Makefile is from the upstream rboot-ota project and the rboot code is taken from #75ca33b.*
For more details on OTA in esp-open-rtos, see https://github.com/SuperHouse/esp-open-rtos/wiki/OTA-Update-Configuration