diff --git a/.gitmodules b/.gitmodules index c828c2366a..c4ac5e4caf 100644 --- a/.gitmodules +++ b/.gitmodules @@ -213,10 +213,6 @@ path = Sming/Libraries/CS5460/CS5460 url = https://github.com/xxzl0130/CS5460.git ignore = dirty -[submodule "Libraries.DIAL"] - path = Sming/Libraries/DIAL - url = https://github.com/slaff/Sming-DIAL.git - ignore = dirty [submodule "Libraries.DFRobotDFPlayerMini"] path = Sming/Libraries/DFRobotDFPlayerMini url = https://github.com/DFRobot/DFRobotDFPlayerMini.git @@ -225,6 +221,18 @@ path = Sming/Libraries/DHTesp url = https://github.com/beegee-tokyo/DHTesp.git ignore = dirty +[submodule "Libraries.DIAL"] + path = Sming/Libraries/DIAL + url = https://github.com/slaff/Sming-DIAL.git + ignore = dirty +[submodule "Libraries.DiskStorage"] + path = Sming/Libraries/DiskStorage + url = https://github.com/mikee47/DiskStorage + ignore = dirty +[submodule "Libraries.FatIFS"] + path = Sming/Libraries/FatIFS + url = https://github.com/mikee47/FatIFS + ignore = dirty [submodule "Libraries.flatbuffers"] path = Sming/Libraries/flatbuffers/src url = https://github.com/google/flatbuffers.git @@ -313,6 +321,10 @@ path = Sming/Libraries/RingTone url = https://github.com/mikee47/RingTone ignore = dirty +[submodule "Libraries.SdStorage"] + path = Sming/Libraries/SdStorage + url = https://github.com/mikee47/SdStorage + ignore = dirty [submodule "Libraries.SignalGenerator"] path = Sming/Libraries/SignalGenerator url = https://github.com/mikee47/SignalGenerator diff --git a/Sming/Arch/Esp8266/Components/esp8266/startup.cpp b/Sming/Arch/Esp8266/Components/esp8266/startup.cpp index facaec0a26..79d1d9794b 100644 --- a/Sming/Arch/Esp8266/Components/esp8266/startup.cpp +++ b/Sming/Arch/Esp8266/Components/esp8266/startup.cpp @@ -48,22 +48,39 @@ extern "C" void ICACHE_FLASH_ATTR WEAK_ATTR user_pre_init(void) { Storage::initialize(); - auto sysParam = *Storage::findPartition(Storage::Partition::SubType::Data::sysParam); - auto rfCal = *Storage::findPartition(Storage::Partition::SubType::Data::rfCal); - auto phy = *Storage::findPartition(Storage::Partition::SubType::Data::phy); + using PartType = Storage::Partition::SubType::Data; + auto sysParam = *Storage::findPartition(PartType::sysParam); + auto rfCal = *Storage::findPartition(PartType::rfCal); + auto phy = *Storage::findPartition(PartType::phy); - static const partition_item_t partitions[] = { - {SYSTEM_PARTITION_BOOTLOADER, 0, SPI_FLASH_SEC_SIZE}, - {SYSTEM_PARTITION_PHY_DATA, phy.address(), phy.size()}, - {SYSTEM_PARTITION_SYSTEM_PARAMETER, sysParam.address(), sysParam.size()}, - {SYSTEM_PARTITION_RF_CAL, rfCal.address(), rfCal.size()}, + static const partition_item_t partitions[]{ + { + SYSTEM_PARTITION_BOOTLOADER, + 0, + SPI_FLASH_SEC_SIZE, + }, + { + SYSTEM_PARTITION_PHY_DATA, + uint32_t(phy.address()), + uint32_t(phy.size()), + }, + { + SYSTEM_PARTITION_SYSTEM_PARAMETER, + uint32_t(sysParam.address()), + uint32_t(sysParam.size()), + }, + { + SYSTEM_PARTITION_RF_CAL, + uint32_t(rfCal.address()), + uint32_t(rfCal.size()), + }, }; enum flash_size_map sizeMap = system_get_flash_size_map(); if(!system_partition_table_regist(partitions, ARRAY_SIZE(partitions), sizeMap)) { os_printf("system_partition_table_regist: failed\n"); os_printf("size_map = %u\n", sizeMap); - for (unsigned i = 0; i < ARRAY_SIZE(partitions); ++i) { + for(unsigned i = 0; i < ARRAY_SIZE(partitions); ++i) { auto& part = partitions[i]; os_printf("partition[%u]: %u, 0x%08x, 0x%08x\n", i, part.type, part.addr, part.size); } diff --git a/Sming/Arch/Host/Components/spi_flash/component.mk b/Sming/Arch/Host/Components/spi_flash/component.mk index 510aaa7e76..0aa8fcafcc 100644 --- a/Sming/Arch/Host/Components/spi_flash/component.mk +++ b/Sming/Arch/Host/Components/spi_flash/component.mk @@ -1 +1,3 @@ COMPONENT_INCDIRS += $(ESP8266_COMPONENTS)/spi_flash/include + +COMPONENT_DEPENDS := IFS diff --git a/Sming/Arch/Rp2040/Components/rp2040/component.mk b/Sming/Arch/Rp2040/Components/rp2040/component.mk index ebbe18cfa1..670b13ba31 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/component.mk +++ b/Sming/Arch/Rp2040/Components/rp2040/component.mk @@ -91,7 +91,8 @@ LIBDIRS += \ EXTRA_LIBS += \ pico \ m \ - stdc++ + stdc++ \ + gcc RP2040_CMAKE_OPTIONS := \ -G Ninja \ diff --git a/Sming/Components/IFS b/Sming/Components/IFS index e69049e93b..1767d7020e 160000 --- a/Sming/Components/IFS +++ b/Sming/Components/IFS @@ -1 +1 @@ -Subproject commit e69049e93bc6efa4b6fe0d4dd07209fac450a0e1 +Subproject commit 1767d7020e18c8ffa0c58b31a5650a5275ee47c6 diff --git a/Sming/Components/Storage/README.rst b/Sming/Components/Storage/README.rst index 56a0dce5ad..6cd6ac162f 100644 --- a/Sming/Components/Storage/README.rst +++ b/Sming/Components/Storage/README.rst @@ -304,6 +304,20 @@ Configuration Set this to adjust the hardware profile using option fragments. See :ref:`hwconfig_options`. +.. envvar:: ENABLE_STORAGE_SIZE64 + + Build with ``ENABLE_STORAGE_SIZE64=1`` to enable support for storage devices of more than 4GB capacity. + + Device and partition addresses and sizes use the :cpp:type:`storage_size_t` type, which by default is ``uint32_t``. + Setting this value changes it to ``uint64_t``. + + When enabling this setting, care must be taken in code especially with ``printf`` style format strings such + as in debug statements. The safest way to handle both cases is like this:: + + debug_i("Partition size: %llu", uint64_t(part.size())); + + + Binary partition table ---------------------- @@ -379,6 +393,9 @@ you can take advantage of the partition API to manage them as follows: in your ``init()`` function (or elsewhere if more appropriate). +See :library:`DiskStorage` for how devices such as SD flash cards are managed. + + API --- diff --git a/Sming/Components/Storage/component.mk b/Sming/Components/Storage/component.mk index 24967d8da7..13b96ee8f1 100644 --- a/Sming/Components/Storage/component.mk +++ b/Sming/Components/Storage/component.mk @@ -2,6 +2,11 @@ COMPONENT_INCDIRS := src/include COMPONENT_SRCDIRS := src COMPONENT_DOXYGEN_INPUT := src/include +COMPONENT_VARS := ENABLE_STORAGE_SIZE64 +ifeq ($(ENABLE_STORAGE_SIZE64),1) +GLOBAL_CFLAGS += -DENABLE_STORAGE_SIZE64 +endif + COMPONENT_RELINK_VARS := PARTITION_TABLE_OFFSET CONFIG_VARS += HWCONFIG HWCONFIG_OPTS diff --git a/Sming/Components/Storage/src/.cs b/Sming/Components/Storage/src/.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Components/Storage/src/Debug.cpp b/Sming/Components/Storage/src/Debug.cpp index 1ff281190b..531cbfec7c 100644 --- a/Sming/Components/Storage/src/Debug.cpp +++ b/Sming/Components/Storage/src/Debug.cpp @@ -16,6 +16,15 @@ void listPartitions(Print& out) out.println(); } +void listPartitions(Print& out, const Device& device) +{ + out << device.getName() << _F(" partitions:") << endl; + for(auto part : device.partitions()) { + out << "- " << part << endl; + } + out.println(); +} + void listDevices(Print& out, bool fullPartitionInfo) { out.println(); diff --git a/Sming/Components/Storage/src/Device.cpp b/Sming/Components/Storage/src/Device.cpp index d7aaa49d71..a1d5560f0f 100644 --- a/Sming/Components/Storage/src/Device.cpp +++ b/Sming/Components/Storage/src/Device.cpp @@ -4,7 +4,7 @@ * http://github.com/SmingHub/Sming * All files of the Sming Core are provided under the LGPL v3 license. * - * Device.h - external storage device API + * Device.cpp * ****/ @@ -89,8 +89,8 @@ bool Device::loadPartitions(Device& source, uint32_t tableOffset) toString(Device::Type(entry->subtype)).c_str(), toString(getType()).c_str()); } if(entry->size != getSize()) { - debug_w("[Device] '%s' size mismatch, 0x%08x in partition table but device reports 0x%08x", - getName().c_str(), entry->size, getSize()); + debug_w("[Device] '%s' size mismatch, 0x%08x in partition table but device reports 0x%08llx", + getName().c_str(), entry->size, uint64_t(getSize())); } // Skip the storage entry, not required diff --git a/Sming/Components/Storage/src/Partition.cpp b/Sming/Components/Storage/src/Partition.cpp index 03761fa929..d9f4bd13f5 100644 --- a/Sming/Components/Storage/src/Partition.cpp +++ b/Sming/Components/Storage/src/Partition.cpp @@ -4,7 +4,7 @@ * http://github.com/SmingHub/Sming * All files of the Sming Core are provided under the LGPL v3 license. * - * Partition.cpp - Partition support for all architectures + * Partition.cpp * ****/ @@ -158,7 +158,7 @@ bool Partition::verify(Partition::Type type, uint8_t subtype) const return true; } -bool Partition::getDeviceAddress(uint32_t& address, size_t size) const +bool Partition::getDeviceAddress(storage_size_t& address, storage_size_t size) const { if(mDevice == nullptr || mPart == nullptr) { debug_e("[Partition] Invalid"); @@ -166,7 +166,7 @@ bool Partition::getDeviceAddress(uint32_t& address, size_t size) const } if(address >= mPart->size || (address + size - 1) >= mPart->size) { - debug_e("[Partition] Invalid range, address: 0x%08x, size: 0x%08x", address, size); + debug_e("[Partition] Invalid range, address: 0x%08llx, size: 0x%08llx", uint64_t(address), uint64_t(size)); return false; } @@ -212,66 +212,82 @@ bool Partition::allowWrite() return true; } -bool Partition::read(uint32_t offset, void* dst, size_t size) +bool Partition::read(storage_size_t offset, void* dst, size_t size) { if(!allowRead()) { return false; } - uint32_t addr = offset; + auto addr = offset; if(!getDeviceAddress(addr, size)) { return false; } - return mDevice ? mDevice->read(addr, dst, size) : false; + return mDevice->read(addr, dst, size); } -bool Partition::write(uint32_t offset, const void* src, size_t size) +bool Partition::write(storage_size_t offset, const void* src, size_t size) { if(!allowWrite()) { return false; } - uint32_t addr = offset; + auto addr = offset; if(!getDeviceAddress(addr, size)) { return false; } - return mDevice ? mDevice->write(addr, src, size) : false; + return mDevice->write(addr, src, size); } -bool Partition::erase_range(uint32_t offset, size_t size) +bool Partition::erase_range(storage_size_t offset, storage_size_t size) { if(!allowWrite()) { return false; } - uint32_t addr = offset; + auto addr = offset; if(!getDeviceAddress(addr, size)) { return false; } - return mDevice ? mDevice->erase_range(addr, size) : false; + return mDevice->erase_range(addr, size); } -size_t Partition::printTo(Print& p) const +uint16_t Partition::getSectorSize() const +{ + return mDevice ? mDevice->getSectorSize() : Device::defaultSectorSize; +} + +bool Partition::sync() +{ + return mDevice ? mDevice->sync() : false; +} + +size_t Partition::Info::printTo(Print& p) const { size_t n{0}; + n += p.print(name.length() == 0 ? _F("(NO NAME)") : name.c_str()); + n += p.print(", "); + n += p.print(fullType()); + n += p.print(" @ 0x"); + n += p.print(offset, HEX); + n += p.print(_F(", size 0x")); + n += p.print(size, HEX); + return n; +} + +size_t Partition::printTo(Print& p) const +{ if(*this) { + size_t n{0}; n += p.print(getDeviceName()); n += p.print('/'); - n += p.print(name()); - n += p.print(" ("); - n += p.print(typeString()); - n += p.print(" @ 0x"); - n += p.print(address(), HEX); - n += p.print(_F(", size 0x")); - n += p.print(size(), HEX); - n += p.print(')'); - } else { - n += p.print(_F("(none)")); + n += p.print(*mPart); + return n; } - return n; + + return p.print(_F("(none)")); } } // namespace Storage diff --git a/Sming/Components/Storage/src/ProgMem.cpp b/Sming/Components/Storage/src/ProgMem.cpp index 34b4f25df0..78c3ebd2af 100644 --- a/Sming/Components/Storage/src/ProgMem.cpp +++ b/Sming/Components/Storage/src/ProgMem.cpp @@ -15,7 +15,7 @@ namespace Storage { ProgMem progMem; -bool ProgMem::read(uint32_t address, void* dst, size_t size) +bool ProgMem::read(storage_size_t address, void* dst, size_t size) { size_t readCount = flashmem_read(dst, address, size); return readCount == size; diff --git a/Sming/Components/Storage/src/SpiFlash.cpp b/Sming/Components/Storage/src/SpiFlash.cpp index 62a764600b..7aa0368699 100644 --- a/Sming/Components/Storage/src/SpiFlash.cpp +++ b/Sming/Components/Storage/src/SpiFlash.cpp @@ -33,24 +33,24 @@ size_t SpiFlash::getBlockSize() const return SPI_FLASH_SEC_SIZE; } -size_t SpiFlash::getSize() const +storage_size_t SpiFlash::getSize() const { return flashmem_get_size_bytes(); } -bool SpiFlash::read(uint32_t address, void* dst, size_t size) +bool SpiFlash::read(storage_size_t address, void* dst, size_t size) { size_t readCount = flashmem_read(dst, address, size); return readCount == size; } -bool SpiFlash::write(uint32_t address, const void* src, size_t size) +bool SpiFlash::write(storage_size_t address, const void* src, size_t size) { size_t writeCount = flashmem_write(src, address, size); return writeCount == size; } -bool SpiFlash::erase_range(uint32_t address, size_t size) +bool SpiFlash::erase_range(storage_size_t address, storage_size_t size) { if(address % SPI_FLASH_SEC_SIZE != 0 || size % SPI_FLASH_SEC_SIZE != 0) { debug_e("[Partition] erase address/size misaligned: 0x%08x / 0x%08x", address, size); diff --git a/Sming/Components/Storage/src/include/Storage/Debug.h b/Sming/Components/Storage/src/include/Storage/Debug.h index 113a1dd19e..659ddca3b3 100644 --- a/Sming/Components/Storage/src/include/Storage/Debug.h +++ b/Sming/Components/Storage/src/include/Storage/Debug.h @@ -8,6 +8,7 @@ namespace Storage namespace Debug { void listPartitions(Print& out); +void listPartitions(Print& out, const Device& device); void listDevices(Print& out, bool fullPartitionInfo = true); } // namespace Debug diff --git a/Sming/Components/Storage/src/include/Storage/Device.h b/Sming/Components/Storage/src/include/Storage/Device.h index 71b4987408..7ebaa32df8 100644 --- a/Sming/Components/Storage/src/include/Storage/Device.h +++ b/Sming/Components/Storage/src/include/Storage/Device.h @@ -111,9 +111,9 @@ class Device : public LinkedObjectTemplate /** * @brief Obtain addressable size of this device - * @retval size_t Must be at least as large as the value declared in the partition table + * @retval storage_size_t Must be at least as large as the value declared in the hardware configuration */ - virtual size_t getSize() const = 0; + virtual storage_size_t getSize() const = 0; /** * @brief Obtain device type @@ -127,7 +127,7 @@ class Device : public LinkedObjectTemplate * @param size Size of data to be read, in bytes. * @retval bool true on success, false on error */ - virtual bool read(uint32_t address, void* dst, size_t size) = 0; + virtual bool read(storage_size_t address, void* dst, size_t size) = 0; /** * @brief Write data to the storage device @@ -136,7 +136,7 @@ class Device : public LinkedObjectTemplate * @param size Size of data to be written, in bytes. * @retval bool true on success, false on error */ - virtual bool write(uint32_t address, const void* src, size_t size) = 0; + virtual bool write(storage_size_t address, const void* src, size_t size) = 0; /** * @brief Erase a region of storage in preparation for writing @@ -144,7 +144,42 @@ class Device : public LinkedObjectTemplate * @param size Size of region to erase, in bytes * @retval bool true on success, false on error */ - virtual bool erase_range(uint32_t address, size_t size) = 0; + virtual bool erase_range(storage_size_t address, storage_size_t size) = 0; + + /** + * @brief Get sector size, the unit of allocation for block-access devices + * + * Override this method only if the device does not support standard 512-byte sector access. + * For example, 'Advanced-Format' drives use 4096-byte sectors. + */ + virtual uint16_t getSectorSize() const + { + return defaultSectorSize; + } + + /** + * @brief Obtain total number of sectors on this device + */ + virtual storage_size_t getSectorCount() const + { + return getSize() / getSectorSize(); + } + + /** + * @brief Flush any pending writes to the physical media + * @retval bool Return false if sync operation failed. + * + * Devices with intermediate buffering should implement this method. + */ + virtual bool sync() + { + return true; + } + + /** + * @name Default sector size for block-based devices + */ + static constexpr uint16_t defaultSectorSize{512}; size_t printTo(Print& p) const; diff --git a/Sming/Components/Storage/src/include/Storage/Partition.h b/Sming/Components/Storage/src/include/Storage/Partition.h index 922d044e96..1dc96822a9 100644 --- a/Sming/Components/Storage/src/include/Storage/Partition.h +++ b/Sming/Components/Storage/src/include/Storage/Partition.h @@ -31,6 +31,7 @@ #include #include #include +#include "Types.h" #define PARTITION_APP_SUBTYPE_MAP(XX) \ XX(factory, 0x00, "Factory application") \ @@ -73,6 +74,11 @@ class Device; class PartitionTable; struct esp_partition_info_t; +namespace Disk +{ +class DiskPart; +} + /** * @brief Represents a flash partition */ @@ -134,12 +140,36 @@ class Partition Type type; uint8_t subtype; - FullType(Type type, uint8_t subtype) : type(type), subtype(subtype) + constexpr FullType() : type(Type::invalid), subtype(SubType::invalid) + { + } + + constexpr FullType(Type type, uint8_t subtype) : type(type), subtype(subtype) + { + } + + explicit operator bool() const + { + return type != Type::invalid && subtype != uint8_t(SubType::invalid); + } + + template constexpr FullType(T subType) : FullType(Type(T::partitionType), uint8_t(subType)) { } - template FullType(T subType) : FullType(Type(T::partitionType), uint8_t(subType)) + bool operator==(const FullType& other) const { + return type == other.type && subtype == other.subtype; + } + + bool operator!=(const FullType& other) const + { + return !operator==(other); + } + + constexpr uint16_t value() const + { + return uint8_t(type) << 8 | subtype; } operator String() const; @@ -148,12 +178,12 @@ class Partition /** * @brief Partition information */ - struct Info : public LinkedObjectTemplate { + struct Info : public LinkedObjectTemplate, public Printable { using OwnedList = OwnedLinkedObjectListTemplate; CString name; - uint32_t offset{0}; - uint32_t size{0}; + storage_size_t offset{0}; + storage_size_t size{0}; Type type{Type::invalid}; uint8_t subtype{SubType::invalid}; Flags flags; @@ -162,15 +192,27 @@ class Partition { } - Info(const String& name, FullType fullType, uint32_t offset, uint32_t size, Flags flags = 0) + Info(const String& name, FullType fullType, storage_size_t offset, storage_size_t size, Flags flags = 0) : name(name), offset(offset), size(size), type(fullType.type), subtype(fullType.subtype), flags(flags) { } + FullType fullType() const + { + return {type, subtype}; + } + bool match(Type type, uint8_t subType) const { return (type == Type::any || type == this->type) && (subType == SubType::any || subType == this->subtype); } + + virtual const Disk::DiskPart* diskpart() const + { + return nullptr; + } + + size_t printTo(Print& p) const override; }; Partition() @@ -235,9 +277,10 @@ class Partition * @param size Size of data to be read, in bytes. * @retval bool true on success, false on error */ - bool read(uint32_t offset, void* dst, size_t size); + bool read(storage_size_t offset, void* dst, size_t size); - template typename std::enable_if::value, bool>::type read(uint32_t offset, T& value) + template + typename std::enable_if::value, bool>::type read(storage_size_t offset, T& value) { return read(offset, &value, sizeof(value)); } @@ -250,7 +293,7 @@ class Partition * @retval bool true on success, false on error * @note Flash region must be erased first */ - bool write(uint32_t offset, const void* src, size_t size); + bool write(storage_size_t offset, const void* src, size_t size); /** * @brief Erase part of the partition @@ -259,7 +302,7 @@ class Partition * @retval bool true on success, false on error * @note Both offset and size must be aligned to flash sector size (4Kbytes) */ - bool erase_range(uint32_t offset, size_t size); + bool erase_range(storage_size_t offset, storage_size_t size); /** * @brief Obtain partition type @@ -277,29 +320,37 @@ class Partition return mPart ? mPart->subtype : SubType::invalid; } + /** + * @brief Obtain both type and subtype + */ + FullType fullType() const + { + return mPart ? mPart->fullType() : FullType{}; + } + /** * @brief Obtain partition starting address - * @param uint32_t Device address + * @retval storage_size_t Device address */ - uint32_t address() const + storage_size_t address() const { return (mPart && mPart->type != Partition::Type::storage) ? mPart->offset : 0; } /** * @brief Obtain address of last byte in this this partition - * @param uint32_t Device address + * @retval storage_size_t Device address */ - uint32_t lastAddress() const + storage_size_t lastAddress() const { return mPart ? (mPart->offset + mPart->size - 1) : 0; } /** * @brief Obtain partition size - * @retval size_t Size in bytes + * @retval storage_size_t Size in bytes */ - size_t size() const + storage_size_t size() const { return mPart ? mPart->size : 0; } @@ -351,7 +402,7 @@ class Partition * @retval bool true on success, false on failure * Fails if the given offset/size combination is out of range, or the partition is undefined. */ - bool getDeviceAddress(uint32_t& address, size_t size) const; + bool getDeviceAddress(storage_size_t& address, storage_size_t size) const; /** * @brief Get name of storage device for this partition @@ -362,7 +413,7 @@ class Partition /** * @brief Determine if given address contained within this partition */ - bool contains(uint32_t addr) const + bool contains(storage_size_t addr) const { return mPart ? (addr >= mPart->offset && addr <= lastAddress()) : false; } @@ -387,6 +438,34 @@ class Partition */ size_t getBlockSize() const; + /** + * @brief Get sector size for block-addressable devices + * @see See `Storage::Device::getSectorSize` + */ + uint16_t getSectorSize() const; + + /** + * @brief Obtain total number of sectors in this partition + */ + storage_size_t getSectorCount() const + { + return size() / getSectorSize(); + } + + /** + * @brief Flush any pending writes to the physical media + * @see See `Storage::Device::sync` + */ + bool sync(); + + /** + * @brief If this is a disk partition, return pointer to the additional information + */ + const Disk::DiskPart* diskpart() const + { + return mPart ? mPart->diskpart() : nullptr; + } + size_t printTo(Print& p) const; protected: diff --git a/Sming/Components/Storage/src/include/Storage/PartitionStream.h b/Sming/Components/Storage/src/include/Storage/PartitionStream.h index 09d19570f8..af0b02ddd5 100644 --- a/Sming/Components/Storage/src/include/Storage/PartitionStream.h +++ b/Sming/Components/Storage/src/include/Storage/PartitionStream.h @@ -34,7 +34,7 @@ class PartitionStream : public ReadWriteStream * * If blockErase is false then region must be pre-erased before writing. */ - PartitionStream(Partition partition, uint32_t offset, size_t size, bool blockErase = false) + PartitionStream(Partition partition, storage_size_t offset, size_t size, bool blockErase = false) : partition(partition), startOffset(offset), size(size), blockErase(blockErase) { } @@ -69,7 +69,7 @@ class PartitionStream : public ReadWriteStream private: Partition partition; - uint32_t startOffset; + storage_size_t startOffset; size_t size; uint32_t writePos{0}; uint32_t readPos{0}; diff --git a/Sming/Components/Storage/src/include/Storage/ProgMem.h b/Sming/Components/Storage/src/include/Storage/ProgMem.h index a9d74580f2..0f43003f3b 100644 --- a/Sming/Components/Storage/src/include/Storage/ProgMem.h +++ b/Sming/Components/Storage/src/include/Storage/ProgMem.h @@ -29,7 +29,7 @@ class ProgMem : public Device return sizeof(uint32_t); } - size_t getSize() const override + storage_size_t getSize() const override { return 0x80000000; } @@ -39,14 +39,14 @@ class ProgMem : public Device return Type::flash; } - bool read(uint32_t address, void* dst, size_t size) override; + bool read(storage_size_t address, void* dst, size_t size) override; - bool write(uint32_t address, const void* src, size_t size) override + bool write(storage_size_t address, const void* src, size_t size) override { return false; } - bool erase_range(uint32_t address, size_t size) override + bool erase_range(storage_size_t address, storage_size_t size) override { return false; } diff --git a/Sming/Components/Storage/src/include/Storage/SpiFlash.h b/Sming/Components/Storage/src/include/Storage/SpiFlash.h index bed0050cb4..b99a1b53f9 100644 --- a/Sming/Components/Storage/src/include/Storage/SpiFlash.h +++ b/Sming/Components/Storage/src/include/Storage/SpiFlash.h @@ -23,7 +23,7 @@ class SpiFlash : public Device public: String getName() const override; size_t getBlockSize() const override; - size_t getSize() const override; + storage_size_t getSize() const override; Type getType() const override { @@ -32,9 +32,9 @@ class SpiFlash : public Device uint32_t getId() const override; - bool read(uint32_t address, void* dst, size_t size) override; - bool write(uint32_t address, const void* src, size_t size) override; - bool erase_range(uint32_t address, size_t size) override; + bool read(storage_size_t address, void* dst, size_t size) override; + bool write(storage_size_t address, const void* src, size_t size) override; + bool erase_range(storage_size_t address, storage_size_t size) override; }; } // namespace Storage diff --git a/Sming/Components/Storage/src/include/Storage/StreamDevice.h b/Sming/Components/Storage/src/include/Storage/StreamDevice.h index ebca8bfc2f..7e9bd08906 100644 --- a/Sming/Components/Storage/src/include/Storage/StreamDevice.h +++ b/Sming/Components/Storage/src/include/Storage/StreamDevice.h @@ -39,23 +39,23 @@ class StreamDevice : public Device return Type::stream; } - bool read(uint32_t address, void* buffer, size_t len) override + bool read(storage_size_t address, void* buffer, size_t len) override { if(mStream == nullptr) { return false; } - if(mStream->seekFrom(address, SeekOrigin::Start) != int(address)) { + if(storage_size_t(mStream->seekFrom(address, SeekOrigin::Start)) != address) { return false; } return mStream->readBytes(static_cast(buffer), len) == len; } - bool write(uint32_t address, const void* data, size_t len) override + bool write(storage_size_t address, const void* data, size_t len) override { return false; } - bool erase_range(uint32_t address, size_t len) override + bool erase_range(storage_size_t address, storage_size_t len) override { return false; } diff --git a/Sming/Components/Storage/src/include/Storage/SysMem.h b/Sming/Components/Storage/src/include/Storage/SysMem.h index aa26598df1..d2d333f1d2 100644 --- a/Sming/Components/Storage/src/include/Storage/SysMem.h +++ b/Sming/Components/Storage/src/include/Storage/SysMem.h @@ -30,7 +30,7 @@ class SysMem : public Device return sizeof(uint32_t); } - size_t getSize() const override + storage_size_t getSize() const override { return 0x80000000; } @@ -40,7 +40,7 @@ class SysMem : public Device return Type::sysmem; } - bool read(uint32_t address, void* buffer, size_t len) override + bool read(storage_size_t address, void* buffer, size_t len) override { if(isFlashPtr(reinterpret_cast(address))) { memcpy_P(buffer, reinterpret_cast(address), len); @@ -50,7 +50,7 @@ class SysMem : public Device return true; } - bool write(uint32_t address, const void* data, size_t len) override + bool write(storage_size_t address, const void* data, size_t len) override { if(isFlashPtr(reinterpret_cast(address))) { return false; @@ -60,7 +60,7 @@ class SysMem : public Device return true; } - bool erase_range(uint32_t address, size_t len) override + bool erase_range(storage_size_t address, storage_size_t len) override { if(isFlashPtr(reinterpret_cast(address))) { return false; diff --git a/Sming/Components/Storage/src/include/Storage/Types.h b/Sming/Components/Storage/src/include/Storage/Types.h new file mode 100644 index 0000000000..846ce55b59 --- /dev/null +++ b/Sming/Components/Storage/src/include/Storage/Types.h @@ -0,0 +1,66 @@ +/**** + * 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. + * + * Types.h + * + ****/ +#pragma once + +#include + +#ifdef ENABLE_STORAGE_SIZE64 +using storage_size_t = uint64_t; +#else +using storage_size_t = uint32_t; +#endif + +namespace Storage +{ +/** + * @brief Determine if a value requires 64-bits to store + */ +inline bool isSize64(uint64_t value) +{ + using Lim = std::numeric_limits; + return value < Lim::min() || value > Lim::max(); +} + +/** + * @brief Determine if a value requires 64-bits to store + */ +inline bool isSize64(int64_t value) +{ + using Lim = std::numeric_limits; + return value < Lim::min() || value > Lim::max(); +} + +/** + * @name Get power of 2 for given value + * @param value Must be an exact power of 2 + * @retval uint8_t Result n such that `value == 1 << n` + * @see Use `isLog2()` to confirm value is power of 2 + * @{ + */ +template constexpr typename std::enable_if<(sizeof(T) <= 4), uint8_t>::type getSizeBits(T value) +{ + return __builtin_ffs(value) - 1; +} + +template constexpr typename std::enable_if<(sizeof(T) > 4), uint8_t>::type getSizeBits(T value) +{ + return __builtin_ffsll(value) - 1; +} +/** @} */ + +/** + * @brief Determine if a value is an exact power of 2 + */ +template constexpr bool isLog2(T value) +{ + return value == (T(1U) << getSizeBits(value)); +} + +} // namespace Storage diff --git a/Sming/Core/FileSystem.h b/Sming/Core/FileSystem.h index 572c1950a9..211813000f 100644 --- a/Sming/Core/FileSystem.h +++ b/Sming/Core/FileSystem.h @@ -170,9 +170,9 @@ inline int fileRead(FileHandle file, void* data, size_t size) * @param file File handle * @param offset Quantity of bytes to move cursor * @param origin Position from where to move cursor - * @retval int Offset within file or negative error code + * @retval file_offset_t Offset within file or negative error code */ -inline int fileSeek(FileHandle file, int offset, SeekOrigin origin) +inline file_offset_t fileSeek(FileHandle file, file_offset_t offset, SeekOrigin origin) { CHECK_FS(seek) return fileSystem->lseek(file, offset, origin); @@ -190,9 +190,9 @@ inline bool fileIsEOF(FileHandle file) /** @brief Get position in file * @param file File handle - * @retval int32_t Read / write cursor position or error code + * @retval file_offset_t Read / write cursor position or error code */ -inline int fileTell(FileHandle file) +inline file_offset_t fileTell(FileHandle file) { CHECK_FS(tell) return fileSystem->tell(file); @@ -243,9 +243,9 @@ template inline int fileSetContent(const /** @brief Get size of file * @param fileName Name of file - * @retval uint32_t Size of file in bytes, 0 on error + * @retval file_size_t Size of file in bytes, 0 on error */ -template inline uint32_t fileGetSize(const TFileName& fileName) +template inline file_size_t fileGetSize(const TFileName& fileName) { auto fileSystem = getFileSystem(); return fileSystem ? fileSystem->getSize(fileName) : 0; @@ -258,7 +258,7 @@ template inline uint32_t fileGetSize(const TFileName& fileN * @note In POSIX `ftruncate()` can also make the file bigger, however SPIFFS can only * reduce the file size and will return an error if newSize > fileSize */ -inline int fileTruncate(FileHandle file, size_t newSize) +inline int fileTruncate(FileHandle file, file_size_t newSize) { CHECK_FS(truncate); return fileSystem->ftruncate(file, newSize); @@ -281,7 +281,7 @@ inline int fileTruncate(FileHandle file) * @note In POSIX `truncate()` can also make the file bigger, however SPIFFS can only * reduce the file size and will return an error if newSize > fileSize */ -template int fileTruncate(const TFileName& fileName, size_t newSize) +template int fileTruncate(const TFileName& fileName, file_size_t newSize) { CHECK_FS(truncate); return fileSystem->truncate(fileName, newSize); diff --git a/Sming/Libraries/DiskStorage b/Sming/Libraries/DiskStorage new file mode 160000 index 0000000000..c467f3f0f9 --- /dev/null +++ b/Sming/Libraries/DiskStorage @@ -0,0 +1 @@ +Subproject commit c467f3f0f9f504aecf134ec45780971da1595399 diff --git a/Sming/Libraries/FatIFS b/Sming/Libraries/FatIFS new file mode 160000 index 0000000000..b4c11f4f28 --- /dev/null +++ b/Sming/Libraries/FatIFS @@ -0,0 +1 @@ +Subproject commit b4c11f4f28deb99fe48c25a16f0f72915202c05d diff --git a/Sming/Libraries/LittleFS b/Sming/Libraries/LittleFS index 9af1d3bd27..f5fc23fbb3 160000 --- a/Sming/Libraries/LittleFS +++ b/Sming/Libraries/LittleFS @@ -1 +1 @@ -Subproject commit 9af1d3bd27915b0180ba7f73fe553a06ad7d9d94 +Subproject commit f5fc23fbb3112460dbd595ddf03b7ec2d45c8cb0 diff --git a/Sming/Libraries/Ota/src/include/Ota/UpgradeOutputStream.h b/Sming/Libraries/Ota/src/include/Ota/UpgradeOutputStream.h index fa3a6157c3..bbbf47b6ee 100644 --- a/Sming/Libraries/Ota/src/include/Ota/UpgradeOutputStream.h +++ b/Sming/Libraries/Ota/src/include/Ota/UpgradeOutputStream.h @@ -30,7 +30,7 @@ class UpgradeOutputStream : public ReadWriteStream * @param partition */ UpgradeOutputStream(Partition partition, size_t maxLength = 0) - : partition(partition), maxLength(maxLength != 0 ? std::min(maxLength, partition.size()) : partition.size()) + : partition(partition), maxLength(std::min(storage_size_t(maxLength ?: 0x1000000), partition.size())) { } diff --git a/Sming/Libraries/SdStorage b/Sming/Libraries/SdStorage new file mode 160000 index 0000000000..99826990a4 --- /dev/null +++ b/Sming/Libraries/SdStorage @@ -0,0 +1 @@ +Subproject commit 99826990a46c3a509ec9c33bbe1572b3b50e663d diff --git a/Sming/Libraries/SmingTest b/Sming/Libraries/SmingTest index a6c7f94341..25a7e24411 160000 --- a/Sming/Libraries/SmingTest +++ b/Sming/Libraries/SmingTest @@ -1 +1 @@ -Subproject commit a6c7f9434135fc6350da72b7e226a825f0092356 +Subproject commit 25a7e2441148cd0805ab7b7ab2d4648a0131b092 diff --git a/Sming/Libraries/Spiffs/component.mk b/Sming/Libraries/Spiffs/component.mk index a482d6ff1f..7ed51e9991 100644 --- a/Sming/Libraries/Spiffs/component.mk +++ b/Sming/Libraries/Spiffs/component.mk @@ -1,4 +1,5 @@ ## SPIFFS library +COMPONENT_DEPENDS := IFS COMPONENT_SUBMODULES := spiffs COMPONENT_SRCDIRS := src spiffs/src COMPONENT_INCDIRS := src/include diff --git a/Sming/Libraries/Spiffs/src/FileSystem.cpp b/Sming/Libraries/Spiffs/src/FileSystem.cpp index 1184e0bcc2..267e961800 100644 --- a/Sming/Libraries/Spiffs/src/FileSystem.cpp +++ b/Sming/Libraries/Spiffs/src/FileSystem.cpp @@ -134,12 +134,18 @@ int FileSystem::mount() return Error::BadPartition; } + auto partSize = partition.size(); + if(partSize > MAX_PARTITION_SIZE) { + debug_e("[SPIFFS] Partition too large"); + return Error::BadPartition; + } + fs.user_data = this; spiffs_config cfg{ .hal_read_f = f_read, .hal_write_f = f_write, .hal_erase_f = f_erase, - .phys_size = partition.size(), + .phys_size = uint32_t(partSize), .phys_addr = 0, .phys_erase_block = partition.getBlockSize(), .log_block_size = logicalBlockSize, @@ -315,6 +321,7 @@ int FileSystem::close(FileHandle file) if(err < 0) { res = translateSpiffsError(err); } + partition.sync(); return res; } @@ -324,13 +331,13 @@ int FileSystem::eof(FileHandle file) return translateSpiffsError(res); } -int32_t FileSystem::tell(FileHandle file) +file_offset_t FileSystem::tell(FileHandle file) { int res = SPIFFS_tell(handle(), file); return translateSpiffsError(res); } -int FileSystem::ftruncate(FileHandle file, size_t new_size) +int FileSystem::ftruncate(FileHandle file, file_size_t new_size) { int res = SPIFFS_ftruncate(handle(), file, new_size); return translateSpiffsError(res); @@ -345,6 +352,7 @@ int FileSystem::flush(FileHandle file) if(err < 0) { res = translateSpiffsError(err); } + partition.sync(); return res; } @@ -372,7 +380,7 @@ int FileSystem::write(FileHandle file, const void* data, size_t size) return res; } -int FileSystem::lseek(FileHandle file, int offset, SeekOrigin origin) +file_offset_t FileSystem::lseek(FileHandle file, file_offset_t offset, SeekOrigin origin) { int res = SPIFFS_lseek(handle(), file, offset, int(origin)); if(res < 0) { @@ -563,6 +571,7 @@ int FileSystem::setxattr(const char* path, AttributeTag tag, const void* data, s return FS_OK; } err = SPIFFS_update_meta(handle(), path, &smb); + partition.sync(); return translateSpiffsError(err); #else return Error::NotSupported; @@ -745,6 +754,7 @@ int FileSystem::rename(const char* oldpath, const char* newpath) } int err = SPIFFS_rename(handle(), oldpath, newpath); + partition.sync(); return translateSpiffsError(err); } @@ -769,6 +779,7 @@ int FileSystem::remove(const char* path) int err = SPIFFS_remove(handle(), path); err = translateSpiffsError(err); debug_ifserr(err, "remove('%s')", path); + partition.sync(); return err; } diff --git a/Sming/Libraries/Spiffs/src/include/IFS/SPIFFS/FileSystem.h b/Sming/Libraries/Spiffs/src/include/IFS/SPIFFS/FileSystem.h index ed9279218e..8afa6305fe 100644 --- a/Sming/Libraries/Spiffs/src/include/IFS/SPIFFS/FileSystem.h +++ b/Sming/Libraries/Spiffs/src/include/IFS/SPIFFS/FileSystem.h @@ -84,10 +84,10 @@ class FileSystem : public IFileSystem int close(FileHandle file) override; int read(FileHandle file, void* data, size_t size) override; int write(FileHandle file, const void* data, size_t size) override; - int lseek(FileHandle file, int offset, SeekOrigin origin) override; + file_offset_t lseek(FileHandle file, file_offset_t offset, SeekOrigin origin) override; int eof(FileHandle file) override; - int32_t tell(FileHandle file) override; - int ftruncate(FileHandle file, size_t new_size) override; + file_offset_t tell(FileHandle file) override; + int ftruncate(FileHandle file, file_size_t new_size) override; int flush(FileHandle file) override; int rename(const char* oldpath, const char* newpath) override; int remove(const char* path) override; @@ -126,6 +126,7 @@ class FileSystem : public IFileSystem static s32_t f_write(struct spiffs_t* spiffs, u32_t addr, u32_t size, u8_t* src); static s32_t f_erase(struct spiffs_t* spiffs, u32_t addr, u32_t size); + static constexpr uint32_t MAX_PARTITION_SIZE{256 * 1024 * 1024}; static constexpr size_t CACHE_PAGES{8}; static constexpr size_t LOG_PAGE_SIZE{256}; static constexpr size_t MIN_BLOCKSIZE{256}; diff --git a/Tools/install.sh b/Tools/install.sh index fcbbb411ea..499f887a04 100755 --- a/Tools/install.sh +++ b/Tools/install.sh @@ -102,6 +102,8 @@ if [ -n "$APPVEYOR" ] || [ -n "$GITHUB_ACTION" ]; then g++-9-multilib \ python3-setuptools \ ninja-build \ + exfat-fuse \ + exfat-utils \ $EXTRA_PACKAGES sudo update-alternatives --set gcc /usr/bin/gcc-9 diff --git a/docs/source/information/index.rst b/docs/source/information/index.rst index 58620c197e..0b360e0604 100644 --- a/docs/source/information/index.rst +++ b/docs/source/information/index.rst @@ -9,6 +9,7 @@ Information events memory flash + storage strings interrupts tasks diff --git a/docs/source/information/storage.rst b/docs/source/information/storage.rst new file mode 100644 index 0000000000..5084b555c6 --- /dev/null +++ b/docs/source/information/storage.rst @@ -0,0 +1,28 @@ +Bulk Storage and Filing Systems +=============================== + +Sming uses a class-based layered approach to bulk storage. + +The :component:`Storage` Component defines the :cpp:class:`Storage::Device` abstract class, +which devices such as SPI flash implement to provide raw read/write/erase access. +Devices are partitioned into areas for specific uses which applications +access using a :cpp:class:`Storage::Partition` object. + +The :library:`DiskStorage` library provides support for block-access devices +which use standard partitioning schemes (MBR, GPT). +SD cards are supported via the :library:`SdStorage` library. + +Sming uses an installable (virtual) filing system mechanism based on :cpp:class:`IFS::IFileSystem`. +This is managed by the :component:`IFS` Component and contains the FWFS lightweight read-only filing system. + +Additional filing system implementations are provided in separate libraries: + +- :library:`Spiffs` +- :library:`LittleFS` +- :library:`FatIFS` + +Note that when using bulk storage of more than about 4GB in size applications should be built with +:cpp:envvar:`ENABLE_STORAGE_SIZE64` =1. This changes all sizes and offsets to 64-bit. + +If manipulating files greated than about 2GB (signed 32-bit value) then the :cpp:envvar:`ENABLE_FILE_SIZE64` +setting should also be enabled. diff --git a/samples/Basic_IFS/README.rst b/samples/Basic_IFS/README.rst index d607593f02..2d01da92bb 100644 --- a/samples/Basic_IFS/README.rst +++ b/samples/Basic_IFS/README.rst @@ -29,3 +29,9 @@ This sample also demonstrates how to store the data in a :cpp:type:`FlashString` Because the data is linked into the program image this is only suitable for small filesystem images. This could be used to store default recovery data, especially with OTA updates because each program image is self-contained. + +To add support for SD Cards to this sample:: + + make ENABLE_SDCARD=1 + +See :library:`FatIFS` for further details of SD Card and FAT filing system support. diff --git a/samples/Basic_IFS/app/application.cpp b/samples/Basic_IFS/app/application.cpp index 5c92b3ddab..68b4f817c1 100644 --- a/samples/Basic_IFS/app/application.cpp +++ b/samples/Basic_IFS/app/application.cpp @@ -19,6 +19,22 @@ #define WIFI_PWD "PleaseEnterPass" #endif +#ifdef ENABLE_SDCARD +#include +#include + +// Chip selects independent of SPI controller in use +#ifdef ARCH_ESP32 +#define PIN_CARD_CS 21 +#else +// Esp8266 cannot use GPIO15 as this affects boot mode +#define PIN_CARD_CS 5 +#endif + +#define SPI_FREQ_LIMIT 0 //2000000 + +#endif + namespace { #ifdef ENABLE_FLASHSTRING_IMAGE @@ -194,6 +210,33 @@ bool initFileSystem() delete spiffs; } +#ifdef ENABLE_SDCARD + auto card = new Storage::SD::Card("card1", SPI); + Storage::registerDevice(card); + + // Buffering allows byte read/write + card.allocateBuffers(2); + + if(card->begin(PIN_CARD_CS, SPI_FREQ_LIMIT)) { + Serial << "CSD" << endl << card->csd << endl; + Serial << "CID" << endl << card->cid; + + auto part = *card->partitions().begin(); + auto fatfs = IFS::createFatFilesystem(part); + if(fatfs != nullptr) { + if(fatfs->mount() == FS_OK) { + fs->setVolume(2, fatfs); + } else { + delete fatfs; + delete card; + } + } + } else { + delete card; + } + +#endif + debug_i("File system initialised"); return true; } diff --git a/samples/Basic_IFS/basic_ifs_Esp8266.hw b/samples/Basic_IFS/basic_ifs_Esp8266.hw index a174c30a45..301edd0a72 100644 --- a/samples/Basic_IFS/basic_ifs_Esp8266.hw +++ b/samples/Basic_IFS/basic_ifs_Esp8266.hw @@ -3,7 +3,7 @@ "arch": "Esp8266", "partitions": { "rom0": { - "size": "480K" + "size": "600K" } } } \ No newline at end of file diff --git a/samples/Basic_IFS/component.mk b/samples/Basic_IFS/component.mk index feec6c667e..50140848dd 100644 --- a/samples/Basic_IFS/component.mk +++ b/samples/Basic_IFS/component.mk @@ -1,4 +1,8 @@ -COMPONENT_DEPENDS := LittleFS +COMPONENT_DEPENDS := \ + Spiffs \ + LittleFS \ + FatIFS \ + SdStorage # Empty SPIFFS partition please SPIFF_FILES := @@ -12,3 +16,8 @@ HWCONFIG := spiffs else HWCONFIG := basic_ifs_$(SMING_ARCH) endif + +CONFIG_VARS += ENABLE_SDCARD +ifeq ($(ENABLE_SDCARD),1) +COMPONENT_CXXFLAGS += -DENABLE_SDCARD +endif diff --git a/samples/Basic_IFS/fsimage.fwfs b/samples/Basic_IFS/fsimage.fwfs index 40051d1e23..cc8b6bfb88 100644 --- a/samples/Basic_IFS/fsimage.fwfs +++ b/samples/Basic_IFS/fsimage.fwfs @@ -11,10 +11,11 @@ "sming.png": "${SMING_HOME}/../docs/api-logo.png", "Data": "${SMING_HOME}/Core/Data" }, - // Directories to mount other object stores + // Directories to mount other filesystems "mountpoints": { "littlefs": 0, - "spiffs": 1 + "spiffs": 1, + "fat": 2 }, // Rules for file metadata. All rules are evaluated in sequence for every file "rules": [ diff --git a/samples/Basic_Storage/app/application.cpp b/samples/Basic_Storage/app/application.cpp index 7c2aa6fa7c..e9fa62b362 100644 --- a/samples/Basic_Storage/app/application.cpp +++ b/samples/Basic_Storage/app/application.cpp @@ -27,7 +27,7 @@ void listSpiffsPartitions() void printPart(Storage::Partition part) { - size_t bufSize = std::min(4096U, part.size()); + size_t bufSize = std::min(storage_size_t(4096), part.size()); char buf[bufSize]; OneShotFastUs timer; if(!part.read(0, buf, bufSize)) { diff --git a/tests/HostTests/modules/Storage.cpp b/tests/HostTests/modules/Storage.cpp index fc329e7586..4c47578f91 100644 --- a/tests/HostTests/modules/Storage.cpp +++ b/tests/HostTests/modules/Storage.cpp @@ -15,7 +15,7 @@ class TestDevice : public Storage::Device return sizeof(uint32_t); } - size_t getSize() const override + storage_size_t getSize() const override { return 0x40000000; } @@ -25,7 +25,7 @@ class TestDevice : public Storage::Device return Type::unknown; } - bool read(uint32_t address, void* dst, size_t size) override + bool read(storage_size_t address, void* dst, size_t size) override { for(unsigned i = 0; i < size; ++i) { static_cast(dst)[i] = address + i; @@ -33,12 +33,12 @@ class TestDevice : public Storage::Device return true; } - bool write(uint32_t address, const void* src, size_t size) override + bool write(storage_size_t address, const void* src, size_t size) override { return false; } - bool erase_range(uint32_t address, size_t size) override + bool erase_range(storage_size_t address, storage_size_t size) override { return false; } @@ -54,7 +54,7 @@ class PartitionTest : public TestGroup void execute() override { auto dev = new TestDevice; - Storage::registerDevice(dev); + REQUIRE(Storage::registerDevice(dev)); listPartitions();