From 7995711ccf2f420b71790cdd8adb10f0b29497ec Mon Sep 17 00:00:00 2001 From: David Crocker Date: Fri, 13 Aug 2021 18:22:18 +0100 Subject: More work on embedded files --- src/Storage/FileStore.cpp | 50 ++++++------ src/Storage/MassStorage.cpp | 155 ++++++++++++++++++++++-------------- src/Storage/MassStorage.h | 12 +++ src/Storage/MassStorageEmbedded.cpp | 103 +++++++++++++++++------- 4 files changed, 207 insertions(+), 113 deletions(-) (limited to 'src/Storage') diff --git a/src/Storage/FileStore.cpp b/src/Storage/FileStore.cpp index 99358aa8..c4575709 100644 --- a/src/Storage/FileStore.cpp +++ b/src/Storage/FileStore.cpp @@ -470,6 +470,33 @@ bool FileStore::ForceClose() noexcept #endif +#if HAS_MASS_STORAGE || HAS_EMBEDDED_FILES + +void FileStore::Duplicate() noexcept +{ + switch (usageMode) + { + case FileUseMode::free: + REPORT_INTERNAL_ERROR; + break; + + case FileUseMode::readOnly: + case FileUseMode::readWrite: + { + const irqflags_t flags = IrqSave(); + ++openCount; + IrqRestore(flags); + } + break; + + case FileUseMode::invalidated: + default: + break; + } +} + +#endif + #if HAS_MASS_STORAGE || HAS_LINUX_INTERFACE bool FileStore::Store(const char *s, size_t len, size_t *bytesWritten) noexcept @@ -663,29 +690,6 @@ bool FileStore::IsOpenOn(const FATFS *fs) const noexcept return openCount != 0 && file.obj.fs == fs; } -void FileStore::Duplicate() noexcept -{ - switch (usageMode) - { - case FileUseMode::free: - REPORT_INTERNAL_ERROR; - break; - - case FileUseMode::readOnly: - case FileUseMode::readWrite: - { - const irqflags_t flags = IrqSave(); - ++openCount; - IrqRestore(flags); - } - break; - - case FileUseMode::invalidated: - default: - break; - } -} - // Return true if the passed file is the same as ours bool FileStore::IsSameFile(const FIL& otherFile) const noexcept { diff --git a/src/Storage/MassStorage.cpp b/src/Storage/MassStorage.cpp index e29701e2..bbb8b09c 100644 --- a/src/Storage/MassStorage.cpp +++ b/src/Storage/MassStorage.cpp @@ -2,20 +2,22 @@ #include #include #include -#include -#include - -#if HAS_LINUX_INTERFACE -# include -#endif +#if HAS_MASS_STORAGE +# include +# include +# include // Check that the LFN configuration in FatFS is sufficient static_assert(FF_MAX_LFN >= MaxFilenameLength, "FF_MAX_LFN too small"); // Check that the correct number of SD cards is configured in the library -#include static_assert(SD_MMC_MEM_CNT == NumSdCards); +#endif + +#if HAS_LINUX_INTERFACE +# include +#endif // A note on using mutexes: // Each SD card volume has its own mutex. There is also one for the file table, and one for the find first/find next buffer. @@ -116,13 +118,11 @@ DEFINE_GET_OBJECT_MODEL_TABLE(SdCardInfo) #endif static SdCardInfo info[NumSdCards]; - -static Mutex dirMutex; - static DIR findDir; #endif #if HAS_MASS_STORAGE || HAS_EMBEDDED_FILES +static Mutex dirMutex; static FileInfoParser infoParser; #endif @@ -281,6 +281,10 @@ void MassStorage::Init() noexcept { fsMutex.Create("FileSystem"); +#if HAS_MASS_STORAGE || HAS_EMBEDDED_FILES + dirMutex.Create("DirSearch"); +#endif + # if HAS_MASS_STORAGE || HAS_LINUX_INTERFACE freeWriteBuffers = nullptr; for (size_t i = 0; i < NumFileWriteBuffers; ++i) @@ -297,9 +301,7 @@ void MassStorage::Init() noexcept static const char * const VolMutexNames[] = { "SD0", "SD1" }; static_assert(ARRAY_SIZE(VolMutexNames) >= NumSdCards, "Incorrect VolMutexNames array"); - // Create the mutexes - dirMutex.Create("DirSearch"); - + // Initialise the SD card structs for (size_t card = 0; card < NumSdCards; ++card) { SdCardInfo& inf = info[card]; @@ -431,6 +433,43 @@ void MassStorage::CloseAllFiles() noexcept #endif +#if HAS_MASS_STORAGE || HAS_EMBEDDED_FILES + +// Check if the specified directory exists +bool MassStorage::DirectoryExists(const char *path) noexcept +{ + // Remove any trailing '/' from the directory name, it sometimes (but not always) confuses f_opendir + String loc; + loc.copy(path); + return DirectoryExists(loc.GetRef()); +} + +// Check if the specified directory exists +// Warning: if 'path' has a trailing '/' or '\\' character, it will be removed! +bool MassStorage::DirectoryExists(const StringRef& path) noexcept +{ + // Remove any trailing '/' from the directory name, it sometimes (but not always) confuses f_opendir + const size_t len = path.strlen(); + if (len != 0 && (path[len - 1] == '/' || path[len - 1] == '\\')) + { + path.Truncate(len - 1); + } + +#if HAS_MASS_STORAGE + DIR dir; + const bool ok = (f_opendir(&dir, path.c_str()) == FR_OK); + if (ok) + { + f_closedir(&dir); + } + return ok; +#elif HAS_EMBEDDED_FILES + return EmbeddedFiles::DirectoryExists(path); +#endif +} + +#endif + #if HAS_MASS_STORAGE || HAS_LINUX_INTERFACE // Static helper functions @@ -564,7 +603,7 @@ bool MassStorage::Delete(const char* filePath, bool messageIfFailed) noexcept #endif -#if HAS_MASS_STORAGE +#if HAS_MASS_STORAGE || HAS_EMBEDDED_FILES // Open a directory to read a file list. Returns true if it contains any files, false otherwise. // If this returns true then the file system mutex is owned. The caller must subsequently release the mutex either @@ -585,6 +624,7 @@ bool MassStorage::FindFirst(const char *directory, FileInfo &file_info) noexcept return false; } +#if HAS_MASS_STORAGE FRESULT res = f_opendir(&findDir, loc.c_str()); if (res == FR_OK) { @@ -605,6 +645,12 @@ bool MassStorage::FindFirst(const char *directory, FileInfo &file_info) noexcept } f_closedir(&findDir); } +#elif HAS_EMBEDDED_FILES + if (EmbeddedFiles::FindFirst(directory, file_info)) + { + return true; + } +#endif dirMutex.Release(); return false; @@ -619,20 +665,28 @@ bool MassStorage::FindNext(FileInfo &file_info) noexcept return false; // error, we don't hold the mutex } +#if HAS_MASS_STORAGE FILINFO entry; - if (f_readdir(&findDir, &entry) != FR_OK || entry.fname[0] == 0) + if (f_readdir(&findDir, &entry) == FR_OK && entry.fname[0] != 0) { - f_closedir(&findDir); - dirMutex.Release(); - return false; + file_info.isDirectory = (entry.fattrib & AM_DIR); + file_info.size = entry.fsize; + file_info.fileName.copy(entry.fname); + file_info.lastModified = ConvertTimeStamp(entry.fdate, entry.ftime); + return true; } - file_info.isDirectory = (entry.fattrib & AM_DIR); - file_info.size = entry.fsize; - file_info.fileName.copy(entry.fname); - file_info.lastModified = ConvertTimeStamp(entry.fdate, entry.ftime); - return true; + f_closedir(&findDir); +#elif HAS_EMBEDDED_FILES + if (EmbeddedFiles::FindNext(file_info)) + { + return true; + } +#endif + + dirMutex.Release(); + return false; } // Quit searching for files. Needed to avoid hanging on to the mutex. Safe to call even if the caller doesn't hold the mutex. @@ -644,6 +698,10 @@ void MassStorage::AbandonFindNext() noexcept } } +#endif + +#if HAS_MASS_STORAGE + // Month names. The first entry is used for invalid month numbers. static const char *monthNames[13] = { "???", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; @@ -789,35 +847,6 @@ bool MassStorage::FileExists(const char *filePath) noexcept #if HAS_MASS_STORAGE -// Check if the specified directory exists -// Warning: if 'path' has a trailing '/' or '\\' character, it will be removed! -bool MassStorage::DirectoryExists(const StringRef& path) noexcept -{ - // Remove any trailing '/' from the directory name, it sometimes (but not always) confuses f_opendir - const size_t len = path.strlen(); - if (len != 0 && (path[len - 1] == '/' || path[len - 1] == '\\')) - { - path.Truncate(len - 1); - } - - DIR dir; - const bool ok = (f_opendir(&dir, path.c_str()) == FR_OK); - if (ok) - { - f_closedir(&dir); - } - return ok; -} - -// Check if the specified directory exists -bool MassStorage::DirectoryExists(const char *path) noexcept -{ - // Remove any trailing '/' from the directory name, it sometimes (but not always) confuses f_opendir - String loc; - loc.copy(path); - return DirectoryExists(loc.GetRef()); -} - // Return the last modified time of a file, or zero if failure time_t MassStorage::GetLastModifiedTime(const char *filePath) noexcept { @@ -1012,6 +1041,15 @@ GCodeResult MassStorage::Unmount(size_t card, const StringRef& reply) noexcept return GCodeResult::ok; } +bool MassStorage::IsDriveMounted(size_t drive) noexcept +{ + return drive < NumSdCards +#if HAS_MASS_STORAGE + && info[drive].isMounted +#endif + ; +} + unsigned int MassStorage::GetNumFreeFiles() noexcept { unsigned int numFreeFiles = 0; @@ -1038,17 +1076,19 @@ void MassStorage::Diagnostics(MessageType mtype) noexcept // Show the number of free entries in the file table platform.MessageF(mtype, "=== Storage ===\nFree file entries: %u\n", MassStorage::GetNumFreeFiles()); -# if HAS_HIGH_SPEED_SD +# if HAS_MASS_STORAGE +# if HAS_HIGH_SPEED_SD // Show the HSMCI CD pin and speed platform.MessageF(mtype, "SD card 0 %s, interface speed: %.1fMBytes/sec\n", (IsCardDetected(0) ? "detected" : "not detected"), (double)((float)sd_mmc_get_interface_speed(0) * 0.000001)); -# elif HAS_MASS_STORAGE +# else platform.MessageF(mtype, "SD card 0 %s\n", (MassStorage::IsCardDetected(0) ? "detected" : "not detected")); -# endif +# endif // Show the longest SD card write time platform.MessageF(mtype, "SD card longest read time %.1fms, write time %.1fms, max retries %u\n", (double)DiskioGetAndClearLongestReadTime(), (double)DiskioGetAndClearLongestWriteTime(), DiskioGetAndClearMaxRetryCount()); +# endif } #endif @@ -1142,11 +1182,6 @@ MassStorage::InfoResult MassStorage::GetCardInfo(size_t slot, uint64_t& capacity return InfoResult::ok; } -bool MassStorage::IsDriveMounted(size_t drive) noexcept -{ - return drive < NumSdCards && info[drive].isMounted; -} - Mutex& MassStorage::GetVolumeMutex(size_t vol) noexcept { return info[vol].volMutex; diff --git a/src/Storage/MassStorage.h b/src/Storage/MassStorage.h index a687ac17..13760fb0 100644 --- a/src/Storage/MassStorage.h +++ b/src/Storage/MassStorage.h @@ -20,6 +20,18 @@ struct FileInfo bool isDirectory; }; +#if HAS_EMBEDDED_FILES + +// Functions that we call out to when using an embedded filesystem +namespace EmbeddedFiles +{ + bool DirectoryExists(const StringRef& path) noexcept; + bool FindFirst(const char *directory, FileInfo& file_info) noexcept; + bool FindNext(FileInfo& file_info) noexcept; +} + +#endif + class ObjectModel; namespace MassStorage diff --git a/src/Storage/MassStorageEmbedded.cpp b/src/Storage/MassStorageEmbedded.cpp index a96e7f92..3e772add 100644 --- a/src/Storage/MassStorageEmbedded.cpp +++ b/src/Storage/MassStorageEmbedded.cpp @@ -8,6 +8,10 @@ #include "MassStorage.h" +#if SAM4S +constexpr uint32_t FlashStart = IFLASH0_ADDR; +#endif + #if HAS_EMBEDDED_FILES #include @@ -15,49 +19,94 @@ #include #include "FileStore.h" -// Members of MassStorage that are replaced -bool MassStorage::FileExists(const char *filePath) noexcept +struct EmbeddedFileDescriptor { - //TODO - return false; -} + uint32_t nameOffset; + uint32_t contentOffset; + uint32_t contentLength; -// Warning: if 'path' has a trailing '/' or '\\' character, it will be removed! -bool MassStorage::DirectoryExists(const StringRef& path) noexcept -{ - //TODO - return false; -} + const char* GetName() const noexcept { return reinterpret_cast(FlashStart + nameOffset); } + const char* GetContent() const noexcept { return reinterpret_cast(FlashStart + contentOffset); } +}; -bool MassStorage::DirectoryExists(const char *path) noexcept +struct EmbeddedFilesHeader { - //TODO - return false; -} + uint32_t magic; + uint32_t directoriesOffset; + uint32_t numFiles; + const EmbeddedFileDescriptor files[]; // gcc extension: array of unspecified length at end of a struct -bool MassStorage::IsDriveMounted(size_t drive) noexcept + static constexpr uint32_t MagicValue = 0; //TODO what is it? + const char* GetDirectories() const noexcept { return reinterpret_cast(FlashStart + directoriesOffset); } +}; + +extern const EmbeddedFilesHeader _firmware_end; + +static const char *fileSearchDirectory = nullptr; +static const char *fileSearchNextNumber = 0; + +// Members of MassStorage that are replaced +bool MassStorage::FileExists(const char *filePath) noexcept { - return drive == 0; + if (_firmware_end.magic == EmbeddedFilesHeader::MagicValue) + { + uint32_t numFiles = _firmware_end.numFiles; + const EmbeddedFileDescriptor *filePtr = _firmware_end.files; + while (numFiles != 0) + { + if (StringEqualsIgnoreCase(filePath, filePtr->GetName())) + { + return true; + } + ++filePtr; + --numFiles; + } + } + return false; } -bool MassStorage::FindFirst(const char *directory, FileInfo &file_info) noexcept +// Test whether a directory exists. Any trailing '/' has already been removed. +bool EmbeddedFiles::DirectoryExists(const StringRef& path) noexcept { - //TODO + if (_firmware_end.magic == EmbeddedFilesHeader::MagicValue) + { + if (path[0] == 0) + { + return true; // root directory + } + + const char *cd = _firmware_end.GetDirectories(); + while (cd[0] != 0) + { + if (StringEqualsIgnoreCase(cd, path.c_str())) + { + return true; + } + cd += strlen(cd) + 1; + } + } return false; } -bool MassStorage::FindNext(FileInfo &file_info) noexcept +bool EmbeddedFiles::FindFirst(const char *directory, FileInfo &file_info) noexcept { - //TODO + if (_firmware_end.magic == EmbeddedFilesHeader::MagicValue) + { + //TODO + } return false; } -void MassStorage::AbandonFindNext() noexcept +bool EmbeddedFiles::FindNext(FileInfo &file_info) noexcept { - //TODO + if (_firmware_end.magic == EmbeddedFilesHeader::MagicValue) + { + //TODO + } + return false; } -// Members of FileStore that are replaced +// Members of FileStore that are replaced (probably to be moved back into FileStore) // Return the file size in bytes FilePosition FileStore::Length() const noexcept @@ -80,12 +129,6 @@ bool FileStore::Open(const char* filePath, OpenMode mode, uint32_t preAllocSize) return false; } -// Create a second reference to this file -void FileStore::Duplicate() noexcept -{ - //TODO -} - #endif // End -- cgit v1.2.3