From 3930525b49463b95a62062547d9f26dddc2fb8fe Mon Sep 17 00:00:00 2001 From: Slavey Karadzhov Date: Wed, 19 May 2021 14:44:25 +0200 Subject: [PATCH 01/15] Initial version. --- Sming/Arch/Esp32/Core/Ota/IdfUpgrader.cpp | 95 ++++++++ Sming/Arch/Esp32/Core/Ota/IdfUpgrader.h | 44 ++++ Sming/Arch/Esp32/Core/Ota/Upgrader.h | 16 ++ Sming/Arch/Esp8266/Core/Ota/RbootUpgrader.cpp | 96 ++++++++ Sming/Arch/Esp8266/Core/Ota/RbootUpgrader.h | 45 ++++ Sming/Arch/Esp8266/Core/Ota/Upgrader.h | 16 ++ Sming/Arch/Host/Core/Ota | 1 + Sming/Core/Ota/UpgraderBase.h | 48 ++++ samples/Basic_Ota/.cproject | 151 +++++++++++++ samples/Basic_Ota/.project | 28 +++ samples/Basic_Ota/Makefile | 9 + samples/Basic_Ota/README.rst | 83 +++++++ samples/Basic_Ota/app/application.cpp | 213 ++++++++++++++++++ samples/Basic_Ota/basic_rboot.hw | 22 ++ samples/Basic_Ota/component.mk | 7 + samples/Basic_Ota/files/testfile.txt | 2 + 16 files changed, 876 insertions(+) create mode 100644 Sming/Arch/Esp32/Core/Ota/IdfUpgrader.cpp create mode 100644 Sming/Arch/Esp32/Core/Ota/IdfUpgrader.h create mode 100644 Sming/Arch/Esp32/Core/Ota/Upgrader.h create mode 100644 Sming/Arch/Esp8266/Core/Ota/RbootUpgrader.cpp create mode 100644 Sming/Arch/Esp8266/Core/Ota/RbootUpgrader.h create mode 100644 Sming/Arch/Esp8266/Core/Ota/Upgrader.h create mode 120000 Sming/Arch/Host/Core/Ota create mode 100644 Sming/Core/Ota/UpgraderBase.h create mode 100644 samples/Basic_Ota/.cproject create mode 100644 samples/Basic_Ota/.project create mode 100644 samples/Basic_Ota/Makefile create mode 100644 samples/Basic_Ota/README.rst create mode 100644 samples/Basic_Ota/app/application.cpp create mode 100644 samples/Basic_Ota/basic_rboot.hw create mode 100644 samples/Basic_Ota/component.mk create mode 100644 samples/Basic_Ota/files/testfile.txt diff --git a/Sming/Arch/Esp32/Core/Ota/IdfUpgrader.cpp b/Sming/Arch/Esp32/Core/Ota/IdfUpgrader.cpp new file mode 100644 index 0000000000..be463807b6 --- /dev/null +++ b/Sming/Arch/Esp32/Core/Ota/IdfUpgrader.cpp @@ -0,0 +1,95 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * IdfUpgrader.cpp + * + ****/ + +#include "IdfUpgrader.h" + +namespace Ota +{ +bool IdfUpgrader::begin(Storage::Partition partition, size_t maxSize) +{ + if(partition.size() < maxSize) { + return false; // the requested size is too big... + } + + writtenSoFar = 0; + + esp_err_t result = esp_ota_begin(convertToIdfPartition(partition), maxSize ? maxSize : partition.size(), &handle); + + return result == ESP_OK; +} + +size_t IdfUpgrader::write(const uint8_t* buffer, size_t size) +{ + if(writtenSoFar + size > maxSize) { + // cannot write more bytes than allowed + return 0; + } + + esp_err_t result = esp_ota_write(handle, buffer, size); + if(result != ESP_OK) { + // write failed + return 0; + } + + writtenSoFar += size; + + return size; +} + +bool IdfUpgrader::end() +{ + return esp_ota_end(handle) == ESP_OK; +} + +bool IdfUpgrader::abort() +{ + return true; +} + +bool IdfUpgrader::setBootPartition(Storage::Partition partition) +{ + return esp_ota_set_boot_partition(convertToIdfPartition(partition)) == ESP_OK; +} + +Storage::Partition IdfUpgrader::getBootPartition(void) +{ + return convertFromIdfPartition(esp_ota_get_boot_partition()); +} + +Storage::Partition IdfUpgrader::getRunningPartition(void) +{ + return convertFromIdfPartition(esp_ota_get_running_partition()); +} + +Storage::Partition IdfUpgrader::getNextUpdatePartition(Storage::Partition* startFrom) +{ + return convertFromIdfPartition(esp_ota_get_next_update_partition(convertToIdfPartition(*startFrom))); +} + +const esp_partition_t* IdfUpgrader::convertToIdfPartition(Storage::Partition partition) +{ + return esp_partition_find_first(ESP_PARTITION_TYPE_APP, + partition.subType() == uint8_t(Storage::Partition::SubType::App::ota0) + ? ESP_PARTITION_SUBTYPE_APP_OTA_0 + : ESP_PARTITION_SUBTYPE_APP_OTA_1, + partition.name().c_str()); +} + +Storage::Partition convertFromIdfPartition(const esp_partition_t* partition) +{ + String label; + if(partition != nullptr) { + label = partition->label; + } + + return Storage::findPartition(label); +} + +} // namespace Ota diff --git a/Sming/Arch/Esp32/Core/Ota/IdfUpgrader.h b/Sming/Arch/Esp32/Core/Ota/IdfUpgrader.h new file mode 100644 index 0000000000..6e8f4dc00f --- /dev/null +++ b/Sming/Arch/Esp32/Core/Ota/IdfUpgrader.h @@ -0,0 +1,44 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * IdfUpgrader.h + * + * This header includes all unified Over-The-Air functions. + * +*/ + +#pragma once +#include +#include + +namespace Ota +{ +class IdfUpgrader : public UpgraderBase +{ +public: + /** + * @brief Prepare the partition for + */ + bool begin(Storage::Partition partition, size_t maxSize = 0) override; + size_t write(const uint8_t* buffer, size_t size) override; + bool end() override; + bool abort() override; + + bool setBootPartition(Storage::Partition partition) override; + Storage::Partition getBootPartition(void) override; + Storage::Partition getRunningPartition(void) override; + Storage::Partition getNextUpdatePartition(Storage::Partition* startFrom = nullptr) override; + + static const esp_partition_t* convertToIdfPartition(Storage::Partition partition); + static Storage::Partition convertFromIdfPartition(const esp_partition_t* partition); + +private: + size_t maxSize{0}; + size_t writtenSoFar{0}; + esp_ota_handle_t handle{}; +}; + +} // namespace Ota diff --git a/Sming/Arch/Esp32/Core/Ota/Upgrader.h b/Sming/Arch/Esp32/Core/Ota/Upgrader.h new file mode 100644 index 0000000000..c2d002c732 --- /dev/null +++ b/Sming/Arch/Esp32/Core/Ota/Upgrader.h @@ -0,0 +1,16 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * Upgrader.h + * + * This header includes all unified Over-The-Air functions. + * +*/ + +#pragma once +#include "IdfUpgrader.h" + +using OtaUpgrader = Ota::IdfUpgrader; diff --git a/Sming/Arch/Esp8266/Core/Ota/RbootUpgrader.cpp b/Sming/Arch/Esp8266/Core/Ota/RbootUpgrader.cpp new file mode 100644 index 0000000000..d324912c0c --- /dev/null +++ b/Sming/Arch/Esp8266/Core/Ota/RbootUpgrader.cpp @@ -0,0 +1,96 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * Ota.cpp + * + ****/ + +#include "RbootUpgrader.h" + +namespace Ota +{ +bool RbootUpgrader::begin(Storage::Partition partition, size_t maxSize) +{ + if(partition.size() < maxSize) { + return false; // the requested size is too big... + } + + status = rboot_write_init(partition.address()); + + if(maxSize) { + this->maxSize = maxSize; + } else { + this->maxSize = partition.size(); + } + + writtenSoFar = 0; + + return true; +} + +size_t RbootUpgrader::write(const uint8_t* buffer, size_t size) +{ + if(writtenSoFar + size > maxSize) { + // cannot write more bytes than allowed + return 0; + } + + if(!rboot_write_flash(&status, buffer, size)) { + // write failed + return 0; + } + + writtenSoFar += size; + + return size; +} + +bool RbootUpgrader::end() +{ + return rboot_write_end(&status); +} + +bool RbootUpgrader::setBootPartition(Storage::Partition partition) +{ + return rboot_set_current_rom(getSlotForPartition(partition)); +} + +Storage::Partition RbootUpgrader::getBootPartition(void) +{ + return getPartitionForSlot(rboot_get_current_rom()); +} + +Storage::Partition RbootUpgrader::getRunningPartition(void) +{ + // TODO: ... + return getPartitionForSlot(rboot_get_current_rom()); +} + +Storage::Partition RbootUpgrader::getNextUpdatePartition(Storage::Partition* startFrom) +{ + uint8_t currentSlot = rboot_get_current_rom(); + return getPartitionForSlot(currentSlot ? 0 : 1); +} + +uint8_t RbootUpgrader::getSlotForPartition(Storage::Partition partition) +{ + if(partition.subType() == uint8_t(Storage::Partition::SubType::App::ota1)) { + return 1; + } + + return 0; +} + +Storage::Partition RbootUpgrader::getPartitionForSlot(uint8_t slot) +{ + auto partitions = Storage::findPartition( + Storage::Partition::Type::app, + uint8_t(slot == 0 ? Storage::Partition::SubType::App::ota0 : Storage::Partition::SubType::App::ota1)); + + return *partitions; +} + +} // namespace Ota diff --git a/Sming/Arch/Esp8266/Core/Ota/RbootUpgrader.h b/Sming/Arch/Esp8266/Core/Ota/RbootUpgrader.h new file mode 100644 index 0000000000..ec607b0129 --- /dev/null +++ b/Sming/Arch/Esp8266/Core/Ota/RbootUpgrader.h @@ -0,0 +1,45 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * Ota.h + * + * This header includes all unified Over-The-Air functions. + * +*/ + +#pragma once +#include +#include + +namespace Ota +{ +class RbootUpgrader : public UpgraderBase +{ +public: + /** + * @brief Prepare the partition for + */ + bool begin(Storage::Partition partition, size_t maxSize = 0) override; + size_t write(const uint8_t* buffer, size_t size) override; + bool end() override; + + bool setBootPartition(Storage::Partition partition) override; + Storage::Partition getBootPartition(void) override; + Storage::Partition getRunningPartition(void) override; + Storage::Partition getNextUpdatePartition(Storage::Partition* startFrom = nullptr) override; + + static uint8_t getSlotForPartition(Storage::Partition partition); + static Storage::Partition getPartitionForSlot(uint8_t slot); + +private: + rboot_write_status status{}; + size_t maxSize{0}; + size_t writtenSoFar{0}; +}; + +using OtaUpgrader = RbootUpgrader; + +} // namespace Ota diff --git a/Sming/Arch/Esp8266/Core/Ota/Upgrader.h b/Sming/Arch/Esp8266/Core/Ota/Upgrader.h new file mode 100644 index 0000000000..5ceee81425 --- /dev/null +++ b/Sming/Arch/Esp8266/Core/Ota/Upgrader.h @@ -0,0 +1,16 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * Upgrader.h + * + * This header includes all unified Over-The-Air functions. + * +*/ + +#pragma once +#include "RbootUpgrader.h" + +using OtaUpgrader = Ota::RbootUpgrader; diff --git a/Sming/Arch/Host/Core/Ota b/Sming/Arch/Host/Core/Ota new file mode 120000 index 0000000000..4af34ca608 --- /dev/null +++ b/Sming/Arch/Host/Core/Ota @@ -0,0 +1 @@ +../../Esp8266/Core/Ota \ No newline at end of file diff --git a/Sming/Core/Ota/UpgraderBase.h b/Sming/Core/Ota/UpgraderBase.h new file mode 100644 index 0000000000..5bd682a87a --- /dev/null +++ b/Sming/Core/Ota/UpgraderBase.h @@ -0,0 +1,48 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * Ota.h + * + * This header includes all unified Over-The-Air functions. + * +*/ + +#pragma once +#include + +namespace Ota +{ +class UpgraderBase +{ +public: + virtual ~UpgraderBase() + { + } + + /** + * @brief Prepare the partition for + */ + virtual bool begin(Storage::Partition partition, size_t size) = 0; + virtual size_t write(const uint8_t* buffer, size_t size) = 0; + virtual bool seek(int len) + { + return false; + } + + virtual bool end() = 0; + + virtual bool abort() + { + return false; + } + + virtual bool setBootPartition(Storage::Partition partition) = 0; + virtual Storage::Partition getBootPartition(void) = 0; + virtual Storage::Partition getRunningPartition(void) = 0; + virtual Storage::Partition getNextUpdatePartition(Storage::Partition* startFrom = nullptr) = 0; +}; + +} // namespace Ota diff --git a/samples/Basic_Ota/.cproject b/samples/Basic_Ota/.cproject new file mode 100644 index 0000000000..e1450b6031 --- /dev/null +++ b/samples/Basic_Ota/.cproject @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + make + -f ${ProjDirPath}/Makefile + all + true + true + true + + + make + -f ${ProjDirPath}/Makefile + clean + true + true + true + + + make + -f ${ProjDirPath}/Makefile + flash + true + true + true + + + make + -f ${ProjDirPath}/Makefile + flashonefile + true + true + true + + + make + -f ${ProjDirPath}/Makefile + flashinit + true + true + true + + + make + -f ${ProjDirPath}/Makefile + flashboot + true + true + true + + + make + -f ${ProjDirPath}/Makefile + rebuild + true + true + true + + + + + + + + + + + + + + + + + + + + diff --git a/samples/Basic_Ota/.project b/samples/Basic_Ota/.project new file mode 100644 index 0000000000..2d511edc6e --- /dev/null +++ b/samples/Basic_Ota/.project @@ -0,0 +1,28 @@ + + + Basic_Ota + + + SmingFramework + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/samples/Basic_Ota/Makefile b/samples/Basic_Ota/Makefile new file mode 100644 index 0000000000..ff51b6c3a7 --- /dev/null +++ b/samples/Basic_Ota/Makefile @@ -0,0 +1,9 @@ +##################################################################### +#### Please don't change this file. Use component.mk instead #### +##################################################################### + +ifndef SMING_HOME +$(error SMING_HOME is not set: please configure it as an environment variable) +endif + +include $(SMING_HOME)/project.mk diff --git a/samples/Basic_Ota/README.rst b/samples/Basic_Ota/README.rst new file mode 100644 index 0000000000..f49ea3da08 --- /dev/null +++ b/samples/Basic_Ota/README.rst @@ -0,0 +1,83 @@ +Basic rBoot +=========== + +.. highlight:: bash + +Introduction +------------ + +This sample integrates :component:`rboot` and Sming, for the many people who have +been asking for it. It demonstrates dual rom booting, big flash support, +OTA updates and dual spiffs filesystems. You must enable big flash +support in rBoot and use on an ESP12 (or similar device with 4MB flash). +When using rBoot big flash support with multiple 1MB slots only one rom +image needs to be created. If you don’t want to use big flash support +(e.g. for a device with smaller flash) see the separate instructions +below. You can easily take the ota files and add them to your own +project to add OTA support. + +Building +-------- + +1) Set :envvar:`ESP_HOME` & :envvar:`SMING_HOME`, as environment variables or edit + component.mk as you would for general Sming app compiling. +2) Set :envvar:`WIFI_SSID` & :envvar:`WIFI_PWD` environment variables with your wifi details. +3) Edit the OTA server details at the top of ``app/application.cpp``. +4) Check overridable variables in component.mk, or set as env vars. +5) ``make && make flash`` +6) Put *rom0.bin* and *spiff_rom.bin* in the root of your webserver for OTA. +7) Interact with the sample using a terminal (``make terminal``). Sorry - no web-gui (yet). + +Flashing +-------- + +If flashing manually use *esptool.py* to flash rBoot, rom & spiffs e.g.:: + + esptool.py –port write_flash -fs 32m 0x00000 rboot.bin 0x02000 rom0.bin 0x100000 spiffs.rom + +Using the correct -fs parameter is important. This will be ``-fs 32m`` on an ESP12. + +You can also flash rom0.bin to 0x202000, but booting and using OTA is quicker! + +Technical Notes +--------------- + +``spiffs_mount_manual(address, length)`` must be called from init. + +.. note:: + + This method is now deprecated. Please configure partitions appropriately, + use PartitionTable methods to locate the desired partition, then mount it:: + + auto part = PartitionTable().find('spiffs0'); + spiffs_mount(part); + + See :ref:`hardware_config` for further details. + +Important compiler flags used: + +- BOOT_BIG_FLASH - when using big flash mode, ensures flash mapping code is built in to the rom. +- RBOOT_INTEGRATION - ensures Sming specific options are pulled in to the rBoot source at compile time. + +Flash layout considerations +--------------------------- + +If you want to use, for example, two 512k roms in the first 1MB block of +flash (old style) then Sming will automatically create two separately linked +roms. If you are flashing a single rom to multiple 1MB flash blocks, all using +the same offset inside their 1MB blocks, only a single rom is created. +See :component:`rboot` for further details. + +- If using a very small flash (e.g. 512k) there may be no room for a + spiffs fileystem, so use *HWCONFIG = standard* +- After building copy all the rom*.bin files to the root of your web + server. + +If you want more than two roms you must be an advanced user and should +be able to work out what to copy and edit to acheive this! + +Credits +------- + +This sample was made possible with the assistance of piperpilot, +gschmott and robotiko on the esp8266.com forum. diff --git a/samples/Basic_Ota/app/application.cpp b/samples/Basic_Ota/app/application.cpp new file mode 100644 index 0000000000..41ec6c47f6 --- /dev/null +++ b/samples/Basic_Ota/app/application.cpp @@ -0,0 +1,213 @@ +#include +#include +#include +#include + +// download urls, set appropriately +#define ROM_0_URL "http://192.168.7.5:80/rom0.bin" +#define ROM_1_URL "http://192.168.7.5:80/rom1.bin" +#define SPIFFS_URL "http://192.168.7.5:80/spiff_rom.bin" + +// If you want, you can define WiFi settings globally in Eclipse Environment Variables +#ifndef WIFI_SSID +#define WIFI_SSID "PleaseEnterSSID" // Put your SSID and password here +#define WIFI_PWD "PleaseEnterPass" +#endif + +RbootHttpUpdater* otaUpdater; +Storage::Partition spiffsPartition; +OtaUpgrader ota; + +Storage::Partition findSpiffsPartition(uint8_t slot) +{ + String name = F("spiffs"); + name += slot; + auto part = Storage::findPartition(name); + if(!part) { + debug_w("Partition '%s' not found", name.c_str()); + } + return part; +} + +void otaUpdateCallBack(RbootHttpUpdater& client, bool result) +{ + Serial.println("In callback..."); + if(result == true) { + // success + ota.end(); + + auto part = ota.getNextUpdatePartition(); + // set to boot new rom and then reboot + Serial.printf("Firmware updated, rebooting to rom %s...\r\n", part.name().c_str()); + ota.setBootPartition(part); + System.restart(); + } else { + ota.abort(); + // fail + Serial.println("Firmware update failed!"); + } +} + +void OtaUpdate() +{ + Serial.println("Updating..."); + + // need a clean object, otherwise if run before and failed will not run again + if(otaUpdater) { + delete otaUpdater; + } + otaUpdater = new RbootHttpUpdater(); + + // select rom slot to flash + auto part = ota.getNextUpdatePartition(); + +#ifndef RBOOT_TWO_ROMS + // flash rom to position indicated in the rBoot config rom table + otaUpdater->addItem(part.address(), ROM_0_URL, part.size()); +#else + // flash appropriate ROM + otaUpdater->addItem(part.address(), (part.subType() == 0) ? ROM_0_URL : ROM_1_URL, part.size()); +#endif + + ota.begin(part); + + auto spiffsPart = findSpiffsPartition(part.subType()); + if(spiffsPart) { + // use user supplied values (defaults for 4mb flash in hardware config) + otaUpdater->addItem(spiffsPart.address(), SPIFFS_URL, spiffsPart.size()); + } + + // request switch and reboot on success + //otaUpdater->switchToRom(slot); + // and/or set a callback (called on failure or success without switching requested) + otaUpdater->setCallback(otaUpdateCallBack); + + // start update + otaUpdater->start(); +} + +void Switch() +{ + auto before = ota.getRunningPartition(); + auto after = ota.getNextUpdatePartition(); + + Serial.printf(_F("Swapping from rom %s to rom %s.\r\n"), before.name().c_str(), after.name().c_str()); + if(ota.setBootPartition(after)) { + Serial.println(F("Restarting...\r\n")); + System.restart(); + } else { + Serial.println(F("Switch failed.")); + } +} + +void ShowInfo() +{ + Serial.printf("\r\nSDK: v%s\r\n", system_get_sdk_version()); + Serial.printf("Free Heap: %d\r\n", system_get_free_heap_size()); + 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: %x\r\n", Storage::spiFlash->getSize()); + + auto before = ota.getRunningPartition(); + auto after = ota.getNextUpdatePartition(); + + Serial.printf(_F("Current rom: %s@%x, future rom: %s@%x\r\n"), before.name().c_str(), before.address(), + after.name().c_str(), after.address()); +} + +void serialCallBack(Stream& stream, char arrivedChar, unsigned short availableCharsCount) +{ + int pos = stream.indexOf('\n'); + if(pos > -1) { + char str[pos + 1]; + for(int i = 0; i < pos + 1; i++) { + str[i] = stream.read(); + if(str[i] == '\r' || str[i] == '\n') { + str[i] = '\0'; + } + } + + if(!strcmp(str, "connect")) { + // connect to wifi + WifiStation.config(WIFI_SSID, WIFI_PWD); + WifiStation.enable(true); + WifiStation.connect(); + } else if(!strcmp(str, "ip")) { + Serial.print("ip: "); + Serial.print(WifiStation.getIP()); + Serial.print("mac: "); + Serial.println(WifiStation.getMacAddress()); + } else if(!strcmp(str, "ota")) { + OtaUpdate(); + } else if(!strcmp(str, "switch")) { + Switch(); + } else if(!strcmp(str, "restart")) { + System.restart(); + } else if(!strcmp(str, "ls")) { + Directory dir; + if(dir.open()) { + while(dir.next()) { + Serial.print(" "); + Serial.println(dir.stat().name); + } + } + Serial.printf("filecount %d\r\n", dir.count()); + } else if(!strcmp(str, "cat")) { + Directory dir; + if(dir.open() && dir.next()) { + auto filename = dir.stat().name.c_str(); + Serial.printf("dumping file %s:\r\n", filename); + // We don't know how big the is, so streaming it is safest + FileStream fs; + fs.open(filename); + Serial.copyFrom(&fs); + Serial.println(); + } else { + Serial.println("Empty spiffs!"); + } + } else if(!strcmp(str, "info")) { + ShowInfo(); + } else if(!strcmp(str, "help")) { + Serial.println(); + Serial.println("available commands:"); + Serial.println(" help - display this message"); + Serial.println(" ip - show current ip address"); + Serial.println(" connect - connect to wifi"); + Serial.println(" restart - restart the esp8266"); + Serial.println(" switch - switch to the other rom and reboot"); + Serial.println(" ota - perform ota update, switch rom and reboot"); + Serial.println(" info - show esp8266 info"); + if(spiffsPartition) { + Serial.println(" ls - list files in spiffs"); + Serial.println(" cat - show first file in spiffs"); + } + Serial.println(); + } else { + Serial.println("unknown command"); + } + } +} + +void init() +{ + Serial.begin(SERIAL_BAUD_RATE); // 115200 by default + Serial.systemDebugOutput(true); // Debug output to serial + + // mount spiffs + auto partition = ota.getRunningPartition(); + spiffsPartition = findSpiffsPartition(partition.subType()); + if(spiffsPartition) { + debugf("trying to mount '%s' at 0x%08x, length %d", spiffsPartition.name().c_str(), spiffsPartition.address(), + spiffsPartition.size()); + spiffs_mount(spiffsPartition); + } + + WifiAccessPoint.enable(false); + + Serial.printf("\r\nCurrently running rom %s.\r\n", partition.name().c_str()); + Serial.println("Type 'help' and press enter for instructions."); + Serial.println(); + + Serial.onDataReceived(serialCallBack); +} diff --git a/samples/Basic_Ota/basic_rboot.hw b/samples/Basic_Ota/basic_rboot.hw new file mode 100644 index 0000000000..b558727f9c --- /dev/null +++ b/samples/Basic_Ota/basic_rboot.hw @@ -0,0 +1,22 @@ +{ + "name": "Two ROM slots, two SPIFFS", + "base_config": "spiffs", + "partitions": { + "rom0": { + "subtype": "ota_0" + }, + "rom1": { + "address": "0x108000", + "size": "992K", + "type": "app", + "subtype": "ota_1", + "filename": "$(RBOOT_ROM_1_BIN)" + }, + "spiffs1": { + "address": "0x300000", + "size": "512K", + "type": "data", + "subtype": "spiffs" + } + } +} diff --git a/samples/Basic_Ota/component.mk b/samples/Basic_Ota/component.mk new file mode 100644 index 0000000000..9555e50099 --- /dev/null +++ b/samples/Basic_Ota/component.mk @@ -0,0 +1,7 @@ +#### overridable rBoot options #### + +## use rboot build mode +RBOOT_ENABLED := 1 + +## Use standard hardware config with two ROM slots and two SPIFFS partitions +HWCONFIG := basic_rboot diff --git a/samples/Basic_Ota/files/testfile.txt b/samples/Basic_Ota/files/testfile.txt new file mode 100644 index 0000000000..f8b77180ca --- /dev/null +++ b/samples/Basic_Ota/files/testfile.txt @@ -0,0 +1,2 @@ +This line is the content of test file. + From a809eba55a14cceec8033f7c50937b383a962a9a Mon Sep 17 00:00:00 2001 From: Slavey Karadzhov Date: Thu, 20 May 2021 13:09:41 +0200 Subject: [PATCH 02/15] Better organization. --- Sming/Arch/Esp32/spiffs-two-roms.hw | 28 ++++++ Sming/Arch/Host/Core/Ota | 1 - Sming/Components/Ota/README.rst | 61 +++++++++++++ Sming/Components/Ota/component.mk | 16 ++++ .../Ota/src/Arch/Esp32}/IdfUpgrader.cpp | 12 +-- .../src/Arch/Esp32/include}/Ota/IdfUpgrader.h | 4 +- .../src/Arch/Esp32/include}/Ota/Upgrader.h | 0 .../Ota/src/Arch/Esp8266}/RbootUpgrader.cpp | 14 ++- .../Arch/Esp8266/include}/Ota/RbootUpgrader.h | 6 +- .../src/Arch/Esp8266/include}/Ota/Upgrader.h | 0 Sming/Components/Ota/src/Manager.cpp | 4 + .../Ota/src/UpgradeOutputStream.cpp | 61 +++++++++++++ .../Components/Ota/src/include/Ota/Manager.h | 7 ++ .../Ota/src/include/Ota/UpgradeOutputStream.h | 90 +++++++++++++++++++ .../Ota/src/include/Ota/UpgraderBase.h | 81 +++++++++++++++++ Sming/Core/Ota/UpgraderBase.h | 48 ---------- Sming/Libraries/OtaUpgradeMqtt/component.mk | 5 +- .../samples/Upgrade/app/application.cpp | 43 ++++----- .../samples/Upgrade/component.mk | 4 +- .../OtaUpgradeMqtt/samples/Upgrade/ota.hw | 11 +++ .../OtaUpgradeMqtt/src/RbootPayloadParser.cpp | 40 --------- .../src/StandardPayloadParser.cpp | 43 +++++++++ .../OtaUpgrade/Mqtt/RbootPayloadParser.h | 23 +---- .../OtaUpgrade/Mqtt/StandardPayloadParser.h | 43 +++++++++ 24 files changed, 483 insertions(+), 162 deletions(-) create mode 100644 Sming/Arch/Esp32/spiffs-two-roms.hw delete mode 120000 Sming/Arch/Host/Core/Ota create mode 100644 Sming/Components/Ota/README.rst create mode 100644 Sming/Components/Ota/component.mk rename Sming/{Arch/Esp32/Core/Ota => Components/Ota/src/Arch/Esp32}/IdfUpgrader.cpp (84%) rename Sming/{Arch/Esp32/Core => Components/Ota/src/Arch/Esp32/include}/Ota/IdfUpgrader.h (86%) rename Sming/{Arch/Esp32/Core => Components/Ota/src/Arch/Esp32/include}/Ota/Upgrader.h (100%) rename Sming/{Arch/Esp8266/Core/Ota => Components/Ota/src/Arch/Esp8266}/RbootUpgrader.cpp (84%) rename Sming/{Arch/Esp8266/Core => Components/Ota/src/Arch/Esp8266/include}/Ota/RbootUpgrader.h (83%) rename Sming/{Arch/Esp8266/Core => Components/Ota/src/Arch/Esp8266/include}/Ota/Upgrader.h (100%) create mode 100644 Sming/Components/Ota/src/Manager.cpp create mode 100644 Sming/Components/Ota/src/UpgradeOutputStream.cpp create mode 100644 Sming/Components/Ota/src/include/Ota/Manager.h create mode 100644 Sming/Components/Ota/src/include/Ota/UpgradeOutputStream.h create mode 100644 Sming/Components/Ota/src/include/Ota/UpgraderBase.h delete mode 100644 Sming/Core/Ota/UpgraderBase.h create mode 100644 Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/ota.hw delete mode 100644 Sming/Libraries/OtaUpgradeMqtt/src/RbootPayloadParser.cpp create mode 100644 Sming/Libraries/OtaUpgradeMqtt/src/StandardPayloadParser.cpp create mode 100644 Sming/Libraries/OtaUpgradeMqtt/src/include/OtaUpgrade/Mqtt/StandardPayloadParser.h diff --git a/Sming/Arch/Esp32/spiffs-two-roms.hw b/Sming/Arch/Esp32/spiffs-two-roms.hw new file mode 100644 index 0000000000..0b74136ba3 --- /dev/null +++ b/Sming/Arch/Esp32/spiffs-two-roms.hw @@ -0,0 +1,28 @@ +{ + "name": "Two ROM slots with single SPIFFS", + "base_config": "spiffs", + "partitions": { + "factory": { + "address": "0x10000", + "size": "1M" + }, + "rom0": { + "address": "0x110000", + "size": "960K", + "type": "app", + "subtype": "ota_0", + "filename": "$(TARGET_BIN)" + }, + "rom1": { + "address": "0x210000", + "size": "960K", + "type": "app", + "subtype": "ota_1", + "filename": "" + }, + "spiffs0": { + "address": "0x300000", + "size": "1M" + } + } +} \ No newline at end of file diff --git a/Sming/Arch/Host/Core/Ota b/Sming/Arch/Host/Core/Ota deleted file mode 120000 index 4af34ca608..0000000000 --- a/Sming/Arch/Host/Core/Ota +++ /dev/null @@ -1 +0,0 @@ -../../Esp8266/Core/Ota \ No newline at end of file diff --git a/Sming/Components/Ota/README.rst b/Sming/Components/Ota/README.rst new file mode 100644 index 0000000000..66e088b585 --- /dev/null +++ b/Sming/Components/Ota/README.rst @@ -0,0 +1,61 @@ +Over-The-Air(OTA) Upgrader +========================== + +.. highlight:: c++ + +Introduction +------------ + +This architecture-agnostic component adds support for Over-The-Air upgrades. + +Usaging +------- +1. Add ``COMPONENT_DEPENDS += Ota`` to your application componenent.mk file. +2. Add these lines to your application:: + + #include + +After that you will have access to a global ``OtaManager`` instance that can be used to manage your OTA upgrade process. + +3. You can use ``OtaManager`` to get information about the bootable partitions and update them. + The code below will display the current bootable and running partition:: + + void init() + { + + // ... + auto part = OtaManager.getRunningPartition(); + + Serial.printf(_F("\r\nCurrently running rom %s@%x.\r\n"), part.name(), part.address()); + + } + +4. If needed you can also create your own instance of the of OtaUpgrader as shown below:: + + + // Call when IP address has been obtained + void onIp(IpAddress ip, IpAddress mask, IpAddress gateway) + { + // ... + + OtaUpgrader ota; + + auto part = ota.getNextBootPartition(); + + ota.begin(part); + + // ... write all the data to the partition + + ota.end(); + + // ... + } + +See the :sample:`Upgrade` sample application. + +API Documentation +----------------- + +.. doxygennamespace:: Ota + :members: + diff --git a/Sming/Components/Ota/component.mk b/Sming/Components/Ota/component.mk new file mode 100644 index 0000000000..1303f4fdc5 --- /dev/null +++ b/Sming/Components/Ota/component.mk @@ -0,0 +1,16 @@ +COMPONENT_ARCH := $(SMING_ARCH) +ifeq ($(COMPONENT_ARCH),Host) + COMPONENT_ARCH := Esp8266 +endif + +COMPONENT_SRCDIRS := \ + src \ + src/Arch/$(COMPONENT_ARCH) + +COMPONENT_INCDIRS := \ + src/include \ + src/Arch/$(COMPONENT_ARCH)/include + +ifeq ($(COMPONENT_ARCH),Esp8266) + COMPONENT_DEPENDS += rboot +endif \ No newline at end of file diff --git a/Sming/Arch/Esp32/Core/Ota/IdfUpgrader.cpp b/Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp similarity index 84% rename from Sming/Arch/Esp32/Core/Ota/IdfUpgrader.cpp rename to Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp index be463807b6..3794af8c67 100644 --- a/Sming/Arch/Esp32/Core/Ota/IdfUpgrader.cpp +++ b/Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp @@ -8,19 +8,19 @@ * ****/ -#include "IdfUpgrader.h" +#include "include/Ota/IdfUpgrader.h" namespace Ota { -bool IdfUpgrader::begin(Storage::Partition partition, size_t maxSize) +bool IdfUpgrader::begin(Storage::Partition partition, size_t size) { - if(partition.size() < maxSize) { + if(partition.size() < size) { return false; // the requested size is too big... } writtenSoFar = 0; - esp_err_t result = esp_ota_begin(convertToIdfPartition(partition), maxSize ? maxSize : partition.size(), &handle); + esp_err_t result = esp_ota_begin(convertToIdfPartition(partition), size ? size : partition.size(), &handle); return result == ESP_OK; } @@ -68,7 +68,7 @@ Storage::Partition IdfUpgrader::getRunningPartition(void) return convertFromIdfPartition(esp_ota_get_running_partition()); } -Storage::Partition IdfUpgrader::getNextUpdatePartition(Storage::Partition* startFrom) +Storage::Partition IdfUpgrader::getNextBootPartition(Storage::Partition* startFrom) { return convertFromIdfPartition(esp_ota_get_next_update_partition(convertToIdfPartition(*startFrom))); } @@ -82,7 +82,7 @@ const esp_partition_t* IdfUpgrader::convertToIdfPartition(Storage::Partition par partition.name().c_str()); } -Storage::Partition convertFromIdfPartition(const esp_partition_t* partition) +Storage::Partition IdfUpgrader::convertFromIdfPartition(const esp_partition_t* partition) { String label; if(partition != nullptr) { diff --git a/Sming/Arch/Esp32/Core/Ota/IdfUpgrader.h b/Sming/Components/Ota/src/Arch/Esp32/include/Ota/IdfUpgrader.h similarity index 86% rename from Sming/Arch/Esp32/Core/Ota/IdfUpgrader.h rename to Sming/Components/Ota/src/Arch/Esp32/include/Ota/IdfUpgrader.h index 6e8f4dc00f..e0453b7cdd 100644 --- a/Sming/Arch/Esp32/Core/Ota/IdfUpgrader.h +++ b/Sming/Components/Ota/src/Arch/Esp32/include/Ota/IdfUpgrader.h @@ -22,7 +22,7 @@ class IdfUpgrader : public UpgraderBase /** * @brief Prepare the partition for */ - bool begin(Storage::Partition partition, size_t maxSize = 0) override; + bool begin(Storage::Partition partition, size_t size = 0) override; size_t write(const uint8_t* buffer, size_t size) override; bool end() override; bool abort() override; @@ -30,7 +30,7 @@ class IdfUpgrader : public UpgraderBase bool setBootPartition(Storage::Partition partition) override; Storage::Partition getBootPartition(void) override; Storage::Partition getRunningPartition(void) override; - Storage::Partition getNextUpdatePartition(Storage::Partition* startFrom = nullptr) override; + Storage::Partition getNextBootPartition(Storage::Partition* startFrom = nullptr) override; static const esp_partition_t* convertToIdfPartition(Storage::Partition partition); static Storage::Partition convertFromIdfPartition(const esp_partition_t* partition); diff --git a/Sming/Arch/Esp32/Core/Ota/Upgrader.h b/Sming/Components/Ota/src/Arch/Esp32/include/Ota/Upgrader.h similarity index 100% rename from Sming/Arch/Esp32/Core/Ota/Upgrader.h rename to Sming/Components/Ota/src/Arch/Esp32/include/Ota/Upgrader.h diff --git a/Sming/Arch/Esp8266/Core/Ota/RbootUpgrader.cpp b/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp similarity index 84% rename from Sming/Arch/Esp8266/Core/Ota/RbootUpgrader.cpp rename to Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp index d324912c0c..3fd5721843 100644 --- a/Sming/Arch/Esp8266/Core/Ota/RbootUpgrader.cpp +++ b/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp @@ -8,23 +8,19 @@ * ****/ -#include "RbootUpgrader.h" +#include "include/Ota/RbootUpgrader.h" namespace Ota { -bool RbootUpgrader::begin(Storage::Partition partition, size_t maxSize) +bool RbootUpgrader::begin(Storage::Partition partition, size_t size) { - if(partition.size() < maxSize) { + if(partition.size() < size) { return false; // the requested size is too big... } status = rboot_write_init(partition.address()); - if(maxSize) { - this->maxSize = maxSize; - } else { - this->maxSize = partition.size(); - } + maxSize = (size ? size : partition.size()); writtenSoFar = 0; @@ -69,7 +65,7 @@ Storage::Partition RbootUpgrader::getRunningPartition(void) return getPartitionForSlot(rboot_get_current_rom()); } -Storage::Partition RbootUpgrader::getNextUpdatePartition(Storage::Partition* startFrom) +Storage::Partition RbootUpgrader::getNextBootPartition(Storage::Partition* startFrom) { uint8_t currentSlot = rboot_get_current_rom(); return getPartitionForSlot(currentSlot ? 0 : 1); diff --git a/Sming/Arch/Esp8266/Core/Ota/RbootUpgrader.h b/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h similarity index 83% rename from Sming/Arch/Esp8266/Core/Ota/RbootUpgrader.h rename to Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h index ec607b0129..6f6a4e646c 100644 --- a/Sming/Arch/Esp8266/Core/Ota/RbootUpgrader.h +++ b/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h @@ -22,14 +22,14 @@ class RbootUpgrader : public UpgraderBase /** * @brief Prepare the partition for */ - bool begin(Storage::Partition partition, size_t maxSize = 0) override; + bool begin(Storage::Partition partition, size_t size = 0) override; size_t write(const uint8_t* buffer, size_t size) override; bool end() override; bool setBootPartition(Storage::Partition partition) override; Storage::Partition getBootPartition(void) override; Storage::Partition getRunningPartition(void) override; - Storage::Partition getNextUpdatePartition(Storage::Partition* startFrom = nullptr) override; + Storage::Partition getNextBootPartition(Storage::Partition* startFrom = nullptr) override; static uint8_t getSlotForPartition(Storage::Partition partition); static Storage::Partition getPartitionForSlot(uint8_t slot); @@ -40,6 +40,4 @@ class RbootUpgrader : public UpgraderBase size_t writtenSoFar{0}; }; -using OtaUpgrader = RbootUpgrader; - } // namespace Ota diff --git a/Sming/Arch/Esp8266/Core/Ota/Upgrader.h b/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/Upgrader.h similarity index 100% rename from Sming/Arch/Esp8266/Core/Ota/Upgrader.h rename to Sming/Components/Ota/src/Arch/Esp8266/include/Ota/Upgrader.h diff --git a/Sming/Components/Ota/src/Manager.cpp b/Sming/Components/Ota/src/Manager.cpp new file mode 100644 index 0000000000..d04ade81d3 --- /dev/null +++ b/Sming/Components/Ota/src/Manager.cpp @@ -0,0 +1,4 @@ +#include "include/Ota/Manager.h" + +/* Global Instance of the OtaManager */ +OtaUpgrader OtaManager; diff --git a/Sming/Components/Ota/src/UpgradeOutputStream.cpp b/Sming/Components/Ota/src/UpgradeOutputStream.cpp new file mode 100644 index 0000000000..43be0bf085 --- /dev/null +++ b/Sming/Components/Ota/src/UpgradeOutputStream.cpp @@ -0,0 +1,61 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * UpgradeOutputStream.cpp + * + * + */ + +#include "include/Ota/UpgradeOutputStream.h" + +namespace Ota +{ + +bool UpgradeOutputStream::init() +{ + bool success = ota.begin(partition, maxLength); + initialized = true; + + return success; +} + +size_t UpgradeOutputStream::write(const uint8_t* data, size_t size) +{ + if(!initialized && size > 0) { + if(!init()) { // unable to initialize + return 0; + } + + initialized = true; + } + + if(written + size > maxLength) { + debug_e("The ROM size is bigger than the maximum allowed"); + return 0; + } + + if(!ota.write(data, size)) { + debug_e("ota_write_flash: Failed. Size: %d", size); + return 0; + } + + written += size; + + debug_d("ota_write_flash: item.size: %d", written); + + return size; +} + +bool UpgradeOutputStream::close() +{ + if(initialized) { + return ota.end(); + } + + return true; +} + +} // namespace Ota diff --git a/Sming/Components/Ota/src/include/Ota/Manager.h b/Sming/Components/Ota/src/include/Ota/Manager.h new file mode 100644 index 0000000000..9e6c1f4114 --- /dev/null +++ b/Sming/Components/Ota/src/include/Ota/Manager.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +/** @brief Global instance of Over-The-Air manager +*/ +extern OtaUpgrader OtaManager; diff --git a/Sming/Components/Ota/src/include/Ota/UpgradeOutputStream.h b/Sming/Components/Ota/src/include/Ota/UpgradeOutputStream.h new file mode 100644 index 0000000000..23154def03 --- /dev/null +++ b/Sming/Components/Ota/src/include/Ota/UpgradeOutputStream.h @@ -0,0 +1,90 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * UpgradeOutputStream.h + * + * +*/ + +#pragma once + +#include +#include +#include + +namespace Ota +{ + +/** + * @brief Write-only stream type used during firmware upgrade + */ +class UpgradeOutputStream : public ReadWriteStream +{ +public: + /** + * @brief Construct a stream for the given partition + * @param partition + */ + UpgradeOutputStream(Storage::Partition partition, size_t maxLength = 0) : partition(partition), maxLength(maxLength !=0 ? std::min(maxLength, partition.size()) : partition.size()) + { + } + + virtual ~UpgradeOutputStream() + { + close(); + } + + size_t write(const uint8_t* data, size_t size) override; + + StreamType getStreamType() const override + { + return eSST_File; + } + + uint16_t readMemoryBlock(char* data, int bufSize) override + { + return 0; + } + + bool seek(int len) override + { + return false; + } + + int available() override + { + return written; + } + + bool isFinished() override + { + return true; + } + + virtual bool close(); + + size_t getStartAddress() const + { + return partition.address(); + } + + size_t getMaxLength() const + { + return maxLength; + } + +protected: + OtaUpgrader ota; + Storage::Partition partition; + bool initialized{false}; + size_t written{0}; // << the number of written bytes + size_t maxLength{0}; // << maximum allowed length + +protected: + virtual bool init(); +}; + +} // namespace Ota diff --git a/Sming/Components/Ota/src/include/Ota/UpgraderBase.h b/Sming/Components/Ota/src/include/Ota/UpgraderBase.h new file mode 100644 index 0000000000..cfc8e4eef6 --- /dev/null +++ b/Sming/Components/Ota/src/include/Ota/UpgraderBase.h @@ -0,0 +1,81 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * Ota.h + * + * This header includes all unified Over-The-Air functions. + * +*/ + +#pragma once +#include + +namespace Ota +{ + +class UpgraderBase +{ +public: + virtual ~UpgraderBase() + { + } + + /** + * @brief Prepares a partition for an upgrade. + * The preparation is bootloader and architecture dependant. + */ + virtual bool begin(Storage::Partition partition, size_t size) = 0; + + /** + * @brief Writes chunk of data to the partition set in ``begin()``. + */ + virtual size_t write(const uint8_t* buffer, size_t size) = 0; + + /** + * @brief Finilizes the partition upgrade. + */ + virtual bool end() = 0; + + /** + * @brief Aborts a partition upgrade + */ + virtual bool abort() + { + return false; + } + + /** + * @brief Sets the default parition from where the application will be booted on next restart. + */ + virtual bool setBootPartition(Storage::Partition partition) = 0; + + /** + * @brief Gets information about the parition that is set as the default one to boot. + * @note The returned parition can be different than the current running partition. + */ + virtual Storage::Partition getBootPartition(void) = 0; + + /** + * @brief Gets information about the parition from which the current application is running. + * @note The returned parition can be different than the default boot partition. + */ + virtual Storage::Partition getRunningPartition(void) = 0; + + /** + * @brief Gets the next bootable partition that can be used after successful OTA upgrade + */ + virtual Storage::Partition getNextBootPartition(Storage::Partition* startFrom = nullptr) = 0; + + /** + * @brief Gets information about all bootable partitions. + */ + Storage::Iterator getBootPartitions() + { + return Storage::findPartition(Storage::Partition::Type::app); + } +}; + +} // namespace Ota diff --git a/Sming/Core/Ota/UpgraderBase.h b/Sming/Core/Ota/UpgraderBase.h deleted file mode 100644 index 5bd682a87a..0000000000 --- a/Sming/Core/Ota/UpgraderBase.h +++ /dev/null @@ -1,48 +0,0 @@ -/**** - * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. - * Created 2015 by Skurydin Alexey - * http://github.com/SmingHub/Sming - * All files of the Sming Core are provided under the LGPL v3 license. - * - * Ota.h - * - * This header includes all unified Over-The-Air functions. - * -*/ - -#pragma once -#include - -namespace Ota -{ -class UpgraderBase -{ -public: - virtual ~UpgraderBase() - { - } - - /** - * @brief Prepare the partition for - */ - virtual bool begin(Storage::Partition partition, size_t size) = 0; - virtual size_t write(const uint8_t* buffer, size_t size) = 0; - virtual bool seek(int len) - { - return false; - } - - virtual bool end() = 0; - - virtual bool abort() - { - return false; - } - - virtual bool setBootPartition(Storage::Partition partition) = 0; - virtual Storage::Partition getBootPartition(void) = 0; - virtual Storage::Partition getRunningPartition(void) = 0; - virtual Storage::Partition getNextUpdatePartition(Storage::Partition* startFrom = nullptr) = 0; -}; - -} // namespace Ota diff --git a/Sming/Libraries/OtaUpgradeMqtt/component.mk b/Sming/Libraries/OtaUpgradeMqtt/component.mk index 7896ab0797..505288b2af 100644 --- a/Sming/Libraries/OtaUpgradeMqtt/component.mk +++ b/Sming/Libraries/OtaUpgradeMqtt/component.mk @@ -1,14 +1,15 @@ COMPONENT_SRCDIRS := -COMPONENT_SRCFILES := src/PayloadParser.cpp src/RbootPayloadParser.cpp +COMPONENT_SRCFILES := src/PayloadParser.cpp src/StandardPayloadParser.cpp COMPONENT_INCDIRS := src/include # If enabled (set to 1) then we can use all sofisticated mechanisms to upgrade the firmware using the ``OtaUpgrade`` library. COMPONENT_VARS := ENABLE_OTA_ADVANCED ENABLE_OTA_ADVANCED ?= 0 +COMPONENT_DEPENDS := Ota ifneq ($(ENABLE_OTA_ADVANCED),0) COMPONENT_SRCFILES += src/AdvancedPayloadParser.cpp - COMPONENT_DEPENDS := OtaUpgrade + COMPONENT_DEPENDS += OtaUpgrade endif # If enabled (set to 1) then we can use unlimited number of patch versions diff --git a/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/app/application.cpp b/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/app/application.cpp index d93860fc1a..2581680437 100644 --- a/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/app/application.cpp +++ b/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/app/application.cpp @@ -1,7 +1,7 @@ #include -#include #include -#include +#include +#include #if ENABLE_OTA_ADVANCED #include @@ -28,15 +28,6 @@ IMPORT_FSTR(privateKeyData, PROJECT_DIR "/files/private.pem.key.der"); IMPORT_FSTR(certificateData, PROJECT_DIR "/files/certificate.pem.crt.der"); #endif -Storage::Partition findRomPartition(uint8_t slot) -{ - auto part = Storage::spiFlash->partitions().findOta(slot); - if(!part) { - debug_w("Rom slot %d not found", slot); - } - return part; -} - void otaUpdate() { if(mqtt.isProcessing()) { @@ -44,16 +35,9 @@ void otaUpdate() return; } - uint8 slot = rboot_get_current_rom(); - if(slot == 0) { - slot = 1; - } else { - slot = 0; - } - Serial.println("Checking for a new application firmware..."); - auto part = findRomPartition(slot); + auto part = OtaManager.getBootPartition(); if(!part) { Serial.println("FAILED: Cannot find application address"); return; @@ -92,7 +76,7 @@ void otaUpdate() * The command below uses class that stores the firmware directly * using RbootOutputStream on a location provided by us */ - auto parser = new OtaUpgrade::Mqtt::RbootPayloadParser(part, APP_VERSION_PATCH); + auto parser = new OtaUpgrade::Mqtt::StandardPayloadParser(part, APP_VERSION_PATCH); #endif mqtt.setPayloadParser([parser](MqttPayloadParserState& state, mqtt_message_t* message, const char* buffer, @@ -113,15 +97,20 @@ void showInfo() Serial.printf(_F("CPU Frequency: %d MHz\r\n"), system_get_cpu_freq()); Serial.printf(_F("System Chip ID: %x\r\n"), system_get_chip_id()); - rboot_config conf = rboot_get_config(); + int total = 0; + for(auto it = OtaManager.getBootPartitions(); it; ++it) { + auto part = *it; + debug_d("ROM %s: 0x%08x, SubType: %s", part.name(), part.address(), + toLongString(part.type(), part.subType()).c_str()); + total++; + } + debug_d("======================="); + debug_d("Bootable ROMs found: %d", total); - debug_d("Count: %d", conf.count); - debug_d("ROM 0: 0x%08x", conf.roms[0]); - debug_d("ROM 1: 0x%08x", conf.roms[1]); - debug_d("ROM 2: 0x%08x", conf.roms[2]); - debug_d("GPIO ROM: %d", conf.gpio_rom); + auto part = OtaManager.getRunningPartition(); - Serial.printf(_F("\r\nCurrently running rom %d. Application version: %s\r\n"), conf.current_rom, APP_VERSION); + Serial.printf(_F("\r\nCurrently running %s: 0x%08x. Application version: %s\r\n"), part.name(), part.address(), + APP_VERSION); Serial.println(); } diff --git a/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/component.mk b/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/component.mk index 806c2b46b6..cb3b098df4 100644 --- a/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/component.mk +++ b/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/component.mk @@ -48,7 +48,7 @@ COMPONENT_DEPENDS := OtaUpgradeMqtt RBOOT_ENABLED := 1 ## Use standard hardware config with two ROM slots and two SPIFFS partitions -HWCONFIG := spiffs-two-roms +HWCONFIG := ota APP_CFLAGS = -DMQTT_URL="\"$(MQTT_URL)"\" \ -DMQTT_FINGERPRINT_SHA1=$(MQTT_FINGERPRINT_SHA1) \ @@ -59,4 +59,4 @@ APP_CFLAGS = -DMQTT_URL="\"$(MQTT_URL)"\" \ ifneq ($(APP_VERSION),) APP_CFLAGS += -DAPP_VERSION="\"$(APP_VERSION)"\" \ -DAPP_VERSION_PATCH=$(APP_VERSION_PATCH) -endif \ No newline at end of file +endif diff --git a/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/ota.hw b/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/ota.hw new file mode 100644 index 0000000000..aceea30053 --- /dev/null +++ b/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/ota.hw @@ -0,0 +1,11 @@ +{ + "base_config": "spiffs-two-roms", + "partitions": { + "rom0": { + "subtype": "ota_0" + }, + "rom1": { + "subtype": "ota_1" + } + } +} \ No newline at end of file diff --git a/Sming/Libraries/OtaUpgradeMqtt/src/RbootPayloadParser.cpp b/Sming/Libraries/OtaUpgradeMqtt/src/RbootPayloadParser.cpp deleted file mode 100644 index b18a8fb151..0000000000 --- a/Sming/Libraries/OtaUpgradeMqtt/src/RbootPayloadParser.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/**** - * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. - * Created 2015 by Skurydin Alexey - * http://github.com/SmingHub/Sming - * All files of the Sming Core are provided under the LGPL v3 license. - * - * RbootPayloadParser.cpp - * - * Created: 2021 - Slavey Karadzhov - * - ****/ - -#include "include/OtaUpgrade/Mqtt/RbootPayloadParser.h" - -namespace OtaUpgrade -{ -namespace Mqtt -{ -bool RbootPayloadParser::switchRom(const UpdateState& updateState) -{ - uint8_t before = rboot_get_current_rom(); - uint8_t after = (before == 0) ? 1 : 0; - - debug_d("Swapping from rom %u to rom %u.\r\n", before, after); - - return rboot_set_current_rom(after); -} - -ReadWriteStream* RbootPayloadParser::getStorageStream(size_t storageSize) -{ - if(storageSize > part.size()) { - debug_e("The new rom is too big to fit!"); - return nullptr; - } - - return new RbootOutputStream(part.address(), part.size()); -} - -} // namespace Mqtt -} // namespace OtaUpgrade diff --git a/Sming/Libraries/OtaUpgradeMqtt/src/StandardPayloadParser.cpp b/Sming/Libraries/OtaUpgradeMqtt/src/StandardPayloadParser.cpp new file mode 100644 index 0000000000..af4445326c --- /dev/null +++ b/Sming/Libraries/OtaUpgradeMqtt/src/StandardPayloadParser.cpp @@ -0,0 +1,43 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * StandardPayloadParser.cpp + * + * Created: 2021 - Slavey Karadzhov + * + ****/ + +#include "include/OtaUpgrade/Mqtt/StandardPayloadParser.h" +#include +#include + +namespace OtaUpgrade +{ +namespace Mqtt +{ +bool StandardPayloadParser::switchRom(const UpdateState& updateState) +{ + auto before = OtaManager.getBootPartition(); + auto after = OtaManager.getNextBootPartition(); + + debug_d("Swapping from rom %s@%x to rom %s@%s.\r\n", before.name(), before.address(), after.name(), + after.address()); + + return OtaManager.setBootPartition(after); +} + +ReadWriteStream* StandardPayloadParser::getStorageStream(size_t storageSize) +{ + if(storageSize > part.size()) { + debug_e("The new rom is too big to fit!"); + return nullptr; + } + + return new Ota::UpgradeOutputStream(part, storageSize); +} + +} // namespace Mqtt +} // namespace OtaUpgrade diff --git a/Sming/Libraries/OtaUpgradeMqtt/src/include/OtaUpgrade/Mqtt/RbootPayloadParser.h b/Sming/Libraries/OtaUpgradeMqtt/src/include/OtaUpgrade/Mqtt/RbootPayloadParser.h index 68e87dd53a..f390c7b6a4 100644 --- a/Sming/Libraries/OtaUpgradeMqtt/src/include/OtaUpgrade/Mqtt/RbootPayloadParser.h +++ b/Sming/Libraries/OtaUpgradeMqtt/src/include/OtaUpgrade/Mqtt/RbootPayloadParser.h @@ -12,32 +12,13 @@ #pragma once -#include "PayloadParser.h" -#include +#include "StandardPayloadParser.h" namespace OtaUpgrade { namespace Mqtt { -/** - * @brief This parser allows the processing of firmware data that is directly stored - * to the flash memory using RbootOutputStream. - */ -class RbootPayloadParser : public PayloadParser -{ -public: - RbootPayloadParser(Storage::Partition part, size_t currentVersion, size_t allowedVersionBytes = 24) - : PayloadParser(currentVersion, allowedVersionBytes), part(part) - { - } - - bool switchRom(const UpdateState& updateState) override; - - ReadWriteStream* getStorageStream(size_t storageSize) override; - -private: - Storage::Partition part; -}; +using RbootPayloadParser = StandardPayloadParser SMING_DEPRECATED; } // namespace Mqtt } // namespace OtaUpgrade diff --git a/Sming/Libraries/OtaUpgradeMqtt/src/include/OtaUpgrade/Mqtt/StandardPayloadParser.h b/Sming/Libraries/OtaUpgradeMqtt/src/include/OtaUpgrade/Mqtt/StandardPayloadParser.h new file mode 100644 index 0000000000..68e9083766 --- /dev/null +++ b/Sming/Libraries/OtaUpgradeMqtt/src/include/OtaUpgrade/Mqtt/StandardPayloadParser.h @@ -0,0 +1,43 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * RbootPayloadParser.h + * + * Created: 2021 - Slavey Karadzhov + * + ****/ + +#pragma once + +#include "PayloadParser.h" +#include + +namespace OtaUpgrade +{ +namespace Mqtt +{ +/** + * @brief This parser allows the processing of firmware data that is directly stored + * to the flash memory using RbootOutputStream. + */ +class StandardPayloadParser : public PayloadParser +{ +public: + StandardPayloadParser(Storage::Partition part, size_t currentVersion, size_t allowedVersionBytes = 24) + : PayloadParser(currentVersion, allowedVersionBytes), part(part) + { + } + + bool switchRom(const UpdateState& updateState) override; + + ReadWriteStream* getStorageStream(size_t storageSize) override; + +private: + Storage::Partition part; +}; + +} // namespace Mqtt +} // namespace OtaUpgrade From 6953930ab5fc68b87045d6f63f3e20ef8439814e Mon Sep 17 00:00:00 2001 From: Slavey Karadzhov Date: Thu, 20 May 2021 15:43:09 +0200 Subject: [PATCH 03/15] Make the OtaUpgrade library architecture-agnostic. --- .../OtaUpgrade/OtaUpgrade/BasicStream.cpp | 28 +++++++---------- .../OtaUpgrade/OtaUpgrade/BasicStream.h | 31 +++++++++---------- Sming/Libraries/OtaUpgrade/component.mk | 2 +- 3 files changed, 27 insertions(+), 34 deletions(-) diff --git a/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.cpp b/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.cpp index af28c04518..837db4a234 100644 --- a/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.cpp +++ b/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.cpp @@ -10,7 +10,6 @@ #include "BasicStream.h" #include -#include #include #include #include @@ -27,14 +26,8 @@ DECLARE_FSTR_ARRAY(AppFlashRegionOffsets, uint32_t); BasicStream::Slot::Slot() { - // Get parameters of the slot where the firmware image should be stored. - uint8_t currentSlot = rboot_get_current_rom(); - index = (currentSlot == 0) ? 1 : 0; - // Lookup slot details from partition table - auto part = Storage::spiFlash->partitions().findOta(index); - address = part.address(); - size = part.size(); + partition = OtaManager.getNextBootPartition(); } BasicStream::BasicStream() @@ -85,11 +78,12 @@ void BasicStream::nextRom() void BasicStream::processRomHeader() { - bool addressMatch = (slot.address & 0xFFFFF) == (romHeader.address & 0xFFFFF); + bool addressMatch = (slot.partition.address() & 0xFFFFF) == (romHeader.address & 0xFFFFF); if(!slot.updated && addressMatch) { - if(romHeader.size <= slot.size) { - debug_i("Update slot %u [0x%08X..0x%08X)", slot.index, slot.address, slot.address + romHeader.size); - rbootWriteStatus = rboot_write_init(slot.address); + if(romHeader.size <= slot.partition.size()) { + debug_i("Update slot %s [0x%08X..0x%08X)", slot.partition.name(), slot.partition.address(), + slot.partition.address() + romHeader.size); + ota.begin(slot.partition); setupChunk(State::WriteRom, romHeader.size); } else { setError(Error::RomTooLarge); @@ -110,7 +104,7 @@ void BasicStream::verifyRoms() if(!verifier.verify(verificationData)) { if(slot.updated) { // Destroy start sector of updated ROM to avoid accidentally booting an unsanctioned firmware - flashmem_erase_sector(slot.address / SECTOR_SIZE); + Storage::spiFlash->erase_range(slot.partition.address(), 1); } setError(Error::VerificationFailed); return; @@ -127,8 +121,8 @@ void BasicStream::verifyRoms() return; } - if(rboot_set_current_rom(slot.index)) { - debug_i("ROM %u activated", slot.index); + if(ota.setBootPartition(slot.partition)) { + debug_i("ROM %u activated", toLongString(slot.partition.type(), slot.partition.subType()).c_str()); } else { setError(Error::RomActivationFailed); } @@ -169,10 +163,10 @@ size_t BasicStream::write(const uint8_t* data, size_t size) break; case State::WriteRom: { - bool ok = rboot_write_flash(&rbootWriteStatus, data, std::min(remainingBytes, size)); + bool ok = ota.write(data, std::min(remainingBytes, size)); if(ok) { if(consume(data, size)) { - ok = slot.updated = rboot_write_end(&rbootWriteStatus); + ok = slot.updated = ota.end(); nextRom(); } } diff --git a/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.h b/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.h index 303431caae..aaa96251bc 100644 --- a/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.h +++ b/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.h @@ -11,7 +11,8 @@ #pragma once #include -#include +#include +#include #include "FileFormat.h" #ifdef ENABLE_OTA_SIGNING #include "SignatureVerifier.h" @@ -24,20 +25,20 @@ namespace OtaUpgrade /** * @brief A write-only stream to parse and apply firmware unencrypted upgrade files generated by otatool.py * - * The class fully automates the firmware upgrade process without any manual - * configuration. At construction time, the rBoot configuration is read to determine + * The class fully automates the firmware upgrade process without any manual + * configuration. At construction time, the rBoot configuration is read to determine * the unused ROM slot which should receive the upgrade. - * Just feed the upgrade file content into the `write()` method in arbitrarily - * sized chunks. The relevant portion(s) of the Flash memory (currently only the + * Just feed the upgrade file content into the `write()` method in arbitrarily + * sized chunks. The relevant portion(s) of the Flash memory (currently only the * application rom) are updated on the fly as data arrives. When the file is complete * and signature validation (if enabled) was successful, the updated slot is activated * in the rBoot configuration. - * Call `hasError()` and/or check the public \c #errorCode member to determine if + * Call `hasError()` and/or check the public \c #errorCode member to determine if * everything went smoothly. - * - * For further information on configuration options and the file format, + * + * For further information on configuration options and the file format, * refer to the library's documentation. - * + * * @see `EncryptedStream` for encryption support. */ class BasicStream : public ReadWriteStream @@ -111,15 +112,13 @@ class BasicStream : public ReadWriteStream /** Determine the parameters of the slot to receive the upgrade. */ Slot(); - uint32_t address; - uint32_t size; - uint8_t index; + Storage::Partition partition; 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{}; + OtaUpgrader ota; enum class State { Error, @@ -165,16 +164,16 @@ class BasicStream : public ReadWriteStream * It "consumes" as much bytes as possible for completing the current chunk (file header, signature, etc.) and * updates \a data and \a size accordingly. Depending on `state`, this method also writes to flash memory and * performs incremental checksum/signature calculation. - * @return `true` if the current chunk is complete and ready for processing. + * @return `true` if the current chunk is complete and ready for processing. * It is the caller's responsibility to setup a new chunk, advance the state machine, etc. */ bool consume(const uint8_t*& data, size_t& size); - /** Called after completion of a single ROM image. + /** Called after completion of a single ROM image. * Sets up reception of next ROM image or the checksum/signature if this was the laste ROM image. */ void nextRom(); - /** Called after reception of an #OTA_RomHeader. + /** Called after reception of an #OTA_RomHeader. * Decides if the ROM fits the selected upgrade slot or must be ignored. */ void processRomHeader(); diff --git a/Sming/Libraries/OtaUpgrade/component.mk b/Sming/Libraries/OtaUpgrade/component.mk index d19bec3b07..50bc8e66bc 100644 --- a/Sming/Libraries/OtaUpgrade/component.mk +++ b/Sming/Libraries/OtaUpgrade/component.mk @@ -1,7 +1,7 @@ COMPONENT_SRCDIRS := COMPONENT_SRCFILES := OtaUpgrade/BasicStream.cpp COMPONENT_APPCODE := appcode -COMPONENT_DEPENDS := +COMPONENT_DEPENDS := Ota COMPONENT_INCDIRS := . From f38edaab71511d9bdac184daaf984230dba9b2a8 Mon Sep 17 00:00:00 2001 From: Slavey Karadzhov Date: Thu, 20 May 2021 18:02:38 +0200 Subject: [PATCH 04/15] Unified Basic_Ota example. Tested on: - [x] Host (on Linux) - [ ] real Esp8266 device - [ ] real Esp32 device --- README.md | 39 +-- .../Ota/src/include/Ota/UpgraderBase.h | 12 + Sming/Components/OtaNetwork/README.rst | 61 +++++ Sming/Components/OtaNetwork/component.mk | 4 + .../OtaNetwork/src/HttpUpgrader.cpp | 128 ++++++++++ .../src/include/Ota/Network/HttpUpgrader.h | 160 +++++++++++++ .../OtaUpgrade/Mqtt/RbootPayloadParser.h | 1 + .../OtaUpgrade/Mqtt/StandardPayloadParser.h | 2 +- samples/Basic_Ota/README.rst | 90 ++++--- samples/Basic_Ota/app/application.cpp | 53 ++--- samples/Basic_Ota/basic_rboot.hw | 22 -- samples/Basic_Ota/component.mk | 26 +- samples/Basic_Ota/ota.hw | 11 + samples/Basic_rBoot/.cproject | 151 ------------ samples/Basic_rBoot/.project | 28 --- samples/Basic_rBoot/Makefile | 9 - samples/Basic_rBoot/README.rst | 83 ------- samples/Basic_rBoot/app/application.cpp | 224 ------------------ samples/Basic_rBoot/basic_rboot.hw | 22 -- samples/Basic_rBoot/component.mk | 7 - samples/Basic_rBoot/files/testfile.txt | 2 - 21 files changed, 488 insertions(+), 647 deletions(-) create mode 100644 Sming/Components/OtaNetwork/README.rst create mode 100644 Sming/Components/OtaNetwork/component.mk create mode 100644 Sming/Components/OtaNetwork/src/HttpUpgrader.cpp create mode 100644 Sming/Components/OtaNetwork/src/include/Ota/Network/HttpUpgrader.h delete mode 100644 samples/Basic_Ota/basic_rboot.hw create mode 100644 samples/Basic_Ota/ota.hw delete mode 100644 samples/Basic_rBoot/.cproject delete mode 100644 samples/Basic_rBoot/.project delete mode 100644 samples/Basic_rBoot/Makefile delete mode 100644 samples/Basic_rBoot/README.rst delete mode 100644 samples/Basic_rBoot/app/application.cpp delete mode 100644 samples/Basic_rBoot/basic_rboot.hw delete mode 100644 samples/Basic_rBoot/component.mk delete mode 100644 samples/Basic_rBoot/files/testfile.txt diff --git a/README.md b/README.md index 102408e219..6d5c61f120 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Table of Contents * [Connect to WiFi](#connect-to-wifi) * [Read DHT22 sensor](#read-dht22-sensor) * [HTTP Client](#http-client) - * [OTA Application Update Based on rBoot](#ota-application-update-based-on-rboot) + * [OTA Application Update](#ota-application-update) * [HTTP Server](#http-server) * [Email Client](#email-client) * [Live Debugging](#live-debugging) @@ -161,7 +161,7 @@ And check some of the examples. - [Connect to WiFi](#connect-to-wifi) - [Read DHT22 sensor](#read-dht22-sensor) - [HTTP Client](#http-client) -- [OTA Application Update Based on rBoot](#ota-application-update-based-on-rboot) +- [OTA Application Update](#ota-application-update) - [HTTP Server](#http-server) - [Email Client](#email-client) @@ -236,34 +236,21 @@ void onDataSent(HttpClient& client, bool successful) For more examples take a look at the [HttpClient](samples/HttpClient/app/application.cpp), [HttpClient_Instapush](samples/HttpClient_Instapush/app/application.cpp) and [HttpClient_ThingSpeak](samples/HttpClient_ThingSpeak/app/application.cpp) samples. -### OTA Application Update Based on rBoot +### OTA Application Update ```c++ void OtaUpdate() { -  uint8 slot; -  rboot_config bootconf; + // need a clean object, otherwise if run before and failed will not run again + if(otaUpdater) { + delete otaUpdater; + } + otaUpdater = new Ota::Network::HttpUpgrader(); -  Serial.println("Updating..."); + // select rom partition to flash + auto part = ota.getNextBootPartition(); -  // need a clean object, otherwise if run before and failed will not run again -  if (otaUpdater) { -    delete otaUpdater; -  } - -  otaUpdater = new RbootHttpUpdater(); - -  // select rom slot to flash -  bootconf = rboot_get_config(); -  slot = bootconf.current_rom; -  if (slot == 0) { -    slot = 1; -  } -  else { -    slot = 0; -  } - -  // flash rom to position indicated in the rBoot config rom table -  otaUpdater->addItem(bootconf.roms[slot], ROM_0_URL); +  // The content located on ROM_0_URL will be stored to the new partition +  otaUpdater->addItem(ROM_0_URL, part);   // and/or set a callback (called on failure or success without switching requested)   otaUpdater->setCallback(OtaUpdate_CallBack); @@ -273,7 +260,7 @@ void OtaUpdate() } ``` -For a complete example take a look at the [Basic_rBoot](samples/Basic_rBoot/app/application.cpp) sample. +For a complete example take a look at the [Basic_Ota](samples/Basic_Ota/app/application.cpp) sample. ### HTTP Server ```c++ diff --git a/Sming/Components/Ota/src/include/Ota/UpgraderBase.h b/Sming/Components/Ota/src/include/Ota/UpgraderBase.h index cfc8e4eef6..eef0b13d73 100644 --- a/Sming/Components/Ota/src/include/Ota/UpgraderBase.h +++ b/Sming/Components/Ota/src/include/Ota/UpgraderBase.h @@ -76,6 +76,18 @@ class UpgraderBase { return Storage::findPartition(Storage::Partition::Type::app); } + + // utility functions + + uint8_t getSlot(Storage::Partition partition) + { + auto s = toString(partition.type(), partition.subType()); + if(!s.startsWith("app/ota")) { + return 255; + } + + return s.substring(7).toInt(); + } }; } // namespace Ota diff --git a/Sming/Components/OtaNetwork/README.rst b/Sming/Components/OtaNetwork/README.rst new file mode 100644 index 0000000000..66e088b585 --- /dev/null +++ b/Sming/Components/OtaNetwork/README.rst @@ -0,0 +1,61 @@ +Over-The-Air(OTA) Upgrader +========================== + +.. highlight:: c++ + +Introduction +------------ + +This architecture-agnostic component adds support for Over-The-Air upgrades. + +Usaging +------- +1. Add ``COMPONENT_DEPENDS += Ota`` to your application componenent.mk file. +2. Add these lines to your application:: + + #include + +After that you will have access to a global ``OtaManager`` instance that can be used to manage your OTA upgrade process. + +3. You can use ``OtaManager`` to get information about the bootable partitions and update them. + The code below will display the current bootable and running partition:: + + void init() + { + + // ... + auto part = OtaManager.getRunningPartition(); + + Serial.printf(_F("\r\nCurrently running rom %s@%x.\r\n"), part.name(), part.address()); + + } + +4. If needed you can also create your own instance of the of OtaUpgrader as shown below:: + + + // Call when IP address has been obtained + void onIp(IpAddress ip, IpAddress mask, IpAddress gateway) + { + // ... + + OtaUpgrader ota; + + auto part = ota.getNextBootPartition(); + + ota.begin(part); + + // ... write all the data to the partition + + ota.end(); + + // ... + } + +See the :sample:`Upgrade` sample application. + +API Documentation +----------------- + +.. doxygennamespace:: Ota + :members: + diff --git a/Sming/Components/OtaNetwork/component.mk b/Sming/Components/OtaNetwork/component.mk new file mode 100644 index 0000000000..176580747f --- /dev/null +++ b/Sming/Components/OtaNetwork/component.mk @@ -0,0 +1,4 @@ +COMPONENT_SRCDIRS := src +COMPONENT_INCDIRS := src/include +COMPONENT_DEPENDS := Ota Network + diff --git a/Sming/Components/OtaNetwork/src/HttpUpgrader.cpp b/Sming/Components/OtaNetwork/src/HttpUpgrader.cpp new file mode 100644 index 0000000000..3ecccd64e9 --- /dev/null +++ b/Sming/Components/OtaNetwork/src/HttpUpgrader.cpp @@ -0,0 +1,128 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * RbootHttpUpdater.cpp + * + * Created on: 2015/09/03. + * Author: Richard A Burton & Anakod + * + * Modified: 2017 - Slavey Karadzhov + * + */ + +#include "include/Ota/Network/HttpUpgrader.h" +#include + +namespace Ota +{ + +namespace Network +{ + +void HttpUpgrader::start() +{ + for(unsigned i = 0; i < items.count(); i++) { + auto& it = items[i]; + debug_d("Download file:\r\n" + " (%u) %s -> %s @ 0x%X", + currentItem, it.url.c_str(), it.partition.name(), it.partition.address()); + + HttpRequest* request; + if(baseRequest != nullptr) { + request = baseRequest->clone(); + request->setURL(it.url); + } else { + request = new HttpRequest(it.url); + } + + request->setMethod(HTTP_GET); + request->setResponseStream(it.getStream()); + + if(i == items.count() - 1) { + request->onRequestComplete(RequestCompletedDelegate(&HttpUpgrader::updateComplete, this)); + } else { + request->onRequestComplete(RequestCompletedDelegate(&HttpUpgrader::itemComplete, this)); + } + + if(!send(request)) { + debug_e("ERROR: Rejected sending new request."); + break; + } + } +} + +int HttpUpgrader::itemComplete(HttpConnection& client, bool success) +{ + if(!success) { + updateFailed(); + return -1; + } + + auto& it = items[currentItem]; + debug_d("Finished: URL: %s, Offset: 0x%X, Length: %u", it.url.c_str(), it.partition.address(), + it.stream->available()); + + it.size = it.stream->available(); + it.stream = nullptr; // the actual deletion will happen outside of this class + currentItem++; + + return 0; +} + +int HttpUpgrader::updateComplete(HttpConnection& client, bool success) +{ + 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: %u, addr: 0x%X, url: %s", i, items[i].partition.address(), items[i].url.c_str()); + } + + if(!success) { + updateFailed(); + return -1; + } + + if(updateDelegate) { + updateDelegate(*this, true); + } + + applyUpdate(); + + return 0; +} + +void HttpUpgrader::updateFailed() +{ + debug_e("\r\nFirmware download failed.."); + if(updateDelegate) { + updateDelegate(*this, false); + } + items.clear(); +} + +void HttpUpgrader::applyUpdate() +{ + 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 %u...\r\n", romSlot); + + OtaManager.setBootPartition(items[romSlot].partition); + System.restart(); +} + + +} // namespace Network + +} // namespace Ota diff --git a/Sming/Components/OtaNetwork/src/include/Ota/Network/HttpUpgrader.h b/Sming/Components/OtaNetwork/src/include/Ota/Network/HttpUpgrader.h new file mode 100644 index 0000000000..9bb65a5d7f --- /dev/null +++ b/Sming/Components/OtaNetwork/src/include/Ota/Network/HttpUpgrader.h @@ -0,0 +1,160 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * HttpUpgrader.h + * + * Created on: 2015/09/03. + * Author: Richard A Burton & Anakod + * + * Modified: 2017 - Slavey Karadzhov + * + ****/ + +#pragma once + +#include +#include + +namespace Ota +{ + +namespace Network +{ + +/** + * @brief Magic value for ROM slot indicating slot won't change after successful OTA + */ +constexpr uint8_t NO_ROM_SWITCH{0xff}; + +class HttpUpgrader : protected HttpClient +{ +public: + using CompletedDelegate = Delegate; + + struct Item { + String url; + Storage::Partition partition; // << partition to write the data to + size_t size{0}; // << actual size of written bytes + ReadWriteStream* stream{nullptr}; // (optional) output stream to use. + + Item(String url, Storage::Partition partition, ReadWriteStream* stream) + : url(url), partition(partition), stream(stream) + { + } + + ~Item() + { + delete stream; + } + + ReadWriteStream* getStream() + { + if(stream == nullptr) { + stream = new Ota::UpgradeOutputStream(partition); + } + return stream; + } + }; + + class ItemList : public Vector + { + public: + bool addNew(Item* it) + { + if(addElement(it)) { + return true; + } + delete it; + return false; + } + }; + + /** + * @brief Add an item to update + * @param firmwareFileUrl + * @param partition Target partition to write + * @param stream + * + * @retval bool + */ + bool addItem(const String& firmwareFileUrl, Storage::Partition partition, ReadWriteStream* stream = nullptr) + { + return items.addNew(new Item{firmwareFileUrl, partition, 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; + } + + void setCallback(CompletedDelegate reqUpdateDelegate) + { + setDelegate(reqUpdateDelegate); + } + + void setDelegate(CompletedDelegate reqUpdateDelegate) + { + this->updateDelegate = reqUpdateDelegate; + } + + /** + * @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 + */ + void setBaseRequest(HttpRequest* request) + { + baseRequest = request; + } + + /** + * @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; + } + +protected: + void applyUpdate(); + void updateFailed(); + + virtual int itemComplete(HttpConnection& client, bool success); + virtual int updateComplete(HttpConnection& client, bool success); + +protected: + ItemList items; + CompletedDelegate updateDelegate; + HttpRequest* baseRequest{nullptr}; + uint8_t romSlot{NO_ROM_SWITCH}; + uint8_t currentItem{0}; +}; + + +} // namespace Network + + +} // namespace Ota diff --git a/Sming/Libraries/OtaUpgradeMqtt/src/include/OtaUpgrade/Mqtt/RbootPayloadParser.h b/Sming/Libraries/OtaUpgradeMqtt/src/include/OtaUpgrade/Mqtt/RbootPayloadParser.h index f390c7b6a4..c3d53498fa 100644 --- a/Sming/Libraries/OtaUpgradeMqtt/src/include/OtaUpgrade/Mqtt/RbootPayloadParser.h +++ b/Sming/Libraries/OtaUpgradeMqtt/src/include/OtaUpgrade/Mqtt/RbootPayloadParser.h @@ -18,6 +18,7 @@ namespace OtaUpgrade { namespace Mqtt { +/** @deprecated Use `StandardPayloadParser` */ using RbootPayloadParser = StandardPayloadParser SMING_DEPRECATED; } // namespace Mqtt diff --git a/Sming/Libraries/OtaUpgradeMqtt/src/include/OtaUpgrade/Mqtt/StandardPayloadParser.h b/Sming/Libraries/OtaUpgradeMqtt/src/include/OtaUpgrade/Mqtt/StandardPayloadParser.h index 68e9083766..e6babbc027 100644 --- a/Sming/Libraries/OtaUpgradeMqtt/src/include/OtaUpgrade/Mqtt/StandardPayloadParser.h +++ b/Sming/Libraries/OtaUpgradeMqtt/src/include/OtaUpgrade/Mqtt/StandardPayloadParser.h @@ -4,7 +4,7 @@ * http://github.com/SmingHub/Sming * All files of the Sming Core are provided under the LGPL v3 license. * - * RbootPayloadParser.h + * StandardPayloadParser.h * * Created: 2021 - Slavey Karadzhov * diff --git a/samples/Basic_Ota/README.rst b/samples/Basic_Ota/README.rst index f49ea3da08..a5d2dba443 100644 --- a/samples/Basic_Ota/README.rst +++ b/samples/Basic_Ota/README.rst @@ -1,15 +1,18 @@ -Basic rBoot -=========== +Basic Ota +========= .. highlight:: bash Introduction ------------ -This sample integrates :component:`rboot` and Sming, for the many people who have -been asking for it. It demonstrates dual rom booting, big flash support, -OTA updates and dual spiffs filesystems. You must enable big flash -support in rBoot and use on an ESP12 (or similar device with 4MB flash). +This sample integrates :component:`Ota`, :component:`OtaNetwork` and Sming. +It demonstrates dual rom booting, big flash support, OTA updates and dual spiffs filesystems. +This sample should work on all supported architectures. + +Esp8266 +~~~~~~~ +On Esp8266 we use rBoot as bootloader. When using rBoot big flash support with multiple 1MB slots only one rom image needs to be created. If you don’t want to use big flash support (e.g. for a device with smaller flash) see the separate instructions @@ -19,41 +22,17 @@ project to add OTA support. Building -------- -1) Set :envvar:`ESP_HOME` & :envvar:`SMING_HOME`, as environment variables or edit - component.mk as you would for general Sming app compiling. -2) Set :envvar:`WIFI_SSID` & :envvar:`WIFI_PWD` environment variables with your wifi details. -3) Edit the OTA server details at the top of ``app/application.cpp``. -4) Check overridable variables in component.mk, or set as env vars. -5) ``make && make flash`` -6) Put *rom0.bin* and *spiff_rom.bin* in the root of your webserver for OTA. -7) Interact with the sample using a terminal (``make terminal``). Sorry - no web-gui (yet). - -Flashing --------- - -If flashing manually use *esptool.py* to flash rBoot, rom & spiffs e.g.:: - - esptool.py –port write_flash -fs 32m 0x00000 rboot.bin 0x02000 rom0.bin 0x100000 spiffs.rom - -Using the correct -fs parameter is important. This will be ``-fs 32m`` on an ESP12. - -You can also flash rom0.bin to 0x202000, but booting and using OTA is quicker! +1) Set :envvar:`WIFI_SSID` & :envvar:`WIFI_PWD` environment variables with your wifi details. +2) Edit the OTA server details defined in the application ``component.mk`` file. +3) ``make && make flash`` +4) Put *rom0.bin* and *spiff_rom.bin* in the root of your webserver for OTA. +5) Interact with the sample using a terminal (``make terminal``). Sorry - no web-gui (yet). Technical Notes --------------- -``spiffs_mount_manual(address, length)`` must be called from init. - -.. note:: - - This method is now deprecated. Please configure partitions appropriately, - use PartitionTable methods to locate the desired partition, then mount it:: - - auto part = PartitionTable().find('spiffs0'); - spiffs_mount(part); - - See :ref:`hardware_config` for further details. - +Esp8266 +~~~~~~~ Important compiler flags used: - BOOT_BIG_FLASH - when using big flash mode, ensures flash mapping code is built in to the rom. @@ -62,8 +41,10 @@ Important compiler flags used: Flash layout considerations --------------------------- +Esp8266 +~~~~~~~ If you want to use, for example, two 512k roms in the first 1MB block of -flash (old style) then Sming will automatically create two separately linked +flash (old style) then Sming will automatically create two separately linked roms. If you are flashing a single rom to multiple 1MB flash blocks, all using the same offset inside their 1MB blocks, only a single rom is created. See :component:`rboot` for further details. @@ -76,8 +57,39 @@ See :component:`rboot` for further details. If you want more than two roms you must be an advanced user and should be able to work out what to copy and edit to acheive this! +Config Variables + +Configuration +------------- +.. envvar:: RBOOT_TWO_ROMS + + Default: 1 (enabled) + + Allows specifying two different URLs for ROM0 and ROM1. + + If not set then only the URL defined in ROM_0_URL will be used. + +.. envvar:: ROM_0_URL + + Default: http://192.168.7.5:80/rom0.bin + + The URL where the firmware for the first application partition can be downloaded. + +.. envvar:: ROM_1_URL + + Default: http://192.168.7.5:80/rom1.bin + + Used when ``RBOOT_TWO_ROMS`` is set. The URL where the firmware for the second application partition can be downloaded. + +.. envvar:: SPIFFS_URL + + Default: http://192.168.7.5:80/spiff_rom.bin + + The URL where the spiffs partition attached can be downloaded. + + Credits ------- -This sample was made possible with the assistance of piperpilot, +The initial sample was made possible with the assistance of piperpilot, gschmott and robotiko on the esp8266.com forum. diff --git a/samples/Basic_Ota/app/application.cpp b/samples/Basic_Ota/app/application.cpp index 41ec6c47f6..05d4a18477 100644 --- a/samples/Basic_Ota/app/application.cpp +++ b/samples/Basic_Ota/app/application.cpp @@ -1,27 +1,23 @@ #include -#include +#include +#include #include #include -// download urls, set appropriately -#define ROM_0_URL "http://192.168.7.5:80/rom0.bin" -#define ROM_1_URL "http://192.168.7.5:80/rom1.bin" -#define SPIFFS_URL "http://192.168.7.5:80/spiff_rom.bin" - // If you want, you can define WiFi settings globally in Eclipse Environment Variables #ifndef WIFI_SSID #define WIFI_SSID "PleaseEnterSSID" // Put your SSID and password here #define WIFI_PWD "PleaseEnterPass" #endif -RbootHttpUpdater* otaUpdater; +Ota::Network::HttpUpgrader* otaUpdater; Storage::Partition spiffsPartition; OtaUpgrader ota; -Storage::Partition findSpiffsPartition(uint8_t slot) +Storage::Partition findSpiffsPartition(Storage::Partition partition) { String name = F("spiffs"); - name += slot; + name += ota.getSlot(partition); auto part = Storage::findPartition(name); if(!part) { debug_w("Partition '%s' not found", name.c_str()); @@ -29,16 +25,16 @@ Storage::Partition findSpiffsPartition(uint8_t slot) return part; } -void otaUpdateCallBack(RbootHttpUpdater& client, bool result) +void otaUpdateCallBack(Ota::Network::HttpUpgrader& client, bool result) { Serial.println("In callback..."); if(result == true) { // success ota.end(); - auto part = ota.getNextUpdatePartition(); + auto part = ota.getNextBootPartition(); // set to boot new rom and then reboot - Serial.printf("Firmware updated, rebooting to rom %s...\r\n", part.name().c_str()); + Serial.printf("Firmware updated, rebooting to %s @ ...\r\n", part.name().c_str()); ota.setBootPartition(part); System.restart(); } else { @@ -56,25 +52,25 @@ void OtaUpdate() if(otaUpdater) { delete otaUpdater; } - otaUpdater = new RbootHttpUpdater(); + otaUpdater = new Ota::Network::HttpUpgrader(); // select rom slot to flash - auto part = ota.getNextUpdatePartition(); + auto part = ota.getNextBootPartition(); #ifndef RBOOT_TWO_ROMS // flash rom to position indicated in the rBoot config rom table - otaUpdater->addItem(part.address(), ROM_0_URL, part.size()); + otaUpdater->addItem(ROM_0_URL, part); #else // flash appropriate ROM - otaUpdater->addItem(part.address(), (part.subType() == 0) ? ROM_0_URL : ROM_1_URL, part.size()); + otaUpdater->addItem((ota.getSlot(part) == 0) ? ROM_0_URL : ROM_1_URL, part); #endif ota.begin(part); - auto spiffsPart = findSpiffsPartition(part.subType()); + auto spiffsPart = findSpiffsPartition(part); if(spiffsPart) { // use user supplied values (defaults for 4mb flash in hardware config) - otaUpdater->addItem(spiffsPart.address(), SPIFFS_URL, spiffsPart.size()); + otaUpdater->addItem(SPIFFS_URL, spiffsPart, new Storage::PartitionStream(spiffsPart)); } // request switch and reboot on success @@ -89,9 +85,10 @@ void OtaUpdate() void Switch() { auto before = ota.getRunningPartition(); - auto after = ota.getNextUpdatePartition(); + auto after = ota.getNextBootPartition(); - Serial.printf(_F("Swapping from rom %s to rom %s.\r\n"), before.name().c_str(), after.name().c_str()); + Serial.printf(_F("Swapping from %s @ 0x%08x to %s @ 0x%08x.\r\n"), before.name().c_str(), before.address(), + after.name().c_str(), after.address()); if(ota.setBootPartition(after)) { Serial.println(F("Restarting...\r\n")); System.restart(); @@ -110,9 +107,9 @@ void ShowInfo() Serial.printf("SPI Flash Size: %x\r\n", Storage::spiFlash->getSize()); auto before = ota.getRunningPartition(); - auto after = ota.getNextUpdatePartition(); + auto after = ota.getNextBootPartition(); - Serial.printf(_F("Current rom: %s@%x, future rom: %s@%x\r\n"), before.name().c_str(), before.address(), + Serial.printf(_F("Current %s @ 0x%08x, future %s @ 0x%08x\r\n"), before.name().c_str(), before.address(), after.name().c_str(), after.address()); } @@ -136,7 +133,7 @@ void serialCallBack(Stream& stream, char arrivedChar, unsigned short availableCh } else if(!strcmp(str, "ip")) { Serial.print("ip: "); Serial.print(WifiStation.getIP()); - Serial.print("mac: "); + Serial.print(" mac: "); Serial.println(WifiStation.getMacAddress()); } else if(!strcmp(str, "ota")) { OtaUpdate(); @@ -174,10 +171,10 @@ void serialCallBack(Stream& stream, char arrivedChar, unsigned short availableCh Serial.println(" help - display this message"); Serial.println(" ip - show current ip address"); Serial.println(" connect - connect to wifi"); - Serial.println(" restart - restart the esp8266"); + Serial.println(" restart - restart the device"); Serial.println(" switch - switch to the other rom and reboot"); Serial.println(" ota - perform ota update, switch rom and reboot"); - Serial.println(" info - show esp8266 info"); + Serial.println(" info - show device info"); if(spiffsPartition) { Serial.println(" ls - list files in spiffs"); Serial.println(" cat - show first file in spiffs"); @@ -196,16 +193,16 @@ void init() // mount spiffs auto partition = ota.getRunningPartition(); - spiffsPartition = findSpiffsPartition(partition.subType()); + spiffsPartition = findSpiffsPartition(partition); if(spiffsPartition) { - debugf("trying to mount '%s' at 0x%08x, length %d", spiffsPartition.name().c_str(), spiffsPartition.address(), + debugf("trying to mount %s @ 0x%08x, length %d", spiffsPartition.name().c_str(), spiffsPartition.address(), spiffsPartition.size()); spiffs_mount(spiffsPartition); } WifiAccessPoint.enable(false); - Serial.printf("\r\nCurrently running rom %s.\r\n", partition.name().c_str()); + Serial.printf("\r\nCurrently running %s @ 0x%08x.\r\n", partition.name().c_str(), partition.address()); Serial.println("Type 'help' and press enter for instructions."); Serial.println(); diff --git a/samples/Basic_Ota/basic_rboot.hw b/samples/Basic_Ota/basic_rboot.hw deleted file mode 100644 index b558727f9c..0000000000 --- a/samples/Basic_Ota/basic_rboot.hw +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "Two ROM slots, two SPIFFS", - "base_config": "spiffs", - "partitions": { - "rom0": { - "subtype": "ota_0" - }, - "rom1": { - "address": "0x108000", - "size": "992K", - "type": "app", - "subtype": "ota_1", - "filename": "$(RBOOT_ROM_1_BIN)" - }, - "spiffs1": { - "address": "0x300000", - "size": "512K", - "type": "data", - "subtype": "spiffs" - } - } -} diff --git a/samples/Basic_Ota/component.mk b/samples/Basic_Ota/component.mk index 9555e50099..e3cab59ca4 100644 --- a/samples/Basic_Ota/component.mk +++ b/samples/Basic_Ota/component.mk @@ -1,7 +1,23 @@ -#### overridable rBoot options #### +COMPONENT_DEPENDS := OtaNetwork -## use rboot build mode -RBOOT_ENABLED := 1 +HWCONFIG := ota -## Use standard hardware config with two ROM slots and two SPIFFS partitions -HWCONFIG := basic_rboot +CONFIG_VARS := RBOOT_TWO_ROMS +RBOOT_TWO_ROMS := 1 + +# download urls, set appropriately +CONFIG_VARS += ROM_0_URL \ + ROM_1_URL \ + SPIFFS_URL + +ROM_0_URL := "http://192.168.7.5:80/rom0.bin" +ROM_1_URL := "http://192.168.7.5:80/rom1.bin" +SPIFFS_URL := "http://192.168.7.5:80/spiff_rom.bin" + +APP_CFLAGS = -DROM_0_URL="\"$(ROM_0_URL)"\" \ + -DROM_1_URL="\"$(ROM_1_URL)"\" \ + -DSPIFFS_URL="\"$(SPIFFS_URL)"\" + +ifneq ($(RBOOT_TWO_ROMS),) + APP_CFLAGS += -DRBOOT_TWO_ROMS=$(RBOOT_TWO_ROMS) +endif \ No newline at end of file diff --git a/samples/Basic_Ota/ota.hw b/samples/Basic_Ota/ota.hw new file mode 100644 index 0000000000..aceea30053 --- /dev/null +++ b/samples/Basic_Ota/ota.hw @@ -0,0 +1,11 @@ +{ + "base_config": "spiffs-two-roms", + "partitions": { + "rom0": { + "subtype": "ota_0" + }, + "rom1": { + "subtype": "ota_1" + } + } +} \ No newline at end of file diff --git a/samples/Basic_rBoot/.cproject b/samples/Basic_rBoot/.cproject deleted file mode 100644 index e1450b6031..0000000000 --- a/samples/Basic_rBoot/.cproject +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - make - -f ${ProjDirPath}/Makefile - all - true - true - true - - - make - -f ${ProjDirPath}/Makefile - clean - true - true - true - - - make - -f ${ProjDirPath}/Makefile - flash - true - true - true - - - make - -f ${ProjDirPath}/Makefile - flashonefile - true - true - true - - - make - -f ${ProjDirPath}/Makefile - flashinit - true - true - true - - - make - -f ${ProjDirPath}/Makefile - flashboot - true - true - true - - - make - -f ${ProjDirPath}/Makefile - rebuild - true - true - true - - - - - - - - - - - - - - - - - - - - diff --git a/samples/Basic_rBoot/.project b/samples/Basic_rBoot/.project deleted file mode 100644 index 6160ca7119..0000000000 --- a/samples/Basic_rBoot/.project +++ /dev/null @@ -1,28 +0,0 @@ - - - Basic_rBoot - - - SmingFramework - - - - org.eclipse.cdt.managedbuilder.core.genmakebuilder - clean,full,incremental, - - - - - org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder - full,incremental, - - - - - - org.eclipse.cdt.core.cnature - org.eclipse.cdt.core.ccnature - org.eclipse.cdt.managedbuilder.core.managedBuildNature - org.eclipse.cdt.managedbuilder.core.ScannerConfigNature - - diff --git a/samples/Basic_rBoot/Makefile b/samples/Basic_rBoot/Makefile deleted file mode 100644 index ff51b6c3a7..0000000000 --- a/samples/Basic_rBoot/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -##################################################################### -#### Please don't change this file. Use component.mk instead #### -##################################################################### - -ifndef SMING_HOME -$(error SMING_HOME is not set: please configure it as an environment variable) -endif - -include $(SMING_HOME)/project.mk diff --git a/samples/Basic_rBoot/README.rst b/samples/Basic_rBoot/README.rst deleted file mode 100644 index f49ea3da08..0000000000 --- a/samples/Basic_rBoot/README.rst +++ /dev/null @@ -1,83 +0,0 @@ -Basic rBoot -=========== - -.. highlight:: bash - -Introduction ------------- - -This sample integrates :component:`rboot` and Sming, for the many people who have -been asking for it. It demonstrates dual rom booting, big flash support, -OTA updates and dual spiffs filesystems. You must enable big flash -support in rBoot and use on an ESP12 (or similar device with 4MB flash). -When using rBoot big flash support with multiple 1MB slots only one rom -image needs to be created. If you don’t want to use big flash support -(e.g. for a device with smaller flash) see the separate instructions -below. You can easily take the ota files and add them to your own -project to add OTA support. - -Building --------- - -1) Set :envvar:`ESP_HOME` & :envvar:`SMING_HOME`, as environment variables or edit - component.mk as you would for general Sming app compiling. -2) Set :envvar:`WIFI_SSID` & :envvar:`WIFI_PWD` environment variables with your wifi details. -3) Edit the OTA server details at the top of ``app/application.cpp``. -4) Check overridable variables in component.mk, or set as env vars. -5) ``make && make flash`` -6) Put *rom0.bin* and *spiff_rom.bin* in the root of your webserver for OTA. -7) Interact with the sample using a terminal (``make terminal``). Sorry - no web-gui (yet). - -Flashing --------- - -If flashing manually use *esptool.py* to flash rBoot, rom & spiffs e.g.:: - - esptool.py –port write_flash -fs 32m 0x00000 rboot.bin 0x02000 rom0.bin 0x100000 spiffs.rom - -Using the correct -fs parameter is important. This will be ``-fs 32m`` on an ESP12. - -You can also flash rom0.bin to 0x202000, but booting and using OTA is quicker! - -Technical Notes ---------------- - -``spiffs_mount_manual(address, length)`` must be called from init. - -.. note:: - - This method is now deprecated. Please configure partitions appropriately, - use PartitionTable methods to locate the desired partition, then mount it:: - - auto part = PartitionTable().find('spiffs0'); - spiffs_mount(part); - - See :ref:`hardware_config` for further details. - -Important compiler flags used: - -- BOOT_BIG_FLASH - when using big flash mode, ensures flash mapping code is built in to the rom. -- RBOOT_INTEGRATION - ensures Sming specific options are pulled in to the rBoot source at compile time. - -Flash layout considerations ---------------------------- - -If you want to use, for example, two 512k roms in the first 1MB block of -flash (old style) then Sming will automatically create two separately linked -roms. If you are flashing a single rom to multiple 1MB flash blocks, all using -the same offset inside their 1MB blocks, only a single rom is created. -See :component:`rboot` for further details. - -- If using a very small flash (e.g. 512k) there may be no room for a - spiffs fileystem, so use *HWCONFIG = standard* -- After building copy all the rom*.bin files to the root of your web - server. - -If you want more than two roms you must be an advanced user and should -be able to work out what to copy and edit to acheive this! - -Credits -------- - -This sample was made possible with the assistance of piperpilot, -gschmott and robotiko on the esp8266.com forum. diff --git a/samples/Basic_rBoot/app/application.cpp b/samples/Basic_rBoot/app/application.cpp deleted file mode 100644 index e53a3a84fc..0000000000 --- a/samples/Basic_rBoot/app/application.cpp +++ /dev/null @@ -1,224 +0,0 @@ -#include -#include -#include - -// download urls, set appropriately -#define ROM_0_URL "http://192.168.7.5:80/rom0.bin" -#define ROM_1_URL "http://192.168.7.5:80/rom1.bin" -#define SPIFFS_URL "http://192.168.7.5:80/spiff_rom.bin" - -// If you want, you can define WiFi settings globally in Eclipse Environment Variables -#ifndef WIFI_SSID -#define WIFI_SSID "PleaseEnterSSID" // Put your SSID and password here -#define WIFI_PWD "PleaseEnterPass" -#endif - -RbootHttpUpdater* otaUpdater; -Storage::Partition spiffsPartition; - -Storage::Partition findSpiffsPartition(uint8_t slot) -{ - String name = F("spiffs"); - name += slot; - auto part = Storage::findPartition(name); - if(!part) { - debug_w("Partition '%s' not found", name.c_str()); - } - return part; -} - -void otaUpdateCallBack(RbootHttpUpdater& client, bool result) -{ - Serial.println("In callback..."); - if(result == true) { - // success - uint8 slot; - slot = rboot_get_current_rom(); - if(slot == 0) { - slot = 1; - } else { - slot = 0; - } - // set to boot new rom and then reboot - Serial.printf("Firmware updated, rebooting to rom %d...\r\n", slot); - rboot_set_current_rom(slot); - System.restart(); - } else { - // fail - Serial.println("Firmware update failed!"); - } -} - -void OtaUpdate() -{ - uint8 slot; - rboot_config bootconf; - - Serial.println("Updating..."); - - // need a clean object, otherwise if run before and failed will not run again - if(otaUpdater) { - delete otaUpdater; - } - otaUpdater = new RbootHttpUpdater(); - - // select rom slot to flash - bootconf = rboot_get_config(); - slot = bootconf.current_rom; - if(slot == 0) { - slot = 1; - } else { - slot = 0; - } - -#ifndef RBOOT_TWO_ROMS - // flash rom to position indicated in the rBoot config rom table - otaUpdater->addItem(bootconf.roms[slot], ROM_0_URL); -#else - // flash appropriate ROM - otaUpdater->addItem(bootconf.roms[slot], (slot == 0) ? ROM_0_URL : ROM_1_URL); -#endif - - auto part = findSpiffsPartition(slot); - if(part) { - // use user supplied values (defaults for 4mb flash in hardware config) - otaUpdater->addItem(part.address(), SPIFFS_URL, part.size()); - } - - // request switch and reboot on success - //otaUpdater->switchToRom(slot); - // and/or set a callback (called on failure or success without switching requested) - otaUpdater->setCallback(otaUpdateCallBack); - - // start update - otaUpdater->start(); -} - -void Switch() -{ - 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 { - Serial.println(F("Switch failed.")); - } -} - -void ShowInfo() -{ - Serial.printf("\r\nSDK: v%s\r\n", system_get_sdk_version()); - Serial.printf("Free Heap: %d\r\n", system_get_free_heap_size()); - 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: %x\r\n", Storage::spiFlash->getSize()); - - rboot_config conf; - conf = rboot_get_config(); - - debugf("Count: %d", conf.count); - for(unsigned i = 0; i < MAX_ROMS; ++i) { - debugf("ROM %u: 0x%08x", i, conf.roms[i]); - } - debugf("GPIO ROM: %d", conf.gpio_rom); -} - -void serialCallBack(Stream& stream, char arrivedChar, unsigned short availableCharsCount) -{ - int pos = stream.indexOf('\n'); - if(pos > -1) { - char str[pos + 1]; - for(int i = 0; i < pos + 1; i++) { - str[i] = stream.read(); - if(str[i] == '\r' || str[i] == '\n') { - str[i] = '\0'; - } - } - - if(!strcmp(str, "connect")) { - // connect to wifi - WifiStation.config(WIFI_SSID, WIFI_PWD); - WifiStation.enable(true); - WifiStation.connect(); - } else if(!strcmp(str, "ip")) { - Serial.print("ip: "); - Serial.print(WifiStation.getIP()); - Serial.print("mac: "); - Serial.println(WifiStation.getMacAddress()); - } else if(!strcmp(str, "ota")) { - OtaUpdate(); - } else if(!strcmp(str, "switch")) { - Switch(); - } else if(!strcmp(str, "restart")) { - System.restart(); - } else if(!strcmp(str, "ls")) { - Directory dir; - if(dir.open()) { - while(dir.next()) { - Serial.print(" "); - Serial.println(dir.stat().name); - } - } - Serial.printf("filecount %d\r\n", dir.count()); - } else if(!strcmp(str, "cat")) { - Directory dir; - if(dir.open() && dir.next()) { - auto filename = dir.stat().name.c_str(); - Serial.printf("dumping file %s:\r\n", filename); - // We don't know how big the is, so streaming it is safest - FileStream fs; - fs.open(filename); - Serial.copyFrom(&fs); - Serial.println(); - } else { - Serial.println("Empty spiffs!"); - } - } else if(!strcmp(str, "info")) { - ShowInfo(); - } else if(!strcmp(str, "help")) { - Serial.println(); - Serial.println("available commands:"); - Serial.println(" help - display this message"); - Serial.println(" ip - show current ip address"); - Serial.println(" connect - connect to wifi"); - Serial.println(" restart - restart the esp8266"); - Serial.println(" switch - switch to the other rom and reboot"); - Serial.println(" ota - perform ota update, switch rom and reboot"); - Serial.println(" info - show esp8266 info"); - if(spiffsPartition) { - Serial.println(" ls - list files in spiffs"); - Serial.println(" cat - show first file in spiffs"); - } - Serial.println(); - } else { - Serial.println("unknown command"); - } - } -} - -void init() -{ - Serial.begin(SERIAL_BAUD_RATE); // 115200 by default - Serial.systemDebugOutput(true); // Debug output to serial - - // mount spiffs - auto slot = rboot_get_current_rom(); - spiffsPartition = findSpiffsPartition(slot); - if(spiffsPartition) { - debugf("trying to mount '%s' at 0x%08x, length %d", spiffsPartition.name().c_str(), spiffsPartition.address(), - spiffsPartition.size()); - spiffs_mount(spiffsPartition); - } - - WifiAccessPoint.enable(false); - - Serial.printf("\r\nCurrently running rom %d.\r\n", slot); - Serial.println("Type 'help' and press enter for instructions."); - Serial.println(); - - Serial.onDataReceived(serialCallBack); -} diff --git a/samples/Basic_rBoot/basic_rboot.hw b/samples/Basic_rBoot/basic_rboot.hw deleted file mode 100644 index 27332cb161..0000000000 --- a/samples/Basic_rBoot/basic_rboot.hw +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "Two ROM slots, two SPIFFS", - "base_config": "spiffs", - "partitions": { - "rom0": { - "subtype": "ota_0" - }, - "rom1": { - "address": "0x108000", - "size": "992K", - "type": "app", - "subtype": "ota_1", - "filename": "$(RBOOT_ROM_1_BIN)" - }, - "spiffs1": { - "address": "0x300000", - "size": "512K", - "type": "data", - "subtype": "spiffs" - } - } -} \ No newline at end of file diff --git a/samples/Basic_rBoot/component.mk b/samples/Basic_rBoot/component.mk deleted file mode 100644 index 9555e50099..0000000000 --- a/samples/Basic_rBoot/component.mk +++ /dev/null @@ -1,7 +0,0 @@ -#### overridable rBoot options #### - -## use rboot build mode -RBOOT_ENABLED := 1 - -## Use standard hardware config with two ROM slots and two SPIFFS partitions -HWCONFIG := basic_rboot diff --git a/samples/Basic_rBoot/files/testfile.txt b/samples/Basic_rBoot/files/testfile.txt deleted file mode 100644 index f8b77180ca..0000000000 --- a/samples/Basic_rBoot/files/testfile.txt +++ /dev/null @@ -1,2 +0,0 @@ -This line is the content of test file. - From 2a0192b428aeacbcbb6ad8d708bd142d4031c849 Mon Sep 17 00:00:00 2001 From: Slavey Karadzhov Date: Tue, 25 May 2021 11:32:14 +0200 Subject: [PATCH 05/15] ESP32 fixes. Tested on: - [x] Host (on Linux) - [x] real Esp8266 device - [x] real Esp32 device --- Sming/Arch/Esp32/spiffs-two-roms.hw | 6 ++++++ Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Sming/Arch/Esp32/spiffs-two-roms.hw b/Sming/Arch/Esp32/spiffs-two-roms.hw index 0b74136ba3..76867643ce 100644 --- a/Sming/Arch/Esp32/spiffs-two-roms.hw +++ b/Sming/Arch/Esp32/spiffs-two-roms.hw @@ -13,6 +13,12 @@ "subtype": "ota_0", "filename": "$(TARGET_BIN)" }, + "ota": { // Ota Table + "address": "0x00200000", + "size": "8K", + "type" : "data", + "subtype": "ota" + }, "rom1": { "address": "0x210000", "size": "960K", diff --git a/Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp b/Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp index 3794af8c67..6373f569c8 100644 --- a/Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp +++ b/Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp @@ -19,6 +19,7 @@ bool IdfUpgrader::begin(Storage::Partition partition, size_t size) } writtenSoFar = 0; + maxSize = (size ? size : partition.size()); esp_err_t result = esp_ota_begin(convertToIdfPartition(partition), size ? size : partition.size(), &handle); @@ -70,7 +71,11 @@ Storage::Partition IdfUpgrader::getRunningPartition(void) Storage::Partition IdfUpgrader::getNextBootPartition(Storage::Partition* startFrom) { - return convertFromIdfPartition(esp_ota_get_next_update_partition(convertToIdfPartition(*startFrom))); + const esp_partition_t* idfFrom = nullptr; + if(startFrom != nullptr) { + idfFrom =convertToIdfPartition(*startFrom); + } + return convertFromIdfPartition(esp_ota_get_next_update_partition(idfFrom)); } const esp_partition_t* IdfUpgrader::convertToIdfPartition(Storage::Partition partition) From 3af0c9614e334940e3781d3eee4f6cabaf45ba91 Mon Sep 17 00:00:00 2001 From: Slavey Karadzhov Date: Tue, 25 May 2021 12:28:25 +0200 Subject: [PATCH 06/15] Bugfuxes: - Basic Stream fix. - StandardPayloadParser fix. --- Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.cpp | 2 +- Sming/Libraries/OtaUpgradeMqtt/src/StandardPayloadParser.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.cpp b/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.cpp index 837db4a234..dfdfa938ef 100644 --- a/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.cpp +++ b/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.cpp @@ -81,7 +81,7 @@ void BasicStream::processRomHeader() bool addressMatch = (slot.partition.address() & 0xFFFFF) == (romHeader.address & 0xFFFFF); if(!slot.updated && addressMatch) { if(romHeader.size <= slot.partition.size()) { - debug_i("Update slot %s [0x%08X..0x%08X)", slot.partition.name(), slot.partition.address(), + debug_i("Update slot %s [0x%08X..0x%08X)", slot.partition.name().c_str(), slot.partition.address(), slot.partition.address() + romHeader.size); ota.begin(slot.partition); setupChunk(State::WriteRom, romHeader.size); diff --git a/Sming/Libraries/OtaUpgradeMqtt/src/StandardPayloadParser.cpp b/Sming/Libraries/OtaUpgradeMqtt/src/StandardPayloadParser.cpp index af4445326c..f312423442 100644 --- a/Sming/Libraries/OtaUpgradeMqtt/src/StandardPayloadParser.cpp +++ b/Sming/Libraries/OtaUpgradeMqtt/src/StandardPayloadParser.cpp @@ -23,8 +23,8 @@ bool StandardPayloadParser::switchRom(const UpdateState& updateState) auto before = OtaManager.getBootPartition(); auto after = OtaManager.getNextBootPartition(); - debug_d("Swapping from rom %s@%x to rom %s@%s.\r\n", before.name(), before.address(), after.name(), - after.address()); + debug_d("Swapping from %s @ 0x%08x to %s @ 0x%08x.\r\n", before.name().c_str(), before.address(), + after.name().c_str(), after.address()); return OtaManager.setBootPartition(after); } From c885a590bf4c2076799c531a496e14cbea1a0118 Mon Sep 17 00:00:00 2001 From: mikee47 Date: Tue, 25 May 2021 14:11:14 +0100 Subject: [PATCH 07/15] Review Simplify code using alias for `Storage::Partition`, etc. Use ?: ternary operator --- Sming/Components/Ota/src/.cs | 0 .../Ota/src/Arch/Esp32/IdfUpgrader.cpp | 37 +++++++------------ .../src/Arch/Esp32/include/Ota/IdfUpgrader.h | 14 +++---- .../Ota/src/Arch/Esp8266/RbootUpgrader.cpp | 30 ++++++--------- .../Arch/Esp8266/include/Ota/RbootUpgrader.h | 14 +++---- .../Ota/src/UpgradeOutputStream.cpp | 1 - .../Ota/src/include/Ota/UpgradeOutputStream.h | 12 +++--- .../Ota/src/include/Ota/UpgraderBase.h | 17 +++++---- Sming/Components/OtaNetwork/src/.cs | 0 .../OtaNetwork/src/HttpUpgrader.cpp | 3 -- .../src/include/Ota/Network/HttpUpgrader.h | 14 +++---- 11 files changed, 61 insertions(+), 81 deletions(-) create mode 100644 Sming/Components/Ota/src/.cs create mode 100644 Sming/Components/OtaNetwork/src/.cs diff --git a/Sming/Components/Ota/src/.cs b/Sming/Components/Ota/src/.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp b/Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp index 6373f569c8..fc1f878f42 100644 --- a/Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp +++ b/Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp @@ -10,16 +10,18 @@ #include "include/Ota/IdfUpgrader.h" +using namespace Storage; + namespace Ota { -bool IdfUpgrader::begin(Storage::Partition partition, size_t size) +bool IdfUpgrader::begin(Partition partition, size_t size) { if(partition.size() < size) { return false; // the requested size is too big... } writtenSoFar = 0; - maxSize = (size ? size : partition.size()); + maxSize = size ?: partition.size(); esp_err_t result = esp_ota_begin(convertToIdfPartition(partition), size ? size : partition.size(), &handle); @@ -54,47 +56,36 @@ bool IdfUpgrader::abort() return true; } -bool IdfUpgrader::setBootPartition(Storage::Partition partition) +bool IdfUpgrader::setBootPartition(Partition partition) { return esp_ota_set_boot_partition(convertToIdfPartition(partition)) == ESP_OK; } -Storage::Partition IdfUpgrader::getBootPartition(void) +Partition IdfUpgrader::getBootPartition(void) { return convertFromIdfPartition(esp_ota_get_boot_partition()); } -Storage::Partition IdfUpgrader::getRunningPartition(void) +Partition IdfUpgrader::getRunningPartition(void) { return convertFromIdfPartition(esp_ota_get_running_partition()); } -Storage::Partition IdfUpgrader::getNextBootPartition(Storage::Partition* startFrom) +Partition IdfUpgrader::getNextBootPartition(Partition startFrom) { - const esp_partition_t* idfFrom = nullptr; - if(startFrom != nullptr) { - idfFrom =convertToIdfPartition(*startFrom); - } + const esp_partition_t* idfFrom = startFrom ? convertToIdfPartition(startFrom) : nullptr; return convertFromIdfPartition(esp_ota_get_next_update_partition(idfFrom)); } -const esp_partition_t* IdfUpgrader::convertToIdfPartition(Storage::Partition partition) +const esp_partition_t* IdfUpgrader::convertToIdfPartition(Partition partition) { - return esp_partition_find_first(ESP_PARTITION_TYPE_APP, - partition.subType() == uint8_t(Storage::Partition::SubType::App::ota0) - ? ESP_PARTITION_SUBTYPE_APP_OTA_0 - : ESP_PARTITION_SUBTYPE_APP_OTA_1, - partition.name().c_str()); + return esp_partition_find_first(esp_partition_type_t(partition.type()), + esp_partition_subtype_t(partition.subType()), partition.name().c_str()); } -Storage::Partition IdfUpgrader::convertFromIdfPartition(const esp_partition_t* partition) +Partition IdfUpgrader::convertFromIdfPartition(const esp_partition_t* partition) { - String label; - if(partition != nullptr) { - label = partition->label; - } - - return Storage::findPartition(label); + return partition ? findPartition(String(partition->label)) : Partition{}; } } // namespace Ota diff --git a/Sming/Components/Ota/src/Arch/Esp32/include/Ota/IdfUpgrader.h b/Sming/Components/Ota/src/Arch/Esp32/include/Ota/IdfUpgrader.h index e0453b7cdd..15e6c78330 100644 --- a/Sming/Components/Ota/src/Arch/Esp32/include/Ota/IdfUpgrader.h +++ b/Sming/Components/Ota/src/Arch/Esp32/include/Ota/IdfUpgrader.h @@ -22,18 +22,18 @@ class IdfUpgrader : public UpgraderBase /** * @brief Prepare the partition for */ - bool begin(Storage::Partition partition, size_t size = 0) override; + bool begin(Partition partition, size_t size = 0) override; size_t write(const uint8_t* buffer, size_t size) override; bool end() override; bool abort() override; - bool setBootPartition(Storage::Partition partition) override; - Storage::Partition getBootPartition(void) override; - Storage::Partition getRunningPartition(void) override; - Storage::Partition getNextBootPartition(Storage::Partition* startFrom = nullptr) override; + bool setBootPartition(Partition partition) override; + Partition getBootPartition(void) override; + Partition getRunningPartition(void) override; + Partition getNextBootPartition(Partition startFrom = {}) override; - static const esp_partition_t* convertToIdfPartition(Storage::Partition partition); - static Storage::Partition convertFromIdfPartition(const esp_partition_t* partition); + static const esp_partition_t* convertToIdfPartition(Partition partition); + static Partition convertFromIdfPartition(const esp_partition_t* partition); private: size_t maxSize{0}; diff --git a/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp b/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp index 3fd5721843..7bde6cea2c 100644 --- a/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp +++ b/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp @@ -10,9 +10,11 @@ #include "include/Ota/RbootUpgrader.h" +using namespace Storage; + namespace Ota { -bool RbootUpgrader::begin(Storage::Partition partition, size_t size) +bool RbootUpgrader::begin(Partition partition, size_t size) { if(partition.size() < size) { return false; // the requested size is too big... @@ -20,7 +22,7 @@ bool RbootUpgrader::begin(Storage::Partition partition, size_t size) status = rboot_write_init(partition.address()); - maxSize = (size ? size : partition.size()); + maxSize = size ?: partition.size(); writtenSoFar = 0; @@ -49,44 +51,36 @@ bool RbootUpgrader::end() return rboot_write_end(&status); } -bool RbootUpgrader::setBootPartition(Storage::Partition partition) +bool RbootUpgrader::setBootPartition(Partition partition) { return rboot_set_current_rom(getSlotForPartition(partition)); } -Storage::Partition RbootUpgrader::getBootPartition(void) +Partition RbootUpgrader::getBootPartition(void) { return getPartitionForSlot(rboot_get_current_rom()); } -Storage::Partition RbootUpgrader::getRunningPartition(void) +Partition RbootUpgrader::getRunningPartition(void) { // TODO: ... return getPartitionForSlot(rboot_get_current_rom()); } -Storage::Partition RbootUpgrader::getNextBootPartition(Storage::Partition* startFrom) +Partition RbootUpgrader::getNextBootPartition(Partition startFrom) { uint8_t currentSlot = rboot_get_current_rom(); return getPartitionForSlot(currentSlot ? 0 : 1); } -uint8_t RbootUpgrader::getSlotForPartition(Storage::Partition partition) +uint8_t RbootUpgrader::getSlotForPartition(Partition partition) { - if(partition.subType() == uint8_t(Storage::Partition::SubType::App::ota1)) { - return 1; - } - - return 0; + return (partition.subType() == uint8_t(Partition::SubType::App::ota1)) ? 1 : 0; } -Storage::Partition RbootUpgrader::getPartitionForSlot(uint8_t slot) +Partition RbootUpgrader::getPartitionForSlot(uint8_t slot) { - auto partitions = Storage::findPartition( - Storage::Partition::Type::app, - uint8_t(slot == 0 ? Storage::Partition::SubType::App::ota0 : Storage::Partition::SubType::App::ota1)); - - return *partitions; + return *findPartition(Partition::apptypeOta(slot)); } } // namespace Ota diff --git a/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h b/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h index 6f6a4e646c..859186b167 100644 --- a/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h +++ b/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h @@ -22,17 +22,17 @@ class RbootUpgrader : public UpgraderBase /** * @brief Prepare the partition for */ - bool begin(Storage::Partition partition, size_t size = 0) override; + bool begin(Partition partition, size_t size = 0) override; size_t write(const uint8_t* buffer, size_t size) override; bool end() override; - bool setBootPartition(Storage::Partition partition) override; - Storage::Partition getBootPartition(void) override; - Storage::Partition getRunningPartition(void) override; - Storage::Partition getNextBootPartition(Storage::Partition* startFrom = nullptr) override; + bool setBootPartition(Partition partition) override; + Partition getBootPartition() override; + Partition getRunningPartition() override; + Partition getNextBootPartition(Partition startFrom = {}) override; - static uint8_t getSlotForPartition(Storage::Partition partition); - static Storage::Partition getPartitionForSlot(uint8_t slot); + static uint8_t getSlotForPartition(Partition partition); + static Partition getPartitionForSlot(uint8_t slot); private: rboot_write_status status{}; diff --git a/Sming/Components/Ota/src/UpgradeOutputStream.cpp b/Sming/Components/Ota/src/UpgradeOutputStream.cpp index 43be0bf085..f84e348ed3 100644 --- a/Sming/Components/Ota/src/UpgradeOutputStream.cpp +++ b/Sming/Components/Ota/src/UpgradeOutputStream.cpp @@ -13,7 +13,6 @@ namespace Ota { - bool UpgradeOutputStream::init() { bool success = ota.begin(partition, maxLength); diff --git a/Sming/Components/Ota/src/include/Ota/UpgradeOutputStream.h b/Sming/Components/Ota/src/include/Ota/UpgradeOutputStream.h index 23154def03..fa3a6157c3 100644 --- a/Sming/Components/Ota/src/include/Ota/UpgradeOutputStream.h +++ b/Sming/Components/Ota/src/include/Ota/UpgradeOutputStream.h @@ -17,18 +17,20 @@ namespace Ota { - /** * @brief Write-only stream type used during firmware upgrade */ class UpgradeOutputStream : public ReadWriteStream { public: + using Partition = Storage::Partition; + /** * @brief Construct a stream for the given partition * @param partition */ - UpgradeOutputStream(Storage::Partition partition, size_t maxLength = 0) : partition(partition), maxLength(maxLength !=0 ? std::min(maxLength, partition.size()) : partition.size()) + UpgradeOutputStream(Partition partition, size_t maxLength = 0) + : partition(partition), maxLength(maxLength != 0 ? std::min(maxLength, partition.size()) : partition.size()) { } @@ -78,10 +80,10 @@ class UpgradeOutputStream : public ReadWriteStream protected: OtaUpgrader ota; - Storage::Partition partition; + Partition partition; bool initialized{false}; - size_t written{0}; // << the number of written bytes - size_t maxLength{0}; // << maximum allowed length + size_t written{0}; // << the number of written bytes + size_t maxLength{0}; // << maximum allowed length protected: virtual bool init(); diff --git a/Sming/Components/Ota/src/include/Ota/UpgraderBase.h b/Sming/Components/Ota/src/include/Ota/UpgraderBase.h index eef0b13d73..02e8c1d119 100644 --- a/Sming/Components/Ota/src/include/Ota/UpgraderBase.h +++ b/Sming/Components/Ota/src/include/Ota/UpgraderBase.h @@ -15,10 +15,11 @@ namespace Ota { - class UpgraderBase { public: + using Partition = Storage::Partition; + virtual ~UpgraderBase() { } @@ -27,7 +28,7 @@ class UpgraderBase * @brief Prepares a partition for an upgrade. * The preparation is bootloader and architecture dependant. */ - virtual bool begin(Storage::Partition partition, size_t size) = 0; + virtual bool begin(Partition partition, size_t size) = 0; /** * @brief Writes chunk of data to the partition set in ``begin()``. @@ -50,36 +51,36 @@ class UpgraderBase /** * @brief Sets the default parition from where the application will be booted on next restart. */ - virtual bool setBootPartition(Storage::Partition partition) = 0; + virtual bool setBootPartition(Partition partition) = 0; /** * @brief Gets information about the parition that is set as the default one to boot. * @note The returned parition can be different than the current running partition. */ - virtual Storage::Partition getBootPartition(void) = 0; + virtual Partition getBootPartition(void) = 0; /** * @brief Gets information about the parition from which the current application is running. * @note The returned parition can be different than the default boot partition. */ - virtual Storage::Partition getRunningPartition(void) = 0; + virtual Partition getRunningPartition(void) = 0; /** * @brief Gets the next bootable partition that can be used after successful OTA upgrade */ - virtual Storage::Partition getNextBootPartition(Storage::Partition* startFrom = nullptr) = 0; + virtual Partition getNextBootPartition(Partition startFrom = {}) = 0; /** * @brief Gets information about all bootable partitions. */ Storage::Iterator getBootPartitions() { - return Storage::findPartition(Storage::Partition::Type::app); + return Storage::findPartition(Partition::Type::app); } // utility functions - uint8_t getSlot(Storage::Partition partition) + uint8_t getSlot(Partition partition) { auto s = toString(partition.type(), partition.subType()); if(!s.startsWith("app/ota")) { diff --git a/Sming/Components/OtaNetwork/src/.cs b/Sming/Components/OtaNetwork/src/.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Components/OtaNetwork/src/HttpUpgrader.cpp b/Sming/Components/OtaNetwork/src/HttpUpgrader.cpp index 3ecccd64e9..9c6822870f 100644 --- a/Sming/Components/OtaNetwork/src/HttpUpgrader.cpp +++ b/Sming/Components/OtaNetwork/src/HttpUpgrader.cpp @@ -18,10 +18,8 @@ namespace Ota { - namespace Network { - void HttpUpgrader::start() { for(unsigned i = 0; i < items.count(); i++) { @@ -122,7 +120,6 @@ void HttpUpgrader::applyUpdate() System.restart(); } - } // namespace Network } // namespace Ota diff --git a/Sming/Components/OtaNetwork/src/include/Ota/Network/HttpUpgrader.h b/Sming/Components/OtaNetwork/src/include/Ota/Network/HttpUpgrader.h index 9bb65a5d7f..3fb528cc5d 100644 --- a/Sming/Components/OtaNetwork/src/include/Ota/Network/HttpUpgrader.h +++ b/Sming/Components/OtaNetwork/src/include/Ota/Network/HttpUpgrader.h @@ -20,10 +20,8 @@ namespace Ota { - namespace Network { - /** * @brief Magic value for ROM slot indicating slot won't change after successful OTA */ @@ -33,15 +31,15 @@ class HttpUpgrader : protected HttpClient { public: using CompletedDelegate = Delegate; + using Partition = Storage::Partition; struct Item { String url; - Storage::Partition partition; // << partition to write the data to - size_t size{0}; // << actual size of written bytes + Partition partition; // << partition to write the data to + size_t size{0}; // << actual size of written bytes ReadWriteStream* stream{nullptr}; // (optional) output stream to use. - Item(String url, Storage::Partition partition, ReadWriteStream* stream) - : url(url), partition(partition), stream(stream) + Item(String url, Partition partition, ReadWriteStream* stream) : url(url), partition(partition), stream(stream) { } @@ -80,7 +78,7 @@ class HttpUpgrader : protected HttpClient * * @retval bool */ - bool addItem(const String& firmwareFileUrl, Storage::Partition partition, ReadWriteStream* stream = nullptr) + bool addItem(const String& firmwareFileUrl, Partition partition, ReadWriteStream* stream = nullptr) { return items.addNew(new Item{firmwareFileUrl, partition, stream}); } @@ -153,8 +151,6 @@ class HttpUpgrader : protected HttpClient uint8_t currentItem{0}; }; - } // namespace Network - } // namespace Ota From 88c2d252b85753704dbf46ef455cb74f5653bcbc Mon Sep 17 00:00:00 2001 From: mikee47 Date: Tue, 25 May 2021 14:39:53 +0100 Subject: [PATCH 08/15] Define `Upgrader::SLOT_NONE` and revise `getSlot()` method --- .../Ota/src/Arch/Esp8266/RbootUpgrader.cpp | 2 +- .../Ota/src/include/Ota/UpgraderBase.h | 16 ++++++++++++---- .../OtaUpgrade/OtaUpgrade/BasicStream.cpp | 1 - 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp b/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp index 7bde6cea2c..2b85683fd9 100644 --- a/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp +++ b/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp @@ -80,7 +80,7 @@ uint8_t RbootUpgrader::getSlotForPartition(Partition partition) Partition RbootUpgrader::getPartitionForSlot(uint8_t slot) { - return *findPartition(Partition::apptypeOta(slot)); + return spiFlash->partitions().findOta(slot); } } // namespace Ota diff --git a/Sming/Components/Ota/src/include/Ota/UpgraderBase.h b/Sming/Components/Ota/src/include/Ota/UpgraderBase.h index 02e8c1d119..7f7ef938a6 100644 --- a/Sming/Components/Ota/src/include/Ota/UpgraderBase.h +++ b/Sming/Components/Ota/src/include/Ota/UpgraderBase.h @@ -12,12 +12,15 @@ #pragma once #include +#include namespace Ota { class UpgraderBase { public: + static constexpr uint8_t SLOT_NONE{255}; + using Partition = Storage::Partition; virtual ~UpgraderBase() @@ -82,12 +85,17 @@ class UpgraderBase uint8_t getSlot(Partition partition) { - auto s = toString(partition.type(), partition.subType()); - if(!s.startsWith("app/ota")) { - return 255; + if(partition.type() != Partition::Type::app) { + return SLOT_NONE; + } + + using App = Partition::SubType::App; + auto subtype = App(partition.subType()); + if(subtype < App::ota_min || subtype > App::ota_max) { + return SLOT_NONE; } - return s.substring(7).toInt(); + return uint8_t(subtype) - uint8_t(App::ota_min); } }; diff --git a/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.cpp b/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.cpp index dfdfa938ef..d68b259350 100644 --- a/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.cpp +++ b/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.cpp @@ -12,7 +12,6 @@ #include #include #include -#include extern "C" uint32 user_rf_cal_sector_set(void); From 238d80f352eef62fe5243826926077b9f45ecd66 Mon Sep 17 00:00:00 2001 From: mikee47 Date: Tue, 25 May 2021 14:53:02 +0100 Subject: [PATCH 09/15] Fix printf statements --- Sming/Components/Ota/README.rst | 2 +- Sming/Components/OtaNetwork/README.rst | 2 +- Sming/Components/OtaNetwork/src/HttpUpgrader.cpp | 4 ++-- .../OtaUpgradeMqtt/samples/Upgrade/app/application.cpp | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Sming/Components/Ota/README.rst b/Sming/Components/Ota/README.rst index 66e088b585..96bb1990f4 100644 --- a/Sming/Components/Ota/README.rst +++ b/Sming/Components/Ota/README.rst @@ -26,7 +26,7 @@ After that you will have access to a global ``OtaManager`` instance that can be // ... auto part = OtaManager.getRunningPartition(); - Serial.printf(_F("\r\nCurrently running rom %s@%x.\r\n"), part.name(), part.address()); + Serial.printf(_F("\r\nCurrently running rom %s@%x.\r\n"), part.name().c_str(), part.address()); } diff --git a/Sming/Components/OtaNetwork/README.rst b/Sming/Components/OtaNetwork/README.rst index 66e088b585..96bb1990f4 100644 --- a/Sming/Components/OtaNetwork/README.rst +++ b/Sming/Components/OtaNetwork/README.rst @@ -26,7 +26,7 @@ After that you will have access to a global ``OtaManager`` instance that can be // ... auto part = OtaManager.getRunningPartition(); - Serial.printf(_F("\r\nCurrently running rom %s@%x.\r\n"), part.name(), part.address()); + Serial.printf(_F("\r\nCurrently running rom %s@%x.\r\n"), part.name().c_str(), part.address()); } diff --git a/Sming/Components/OtaNetwork/src/HttpUpgrader.cpp b/Sming/Components/OtaNetwork/src/HttpUpgrader.cpp index 9c6822870f..ea9e440818 100644 --- a/Sming/Components/OtaNetwork/src/HttpUpgrader.cpp +++ b/Sming/Components/OtaNetwork/src/HttpUpgrader.cpp @@ -25,8 +25,8 @@ void HttpUpgrader::start() for(unsigned i = 0; i < items.count(); i++) { auto& it = items[i]; debug_d("Download file:\r\n" - " (%u) %s -> %s @ 0x%X", - currentItem, it.url.c_str(), it.partition.name(), it.partition.address()); + " (%u) %s -> %s @ 0x%X", + currentItem, it.url.c_str(), it.partition.name().c_str(), it.partition.address()); HttpRequest* request; if(baseRequest != nullptr) { diff --git a/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/app/application.cpp b/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/app/application.cpp index 2581680437..37f8125182 100644 --- a/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/app/application.cpp +++ b/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/app/application.cpp @@ -100,7 +100,7 @@ void showInfo() int total = 0; for(auto it = OtaManager.getBootPartitions(); it; ++it) { auto part = *it; - debug_d("ROM %s: 0x%08x, SubType: %s", part.name(), part.address(), + debug_d("ROM %s: 0x%08x, SubType: %s", part.name().c_str(), part.address(), toLongString(part.type(), part.subType()).c_str()); total++; } @@ -109,8 +109,8 @@ void showInfo() auto part = OtaManager.getRunningPartition(); - Serial.printf(_F("\r\nCurrently running %s: 0x%08x. Application version: %s\r\n"), part.name(), part.address(), - APP_VERSION); + Serial.printf(_F("\r\nCurrently running %s: 0x%08x. Application version: %s\r\n"), part.name().c_str(), + part.address(), APP_VERSION); Serial.println(); } From f31ca21daa5922939f993620fe3ad48d7e7f621b Mon Sep 17 00:00:00 2001 From: mikee47 Date: Tue, 25 May 2021 15:08:08 +0100 Subject: [PATCH 10/15] `erase_range` should specify block size / sector size --- Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.cpp b/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.cpp index d68b259350..451936f54f 100644 --- a/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.cpp +++ b/Sming/Libraries/OtaUpgrade/OtaUpgrade/BasicStream.cpp @@ -103,7 +103,7 @@ void BasicStream::verifyRoms() if(!verifier.verify(verificationData)) { if(slot.updated) { // Destroy start sector of updated ROM to avoid accidentally booting an unsanctioned firmware - Storage::spiFlash->erase_range(slot.partition.address(), 1); + Storage::spiFlash->erase_range(slot.partition.address(), Storage::spiFlash->getBlockSize()); } setError(Error::VerificationFailed); return; From 649e41d107b4ebb7d031b08e5d5009f0adae3cbd Mon Sep 17 00:00:00 2001 From: mikee47 Date: Tue, 25 May 2021 15:32:08 +0100 Subject: [PATCH 11/15] Move trivial code into header --- .../Ota/src/Arch/Esp32/IdfUpgrader.cpp | 44 ----------------- .../src/Arch/Esp32/include/Ota/IdfUpgrader.h | 48 +++++++++++++++---- .../Ota/src/Arch/Esp8266/RbootUpgrader.cpp | 37 -------------- .../Arch/Esp8266/include/Ota/RbootUpgrader.h | 42 +++++++++++++--- 4 files changed, 75 insertions(+), 96 deletions(-) diff --git a/Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp b/Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp index fc1f878f42..dc97261695 100644 --- a/Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp +++ b/Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp @@ -10,8 +10,6 @@ #include "include/Ota/IdfUpgrader.h" -using namespace Storage; - namespace Ota { bool IdfUpgrader::begin(Partition partition, size_t size) @@ -46,46 +44,4 @@ size_t IdfUpgrader::write(const uint8_t* buffer, size_t size) return size; } -bool IdfUpgrader::end() -{ - return esp_ota_end(handle) == ESP_OK; -} - -bool IdfUpgrader::abort() -{ - return true; -} - -bool IdfUpgrader::setBootPartition(Partition partition) -{ - return esp_ota_set_boot_partition(convertToIdfPartition(partition)) == ESP_OK; -} - -Partition IdfUpgrader::getBootPartition(void) -{ - return convertFromIdfPartition(esp_ota_get_boot_partition()); -} - -Partition IdfUpgrader::getRunningPartition(void) -{ - return convertFromIdfPartition(esp_ota_get_running_partition()); -} - -Partition IdfUpgrader::getNextBootPartition(Partition startFrom) -{ - const esp_partition_t* idfFrom = startFrom ? convertToIdfPartition(startFrom) : nullptr; - return convertFromIdfPartition(esp_ota_get_next_update_partition(idfFrom)); -} - -const esp_partition_t* IdfUpgrader::convertToIdfPartition(Partition partition) -{ - return esp_partition_find_first(esp_partition_type_t(partition.type()), - esp_partition_subtype_t(partition.subType()), partition.name().c_str()); -} - -Partition IdfUpgrader::convertFromIdfPartition(const esp_partition_t* partition) -{ - return partition ? findPartition(String(partition->label)) : Partition{}; -} - } // namespace Ota diff --git a/Sming/Components/Ota/src/Arch/Esp32/include/Ota/IdfUpgrader.h b/Sming/Components/Ota/src/Arch/Esp32/include/Ota/IdfUpgrader.h index 15e6c78330..445358d8e6 100644 --- a/Sming/Components/Ota/src/Arch/Esp32/include/Ota/IdfUpgrader.h +++ b/Sming/Components/Ota/src/Arch/Esp32/include/Ota/IdfUpgrader.h @@ -24,16 +24,48 @@ class IdfUpgrader : public UpgraderBase */ bool begin(Partition partition, size_t size = 0) override; size_t write(const uint8_t* buffer, size_t size) override; - bool end() override; - bool abort() override; - bool setBootPartition(Partition partition) override; - Partition getBootPartition(void) override; - Partition getRunningPartition(void) override; - Partition getNextBootPartition(Partition startFrom = {}) override; + bool end() override + { + return esp_ota_end(handle) == ESP_OK; + } - static const esp_partition_t* convertToIdfPartition(Partition partition); - static Partition convertFromIdfPartition(const esp_partition_t* partition); + bool abort() override + { + return true; + } + + bool setBootPartition(Partition partition) override + { + return esp_ota_set_boot_partition(convertToIdfPartition(partition)) == ESP_OK; + } + + Partition getBootPartition(void) override + { + return convertFromIdfPartition(esp_ota_get_boot_partition()); + } + + Partition getRunningPartition(void) override + { + return convertFromIdfPartition(esp_ota_get_running_partition()); + } + + Partition getNextBootPartition(Partition startFrom = {}) override + { + const esp_partition_t* idfFrom = startFrom ? convertToIdfPartition(startFrom) : nullptr; + return convertFromIdfPartition(esp_ota_get_next_update_partition(idfFrom)); + } + + static const esp_partition_t* convertToIdfPartition(Partition partition) + { + return esp_partition_find_first(esp_partition_type_t(partition.type()), + esp_partition_subtype_t(partition.subType()), partition.name().c_str()); + } + + static Partition convertFromIdfPartition(const esp_partition_t* partition) + { + return partition ? Storage::findPartition(String(partition->label)) : Partition{}; + } private: size_t maxSize{0}; diff --git a/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp b/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp index 2b85683fd9..e015480e43 100644 --- a/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp +++ b/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp @@ -46,41 +46,4 @@ size_t RbootUpgrader::write(const uint8_t* buffer, size_t size) return size; } -bool RbootUpgrader::end() -{ - return rboot_write_end(&status); -} - -bool RbootUpgrader::setBootPartition(Partition partition) -{ - return rboot_set_current_rom(getSlotForPartition(partition)); -} - -Partition RbootUpgrader::getBootPartition(void) -{ - return getPartitionForSlot(rboot_get_current_rom()); -} - -Partition RbootUpgrader::getRunningPartition(void) -{ - // TODO: ... - return getPartitionForSlot(rboot_get_current_rom()); -} - -Partition RbootUpgrader::getNextBootPartition(Partition startFrom) -{ - uint8_t currentSlot = rboot_get_current_rom(); - return getPartitionForSlot(currentSlot ? 0 : 1); -} - -uint8_t RbootUpgrader::getSlotForPartition(Partition partition) -{ - return (partition.subType() == uint8_t(Partition::SubType::App::ota1)) ? 1 : 0; -} - -Partition RbootUpgrader::getPartitionForSlot(uint8_t slot) -{ - return spiFlash->partitions().findOta(slot); -} - } // namespace Ota diff --git a/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h b/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h index 859186b167..34585071a4 100644 --- a/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h +++ b/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h @@ -24,15 +24,43 @@ class RbootUpgrader : public UpgraderBase */ bool begin(Partition partition, size_t size = 0) override; size_t write(const uint8_t* buffer, size_t size) override; - bool end() override; - bool setBootPartition(Partition partition) override; - Partition getBootPartition() override; - Partition getRunningPartition() override; - Partition getNextBootPartition(Partition startFrom = {}) override; + bool end() override + { + return rboot_write_end(&status); + } - static uint8_t getSlotForPartition(Partition partition); - static Partition getPartitionForSlot(uint8_t slot); + bool setBootPartition(Partition partition) override + { + return rboot_set_current_rom(getSlotForPartition(partition)); + } + + Partition getBootPartition() override + { + return getPartitionForSlot(rboot_get_current_rom()); + } + + Partition getRunningPartition() override + { + // TODO: ... + return getPartitionForSlot(rboot_get_current_rom()); + } + + Partition getNextBootPartition(Partition startFrom = {}) override + { + uint8_t currentSlot = rboot_get_current_rom(); + return getPartitionForSlot(currentSlot ? 0 : 1); + } + + static uint8_t getSlotForPartition(Partition partition) + { + return (partition.subType() == uint8_t(Partition::SubType::App::ota1)) ? 1 : 0; + } + + static Partition getPartitionForSlot(uint8_t slot) + { + return Storage::spiFlash->partitions().findOta(slot); + } private: rboot_write_status status{}; From c91b5f002250ecfb1d43c57fb8db188bec4fe005 Mon Sep 17 00:00:00 2001 From: Slavey Karadzhov Date: Tue, 25 May 2021 17:37:55 +0200 Subject: [PATCH 12/15] Added review fixes. --- Sming/Arch/Esp32/spiffs-two-roms.hw | 27 +++++++++---------- Sming/Components/Ota/README.rst | 8 +++--- .../Ota/src/Arch/Esp32/IdfUpgrader.cpp | 2 +- .../src/Arch/Esp32/include/Ota/IdfUpgrader.h | 7 ++--- .../Ota/src/Arch/Esp8266/RbootUpgrader.cpp | 2 +- .../Ota/src/include/Ota/UpgraderBase.h | 4 +-- Sming/Components/OtaNetwork/README.rst | 12 ++++----- samples/Basic_Ota/app/application.cpp | 16 +++++------ 8 files changed, 37 insertions(+), 41 deletions(-) diff --git a/Sming/Arch/Esp32/spiffs-two-roms.hw b/Sming/Arch/Esp32/spiffs-two-roms.hw index 76867643ce..0d7f3d35ea 100644 --- a/Sming/Arch/Esp32/spiffs-two-roms.hw +++ b/Sming/Arch/Esp32/spiffs-two-roms.hw @@ -2,22 +2,21 @@ "name": "Two ROM slots with single SPIFFS", "base_config": "spiffs", "partitions": { - "factory": { - "address": "0x10000", - "size": "1M" - }, + "factory": { + "size": "1M" + }, "rom0": { - "address": "0x110000", - "size": "960K", - "type": "app", + "address": "0x110000", + "size": "960K", + "type": "app", "subtype": "ota_0", "filename": "$(TARGET_BIN)" }, - "ota": { // Ota Table - "address": "0x00200000", - "size": "8K", - "type" : "data", - "subtype": "ota" + "ota": { + "address": "0x00200000", + "size": "8K", + "type": "data", + "subtype": "ota" }, "rom1": { "address": "0x210000", @@ -27,8 +26,8 @@ "filename": "" }, "spiffs0": { - "address": "0x300000", - "size": "1M" + "address": "0x300000", + "size": "1M" } } } \ No newline at end of file diff --git a/Sming/Components/Ota/README.rst b/Sming/Components/Ota/README.rst index 96bb1990f4..5b0c046e43 100644 --- a/Sming/Components/Ota/README.rst +++ b/Sming/Components/Ota/README.rst @@ -8,8 +8,8 @@ Introduction This architecture-agnostic component adds support for Over-The-Air upgrades. -Usaging -------- +Usage +----- 1. Add ``COMPONENT_DEPENDS += Ota`` to your application componenent.mk file. 2. Add these lines to your application:: @@ -24,9 +24,9 @@ After that you will have access to a global ``OtaManager`` instance that can be { // ... - auto part = OtaManager.getRunningPartition(); + auto partition = OtaManager.getRunningPartition(); - Serial.printf(_F("\r\nCurrently running rom %s@%x.\r\n"), part.name().c_str(), part.address()); + Serial.printf("\r\nCurrently running %s @ 0x%08x.\r\n", partition.name().c_str(), partition.address()); } diff --git a/Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp b/Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp index dc97261695..3b2af6d886 100644 --- a/Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp +++ b/Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp @@ -21,7 +21,7 @@ bool IdfUpgrader::begin(Partition partition, size_t size) writtenSoFar = 0; maxSize = size ?: partition.size(); - esp_err_t result = esp_ota_begin(convertToIdfPartition(partition), size ? size : partition.size(), &handle); + esp_err_t result = esp_ota_begin(convertToIdfPartition(partition), size ?: partition.size(), &handle); return result == ESP_OK; } diff --git a/Sming/Components/Ota/src/Arch/Esp32/include/Ota/IdfUpgrader.h b/Sming/Components/Ota/src/Arch/Esp32/include/Ota/IdfUpgrader.h index 445358d8e6..b8cd357320 100644 --- a/Sming/Components/Ota/src/Arch/Esp32/include/Ota/IdfUpgrader.h +++ b/Sming/Components/Ota/src/Arch/Esp32/include/Ota/IdfUpgrader.h @@ -19,9 +19,6 @@ namespace Ota class IdfUpgrader : public UpgraderBase { public: - /** - * @brief Prepare the partition for - */ bool begin(Partition partition, size_t size = 0) override; size_t write(const uint8_t* buffer, size_t size) override; @@ -40,12 +37,12 @@ class IdfUpgrader : public UpgraderBase return esp_ota_set_boot_partition(convertToIdfPartition(partition)) == ESP_OK; } - Partition getBootPartition(void) override + Partition getBootPartition() override { return convertFromIdfPartition(esp_ota_get_boot_partition()); } - Partition getRunningPartition(void) override + Partition getRunningPartition() override { return convertFromIdfPartition(esp_ota_get_running_partition()); } diff --git a/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp b/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp index e015480e43..c5ba55502e 100644 --- a/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp +++ b/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp @@ -4,7 +4,7 @@ * http://github.com/SmingHub/Sming * All files of the Sming Core are provided under the LGPL v3 license. * - * Ota.cpp + * RbootUpgrader.cpp * ****/ diff --git a/Sming/Components/Ota/src/include/Ota/UpgraderBase.h b/Sming/Components/Ota/src/include/Ota/UpgraderBase.h index 7f7ef938a6..79d3e9c7de 100644 --- a/Sming/Components/Ota/src/include/Ota/UpgraderBase.h +++ b/Sming/Components/Ota/src/include/Ota/UpgraderBase.h @@ -60,13 +60,13 @@ class UpgraderBase * @brief Gets information about the parition that is set as the default one to boot. * @note The returned parition can be different than the current running partition. */ - virtual Partition getBootPartition(void) = 0; + virtual Partition getBootPartition() = 0; /** * @brief Gets information about the parition from which the current application is running. * @note The returned parition can be different than the default boot partition. */ - virtual Partition getRunningPartition(void) = 0; + virtual Partition getRunningPartition() = 0; /** * @brief Gets the next bootable partition that can be used after successful OTA upgrade diff --git a/Sming/Components/OtaNetwork/README.rst b/Sming/Components/OtaNetwork/README.rst index 96bb1990f4..c9b4f283c7 100644 --- a/Sming/Components/OtaNetwork/README.rst +++ b/Sming/Components/OtaNetwork/README.rst @@ -8,8 +8,8 @@ Introduction This architecture-agnostic component adds support for Over-The-Air upgrades. -Usaging -------- +Usage +----- 1. Add ``COMPONENT_DEPENDS += Ota`` to your application componenent.mk file. 2. Add these lines to your application:: @@ -24,9 +24,9 @@ After that you will have access to a global ``OtaManager`` instance that can be { // ... - auto part = OtaManager.getRunningPartition(); + auto partition = OtaManager.getRunningPartition(); - Serial.printf(_F("\r\nCurrently running rom %s@%x.\r\n"), part.name().c_str(), part.address()); + Serial.printf("\r\nCurrently running %s @ 0x%08x.\r\n", partition.name().c_str(), partition.address()); } @@ -40,9 +40,9 @@ After that you will have access to a global ``OtaManager`` instance that can be OtaUpgrader ota; - auto part = ota.getNextBootPartition(); + auto partition = ota.getNextBootPartition(); - ota.begin(part); + ota.begin(partition); // ... write all the data to the partition diff --git a/samples/Basic_Ota/app/application.cpp b/samples/Basic_Ota/app/application.cpp index 05d4a18477..dbeabcaf06 100644 --- a/samples/Basic_Ota/app/application.cpp +++ b/samples/Basic_Ota/app/application.cpp @@ -25,7 +25,7 @@ Storage::Partition findSpiffsPartition(Storage::Partition partition) return part; } -void otaUpdateCallBack(Ota::Network::HttpUpgrader& client, bool result) +void upgradeCallback(Ota::Network::HttpUpgrader& client, bool result) { Serial.println("In callback..."); if(result == true) { @@ -44,7 +44,7 @@ void otaUpdateCallBack(Ota::Network::HttpUpgrader& client, bool result) } } -void OtaUpdate() +void doUpgrade() { Serial.println("Updating..."); @@ -76,13 +76,13 @@ void OtaUpdate() // request switch and reboot on success //otaUpdater->switchToRom(slot); // and/or set a callback (called on failure or success without switching requested) - otaUpdater->setCallback(otaUpdateCallBack); + otaUpdater->setCallback(upgradeCallback); // start update otaUpdater->start(); } -void Switch() +void doSwitch() { auto before = ota.getRunningPartition(); auto after = ota.getNextBootPartition(); @@ -97,7 +97,7 @@ void Switch() } } -void ShowInfo() +void showInfo() { Serial.printf("\r\nSDK: v%s\r\n", system_get_sdk_version()); Serial.printf("Free Heap: %d\r\n", system_get_free_heap_size()); @@ -136,9 +136,9 @@ void serialCallBack(Stream& stream, char arrivedChar, unsigned short availableCh Serial.print(" mac: "); Serial.println(WifiStation.getMacAddress()); } else if(!strcmp(str, "ota")) { - OtaUpdate(); + doUpgrade(); } else if(!strcmp(str, "switch")) { - Switch(); + doSwitch(); } else if(!strcmp(str, "restart")) { System.restart(); } else if(!strcmp(str, "ls")) { @@ -164,7 +164,7 @@ void serialCallBack(Stream& stream, char arrivedChar, unsigned short availableCh Serial.println("Empty spiffs!"); } } else if(!strcmp(str, "info")) { - ShowInfo(); + showInfo(); } else if(!strcmp(str, "help")) { Serial.println(); Serial.println("available commands:"); From c9323e1c1fd4e70ec690bc9469def37f5c1e5a90 Mon Sep 17 00:00:00 2001 From: Slavey Karadzhov Date: Tue, 25 May 2021 17:59:22 +0200 Subject: [PATCH 13/15] Added better detection of running partition for rBoot. --- .../Ota/src/Arch/Esp8266/RbootUpgrader.cpp | 13 +++++++++++++ .../src/Arch/Esp8266/include/Ota/RbootUpgrader.h | 6 +----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp b/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp index c5ba55502e..bcd0dbfd29 100644 --- a/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp +++ b/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp @@ -46,4 +46,17 @@ size_t RbootUpgrader::write(const uint8_t* buffer, size_t size) return size; } +Partition RbootUpgrader::getRunningPartition() +{ + uint8_t slot = rboot_get_current_rom(); +#ifdef RBOOT_ENABLE_RTC + rboot_rtc_data rtc; + rboot_get_rtc_data(&rtc); + if(rtc.last_mode == MODE_TEMP_ROM) { + slot = rtc.last_rom; + } +#endif + return getPartitionForSlot(slot); +} + } // namespace Ota diff --git a/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h b/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h index 34585071a4..8bf8901039 100644 --- a/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h +++ b/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h @@ -40,11 +40,7 @@ class RbootUpgrader : public UpgraderBase return getPartitionForSlot(rboot_get_current_rom()); } - Partition getRunningPartition() override - { - // TODO: ... - return getPartitionForSlot(rboot_get_current_rom()); - } + Partition getRunningPartition() override; Partition getNextBootPartition(Partition startFrom = {}) override { From a14cb1bdfdeab03329ccdb442bfcc20ec75d8fb5 Mon Sep 17 00:00:00 2001 From: Slavey Karadzhov Date: Wed, 26 May 2021 09:56:13 +0200 Subject: [PATCH 14/15] Polishing. --- README.md | 4 +- Sming/Arch/Esp8266/spiffs-two-roms.hw | 4 +- .../Ota/src/Arch/Esp32/IdfUpgrader.cpp | 2 +- .../Ota/src/Arch/Esp8266/RbootUpgrader.cpp | 3 +- .../Arch/Esp8266/include/Ota/RbootUpgrader.h | 3 ++ Sming/Components/OtaNetwork/README.rst | 4 +- .../OtaNetwork/src/HttpUpgrader.cpp | 7 +-- .../src/include/Ota/Network/HttpUpgrader.h | 2 +- .../samples/Upgrade/component.mk | 2 +- .../OtaUpgradeMqtt/samples/Upgrade/ota.hw | 18 ++++---- docs/source/getting-started/index.rst | 45 +++++++------------ samples/Basic_Ota/README.rst | 22 +++++---- samples/Basic_Ota/ota.hw | 18 ++++---- 13 files changed, 61 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index 6d5c61f120..74afea59b8 100644 --- a/README.md +++ b/README.md @@ -238,7 +238,7 @@ For more examples take a look at the [HttpClient](samples/HttpClient/app/applica ### OTA Application Update ```c++ -void OtaUpdate() +void doUpgrade() { // need a clean object, otherwise if run before and failed will not run again if(otaUpdater) { @@ -253,7 +253,7 @@ void OtaUpdate()   otaUpdater->addItem(ROM_0_URL, part);   // and/or set a callback (called on failure or success without switching requested) -  otaUpdater->setCallback(OtaUpdate_CallBack); +  otaUpdater->setCallback(upgradeCallback);   // start update   otaUpdater->start(); diff --git a/Sming/Arch/Esp8266/spiffs-two-roms.hw b/Sming/Arch/Esp8266/spiffs-two-roms.hw index 93e4605b47..204546a8f7 100644 --- a/Sming/Arch/Esp8266/spiffs-two-roms.hw +++ b/Sming/Arch/Esp8266/spiffs-two-roms.hw @@ -6,11 +6,11 @@ "subtype": "ota_0" }, "rom1": { - "address": "0x108000", + "address": "0x102000", "size": "992K", "type": "app", "subtype": "ota_1", - "filename": "$(RBOOT_ROM_1_BIN)" + "filename": "$(RBOOT_ROM_0_BIN)" } } } diff --git a/Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp b/Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp index 3b2af6d886..39af014010 100644 --- a/Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp +++ b/Sming/Components/Ota/src/Arch/Esp32/IdfUpgrader.cpp @@ -21,7 +21,7 @@ bool IdfUpgrader::begin(Partition partition, size_t size) writtenSoFar = 0; maxSize = size ?: partition.size(); - esp_err_t result = esp_ota_begin(convertToIdfPartition(partition), size ?: partition.size(), &handle); + esp_err_t result = esp_ota_begin(convertToIdfPartition(partition), maxSize, &handle); return result == ESP_OK; } diff --git a/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp b/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp index bcd0dbfd29..a760f6223a 100644 --- a/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp +++ b/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp @@ -51,8 +51,7 @@ Partition RbootUpgrader::getRunningPartition() uint8_t slot = rboot_get_current_rom(); #ifdef RBOOT_ENABLE_RTC rboot_rtc_data rtc; - rboot_get_rtc_data(&rtc); - if(rtc.last_mode == MODE_TEMP_ROM) { + if(rboot_get_rtc_data(&rtc) && rtc.last_mode == MODE_TEMP_ROM) { slot = rtc.last_rom; } #endif diff --git a/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h b/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h index 8bf8901039..dbf693acb9 100644 --- a/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h +++ b/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h @@ -45,6 +45,9 @@ class RbootUpgrader : public UpgraderBase Partition getNextBootPartition(Partition startFrom = {}) override { uint8_t currentSlot = rboot_get_current_rom(); + if(startFrom) { + currentSlot = getSlotForPartition(startFrom); + } return getPartitionForSlot(currentSlot ? 0 : 1); } diff --git a/Sming/Components/OtaNetwork/README.rst b/Sming/Components/OtaNetwork/README.rst index c9b4f283c7..84f479d9cf 100644 --- a/Sming/Components/OtaNetwork/README.rst +++ b/Sming/Components/OtaNetwork/README.rst @@ -1,5 +1,5 @@ -Over-The-Air(OTA) Upgrader -========================== +Over-The-Air(OTA) Network Upgrader +================================== .. highlight:: c++ diff --git a/Sming/Components/OtaNetwork/src/HttpUpgrader.cpp b/Sming/Components/OtaNetwork/src/HttpUpgrader.cpp index ea9e440818..90b893391f 100644 --- a/Sming/Components/OtaNetwork/src/HttpUpgrader.cpp +++ b/Sming/Components/OtaNetwork/src/HttpUpgrader.cpp @@ -4,12 +4,7 @@ * http://github.com/SmingHub/Sming * All files of the Sming Core are provided under the LGPL v3 license. * - * RbootHttpUpdater.cpp - * - * Created on: 2015/09/03. - * Author: Richard A Burton & Anakod - * - * Modified: 2017 - Slavey Karadzhov + * HttpUpdater.cpp * */ diff --git a/Sming/Components/OtaNetwork/src/include/Ota/Network/HttpUpgrader.h b/Sming/Components/OtaNetwork/src/include/Ota/Network/HttpUpgrader.h index 3fb528cc5d..40816b6491 100644 --- a/Sming/Components/OtaNetwork/src/include/Ota/Network/HttpUpgrader.h +++ b/Sming/Components/OtaNetwork/src/include/Ota/Network/HttpUpgrader.h @@ -9,7 +9,7 @@ * Created on: 2015/09/03. * Author: Richard A Burton & Anakod * - * Modified: 2017 - Slavey Karadzhov + * Modified: 2017, 2021 - Slavey Karadzhov * ****/ diff --git a/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/component.mk b/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/component.mk index cb3b098df4..7b087c1768 100644 --- a/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/component.mk +++ b/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/component.mk @@ -48,7 +48,7 @@ COMPONENT_DEPENDS := OtaUpgradeMqtt RBOOT_ENABLED := 1 ## Use standard hardware config with two ROM slots and two SPIFFS partitions -HWCONFIG := ota +HWCONFIG := ota APP_CFLAGS = -DMQTT_URL="\"$(MQTT_URL)"\" \ -DMQTT_FINGERPRINT_SHA1=$(MQTT_FINGERPRINT_SHA1) \ diff --git a/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/ota.hw b/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/ota.hw index aceea30053..c5d71daa72 100644 --- a/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/ota.hw +++ b/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/ota.hw @@ -1,11 +1,11 @@ { - "base_config": "spiffs-two-roms", - "partitions": { - "rom0": { - "subtype": "ota_0" - }, - "rom1": { - "subtype": "ota_1" - } - } + "base_config": "spiffs-two-roms", + "partitions": { + "rom0": { + "subtype": "ota_0" + }, + "rom1": { + "subtype": "ota_1" + } + } } \ No newline at end of file diff --git a/docs/source/getting-started/index.rst b/docs/source/getting-started/index.rst index 9de62a7292..3f8e4e04d5 100644 --- a/docs/source/getting-started/index.rst +++ b/docs/source/getting-started/index.rst @@ -47,7 +47,7 @@ The examples are a great way to learn the API and brush up your C/C++ knowledge. - `Connect to WiFi <#connect-to-wifi>`__ - `Read DHT22 sensor <#read-dht22-sensor>`__ - `HTTP client <#http-client>`__ -- `OTA application update based on rBoot <#ota-application-update-based-on-rboot>`__ +- `OTA application update based on rBoot <#ota-application-update>`__ - `Embedded HTTP Web Server <#embedded-http-web-server>`__ - `Email Client <#email-client>`__ @@ -140,46 +140,33 @@ For more examples take a look at the :sample:`HttpClient_Instapush` and :sample:`HttpClient_ThingSpeak` samples. -OTA application update based on rBoot -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +OTA application update +~~~~~~~~~~~~~~~~~~~~~~ :: - void OtaUpdate() + void doUpgrade() { - uint8 slot; - rboot_config bootconf; - - Serial.println("Updating..."); - // need a clean object, otherwise if run before and failed will not run again - if (otaUpdater) { - delete otaUpdater; + if(otaUpdater) { + delete otaUpdater; } + otaUpdater = new Ota::Network::HttpUpgrader(); - otaUpdater = new RbootHttpUpdater(); - - // select rom slot to flash - bootconf = rboot_get_config(); - slot = bootconf.current_rom; - if (slot == 0) { - slot = 1; - } - else { - slot = 0; - } + // select rom partition to flash + auto part = ota.getNextBootPartition(); - // flash rom to position indicated in the rBoot config rom table - otaUpdater->addItem(bootconf.roms[slot], ROM_0_URL); +   // The content located on ROM_0_URL will be stored to the new partition +   otaUpdater->addItem(ROM_0_URL, part); - // and/or set a callback (called on failure or success without switching requested) - otaUpdater->setCallback(OtaUpdate_CallBack); +   // and/or set a callback (called on failure or success without switching requested) +   otaUpdater->setCallback(upgradeCallback); - // start update - otaUpdater->start(); +   // start update +   otaUpdater->start(); } -For a complete example take a look at the :sample:`Basic_rBoot` sample. +For a complete example take a look at the :sample:`Basic_Ota` sample. Embedded HTTP Web Server ~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/samples/Basic_Ota/README.rst b/samples/Basic_Ota/README.rst index a5d2dba443..c099370144 100644 --- a/samples/Basic_Ota/README.rst +++ b/samples/Basic_Ota/README.rst @@ -28,15 +28,21 @@ Building 4) Put *rom0.bin* and *spiff_rom.bin* in the root of your webserver for OTA. 5) Interact with the sample using a terminal (``make terminal``). Sorry - no web-gui (yet). -Technical Notes ---------------- -Esp8266 -~~~~~~~ -Important compiler flags used: +Testing +------- + +For testing purposes we provide an Ota server that can be started on your desktop machine:: -- BOOT_BIG_FLASH - when using big flash mode, ensures flash mapping code is built in to the rom. -- RBOOT_INTEGRATION - ensures Sming specific options are pulled in to the rBoot source at compile time. + make otaserver + +The server listens on port 9999 and all network interfaces. If your desktop has the following IP address ``192.168.1.30`` +after connecting to your WIFI router then you can compile the sample to use this IP address and the testing OTA server:: + + make ROM_0_URL=http://192.168.1.30:9999/rom0.bin SPIFFS_URL=http://192.168.1.30:9999/spiff_rom.bin + make flash + +Make sure to replace ``192.168.1.30`` with your WIFI IP address. Flash layout considerations --------------------------- @@ -57,8 +63,6 @@ See :component:`rboot` for further details. If you want more than two roms you must be an advanced user and should be able to work out what to copy and edit to acheive this! -Config Variables - Configuration ------------- .. envvar:: RBOOT_TWO_ROMS diff --git a/samples/Basic_Ota/ota.hw b/samples/Basic_Ota/ota.hw index aceea30053..c5d71daa72 100644 --- a/samples/Basic_Ota/ota.hw +++ b/samples/Basic_Ota/ota.hw @@ -1,11 +1,11 @@ { - "base_config": "spiffs-two-roms", - "partitions": { - "rom0": { - "subtype": "ota_0" - }, - "rom1": { - "subtype": "ota_1" - } - } + "base_config": "spiffs-two-roms", + "partitions": { + "rom0": { + "subtype": "ota_0" + }, + "rom1": { + "subtype": "ota_1" + } + } } \ No newline at end of file From 38465c3952bbf613d272bf134868d392329775f7 Mon Sep 17 00:00:00 2001 From: Slavey Karadzhov Date: Wed, 26 May 2021 15:31:05 +0200 Subject: [PATCH 15/15] Add support for temporary switch to the next rom. --- .../src/Arch/Esp32/include/Ota/IdfUpgrader.h | 6 +++- .../Ota/src/Arch/Esp8266/RbootUpgrader.cpp | 14 ++++++++ .../Arch/Esp8266/include/Ota/RbootUpgrader.h | 5 +-- .../Ota/src/include/Ota/UpgraderBase.h | 33 +++++++++++++++++-- 4 files changed, 50 insertions(+), 8 deletions(-) diff --git a/Sming/Components/Ota/src/Arch/Esp32/include/Ota/IdfUpgrader.h b/Sming/Components/Ota/src/Arch/Esp32/include/Ota/IdfUpgrader.h index b8cd357320..906354e45c 100644 --- a/Sming/Components/Ota/src/Arch/Esp32/include/Ota/IdfUpgrader.h +++ b/Sming/Components/Ota/src/Arch/Esp32/include/Ota/IdfUpgrader.h @@ -32,8 +32,12 @@ class IdfUpgrader : public UpgraderBase return true; } - bool setBootPartition(Partition partition) override + bool setBootPartition(Partition partition, bool save = true) override { + if(!save) { + return false; + } + return esp_ota_set_boot_partition(convertToIdfPartition(partition)) == ESP_OK; } diff --git a/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp b/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp index a760f6223a..50bbe5b372 100644 --- a/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp +++ b/Sming/Components/Ota/src/Arch/Esp8266/RbootUpgrader.cpp @@ -46,6 +46,20 @@ size_t RbootUpgrader::write(const uint8_t* buffer, size_t size) return size; } +bool RbootUpgrader::setBootPartition(Partition partition, bool save) +{ + uint8_t slot = getSlotForPartition(partition); + if(!save) { +#ifdef RBOOT_ENABLE_RTC + return rboot_set_temp_rom(slot); +#else + return false; +#endif + } + + return rboot_set_current_rom(slot); +} + Partition RbootUpgrader::getRunningPartition() { uint8_t slot = rboot_get_current_rom(); diff --git a/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h b/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h index dbf693acb9..ecf42af05c 100644 --- a/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h +++ b/Sming/Components/Ota/src/Arch/Esp8266/include/Ota/RbootUpgrader.h @@ -30,10 +30,7 @@ class RbootUpgrader : public UpgraderBase return rboot_write_end(&status); } - bool setBootPartition(Partition partition) override - { - return rboot_set_current_rom(getSlotForPartition(partition)); - } + bool setBootPartition(Partition partition, bool save = true) override; Partition getBootPartition() override { diff --git a/Sming/Components/Ota/src/include/Ota/UpgraderBase.h b/Sming/Components/Ota/src/include/Ota/UpgraderBase.h index 79d3e9c7de..ebfbf2781a 100644 --- a/Sming/Components/Ota/src/include/Ota/UpgraderBase.h +++ b/Sming/Components/Ota/src/include/Ota/UpgraderBase.h @@ -30,11 +30,19 @@ class UpgraderBase /** * @brief Prepares a partition for an upgrade. * The preparation is bootloader and architecture dependant. + * @param partition + * @param size + * + * @retval bool */ - virtual bool begin(Partition partition, size_t size) = 0; + virtual bool begin(Partition partition, size_t size = 0) = 0; /** * @brief Writes chunk of data to the partition set in ``begin()``. + * @param buffer + * @param size + * + * @retval size_t actually written bytes */ virtual size_t write(const uint8_t* buffer, size_t size) = 0; @@ -53,28 +61,41 @@ class UpgraderBase /** * @brief Sets the default parition from where the application will be booted on next restart. + * @param partition + * @param save if true the change is persisted on the flash, otherwise it will be valid only for the next boot + * + * @retval bool */ - virtual bool setBootPartition(Partition partition) = 0; + virtual bool setBootPartition(Partition partition, bool save = true) = 0; /** * @brief Gets information about the parition that is set as the default one to boot. * @note The returned parition can be different than the current running partition. + * + * @retval partition */ virtual Partition getBootPartition() = 0; /** * @brief Gets information about the parition from which the current application is running. * @note The returned parition can be different than the default boot partition. - */ + * + * @retval partition + */ virtual Partition getRunningPartition() = 0; /** * @brief Gets the next bootable partition that can be used after successful OTA upgrade + * @param startFrom - optional + * + * @retval partition */ virtual Partition getNextBootPartition(Partition startFrom = {}) = 0; /** * @brief Gets information about all bootable partitions. + * + * @retval Storage::Iterator */ Storage::Iterator getBootPartitions() { @@ -83,6 +104,12 @@ class UpgraderBase // utility functions + /** + * @brief Gets slot number for a partition + * @param partition + * + * @retval uint8_t slot number + */ uint8_t getSlot(Partition partition) { if(partition.type() != Partition::Type::app) {