diff --git a/.gitmodules b/.gitmodules index 84a5e304aa..85003018ee 100644 --- a/.gitmodules +++ b/.gitmodules @@ -63,7 +63,7 @@ ignore = dirty [submodule "rboot"] path = Sming/Components/rboot/rboot - url = https://github.com/raburton/rboot.git + url = https://github.com/mikee47/rboot ignore = dirty [submodule "spiffs"] path = Sming/Components/spiffs/spiffs diff --git a/Sming/Arch/Esp8266/Components/esp8266/startup.cpp b/Sming/Arch/Esp8266/Components/esp8266/startup.cpp index ef6d1d07d3..ff62f084d2 100644 --- a/Sming/Arch/Esp8266/Components/esp8266/startup.cpp +++ b/Sming/Arch/Esp8266/Components/esp8266/startup.cpp @@ -55,9 +55,8 @@ extern "C" void WEAK_ATTR user_rf_pre_init(void) extern "C" uint32 ICACHE_FLASH_ATTR WEAK_ATTR user_rf_cal_sector_set(void) { - // RF calibration stored in last sector of sysParam - auto sysParam = *Storage::findPartition(Storage::Partition::SubType::Data::sysParam); - return ((sysParam.address() + sysParam.size()) / SPI_FLASH_SEC_SIZE) - 1; + auto rfCal = *Storage::findPartition(Storage::Partition::SubType::Data::rfCal); + return rfCal.address(); } #ifdef SDK_INTERNAL @@ -71,16 +70,14 @@ extern "C" void ICACHE_FLASH_ATTR WEAK_ATTR user_pre_init(void) Storage::initialize(); auto sysParam = *Storage::findPartition(Storage::Partition::SubType::Data::sysParam); + auto rfCal = *Storage::findPartition(Storage::Partition::SubType::Data::rfCal); auto phy = *Storage::findPartition(Storage::Partition::SubType::Data::phy); - // RF calibration stored in last sector of sysParam - auto sysParamSize = sysParam.size() - SPI_FLASH_SEC_SIZE; - static const partition_item_t partitions[] = { {SYSTEM_PARTITION_BOOTLOADER, 0, SPI_FLASH_SEC_SIZE}, {SYSTEM_PARTITION_PHY_DATA, phy.address(), phy.size()}, - {SYSTEM_PARTITION_SYSTEM_PARAMETER, sysParam.address(), sysParamSize}, - {SYSTEM_PARTITION_RF_CAL, sysParam.address() + sysParamSize, SPI_FLASH_SEC_SIZE}, + {SYSTEM_PARTITION_SYSTEM_PARAMETER, sysParam.address(), sysParam.size()}, + {SYSTEM_PARTITION_RF_CAL, rfCal.address(), rfCal.size()}, }; enum flash_size_map sizeMap = system_get_flash_size_map(); diff --git a/Sming/Arch/Esp8266/options.json b/Sming/Arch/Esp8266/options.json index 7e3d545649..dfa35550eb 100644 --- a/Sming/Arch/Esp8266/options.json +++ b/Sming/Arch/Esp8266/options.json @@ -6,5 +6,23 @@ "filename": "$(FLASH_INIT_DATA_VCC)" } } + }, + "alternate": { + "description": "ESP8266 layout with critical partitions at start of flash", + "partition_table_offset": "0x2000", + "partitions": { + "rf_cal": { + "address": "0x3000" + }, + "phy_init": { + "address": "0x4000" + }, + "sys_param": { + "address": "0x5000" + }, + "rom0": { + "address": "0x8000" + } + } } } \ No newline at end of file diff --git a/Sming/Arch/Esp8266/spiffs-two-roms.hw b/Sming/Arch/Esp8266/spiffs-two-roms.hw index 9503891e2a..93e4605b47 100644 --- a/Sming/Arch/Esp8266/spiffs-two-roms.hw +++ b/Sming/Arch/Esp8266/spiffs-two-roms.hw @@ -2,11 +2,14 @@ "name": "Two ROM slots with single SPIFFS", "base_config": "spiffs", "partitions": { + "rom0": { + "subtype": "ota_0" + }, "rom1": { "address": "0x108000", "size": "992K", "type": "app", - "subtype": "ota_0", + "subtype": "ota_1", "filename": "$(RBOOT_ROM_1_BIN)" } } diff --git a/Sming/Arch/Esp8266/standard.hw b/Sming/Arch/Esp8266/standard.hw index 240e56f679..37d6bd7d68 100644 --- a/Sming/Arch/Esp8266/standard.hw +++ b/Sming/Arch/Esp8266/standard.hw @@ -2,7 +2,7 @@ "name": "Standard config with single ROM", "comment": "Should work with any Esp8266 variant", "arch": "Esp8266", - "partition_table_offset": "0x2000", + "partition_table_offset": "self.devices[0].size - 0x6000", "devices": { "spiFlash": { "type": "flash", @@ -12,25 +12,31 @@ } }, "partitions": { + "rom0": { + "address": "0x002000", + "size": "992K", + "type": "app", + "subtype": "factory", + "filename": "$(RBOOT_ROM_0_BIN)" + }, + "rf_cal": { + "address": "self.device.size - 0x5000", + "size": "4K", + "type": "data", + "subtype": "rfcal" + }, "phy_init": { - "address": "0x003000", + "address": "self.device.size - 0x4000", "size": "4K", "type": "data", "subtype": "phy", "filename": "$(FLASH_INIT_DATA)" }, "sys_param": { - "address": "0x004000", - "size": "16K", + "address": "self.device.size - 0x3000", + "size": "12K", "type": "data", "subtype": "sysparam" - }, - "rom0": { - "address": "0x008000", - "size": "992K", - "type": "app", - "subtype": "factory", - "filename": "$(RBOOT_ROM_0_BIN)" } } -} +} \ No newline at end of file diff --git a/Sming/Arch/Esp8266/two-rom-mode.hw b/Sming/Arch/Esp8266/two-rom-mode.hw index 9d6399179f..2be8a10eca 100644 --- a/Sming/Arch/Esp8266/two-rom-mode.hw +++ b/Sming/Arch/Esp8266/two-rom-mode.hw @@ -3,13 +3,14 @@ "base_config": "standard", "partitions": { "rom0": { + "subtype": "ota_0", "size": "480K" }, "rom1": { "address": "0x80000", - "size": "512K", + "size": "488K", "type": "app", - "subtype": "ota_0", + "subtype": "ota_1", "filename": "$(RBOOT_ROM_1_BIN)" } } diff --git a/Sming/Components/Storage/README.rst b/Sming/Components/Storage/README.rst index 8b609fee02..0ab3666e67 100644 --- a/Sming/Components/Storage/README.rst +++ b/Sming/Components/Storage/README.rst @@ -84,6 +84,16 @@ If using this approach, remember to updated your project's ``component.mk`` with and verify the layout is correct using ``make map``. +OTA updates +----------- + +When planning OTA updates please check that the displayed partition map corresponds to your project. +For example, the partition table requires a free sector so must not overlap other partitions. + +Your OTA update process must include a step to write the partition table to the correct location. + +It is not necessary to update the bootloader. See :component:`rboot` for further information. + Custom configurations --------------------- @@ -173,6 +183,19 @@ To customise the hardware configuration for a project, for example 'my_project': This will flash everything: bootloader, partition table and all defined partitions (those with a ``filename`` entry). +.. note:: + + The build system isn't smart enough to track dependencies for partition build targets. + + To rebuild these manually type:: + + make partbuild + + These will be removed when ``make clean`` is run, but you can also clean them separately thus:: + + make part-clean + + Partition maps -------------- @@ -356,7 +379,7 @@ you can take advantage of the partition API to manage them as follows: - Create an instance of your custom device and make a call to :cpp:func:`Storage::registerDevice` in your ``init()`` function (or elsewhere if more appropriate). - + API --- diff --git a/Sming/Components/Storage/Tools/hwconfig/config.py b/Sming/Components/Storage/Tools/hwconfig/config.py index 19bad09f79..67a465bd0c 100644 --- a/Sming/Components/Storage/Tools/hwconfig/config.py +++ b/Sming/Components/Storage/Tools/hwconfig/config.py @@ -46,6 +46,7 @@ def from_name(cls, name): config.load(name) if options != '': config.parse_options(options.split(',')) + config.resolve_expressions() config.partitions.sort() return config @@ -73,6 +74,9 @@ def parse_options(self, options): temp.pop('description', None) self.parse_dict(temp) + def resolve_expressions(self): + self.partitions.offset = eval(str(self.partitions.offset)) + def parse_dict(self, data): base_config = data.pop('base_config', None) if base_config is not None: @@ -89,7 +93,7 @@ def parse_dict(self, data): elif k == 'arch': self.arch = v elif k == 'partition_table_offset': - self.partitions.offset = parse_int(v) + self.partitions.offset = v elif k == 'devices': self.devices.parse_dict(v) elif k == 'comment': @@ -132,7 +136,7 @@ def buildVars(self): return res def verify(self, secure): - self.partitions.verify(self.arch, secure) + self.partitions.verify(self.arch, self.devices[0], secure) def map(self): return partition.Map(self.partitions, self.devices) diff --git a/Sming/Components/Storage/Tools/hwconfig/hwconfig.py b/Sming/Components/Storage/Tools/hwconfig/hwconfig.py index 7c388ff726..e2b3d90ddb 100644 --- a/Sming/Components/Storage/Tools/hwconfig/hwconfig.py +++ b/Sming/Components/Storage/Tools/hwconfig/hwconfig.py @@ -44,7 +44,7 @@ def handle_flashcheck(args, config, part): for e in list: addr, filename = e.split('=') addr = int(addr, 0) - part = config.partitions.find_by_address(addr) + part = config.partitions.find_by_address(config.devices[0], addr) if part is None: raise InputError("No partition contains address 0x%08x" % addr) if part.address != addr: @@ -113,5 +113,5 @@ def main(): try: main() except InputError as e: - print(e, file=sys.stderr) + print("** ERROR! %s" % e, file=sys.stderr) sys.exit(2) diff --git a/Sming/Components/Storage/Tools/hwconfig/partition.py b/Sming/Components/Storage/Tools/hwconfig/partition.py index d0a0e07f1e..18e78435d5 100644 --- a/Sming/Components/Storage/Tools/hwconfig/partition.py +++ b/Sming/Components/Storage/Tools/hwconfig/partition.py @@ -16,11 +16,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -import struct, hashlib, storage, binascii +import struct, hashlib, storage, binascii, copy from common import * MAX_PARTITION_LENGTH = 0xC00 # 3K for partition data (96 entries) leaves 1K in a 4K sector for signature MD5_PARTITION_BEGIN = b"\xEB\xEB" + b"\xFF" * 14 # The first 2 bytes are like magic numbers for MD5 sum +FLASH_SECTOR_SIZE = 0x1000 PARTITION_TABLE_SIZE = 0x1000 # Size of partition table PARTITION_ENTRY_SIZE = 32 @@ -84,6 +85,7 @@ "nvs_keys": 0x04, "efuse": 0x05, "sysparam": 0x40, + "rfcal": 0x41, "esphttpd": 0x80, "fat": 0x81, "spiffs": 0x82, @@ -154,6 +156,10 @@ def offset_str(self): def buildVars(self): dict = {} dict['PARTITION_NAMES'] = " ".join(p.name for p in self) + buildparts = [p for p in self if p.build is not None] + dict['PARTITIONS_WITH_TARGETS'] = " ".join(p.name for p in buildparts) + dict['PARTITION_BUILD_TARGETS'] = " ".join(p.filename for p in buildparts) + for p in self: dict.update(p.buildVars()) return dict @@ -198,19 +204,28 @@ def find_by_name(self, name): return p return None - def find_by_address(self, addr): + def find_by_address(self, device, addr): for p in self: - if p.contains(addr): + if p.device == device and p.contains(addr): return p return None - def verify(self, arch, secure): + def verify(self, arch, spiFlash, secure): """Verify partition layout """ # verify each partition individually for p in self: p.verify(arch, secure) + if self.offset % FLASH_SECTOR_SIZE != 0: + raise InputError("Partition table offset not aligned to flash sector") + + p = self.find_by_address(spiFlash, self.offset) + if p is None: + p = self.find_by_address(spiFlash, self.offset + PARTITION_TABLE_SIZE - 1) + if not p is None: + raise InputError("Partition table conflict with '%s'" % p.name) + # check on duplicate name names = [p.name for p in self] duplicates = set(n for n in names if names.count(n) > 1) @@ -224,7 +239,10 @@ def verify(self, arch, secure): raise InputError("Partition names must be unique") # check for overlaps - minPartitionAddress = self.offset + PARTITION_TABLE_SIZE + if arch == 'Esp32': + minPartitionAddress = self.offset + PARTITION_TABLE_SIZE + else: + minPartitionAddress = 0x00002000 dev = '' last = None for p in self: @@ -345,7 +363,7 @@ def parse_dict(self, data, devices): if k == 'device': self.device = devices.find_by_name(v) elif k == 'address': - self.address = parse_int(v) + self.address = eval(str(v)) elif k == 'size': self.size = parse_int(v) elif k == 'filename': @@ -523,13 +541,17 @@ def add_unused(address, last_end): if address > last_end + 1: add('(unused)', last_end + 1, address - last_end - 1) + partitions = copy.copy(table) + if table.offset == 0: last = None else: - add("Boot Sector", 0, table.offset) - last = add("Partition Table", table.offset, PARTITION_TABLE_SIZE) + last = add('Boot Sector', 0, min(table.offset, partitions[0].address)) + p = Entry(device, 'Partition Table', table.offset, PARTITION_TABLE_SIZE, 0xff, 0xff) + partitions.append(p) + partitions.sort() - for p in table: + for p in partitions: if last is not None: if p.device != last.device: add_unused(last.device.size, last.end()) diff --git a/Sming/Components/Storage/component.mk b/Sming/Components/Storage/component.mk index a6627c056a..986d7fe0d0 100644 --- a/Sming/Components/Storage/component.mk +++ b/Sming/Components/Storage/component.mk @@ -35,10 +35,11 @@ HWCONFIG_TOOL := \ BUILD_BASE=$(BUILD_BASE) \ $(PYTHON) $(PARTITION_TOOLS)/hwconfig/hwconfig.py -ifeq (,$(MAKE_DOCS)$(MAKE_CLEAN)) - -# Generate build variables from hardware configuration HWCONFIG_MK := $(PROJECT_DIR)/$(OUT_BASE)/hwconfig.mk +ifneq (,$(MAKE_DOCS)$(MAKE_CLEAN)) +-include $(HWCONFIG_MK) +else +# Generate build variables from hardware configuration $(shell $(HWCONFIG_TOOL) --quiet expr $(HWCONFIG) $(HWCONFIG_MK) "config.buildVars()") include $(HWCONFIG_MK) ifeq ($(SMING_ARCH_HW),) @@ -47,6 +48,7 @@ else ifneq ($(SMING_ARCH),$(SMING_ARCH_HW)) $(error Hardware configuration is for arch $(SMING_ARCH_HW), does not match SMING_ARCH ($(SMING_ARCH))) endif COMPONENT_CXXFLAGS := -DPARTITION_TABLE_OFFSET=$(PARTITION_TABLE_OFFSET) +COMPONENT_CPPFLAGS := -DPARTITION_TABLE_OFFSET=$(PARTITION_TABLE_OFFSET) # Function to evaluate expression against config HWEXPR := $(HWCONFIG_TOOL) $(if $(PART),--part "$(PART)") expr $(HWCONFIG) - @@ -109,22 +111,25 @@ $(PARTITIONS_BIN): $(HWCONFIG_DEPENDS) # Create build target for a partition # $1 -> Partition name define PartitionTarget -PTARG := $(shell $(HWCONFIG_TOOL) --part $1 expr $(HWCONFIG) - part.filename) -$$(PTARG): +$(PARTITION_$1_FILENAME): $$(Q) $$(MAKE) --no-print-directory $$(shell $$(HWCONFIG_TOOL) --part $1 expr $$(HWCONFIG) - "part.build['target']") PART=$1 -CUSTOM_TARGETS += $$(PTARG) +CUSTOM_TARGETS += $(PARTITION_$1_FILENAME) endef -# Create build targets for all partitions with 'build' property -DEBUG_VARS += PARTITIONS_WITH_TARGETS -PARTITIONS_WITH_TARGETS := $(call HwExpr,(' '.join([part.name for part in filter(lambda part: part.build is not None, config.partitions)]))) - # Must be invoked from project.mk after all Components have been processed # This allows partition definitions to include variables which may not yet be defined define PartitionCreateTargets $(foreach p,$(PARTITIONS_WITH_TARGETS),$(eval $(call PartitionTarget,$p))) endef +.PHONY: buildpart +buildpart: ##Rebuild all partition targets +ifeq (,$(PARTITION_BUILD_TARGETS)) + @echo "No partitions have build targets" +else + $(Q) rm -f $(PARTITION_BUILD_TARGETS) + $(MAKE) $(PARTITION_BUILD_TARGETS) +endif ##@Flashing @@ -192,3 +197,11 @@ flashmap: $(PARTITIONS_BIN) kill_term ##Write partition table to device endif # MAKE_DOCS + +##@Cleaning + +clean: part-clean + +.PHONY: part-clean +part-clean: ##Clean partition targets + $(Q) rm -f $(PARTITION_BUILD_TARGETS) diff --git a/Sming/Components/Storage/src/include/Storage/Partition.h b/Sming/Components/Storage/src/include/Storage/Partition.h index 0c141abad0..9b5badeee1 100644 --- a/Sming/Components/Storage/src/include/Storage/Partition.h +++ b/Sming/Components/Storage/src/include/Storage/Partition.h @@ -59,6 +59,7 @@ XX(nvsKeys, 0x04, "NVS key information") \ XX(eFuseEm, 0x05, "eFuse emulation") \ XX(sysParam, 0x40, "System Parameters") \ + XX(rfCal, 0x41, "RF Calibration") \ XX(espHttpd, 0x80, "ESPHTTPD") \ XX(fat, 0x81, "FAT") \ XX(spiffs, 0x82, "SPIFFS") \ diff --git a/Sming/Components/Storage/src/include/Storage/PartitionTable.h b/Sming/Components/Storage/src/include/Storage/PartitionTable.h index 1dd4ee7b16..5acfc135bd 100644 --- a/Sming/Components/Storage/src/include/Storage/PartitionTable.h +++ b/Sming/Components/Storage/src/include/Storage/PartitionTable.h @@ -45,7 +45,7 @@ class PartitionTable /** * @brief Find partition by name - * @param Name to search for, case-sensitive + * @param Name Name to search for, case-sensitive * @retval Partition * * Names are unique so at most only one match @@ -55,6 +55,26 @@ class PartitionTable return *std::find(begin(), end(), name); } + /** + * @brief Find partition containing the given address + * @param address Address to search for + * @retval Partition + */ + Partition find(uint32_t address) const + { + return *std::find_if(begin(), end(), [address](Partition part) { return part.contains(address); }); + } + + /** + * @brief Find the n'th OTA partition + */ + Partition findOta(uint8_t index) + { + using App = Partition::SubType::App; + auto subtype = App(uint8_t(App::ota0) + index); + return (subtype >= App::ota_min && subtype <= App::ota_max) ? *find(subtype) : Partition{}; + } + Iterator begin() const { return Iterator(mDevice, 0); diff --git a/Sming/Components/rboot/.patches/rboot.patch b/Sming/Components/rboot/.patches/rboot.patch deleted file mode 100644 index b8cd1ce078..0000000000 --- a/Sming/Components/rboot/.patches/rboot.patch +++ /dev/null @@ -1,402 +0,0 @@ -diff --git a/Makefile b/Makefile -index 638a8f7..5176f8f 100644 ---- a/Makefile -+++ b/Makefile -@@ -58,6 +58,19 @@ endif - ifeq ($(RBOOT_IROM_CHKSUM),1) - CFLAGS += -DBOOT_IROM_CHKSUM - endif -+ifneq ($(RBOOT_ROM0_ADDR),) -+ CFLAGS += -DBOOT_ROM0_ADDR=$(RBOOT_ROM0_ADDR) -+endif -+ifneq ($(RBOOT_ROM1_ADDR),) -+ CFLAGS += -DBOOT_ROM1_ADDR=$(RBOOT_ROM1_ADDR) -+endif -+ifneq ($(RBOOT_ROM2_ADDR),) -+ CFLAGS += -DBOOT_ROM2_ADDR=$(RBOOT_ROM2_ADDR) -+endif -+ifeq ($(RBOOT_SILENT),1) -+ CFLAGS += -DBOOT_SILENT=$(RBOOT_SILENT) -+endif -+ - ifneq ($(RBOOT_EXTRA_INCDIR),) - CFLAGS += $(addprefix -I,$(RBOOT_EXTRA_INCDIR)) - endif - -diff --git a/rboot.c b/rboot.c -index d622f97..5e254fa 100644 ---- a/rboot.c -+++ b/rboot.c -@@ -13,6 +13,12 @@ - #define UART_CLK_FREQ (26000000 * 2) - #endif - -+#ifndef BOOT_SILENT -+#define echof(fmt, ...) ets_printf(fmt, ##__VA_ARGS__) -+#else -+#define echof(fmt, ...) -+#endif -+ - static uint32_t check_image(uint32_t readpos) { - - uint8_t buffer[BUFFER_SIZE]; -@@ -257,8 +263,30 @@ static uint8_t calc_chksum(uint8_t *start, uint8_t *end) { - // created on first boot or in case of corruption - static uint8_t default_config(rboot_config *romconf, uint32_t flashsize) { - romconf->count = 2; -+#ifdef BOOT_ROM0_ADDR -+ romconf->roms[0] = BOOT_ROM0_ADDR; -+#else - romconf->roms[0] = SECTOR_SIZE * (BOOT_CONFIG_SECTOR + 1); -+#endif -+ -+#ifdef BOOT_ROM1_ADDR -+ romconf->roms[1] = BOOT_ROM1_ADDR; -+#else - romconf->roms[1] = (flashsize / 2) + (SECTOR_SIZE * (BOOT_CONFIG_SECTOR + 1)); -+#endif -+ -+#if defined(BOOT_BIG_FLASH) && defined(BOOT_GPIO_ENABLED) -+ if(flashsize > 0x200000) { -+ romconf->count += 1; -+#ifdef BOOT_ROM2_ADDR -+ romconf->roms[2] = BOOT_ROM2_ADDR; -+#else -+ romconf->roms[2] = 0x310000; -+#endif -+ romconf->gpio_rom = 2; -+} -+#endif -+ - #ifdef BOOT_GPIO_ENABLED - romconf->mode = MODE_GPIO_ROM; - #endif -@@ -306,100 +334,100 @@ uint32_t NOINLINE find_image(void) { - ets_delay_us(BOOT_DELAY_MICROS); - #endif - -- ets_printf("\r\nrBoot v1.4.2 - richardaburton@gmail.com\r\n"); -+ echof("\r\nrBoot v1.4.2 - richardaburton@gmail.com\r\n"); - - // read rom header - SPIRead(0, header, sizeof(rom_header)); - - // print and get flash size -- ets_printf("Flash Size: "); -+ echof("Flash Size: "); - flag = header->flags2 >> 4; - if (flag == 0) { -- ets_printf("4 Mbit\r\n"); -+ echof("4 Mbit\r\n"); - flashsize = 0x80000; - } else if (flag == 1) { -- ets_printf("2 Mbit\r\n"); -+ echof("2 Mbit\r\n"); - flashsize = 0x40000; - } else if (flag == 2) { -- ets_printf("8 Mbit\r\n"); -+ echof("8 Mbit\r\n"); - flashsize = 0x100000; - } else if (flag == 3 || flag == 5) { -- ets_printf("16 Mbit\r\n"); -+ echof("16 Mbit\r\n"); - #ifdef BOOT_BIG_FLASH - flashsize = 0x200000; - #else - flashsize = 0x100000; // limit to 8Mbit - #endif - } else if (flag == 4 || flag == 6) { -- ets_printf("32 Mbit\r\n"); -+ echof("32 Mbit\r\n"); - #ifdef BOOT_BIG_FLASH - flashsize = 0x400000; - #else - flashsize = 0x100000; // limit to 8Mbit - #endif - } else if (flag == 8) { -- ets_printf("64 Mbit\r\n"); -+ echof("64 Mbit\r\n"); - #ifdef BOOT_BIG_FLASH - flashsize = 0x800000; - #else - flashsize = 0x100000; // limit to 8Mbit - #endif - } else if (flag == 9) { -- ets_printf("128 Mbit\r\n"); -+ echof("128 Mbit\r\n"); - #ifdef BOOT_BIG_FLASH - flashsize = 0x1000000; - #else - flashsize = 0x100000; // limit to 8Mbit - #endif - } else { -- ets_printf("unknown\r\n"); -+ echof("unknown\r\n"); - // assume at least 4mbit - flashsize = 0x80000; - } - - // print spi mode -- ets_printf("Flash Mode: "); -+ echof("Flash Mode: "); - if (header->flags1 == 0) { -- ets_printf("QIO\r\n"); -+ echof("QIO\r\n"); - } else if (header->flags1 == 1) { -- ets_printf("QOUT\r\n"); -+ echof("QOUT\r\n"); - } else if (header->flags1 == 2) { -- ets_printf("DIO\r\n"); -+ echof("DIO\r\n"); - } else if (header->flags1 == 3) { -- ets_printf("DOUT\r\n"); -+ echof("DOUT\r\n"); - } else { -- ets_printf("unknown\r\n"); -+ echof("unknown\r\n"); - } - - // print spi speed -- ets_printf("Flash Speed: "); -+ echof("Flash Speed: "); - flag = header->flags2 & 0x0f; -- if (flag == 0) ets_printf("40 MHz\r\n"); -- else if (flag == 1) ets_printf("26.7 MHz\r\n"); -- else if (flag == 2) ets_printf("20 MHz\r\n"); -- else if (flag == 0x0f) ets_printf("80 MHz\r\n"); -- else ets_printf("unknown\r\n"); -+ if (flag == 0) echof("40 MHz\r\n"); -+ else if (flag == 1) echof("26.7 MHz\r\n"); -+ else if (flag == 2) echof("20 MHz\r\n"); -+ else if (flag == 0x0f) echof("80 MHz\r\n"); -+ else echof("unknown\r\n"); - - // print enabled options - #ifdef BOOT_BIG_FLASH -- ets_printf("rBoot Option: Big flash\r\n"); -+ echof("rBoot Option: Big flash\r\n"); - #endif - #ifdef BOOT_CONFIG_CHKSUM -- ets_printf("rBoot Option: Config chksum\r\n"); -+ echof("rBoot Option: Config chksum\r\n"); - #endif - #ifdef BOOT_GPIO_ENABLED -- ets_printf("rBoot Option: GPIO rom mode (%d)\r\n", BOOT_GPIO_NUM); -+ echof("rBoot Option: GPIO rom mode (%d)\r\n", BOOT_GPIO_NUM); - #endif - #ifdef BOOT_GPIO_SKIP_ENABLED -- ets_printf("rBoot Option: GPIO skip mode (%d)\r\n", BOOT_GPIO_NUM); -+ echof("rBoot Option: GPIO skip mode (%d)\r\n", BOOT_GPIO_NUM); - #endif - #ifdef BOOT_RTC_ENABLED -- ets_printf("rBoot Option: RTC data\r\n"); -+ echof("rBoot Option: RTC data\r\n"); - #endif - #ifdef BOOT_IROM_CHKSUM -- ets_printf("rBoot Option: irom chksum\r\n"); -+ echof("rBoot Option: irom chksum\r\n"); - #endif -- ets_printf("\r\n"); -+ echof("\r\n"); - - // read boot config - SPIRead(BOOT_CONFIG_SECTOR * SECTOR_SIZE, buffer, SECTOR_SIZE); -@@ -410,7 +438,7 @@ uint32_t NOINLINE find_image(void) { - #endif - ) { - // create a default config for a standard 2 rom setup -- ets_printf("Writing default boot config.\r\n"); -+ echof("Writing default boot config.\r\n"); - ets_memset(romconf, 0x00, sizeof(rboot_config)); - romconf->magic = BOOT_CONFIG_MAGIC; - romconf->version = BOOT_CONFIG_VERSION; -@@ -433,10 +461,10 @@ uint32_t NOINLINE find_image(void) { - - if (rtc.next_mode & MODE_TEMP_ROM) { - if (rtc.temp_rom >= romconf->count) { -- ets_printf("Invalid temp rom selected.\r\n"); -+ echof("Invalid temp rom selected.\r\n"); - return 0; - } -- ets_printf("Booting temp rom.\r\n"); -+ echof("Booting temp rom.\r\n"); - temp_boot = 1; - romToBoot = rtc.temp_rom; - } -@@ -447,10 +475,10 @@ uint32_t NOINLINE find_image(void) { - if (perform_gpio_boot(romconf)) { - #if defined(BOOT_GPIO_ENABLED) - if (romconf->gpio_rom >= romconf->count) { -- ets_printf("Invalid GPIO rom selected.\r\n"); -+ echof("Invalid GPIO rom selected.\r\n"); - return 0; - } -- ets_printf("Booting GPIO-selected rom.\r\n"); -+ echof("Booting GPIO-selected rom.\r\n"); - romToBoot = romconf->gpio_rom; - gpio_boot = 1; - #elif defined(BOOT_GPIO_SKIP_ENABLED) -@@ -462,7 +490,7 @@ uint32_t NOINLINE find_image(void) { - #endif - updateConfig = 1; - if (romconf->mode & MODE_GPIO_ERASES_SDKCONFIG) { -- ets_printf("Erasing SDK config sectors before booting.\r\n"); -+ echof("Erasing SDK config sectors before booting.\r\n"); - for (sec = 1; sec < 5; sec++) { - SPIEraseSector((flashsize / SECTOR_SIZE) - sec); - } -@@ -474,7 +502,7 @@ uint32_t NOINLINE find_image(void) { - // gpio/temp boots will have already validated this - if (romconf->current_rom >= romconf->count) { - // if invalid rom selected try rom 0 -- ets_printf("Invalid rom selected, defaulting to 0.\r\n"); -+ echof("Invalid rom selected, defaulting to 0.\r\n"); - romToBoot = 0; - romconf->current_rom = 0; - updateConfig = 1; -@@ -486,14 +514,14 @@ uint32_t NOINLINE find_image(void) { - #ifdef BOOT_GPIO_ENABLED - if (gpio_boot && loadAddr == 0) { - // don't switch to backup for gpio-selected rom -- ets_printf("GPIO boot rom (%d) is bad.\r\n", romToBoot); -+ echof("GPIO boot rom (%d) is bad.\r\n", romToBoot); - return 0; - } - #endif - #ifdef BOOT_RTC_ENABLED - if (temp_boot && loadAddr == 0) { - // don't switch to backup for temp rom -- ets_printf("Temp boot rom (%d) is bad.\r\n", romToBoot); -+ echof("Temp boot rom (%d) is bad.\r\n", romToBoot); - // make sure rtc temp boot mode doesn't persist - rtc.next_mode = MODE_STANDARD; - rtc.chksum = calc_chksum((uint8_t*)&rtc, (uint8_t*)&rtc.chksum); -@@ -504,7 +532,7 @@ uint32_t NOINLINE find_image(void) { - - // check we have a good rom - while (loadAddr == 0) { -- ets_printf("Rom %d at %x is bad.\r\n", romToBoot, romconf->roms[romToBoot]); -+ echof("Rom %d at %x is bad.\r\n", romToBoot, romconf->roms[romToBoot]); - // for normal mode try each previous rom - // until we find a good one or run out - updateConfig = 1; -@@ -512,7 +540,7 @@ uint32_t NOINLINE find_image(void) { - if (romToBoot < 0) romToBoot = romconf->count - 1; - if (romToBoot == romconf->current_rom) { - // tried them all and all are bad! -- ets_printf("No good rom available.\r\n"); -+ echof("No good rom available.\r\n"); - return 0; - } - loadAddr = check_image(romconf->roms[romToBoot]); -@@ -543,7 +571,7 @@ uint32_t NOINLINE find_image(void) { - system_rtc_mem(RBOOT_RTC_ADDR, &rtc, sizeof(rboot_rtc_data), RBOOT_RTC_WRITE); - #endif - -- ets_printf("Booting rom %d at %x, load addr %x.\r\n", romToBoot, romconf->roms[romToBoot], loadAddr); -+ echof("Booting rom %d at %x, load addr %x.\r\n", romToBoot, romconf->roms[romToBoot], loadAddr); - // copy the loader to top of iram - ets_memcpy((void*)_text_addr, _text_data, _text_len); - // return address to load from -diff --git a/appcode/rboot-api.c b/appcode/rboot-api.c -index eb4d028..bf276a7 100644 ---- a/appcode/rboot-api.c -+++ b/appcode/rboot-api.c -@@ -9,7 +9,7 @@ - #include - // c_types.h needed for spi_flash.h - #include --#include -+#include - - #include "rboot-api.h" - -@@ -33,7 +33,7 @@ static uint8_t calc_chksum(uint8_t *start, uint8_t *end) { - // 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_t*)&conf, sizeof(rboot_config)); -+ flashmem_read(&conf, BOOT_CONFIG_SECTOR * SECTOR_SIZE, sizeof(rboot_config)); - return conf; - } - -@@ -43,7 +43,7 @@ rboot_config ICACHE_FLASH_ATTR rboot_get_config(void) { - // updates checksum automatically (if enabled) - bool ICACHE_FLASH_ATTR rboot_set_config(rboot_config *conf) { - uint8_t *buffer; -- buffer = (uint8_t*)pvPortMalloc(SECTOR_SIZE, 0, 0); -+ buffer = (uint8_t*)os_malloc(SECTOR_SIZE); - if (!buffer) { - //os_printf("No ram!\r\n"); - return false; -@@ -53,12 +53,12 @@ bool ICACHE_FLASH_ATTR rboot_set_config(rboot_config *conf) { - conf->chksum = calc_chksum((uint8_t*)conf, (uint8_t*)&conf->chksum); - #endif - -- spi_flash_read(BOOT_CONFIG_SECTOR * SECTOR_SIZE, (uint32_t*)((void*)buffer), SECTOR_SIZE); -+ flashmem_read(buffer, BOOT_CONFIG_SECTOR * SECTOR_SIZE, SECTOR_SIZE); - memcpy(buffer, conf, sizeof(rboot_config)); -- spi_flash_erase_sector(BOOT_CONFIG_SECTOR); -- spi_flash_write(BOOT_CONFIG_SECTOR * SECTOR_SIZE, (uint32_t*)((void*)buffer), SECTOR_SIZE); -+ flashmem_erase_sector(BOOT_CONFIG_SECTOR); -+ flashmem_write(buffer, BOOT_CONFIG_SECTOR * SECTOR_SIZE, SECTOR_SIZE); - -- vPortFree(buffer, 0, 0); -+ os_free(buffer); - return true; - } - -@@ -103,7 +103,7 @@ bool ICACHE_FLASH_ATTR rboot_write_end(rboot_write_status *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_t *data, uint16_t len) { -+bool ICACHE_FLASH_ATTR rboot_write_flash(rboot_write_status *status, const uint8_t *data, uint16_t len) { - - bool ret = false; - uint8_t *buffer; -@@ -114,7 +114,7 @@ bool ICACHE_FLASH_ATTR rboot_write_flash(rboot_write_status *status, uint8_t *da - } - - // get a buffer -- buffer = (uint8_t *)pvPortMalloc(len + status->extra_count, 0, 0); -+ buffer = (uint8_t *)os_malloc(len + status->extra_count); - if (!buffer) { - //os_printf("No ram!\r\n"); - return false; -@@ -141,18 +141,18 @@ bool ICACHE_FLASH_ATTR rboot_write_flash(rboot_write_status *status, uint8_t *da - 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); -+ flashmem_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_t *)((void*)buffer), len) == SPI_FLASH_RESULT_OK) { -+ if (flashmem_write(buffer, status->start_addr, len) == len) { - ret = true; - status->start_addr += len; - } - //} - -- vPortFree(buffer, 0, 0); -+ os_free(buffer); - return ret; - } - -diff --git a/appcode/rboot-api.h b/appcode/rboot-api.h -index a98c209..ec4f0e5 100644 ---- a/appcode/rboot-api.h -+++ b/appcode/rboot-api.h -@@ -93,7 +93,7 @@ bool ICACHE_FLASH_ATTR rboot_write_end(rboot_write_status *status); - * 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_t *data, uint16_t len); -+bool ICACHE_FLASH_ATTR rboot_write_flash(rboot_write_status *status, const uint8_t *data, uint16_t len); - - #ifdef BOOT_RTC_ENABLED - /** @brief Get rBoot status/control data from RTC data area - diff --git a/Sming/Components/rboot/.patches/rboot/README.rst b/Sming/Components/rboot/.patches/rboot/README.rst deleted file mode 100644 index e365cdb1f0..0000000000 --- a/Sming/Components/rboot/.patches/rboot/README.rst +++ /dev/null @@ -1,349 +0,0 @@ -================================================== -rBoot - An open source boot loader for the ESP8266 -================================================== - -by Richard A Burton, richardaburton@gmail.com -http://richard.burtons.org/ - -rBoot is designed to be a flexible open source boot loader, a -replacement for the binary blob supplied with the SDK. It has the -following advantages over the Espressif loader: - -- Open source (written in C). -- Supports up to 256 roms. -- Roms can be variable size. -- Able to test multiple roms to find a valid backup (without - resetting). -- Flash layout can be changed on the fly (with care and appropriately - linked rom images). -- GPIO support for rom selection. -- Wastes no stack space (SDK boot loader uses 144 bytes). -- Documented config structure to allow easy editing from user code. -- Can validate .irom0.text section with checksum. -- Temporary next-boot rom selection. - -Limitations -=========== - -The ESP8266 can only map 8Mbits (1MB) of flash to memory, but which -8Mbits to map is selectable. This allows individual roms to be up to 1MB -in size, so long as they do not straddle an 8Mbit boundary on the flash. -This means you could have four 1MB roms or 8 512KB roms on a 32Mbit -flash (such as on the ESP-12), or a combination. Note, however, that you -could not have, for example, a 512KB rom followed immediately by a 1MB -rom because the 2nd rom would then straddle an 8MBit boundary. By -default support for using more than the first 8Mbit of the flash is -disabled, because it requires several steps to get it working. See below -for instructions. - -Building -======== - -A Makefile is included, which should work with the gcc xtensa cross -compiler. There are two source files, the first is compiled and included -as data in the second. When run this code is copied to memory and -executed (there is a good reason for this, see my blog for an -explanation). The make file will handle this for you, but you’ll need my -esptool2 (see github). - -To use the Makefile set ``SDK_BASE`` to point to the root of the -Espressif SDK and either set ``XTENSA_BINDIR`` to the gcc xtensa bin -directory or include it in your ``PATH``. These can be set as -environment variables or by editing the Makefile. - -Two small assembler stub functions allow the bootloader to launch the -user code without reserving any space on the stack (while the SDK boot -loader uses 144 bytes). This compiles fine with GCC, but if you use -another compiler and it will not compile/work for you then uncomment the -``#define BOOT_NO_ASM`` in ``rboot.h`` to use a C version of these -functions (this uses 32 bytes). - -Tested with SDK v2.2 and GCC v4.8.5. - -Installation -============ - -Simply write rboot.bin to the first sector of the flash. Remember to set -your flash size correctly with your chosen flash tool (e.g. for -esptool.py use the ``-fs`` option). When run rBoot will create it’s own -config at the start of sector two for a simple two rom system. You can -can then write your two roms to flash addresses ``0x2000`` and (half -chip size + ``0x2000``). E.g. for 8Mbit flash: -``esptool.py write_flash -fs 8m 0x0000 rboot.bin 0x2000 user1.bin 0x82000 user2.bin`` - -Note: your device may need other options specified. E.g. The nodemcu -devkit v1.0 (commonly, but incorrectly, sold as v2) also needs the -``-fm dio`` option. - -For more interesting rom layouts you’ll need to write an rBoot config -sector manually, see next step. - -The two testload bin files can be flashed in place of normal user roms -for testing rBoot. You do not need these for normal use. - -rBoot Config -============ - -:: - - 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[MAX_ROMS]; // flash addresses of the roms - #ifdef BOOT_CONFIG_CHKSUM - uint8_t chksum; // boot config chksum - #endif - } rboot_config; - -Write a config structure as above to address ``0x1000`` on the flash. If -you want more than 4 roms (default) just increase MAX_ROMS when you -compile rBoot. Think about how you intend to layout your flash before -you start! Rom addresses must be sector aligned i.e start on a multiple -of 4096. - -- ``magic`` should have value ``0xe1`` (defined as - ``BOOT_CONFIG_MAGIC``). -- ``version`` is used in case the config structure changes after - deployment. It is defined as ``0x01`` (``BOOT_CONFIG_VERSION``). I - don’t intend to increase this, but you should if you choose to - reflash the bootloader after deployment and the config structure has - changed. -- ``mode`` can be ``0x00`` (``MODE_STANDARD``) or ``0x01`` - (``MODE_GPIO_ROM``). See below for an explanation of - ``MODE_GPIO_ROM``. There is also an optional extra mode flag ``0x04`` - (``MODE_GPIO_ERASES_SDKCONFIG``), see below for details. -- ``current_rom`` is the rom to boot, numbered ``0`` to ``count-1``. -- ``gpio_rom`` is the rom to boot when the GPIO is triggered at boot. -- ``count`` is the number of roms available (may be less than - ``MAX_ROMS``, but not more). -- ``unused[2]`` is padding so the ``uint32_t`` rom addresses are 4 - bytes aligned. -- ``roms`` is the array of flash address for the roms. The default - generated config will contain two entries: ``0x00002000`` and - ``0x00082000``. -- ``chksum`` (if enabled, not by deafult) should be the xor of ``0xef`` - followed by each of the bytes of the config structure up to (but - obviously not including) the chksum byte itself. - -Default config -============== - -A default config sector will be created on boot if one does not exists, -or if an existing config is corrupted, and the default rom will be set -to rom 0. If you want to have a very customised config for which the -default would not be suitable, you can override the implementation in -the ``rboot.h`` header file. See the comments and example code in -``rboot.h`` for more information. - -GPIO boot mode -============== - -.. envvar:: RBOOT_GPIO_ENABLED - -If rBoot is compiled with ``BOOT_GPIO_ENABLED`` set in ``rboot.h`` (or -``RBOOT_GPIO_ENABLED`` set in the Makefile), then GPIO boot -functionality will be included in the rBoot binary. The feature can then -be enabled by setting the rboot_config ``mode`` field to -``MODE_GPIO_ROM``. You must also set ``gpio_rom`` in the config to -indicate which rom to boot when the GPIO is activated at boot. - -If the GPIO input pin reads high at boot then rBoot will start the -currently selected normal or temp rom (as appropriate). However if the -GPIO is pulled low then the rom indicated in config option ``gpio_rom`` -is started instead. - -The default GPIO is 16, but this can be overriden in the Makefile -(``RBOOT_GPIO_NUMBER``) or ``rboot.h`` (``BOOT_GPIO_NUM``). If GPIOs -other than 16 are used, the internal pullup resistor is enabled before -the pin is read and disabled immediately afterwards. For pins that -default on reset to configuration other than GPIO input, the pin mode is -changed to input when reading but changed back before rboot continues. - -After a GPIO boot the ``current_rom`` field will be updated in the -config, so the GPIO booted rom should change this again if required. - -GPIO boot skip mode -=================== - -.. envvar:: RBOOT_GPIO_SKIP_ENABLED - -If rBoot is compiled with ``BOOT_GPIO_SKIP_ENABLED`` set in ``rboot.h`` -(or ``RBOOT_GPIO_SKIP_ENABLED`` set in the Makefile), then a GPIO can be -used to skip to the next rom at boot. The feature must then be enabled -by setting the rboot_config ‘mode’ field to ``MODE_GPIO_SKIP``. This -means you do not need to have a dedicated GPIO boot rom. If you have a -rom that is technically good (valid checksum, etc.) but has operational -problems, e.g. wifi doesn’t work or it crashes on boot, rBoot will not -be able to detect that and switch rom automatically. In this scenario -rebooting the device while pulling the GPIO low will force rBoot to skip -this rom and try the next one instead. In a simple two rom setup this -simply toggles booting of the other rom. - -``RBOOT_GPIO_SKIP_ENABLED`` and ``RBOOT_GPIO_ENABLED`` cannot be used at -the same time. ``BOOT_GPIO_NUM`` is used to select the GPIO pin, as with -``RBOOT_GPIO_ENABLED``. - -Erasing SDK configuration on GPIO boot (rom or skip mode) -========================================================= - -If you set the ``MODE_GPIO_ERASES_SDKCONFIG`` flag in the configuration -like this: ``conf.mode = MODE_GPIO_ROM|MODE_GPIO_ERASES_SDKCONFIG``; -then a GPIO boot will also the erase the Espressif SDK persistent -settings store in the final 16KB of flash. This includes removing -calibration constants, saved SSIDs, etc. - -Note that ``MODE_GPIO_ERASES_SDKCONFIG`` is a flag, so it has to be set -as well as ``MODE_GPIO_ROM`` to take effect. - -Linking user code -================= - -Each rom will need to be linked with an appropriate linker file, -specifying where it will reside on the flash. If you are only flashing -one rom to multiple places on the flash it must be linked multiple times -to produce the set of rom images. This is the same as with the SDK -loader. - -Because there are endless possibilities for layout with this loader I -don’t supply sample linker files. Instead I’ll tell you how to make -them. - -For each rom slot on the flash take a copy of the ``eagle.app.v6.ld`` -linker script from the sdk. You then need to modify just one line in it -for each rom: -``irom0_0_seg : org = 0x40240000, len = 0x3C000`` - -Change the org address to be ``0x40200000`` (base memory mapped location -of the flash) + flash address + ``0x10`` (offset of data after the -header). The logical place for your first rom is the third sector, -address ``0x2000``. ``0x40200000 + 0x2000 + 0x10 = 0x40202010`` If you -use the default generated config the loader will expect to find the -second rom at flash address half-chip-size + ``0x2000`` -(e.g. ``0x82000`` on an 8MBit flash) so the ``irom0_0_seg`` should be: -``0x40200000 + 0x82000 + 0x10 = 0x40282010`` Due to the limitation of -mapped flash (max 8MBit) if you use a larger chip and do not have big -flash support enabled the second rom in the default config will still be -placed at ``0x082000``, not truly half-chip-size + ``0x2000``. Ideally -you should also adjust the len to help detect over sized sections at -link time, but more important is the overall size of the rom which you -need to ensure fits in the space you have allocated for it in your flash -layout plan. - -Then simply compile and link as you would normally for OTA updates with -the SDK boot loader, except using the linker scripts you’ve just -prepared rather than the ones supplied with the SDK. Remember when -building roms to create them as ‘new’ type roms (for use with SDK boot -loader v1.2+). Or if using my esptool2 use the ``-boot2`` option. Note: -the test loads included with rBoot are built with ``-boot0`` because -they do not contain a ``.irom0.text`` section (and so the value of -``irom0_0_seg`` in the linker file is irrelevant to them) but ‘normal’ -user apps always do. - -irom checksum -============= - -The SDK boot loader checksum only covers sections loaded into ram (data -and some code). Most of the SDK and user code remains on the flash and -that is not included in the checksum. This means you could attempt to -boot a corrupt rom and, because it looks ok to the boot loader, there -will be no attempt to switch to a backup rom. rBoot improves on this by -allowing the ``.irom0.text`` section to be included in the checksum. To -enable this uncomment ``#define BOOT_IROM_CHKSUM`` in ``rboot.h`` and -build your roms with esptool2 using the ``-iromchksum`` option. - -.. _big_flash_support: - -Big flash support -================= - -This only needs to be enabled if you wish to be able to memory map more -than the first 8MBit of the flash. Note you can still only map 8Mbit at -a time. Use this if you want to have multiple 1MB roms, or more smaller -roms than will fit in 8Mbits. If you have a large flash but only need, -for example, two 512KB roms you do not need to enable this mode. - -Support in rBoot is enabled by uncommenting the -``#define BOOT_BIG_FLASH`` in ``rboot.h``. - -Thinking about your linker files is either simpler or more complicated, -depending on your usage of the flash. If you intend to use multiple 1MB -roms you will only need one linker file and you only need to link once -for OTA updates. Although when you perform an OTA update the rom will be -written to a different position on the flash, each 8Mbit of flash is -mapped (separately) to ``0x40200000``. So when any given rom is run the -code will appear at the same place in memory regardless of where it is -on the flash. Your base address for the linker would be ``0x40202010``. -(Actually all but the first rom could base at ``0x40200010`` (because -they don’t need to leave space for rBoot and config) but then you’re -just making it more complicated again!) - -If you wanted eight 512KB roms you would need two linker files - one for -the first half of any given 8Mbits of flash and another for the second -half. Just remember you are really laying out within a single 8MBit -area, which can then be replicated multiple times on the flash. - -Now the clever bit - rBoot needs to hijack the memory mapping code to -select which 8Mbits gets mapped. There is no API for this, but we can -override the SDK function. First we need to slightly modify the SDK -library ``libmain.a``, like so: - -:: - - xtensa-lx106-elf-objcopy -W Cache_Read_Enable_New libmain.a libmain2.a - -This produces a version of libmain with a ‘weakened’ -``Cache_Read_Enable_New`` function, which we can then override with our -own. Modify your Makefile to link against the library ``main2`` instead -of ``main``. - -Next add ``rboot-bigflash.c`` (from the ``appcode`` directory) & -``rboot.h`` to your project - this adds the replacement -``Cache_Read_Enable_New`` to your code. - -Getting gcc to apply the override correctly can be slightly tricky (I’m -not sure why, it shouldn’t be). One option is to add -``-u Cache_Read_Enable_New`` to your ``LD_FLAGS`` and change the order -of objects on the LD command so your ``objects/.a`` file is before the -libraries. Another way that seems easier was to -``#include rboot-bigflash.c`` into the main .c file, rather than -compiling it to a separate object file. I can’t make any sense of that, -but I suggest you uncomment the message in the ``Cache_Read_Enable_New`` -function when you first build with it, to make sure you are getting your -version into the rom. - -Now when rBoot starts your rom, the SDK code linked in it that normally -performs the memory mapping will delegate part of that task to rBoot -code (linked in your rom, not in rBoot itself) to choose which part of -the flash to map. - -Temporary boot option and rBoot<–>app communication -=================================================== - -.. envvar:: RBOOT_RTC_ENABLED - -To enable communication between rBoot and your app you should enable the -``BOOT_RTC_ENABLED`` option in ``rboot.h``. rBoot will then use the RTC -data area to pass a structure with boot information which can be read by -the app. This will allow the app to determine the boot mode (normal, -temporary or GPIO) and the booted rom (even if it is a tempoary boot). -Your app can also update this structure to communicate with rBoot when -the device is next rebooted, e.g. to instruct it to temporarily boot a -different rom to the one saved in the config. See the api documentation -and/or the rBoot sample project for more details. Note: the message -“don’t use rtc mem data”, commonly seen on startup, comes from the sdk -and is not related to this rBoot feature. - -Integration into other frameworks -================================= - -If you wish to integrate rBoot into a development framework (e.g. Sming) -you can set the define ``RBOOT_INTEGRATION`` and at compile time the -file ``rboot-integration.h`` will be included into the source. This -should allow you to set some platform specific options without having to -modify the source of rBoot which makes it easier to integrate and -maintain. diff --git a/Sming/Components/rboot/README.rst b/Sming/Components/rboot/README.rst index 50cd239c2a..95ddeb0203 100644 --- a/Sming/Components/rboot/README.rst +++ b/Sming/Components/rboot/README.rst @@ -10,10 +10,24 @@ pre-configured flash memory addresses, called "slots". Sming supports up to thre .. note:: With Sming 4.3 partitions are used to manage flash storage. - A "slot" refers to a specific application partition, namely ``rom0``, ``rom1`` or ``rom2``. + A "slot" refers to a specific application partition, typically ``rom0``, ``rom1`` or ``rom2``. The location or size of these partitions is determined by the :ref:`hardware_config`. + The bootloader has been modified to use the partition table as reference, identifying slots + by the partition sub-type. + + Where systems are to be updated Over the Air (OTA) at least two application partitions are required. + The bootloader identifies these by their partition subtype: ``slot #0`` -> ``App/Ota_0``, ``slot #1`` -> ``App/Ota_1``, etc. + + Fixed applications without OTA capability use a single application image. + This must be the ``App/Factory`` partition type, and corresponds to ``slot #0``. + + At startup, the bootloader will use the partition table to locate the application image. + It will also ensure that the ROM slot information in the boot configuration is consistent, + and update it if necessary. + + .. attention:: Make sure that your slots do not extend beyond a 1MB boundary and diff --git a/Sming/Components/rboot/component.mk b/Sming/Components/rboot/component.mk index 814296d7d5..96f9441e53 100644 --- a/Sming/Components/rboot/component.mk +++ b/Sming/Components/rboot/component.mk @@ -125,7 +125,11 @@ endif COMPONENT_CXXFLAGS += \ -DRBOOT_ROM0_ADDR=$(RBOOT_ROM0_ADDR) \ - -DRBOOT_ROM1_ADDR=$(RBOOT_ROM1_ADDR) + -DRBOOT_ROM1_ADDR=$(RBOOT_ROM1_ADDR) \ + -DPARTITION_TABLE_OFFSET=$(PARTITION_TABLE_OFFSET) + +COMPONENT_CFLAGS += \ + -DPARTITION_TABLE_OFFSET=$(PARTITION_TABLE_OFFSET) ifdef RBOOT_EMULATION FLASH_BOOT_CHUNKS = 0x00000=$(BLANK_BIN) @@ -136,7 +140,7 @@ export RBOOT_ROM1_ADDR RBOOT_BIN := $(FW_BASE)/rboot.bin CUSTOM_TARGETS += $(RBOOT_BIN) $(RBOOT_BIN): - $(Q) $(MAKE) -C $(RBOOT_DIR)/rboot $(RBOOT_CFLAGS) + $(Q) $(MAKE) -C $(RBOOT_DIR)/rboot PARTITION_TABLE_OFFSET=$(PARTITION_TABLE_OFFSET) $(RBOOT_CFLAGS) EXTRA_LDFLAGS := -u Cache_Read_Enable_New diff --git a/Sming/Components/rboot/include/Data/Stream/RbootOutputStream.h b/Sming/Components/rboot/include/Data/Stream/RbootOutputStream.h index 30c8b85db8..1873d01885 100644 --- a/Sming/Components/rboot/include/Data/Stream/RbootOutputStream.h +++ b/Sming/Components/rboot/include/Data/Stream/RbootOutputStream.h @@ -17,6 +17,7 @@ #include #include +#include /** * @brief Write-only stream type used during rBoot firmware updates @@ -25,13 +26,23 @@ class RbootOutputStream : public ReadWriteStream { public: /** + * @brief Construct a stream using raw flash address/size * @param startAddress the start address on the storage media * @param maxLength the maximum allowed length of the rom. Use 0 if unlimited. + * @note This should be avoided, use partition where possible */ RbootOutputStream(uint32_t startAddress, size_t maxLength = 0) : startAddress(startAddress), maxLength(maxLength) { } + /** + * @brief Construct a stream for the given partition + * @param partition + */ + RbootOutputStream(Storage::Partition partition) : startAddress(partition.address()), maxLength(partition.size()) + { + } + virtual ~RbootOutputStream() { close(); @@ -77,11 +88,11 @@ class RbootOutputStream : public ReadWriteStream } protected: - bool initialized = false; - rboot_write_status rBootWriteStatus = {}; - size_t written = 0; // << the number of written bytes - uint32_t startAddress = 0; // << the start address on the storage - size_t maxLength = 0; // << maximum allowed length + bool initialized{false}; + rboot_write_status rBootWriteStatus{}; + size_t written{0}; // << the number of written bytes + uint32_t startAddress{0}; // << the start address on the storage + size_t maxLength{0}; // << maximum allowed length protected: virtual bool init(); diff --git a/Sming/Components/rboot/include/Network/RbootHttpUpdater.h b/Sming/Components/rboot/include/Network/RbootHttpUpdater.h index c7ed16a43c..f8328ed764 100644 --- a/Sming/Components/rboot/include/Network/RbootHttpUpdater.h +++ b/Sming/Components/rboot/include/Network/RbootHttpUpdater.h @@ -18,32 +18,101 @@ #include #include "../Data/Stream/RbootOutputStream.h" -#define NO_ROM_SWITCH 0xff +/** + * @brief Magic value for ROM slot indicating slot won't change after successful OTA + */ +constexpr uint8_t NO_ROM_SWITCH{0xff}; class RbootHttpUpdater; -typedef Delegate OtaUpdateDelegate; - -struct RbootHttpUpdaterItem { - String url; - uint32_t targetOffset; - size_t size; // << max allowed size - RbootOutputStream* stream = nullptr; // (optional) output stream to use. -}; +using OtaUpdateDelegate = Delegate; class RbootHttpUpdater : protected HttpClient { public: - virtual ~RbootHttpUpdater() + struct Item { + String url; + uint32_t targetOffset; + size_t size; // << max allowed size + RbootOutputStream* stream{nullptr}; // (optional) output stream to use. + + Item(String url, uint32_t targetOffset, size_t size, RbootOutputStream* stream) + : url(url), targetOffset(targetOffset), size(size), stream(stream) + { + } + + ~Item() + { + delete stream; + } + + RbootOutputStream* getStream() + { + if(stream == nullptr) { + stream = new RbootOutputStream(targetOffset, size); + } + return stream; + } + }; + + class ItemList : public Vector { - cleanup(); + public: + bool addNew(Item* it) + { + if(addElement(it)) { + return true; + } + delete it; + return false; + } + }; + + /** + * @brief Add an item to update + * @param offset + * @param firmwareFileUrl + * @param maxSize + * @retval bool + * @note Use the `Partition` overload where possible + */ + bool addItem(uint32_t offset, const String& firmwareFileUrl, size_t maxSize = 0) + { + return items.addNew(new Item{firmwareFileUrl, offset, maxSize, nullptr}); + } + + /** + * @brief Add an item to update + * @param firmwareFileUrl + * @param partition Target partition to write + * @retval bool + */ + bool addItem(const String& firmwareFileUrl, Storage::Partition partition) + { + return addItem(partition.address(), firmwareFileUrl, partition.size()); } - bool addItem(uint32_t offset, const String& firmwareFileUrl, size_t maxSize = 0); - bool addItem(const String& firmwareFileUrl, RbootOutputStream* stream = nullptr); + /** + * @brief Add an item to update use a pre-constructed stream + * @param firmwareFileUrl + * @param stream + * @retval bool + */ + bool addItem(const String& firmwareFileUrl, RbootOutputStream* stream) + { + if(stream == nullptr) { + return false; + } + + return items.addNew(new Item{firmwareFileUrl, stream->getStartAddress(), stream->getMaxLength(), stream}); + } void start(); + /** + * @brief On completion, switch to the given ROM slot + * @param romSlot specify NO_ROM_SWITCH (the default) to cancel any previously set switch + */ void switchToRom(uint8_t romSlot) { this->romSlot = romSlot; @@ -59,11 +128,13 @@ class RbootHttpUpdater : protected HttpClient this->updateDelegate = reqUpdateDelegate; } - /* Sets the base request that can be used to pass - * - default request parameters, like request headers... - * - default SSL options - * - default SSL fingeprints - * - default SSL client certificates + /** + * @brief Sets the base request that can be used to pass + * + * - default request parameters, like request headers... + * - default SSL options + * - default SSL fingeprints + * - default SSL client certificates * * @param request */ @@ -72,10 +143,21 @@ class RbootHttpUpdater : protected HttpClient baseRequest = request; } - // Allow reading items - RbootHttpUpdaterItem getItem(unsigned int index) + /** + * @brief Allow reading items + * @deprecated Access list directly using `getItems()` + */ + const Item& getItem(unsigned int index) const SMING_DEPRECATED + { + return items[index]; + } + + /** + * @brief Allow read access to item list + */ + const ItemList& getItems() const { - return items.elementAt(index); + return items; } protected: @@ -86,24 +168,16 @@ class RbootHttpUpdater : protected HttpClient virtual int updateComplete(HttpConnection& client, bool success); protected: - Vector items; - int currentItem = 0; - rboot_write_status rbootWriteStatus; - uint8_t romSlot = NO_ROM_SWITCH; - OtaUpdateDelegate updateDelegate = nullptr; - - HttpRequest* baseRequest = nullptr; - -private: - void cleanup() - { - for(unsigned i = 0; i < items.count(); i++) { - delete items[i].stream; - items[i].stream = nullptr; - } - items.clear(); - } + ItemList items; + OtaUpdateDelegate updateDelegate; + HttpRequest* baseRequest{nullptr}; + uint8_t romSlot{NO_ROM_SWITCH}; + uint8_t currentItem{0}; + rboot_write_status rbootWriteStatus{}; }; /** @deprecated Use `RbootHttpUpdater` */ typedef RbootHttpUpdater rBootHttpUpdate SMING_DEPRECATED; + +/** @deprecated Use 'auto' in expressions or `RbootHttpUpdater::Item` */ +typedef RbootHttpUpdater::Item RBootHttpUpdaterItem SMING_DEPRECATED; diff --git a/Sming/Components/rboot/rboot b/Sming/Components/rboot/rboot index 614f33685d..4ad3ba2a8f 160000 --- a/Sming/Components/rboot/rboot +++ b/Sming/Components/rboot/rboot @@ -1 +1 @@ -Subproject commit 614f33685d0dd990fc4202f2409b0d2365eeaef3 +Subproject commit 4ad3ba2a8f6d48d8ab90e0e7c67d42cac49f4da3 diff --git a/Sming/Components/rboot/src/Arch/Host/rboot.cpp b/Sming/Components/rboot/src/Arch/Host/rboot.cpp index 96c5719d88..3eec026938 100644 --- a/Sming/Components/rboot/src/Arch/Host/rboot.cpp +++ b/Sming/Components/rboot/src/Arch/Host/rboot.cpp @@ -13,6 +13,16 @@ #include #include +static uint32_t SPIRead(uint32_t addr, void* outptr, uint32_t len) +{ + return (flashmem_read(outptr, addr, len) == len) ? 0 : 1; +} + +#define SPIEraseSector(sector) flashmem_erase_sector(sector) +#define echof(fmt, ...) host_printf(fmt, ##__VA_ARGS__) + +#include + /* * Called from emulator startup code after flash has been initialised. */ @@ -20,18 +30,14 @@ void host_init_bootloader() { rboot_config romconf = rboot_get_config(); - bool init; - // fresh install or old version? + bool init = false; if(romconf.magic != BOOT_CONFIG_MAGIC) { hostmsg("MAGIC mismatch"); init = true; } else if(romconf.version != BOOT_CONFIG_VERSION) { hostmsg("VERSION mismatch: %u found, current %u", romconf.version, BOOT_CONFIG_VERSION); init = true; - } else { - // OK - init = false; } if(init) { @@ -39,16 +45,22 @@ void host_init_bootloader() memset(&romconf, 0, sizeof(romconf)); romconf.magic = BOOT_CONFIG_MAGIC; romconf.version = BOOT_CONFIG_VERSION; - romconf.count = 2; - romconf.roms[0] = RBOOT_ROM0_ADDR; -#ifdef BOOT_ROM1_ADDR - romconf.roms[1] = RBOOT_ROM1_ADDR; -#else - size_t flashsize = flashmem_get_size_bytes(); - romconf.roms[1] = RBOOT_ROM0_ADDR + (flashsize / 2); -#endif + } + + // Read ROM locations from partition table + bool config_changed = false; + if(scan_partitions(&romconf)) { + config_changed = true; + } + + if(romconf.count == 0) { + hostmsg("ERROR! No App partitions found\r\n"); + return; + } + + if(init || config_changed) { bool ok = rboot_set_config(&romconf); - hostmsg("Write default config: %s", ok ? "OK" : "FAIL"); + hostmsg("Update rBoot config: %s", ok ? "OK" : "FAIL"); } String addr; diff --git a/Sming/Components/rboot/src/RbootHttpUpdater.cpp b/Sming/Components/rboot/src/RbootHttpUpdater.cpp index 07d28bf31d..78ed79e27a 100644 --- a/Sming/Components/rboot/src/RbootHttpUpdater.cpp +++ b/Sming/Components/rboot/src/RbootHttpUpdater.cpp @@ -15,36 +15,13 @@ #include -bool RbootHttpUpdater::addItem(uint32_t offset, const String& firmwareFileUrl, size_t maxSize) -{ - RbootHttpUpdaterItem add; - add.targetOffset = offset; - add.url = firmwareFileUrl; - add.size = maxSize; - add.stream = nullptr; - return items.add(add); -} - -bool RbootHttpUpdater::addItem(const String& firmwareFileUrl, RbootOutputStream* stream) -{ - if(stream == nullptr) { - return false; - } - - RbootHttpUpdaterItem add; - add.targetOffset = stream->getStartAddress(); - add.url = firmwareFileUrl; - add.size = stream->getMaxLength(); - add.stream = stream; - - return items.add(add); -} - void RbootHttpUpdater::start() { for(unsigned i = 0; i < items.count(); i++) { - RbootHttpUpdaterItem& it = items[i]; - debug_d("Download file:\r\n (%d) %s -> %X", currentItem, it.url.c_str(), it.targetOffset); + auto& it = items[i]; + debug_d("Download file:\r\n" + " (%u) %s -> %X", + currentItem, it.url.c_str(), it.targetOffset); HttpRequest* request; if(baseRequest != nullptr) { @@ -55,12 +32,7 @@ void RbootHttpUpdater::start() } request->setMethod(HTTP_GET); - - if(it.stream == nullptr) { - it.stream = new RbootOutputStream(it.targetOffset, it.size); - } - - request->setResponseStream(it.stream); + request->setResponseStream(it.getStream()); if(i == items.count() - 1) { request->onRequestComplete(RequestCompletedDelegate(&RbootHttpUpdater::updateComplete, this)); @@ -82,8 +54,8 @@ int RbootHttpUpdater::itemComplete(HttpConnection& client, bool success) return -1; } - RbootHttpUpdaterItem& it = items[currentItem]; - debug_d("Finished: URL: %s, Offset: %d, Length: %d", it.url.c_str(), it.stream->getStartAddress(), + auto& it = items[currentItem]; + debug_d("Finished: URL: %s, Offset: 0x%X, Length: %u", it.url.c_str(), it.stream->getStartAddress(), it.stream->available()); it.stream = nullptr; // the actual deletion will happen outside of this class @@ -94,14 +66,14 @@ int RbootHttpUpdater::itemComplete(HttpConnection& client, bool success) int RbootHttpUpdater::updateComplete(HttpConnection& client, bool success) { - auto hasError = itemComplete(client, success); - if(hasError) { + int hasError = itemComplete(client, success); + if(hasError != 0) { return hasError; } debug_d("\r\nFirmware download finished!"); for(unsigned i = 0; i < items.count(); i++) { - debug_d(" - item: %d, addr: %X, url: %s", i, items[i].targetOffset, items[i].url.c_str()); + debug_d(" - item: %u, addr: 0x%X, url: %s", i, items[i].targetOffset, items[i].url.c_str()); } if(!success) { @@ -124,19 +96,19 @@ void RbootHttpUpdater::updateFailed() if(updateDelegate) { updateDelegate(*this, false); } - cleanup(); + items.clear(); } void RbootHttpUpdater::applyUpdate() { - cleanup(); + items.clear(); if(romSlot == NO_ROM_SWITCH) { debug_d("Firmware updated."); return; } // set to boot new rom and then reboot - debug_d("Firmware updated, rebooting to rom %d...\r\n", romSlot); + debug_d("Firmware updated, rebooting to rom %u...\r\n", romSlot); rboot_set_current_rom(romSlot); System.restart(); } diff --git a/Sming/Components/spiffs/component.mk b/Sming/Components/spiffs/component.mk index e82a68d993..77064eb4a3 100644 --- a/Sming/Components/spiffs/component.mk +++ b/Sming/Components/spiffs/component.mk @@ -25,22 +25,12 @@ COMPONENT_RELINK_VARS += SPIFFS_OBJ_META_LEN SPIFFS_OBJ_META_LEN ?= 16 COMPONENT_CFLAGS += -DSPIFFS_OBJ_META_LEN=$(SPIFFS_OBJ_META_LEN) -##@Cleaning - -.PHONY: spiffs-image-clean -spiffs-image-clean: ##Remove SPIFFS image file - $(info Cleaning $(SPIFF_BIN_OUT)) - $(Q) rm -f $(SPIFF_BIN_OUT) - ##@Building # Spiffs image generation tool SPIFFSGEN := $(PYTHON) $(COMPONENT_PATH)/spiffsgen.py SPIFFSGEN_SMING = $(SPIFFSGEN) --meta-len=$(SPIFFS_OBJ_META_LEN) --block-size=8192 -.PHONY: spiffs-image-update -spiffs-image-update: spiffs-image-clean $(SPIFF_BIN_OUT) ##Rebuild the SPIFFS filesystem image - # Target invoked via partition table ifneq (,$(filter spiffsgen,$(MAKECMDGOALS))) PART_TARGET := $(PARTITION_$(PART)_FILENAME) diff --git a/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.cpp b/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.cpp index c1ac6be9e4..af28c04518 100644 --- a/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.cpp +++ b/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.cpp @@ -13,6 +13,7 @@ #include #include #include +#include extern "C" uint32 user_rf_cal_sector_set(void); @@ -27,29 +28,13 @@ DECLARE_FSTR_ARRAY(AppFlashRegionOffsets, uint32_t); BasicStream::Slot::Slot() { // Get parameters of the slot where the firmware image should be stored. - const rboot_config bootConfig = rboot_get_config(); - uint8_t currentSlot = bootConfig.current_rom; - index = (currentSlot == 0 ? 1 : 0); - address = bootConfig.roms[index]; - size = 0x100000 - (address & 0xFFFFF); + uint8_t currentSlot = rboot_get_current_rom(); + index = (currentSlot == 0) ? 1 : 0; - const auto limitSize = [&](uint32_t otherAddress) { - if(otherAddress > address) { - size = std::min(size, otherAddress - address); - } - }; - - limitSize(flashmem_get_size_bytes()); - limitSize(user_rf_cal_sector_set() * INTERNAL_FLASH_SECTOR_SIZE); - for(uint8_t i = 0; i < bootConfig.count; ++i) { - if(i != currentSlot) { - limitSize(bootConfig.roms[i]); - } - } - - for(auto offset : AppFlashRegionOffsets) { - limitSize(offset); - } + // Lookup slot details from partition table + auto part = Storage::spiFlash->partitions().findOta(index); + address = part.address(); + size = part.size(); } BasicStream::BasicStream() @@ -83,7 +68,7 @@ bool BasicStream::consume(const uint8_t*& data, size_t& size) void BasicStream::setError(Error code) { assert(code != Error::None); - debug_e("Error: %s", errorToString(code).c_str()); + debug_e("Error: %s", toString(code).c_str()); errorCode = code; state = State::Error; } @@ -225,6 +210,14 @@ size_t BasicStream::write(const uint8_t* data, size_t size) String BasicStream::errorToString(Error code) { + return toString(code); +} + +} // namespace OtaUpgrade + +String toString(OtaUpgrade::BasicStream::Error code) +{ + using Error = OtaUpgrade::BasicStream::Error; switch(code) { case Error::None: return nullptr; @@ -254,5 +247,3 @@ String BasicStream::errorToString(Error code) return F(""); } } - -} // namespace OtaUpgrade diff --git a/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.h b/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.h index 995c57034d..303431caae 100644 --- a/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.h +++ b/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.h @@ -48,7 +48,7 @@ class BasicStream : public ReadWriteStream /** * @brief Error code values */ - enum Error { + enum class Error { None, ///< No error occured thus far (default value of \c #errorCode if `hasError()` returns false) InvalidFormat, ///< Invalid/unsupported upgrade file format UnsupportedData, ///< Some content of the upgrade file is not supported by this version of OtaUpgradeStream. @@ -67,8 +67,9 @@ class BasicStream : public ReadWriteStream /** @brief Convert error code to string. * @see #errorCode + * @deprecated Use `toString()` global function */ - static String errorToString(Error code); + static String errorToString(Error code) SMING_DEPRECATED; /** @brief Process chunk of upgrade file. * @param data Pointer to chunk of data. @@ -113,11 +114,12 @@ class BasicStream : public ReadWriteStream uint32_t address; uint32_t size; uint8_t index; - bool updated = false; - } slot; + bool updated{false}; + }; + Slot slot; // Instead of RbootOutputStream, the rboot write API is used directly because in a future extension the OTA file may contain data for multiple FLASH regions. - rboot_write_status rbootWriteStatus = {}; + rboot_write_status rbootWriteStatus{}; enum class State { Error, @@ -128,14 +130,14 @@ class BasicStream : public ReadWriteStream VerifyRoms, RomsComplete, }; - State state = State::Header; + State state{State::Header}; #ifdef ENABLE_OTA_SIGNING using Verifier = SignatureVerifier; - static const uint32_t expectedHeaderMagic = OTA_HEADER_MAGIC_SIGNED; + static const uint32_t expectedHeaderMagic{OTA_HEADER_MAGIC_SIGNED}; #else using Verifier = ChecksumVerifier; - static const uint32_t expectedHeaderMagic = OTA_HEADER_MAGIC_NOT_SIGNED; + static const uint32_t expectedHeaderMagic{OTA_HEADER_MAGIC_NOT_SIGNED}; #endif Verifier verifier; @@ -144,9 +146,9 @@ class BasicStream : public ReadWriteStream Verifier::VerificationData verificationData; - size_t remainingBytes = 0; - uint8_t* destinationPtr = nullptr; - uint8_t romIndex = 0; + size_t remainingBytes{0}; + uint8_t* destinationPtr{nullptr}; + uint8_t romIndex{0}; void setupChunk(State nextState, size_t size, void* destination = nullptr) { @@ -183,3 +185,8 @@ class BasicStream : public ReadWriteStream }; } // namespace OtaUpgrade + +/** @brief Convert error code to string. + * @see #errorCode + */ +String toString(OtaUpgrade::BasicStream::Error code); diff --git a/Sming/Libraries/OtaUpgrade/OtaUpgrade/EncryptedStream.cpp b/Sming/Libraries/OtaUpgrade/OtaUpgrade/EncryptedStream.cpp index 80a88457af..fa1c09a0f8 100644 --- a/Sming/Libraries/OtaUpgrade/OtaUpgrade/EncryptedStream.cpp +++ b/Sming/Libraries/OtaUpgrade/OtaUpgrade/EncryptedStream.cpp @@ -46,16 +46,15 @@ size_t EncryptedStream::write(const uint8_t* data, size_t size) case Fragment::ChunkSize: remainingBytes = 1 + chunkSizeMinusOne; - if(buffer == nullptr || bufferSize < remainingBytes) { - free(buffer); - buffer = (uint8_t*)malloc(remainingBytes); - if(buffer == nullptr) { + if(!buffer || bufferSize < remainingBytes) { + buffer.reset(new uint8_t[remainingBytes]); + if(!buffer) { setError(Error::OutOfMemory); break; } bufferSize = remainingBytes; } - fragmentPtr = buffer; + fragmentPtr = buffer.get(); fragment = Fragment::Chunk; break; @@ -63,8 +62,8 @@ size_t EncryptedStream::write(const uint8_t* data, size_t size) unsigned char tag; size_t chiperTextLength = 1 + chunkSizeMinusOne; unsigned long long messageLength = 0; - bool ok = (crypto_secretstream_xchacha20poly1305_pull(&state, buffer, &messageLength, &tag, buffer, - chiperTextLength, nullptr, 0) == 0); + bool ok = (crypto_secretstream_xchacha20poly1305_pull(&state, buffer.get(), &messageLength, &tag, + buffer.get(), chiperTextLength, nullptr, 0) == 0); if(!ok || messageLength > bufferSize) { setError(Error::DecryptionFailed); break; @@ -77,7 +76,7 @@ size_t EncryptedStream::write(const uint8_t* data, size_t size) fragment = Fragment::None; } - BasicStream::write(buffer, static_cast(messageLength)); + BasicStream::write(buffer.get(), size_t(messageLength)); } break; case Fragment::None: diff --git a/Sming/Libraries/OtaUpgrade/OtaUpgrade/EncryptedStream.h b/Sming/Libraries/OtaUpgrade/OtaUpgrade/EncryptedStream.h index 3557c56f82..7b34375a33 100644 --- a/Sming/Libraries/OtaUpgrade/OtaUpgrade/EncryptedStream.h +++ b/Sming/Libraries/OtaUpgrade/OtaUpgrade/EncryptedStream.h @@ -28,11 +28,6 @@ class EncryptedStream : public BasicStream public: EncryptedStream() = default; - ~EncryptedStream() - { - free(buffer); - } - /** @brief Process an arbitrarily sized chunk of an encrypted OTA upgrade file. * @param data Pointer to chunk of data. * @param size Size of chunk pointed to by \a data in bytes. @@ -55,12 +50,12 @@ class EncryptedStream : public BasicStream Chunk, None, }; - Fragment fragment = Fragment::Header; - size_t remainingBytes = sizeof(header); - uint8_t* fragmentPtr = header; - uint8_t* buffer = nullptr; - size_t bufferSize = 0; + Fragment fragment{Fragment::Header}; + size_t remainingBytes{sizeof header}; + uint8_t* fragmentPtr{header}; + std::unique_ptr buffer; + size_t bufferSize{0}; }; } // namespace OtaUpgrade diff --git a/Sming/component.mk b/Sming/component.mk index 8f3471a83c..4d3ba173fa 100644 --- a/Sming/component.mk +++ b/Sming/component.mk @@ -149,10 +149,9 @@ GLOBAL_CFLAGS += -DSTRING_OBJECT_SIZE=$(STRING_OBJECT_SIZE) ##@Flashing .PHONY: flashinit -flashinit: $(ESPTOOL) $(FLASH_INIT_DATA) | $(FW_BASE) ##Erase your device's flash memory +flashinit: $(ESPTOOL) | $(FW_BASE) ##Erase your device's flash memory $(info Flash init data default and blank data) $(Q) $(EraseFlash) - $(call WriteFlash,$(FLASH_INIT_CHUNKS)) .PHONY: flashboot flashboot: $(FLASH_BOOT_LOADER) kill_term ##Write just the Bootloader diff --git a/Tools/vscode/setup.py b/Tools/vscode/setup.py index 4e59b0a0ab..8363406a23 100644 --- a/Tools/vscode/setup.py +++ b/Tools/vscode/setup.py @@ -32,6 +32,11 @@ def replace(self, path, name, prefix): return '${%s%s}%s' % (prefix, name, s[len(value):]) return path + def resolve(self, path): + """Convert any embedded environment variables into real paths + """ + return os.path.expandvars(path) + def subst_path(self, path, prefix=''): path = self.replace(path, 'SMING_HOME', prefix) path = self.replace(path, 'ESP_HOME', prefix) @@ -113,9 +118,10 @@ def get_property(data, name, default): return data[name] def update_intellisense(): - dirs = os.environ['COMPONENTS_EXTRA_INCDIR'].split() - for i, d in enumerate(dirs): - dirs[i] = check_path(env.subst_path(d)) + dirs = [] + for d in os.environ['COMPONENTS_EXTRA_INCDIR'].split(): + if os.path.exists(d): + dirs += [check_path(env.subst_path(d))] propertiesFile = '.vscode/c_cpp_properties.json' if os.path.exists(propertiesFile): @@ -185,11 +191,15 @@ def update_launch(): def update_workspace(): filename = 'sming.code-workspace' ws = load_json(filename, False) + template = load_template('workspace.json') if ws is None: - template = load_template('workspace.json') ws = template.copy() - # TODO: Make any required changes to generated - save_json(ws, filename) + schemas = ws['settings']['json.schemas'] = [] + # ws['settings']['json.schemas'] + for schema in template['settings']['json.schemas']: + schema['url'] = env.resolve(schema['url']) + schemas += [schema] + save_json(ws, filename) def main(): if not env.SMING_HOME or not env.SMING_ARCH: diff --git a/Tools/vscode/template/workspace.json b/Tools/vscode/template/workspace.json index f5d5823978..a79cc17307 100644 --- a/Tools/vscode/template/workspace.json +++ b/Tools/vscode/template/workspace.json @@ -15,13 +15,13 @@ "fileMatch": [ "*.hw" ], - "url": "{$SMING_HOME}/Components/Storage/schema.json" + "url": "file://${SMING_HOME}/Components/Storage/schema.json" }, { "fileMatch": [ "*.fwfs" ], - "url": "${SMING_HOME}/Components/IFS/fsbuild/schema.json" + "url": "file://${SMING_HOME}/Components/IFS/fsbuild/schema.json" } ] } diff --git a/docs/source/upgrading/4.2-4.3.rst b/docs/source/upgrading/4.2-4.3.rst index 69fb0498e4..6698e12634 100644 --- a/docs/source/upgrading/4.2-4.3.rst +++ b/docs/source/upgrading/4.2-4.3.rst @@ -17,6 +17,12 @@ the :envvar:`HWCONFIG` setting. You can find full details in the :component:`Storage` library. See also background on :doc:`/information/flash`. +Removed build targets + spiffs-image-update + Use the new `buildpart` target instead + spiffs-image-clean + Use the new `part-clean` target instead + New and updated build targets hwconfig Displays the current configuration in JSON format @@ -36,22 +42,18 @@ New and updated build targets ``make flashinit`` to write system parameter information. Failure to do this was a common problem and should now be a thing of the past. flashinit - This now just erases the flash memory, and is no longer a pre-requisite for ``make flash``. - - The ESP8266 system parameter information has been moved into registered - partitions (phy_init and sys_param) near the beginning of flash memory. - It now gets written when running ``make flash``. - - Previously, this information was kept right at the end of the flash memory, - so the location would vary depending on the setting of ``SPI_SIZE``. - This was a frequent cause of problems as the system would fail to start if this - was set incorrectly. + This now just erases the flash memory. + The ESP8266 initialisation data gets written when running ``make flash``. flashmap Flash just the partition map flashpart Flash a single partition, e.g. ``make flashpart PART=spiffs0`` erasepart Erase a partition, e.g. ``make erasepart PART=spiffs0`` + buildpart + Re-builds images associated with partitions, such as SPIFFS or other filesystem images. + part-clean + Removes any partition images with build information. This is done as part of a normal project `clean`. Configuration variables A number of configuration variables have been removed or made read-only, as these are now diff --git a/samples/Basic_Storage/basic_storage.hw b/samples/Basic_Storage/basic_storage.hw index 90da02eb6d..44caa91626 100644 --- a/samples/Basic_Storage/basic_storage.hw +++ b/samples/Basic_Storage/basic_storage.hw @@ -2,8 +2,15 @@ "name": "Basic Storage sample", "base_config": "spiffs", "devices": { - // Override default (conservative) flash settings for maximum performance + // If required, override default (conservative) flash settings "spiFlash": { + /* + * The default mode (dio) should work with all flash devices. + * Make sure to set the mode according to your flash chip. + * Allowed SPI modes are listed here: + * https://sming.readthedocs.io/en/latest/_inc/Sming/Components/esptool/index.html#envvar-SPI_MODE. + */ + // "mode": "qio", "speed": 80 } }, diff --git a/samples/Basic_rBoot/app/application.cpp b/samples/Basic_rBoot/app/application.cpp index b8e7397a30..cfb3f85655 100644 --- a/samples/Basic_rBoot/app/application.cpp +++ b/samples/Basic_rBoot/app/application.cpp @@ -96,17 +96,16 @@ void OtaUpdate() void Switch() { - uint8 before, after; - before = rboot_get_current_rom(); - if(before == 0) { - after = 1; + uint8_t before = rboot_get_current_rom(); + uint8_t after = (before == 0) ? 1 : 0; + + Serial.printf(_F("Swapping from rom %u to rom %u.\r\n"), before, after); + if(rboot_set_current_rom(after)) { + Serial.println(F("Restarting...\r\n")); + System.restart(); } else { - after = 0; + Serial.println(F("Switch failed.")); } - Serial.printf("Swapping from rom %d to rom %d.\r\n", before, after); - rboot_set_current_rom(after); - Serial.println("Restarting...\r\n"); - System.restart(); } void ShowInfo() @@ -116,15 +115,15 @@ void ShowInfo() Serial.printf("CPU Frequency: %d MHz\r\n", system_get_cpu_freq()); Serial.printf("System Chip ID: %x\r\n", system_get_chip_id()); Serial.printf("SPI Flash ID: %x\r\n", Storage::spiFlash->getId()); - //Serial.printf("SPI Flash Size: %d\r\n", (1 << ((spi_flash_get_id() >> 16) & 0xff))); + Serial.printf("SPI Flash Size: %x\r\n", Storage::spiFlash->getSize()); rboot_config conf; conf = rboot_get_config(); debugf("Count: %d", conf.count); - debugf("ROM 0: 0x%08x", conf.roms[0]); - debugf("ROM 1: 0x%08x", conf.roms[1]); - debugf("ROM 2: 0x%08x", conf.roms[2]); + for(unsigned i = 0; i < MAX_ROMS; ++i) { + debugf("ROM %u: 0x%08x", i, conf.roms[i]); + } debugf("GPIO ROM: %d", conf.gpio_rom); } diff --git a/samples/Basic_rBoot/basic_rboot.hw b/samples/Basic_rBoot/basic_rboot.hw index 64465e1b3a..27332cb161 100644 --- a/samples/Basic_rBoot/basic_rboot.hw +++ b/samples/Basic_rBoot/basic_rboot.hw @@ -2,11 +2,14 @@ "name": "Two ROM slots, two SPIFFS", "base_config": "spiffs", "partitions": { + "rom0": { + "subtype": "ota_0" + }, "rom1": { "address": "0x108000", "size": "992K", "type": "app", - "subtype": "ota_0", + "subtype": "ota_1", "filename": "$(RBOOT_ROM_1_BIN)" }, "spiffs1": { @@ -16,4 +19,4 @@ "subtype": "spiffs" } } -} +} \ No newline at end of file diff --git a/samples/Basic_rBoot/component.mk b/samples/Basic_rBoot/component.mk index df007c2dfe..9555e50099 100644 --- a/samples/Basic_rBoot/component.mk +++ b/samples/Basic_rBoot/component.mk @@ -4,8 +4,4 @@ RBOOT_ENABLED := 1 ## Use standard hardware config with two ROM slots and two SPIFFS partitions -ifeq ($(SMING_ARCH),Esp8266) HWCONFIG := basic_rboot -else -HWCONFIG := spiffs -endif diff --git a/samples/HttpServer_FirmwareUpload/app/application.cpp b/samples/HttpServer_FirmwareUpload/app/application.cpp index 6c97838a30..2dbfe83325 100644 --- a/samples/HttpServer_FirmwareUpload/app/application.cpp +++ b/samples/HttpServer_FirmwareUpload/app/application.cpp @@ -38,7 +38,7 @@ int onUpload(HttpServerConnection& connection, HttpRequest& request, HttpRespons response.code = HTTP_STATUS_BAD_REQUEST; response.setContentType(MIME_HTML); - String html = "

" + OtaUpgradeStream::errorToString(otaStream->errorCode) + "

"; + String html = "

" + toString(otaStream->errorCode) + "

"; response.headers[HTTP_HEADER_CONTENT_LENGTH] = html.length(); response.sendString(html);