Working version

Dependents:   PUB_RA8875_Bitmap

This version of the FlashFileSystem is directly derived from a library of the same name by Adam Green. See Adam's original at Flash File System.

Important in the use of this library is the generation of the embedded resource. For this there is a companion tool - rofs.exe. Adam provided a link to the source in github. I used that but found I wanted a few more features, so I made a large number of changes.

ROFS.exe Features

  • Bidirectional:
    • Create flash file system from folder of resources
    • Extract resources from flash file system [.h/.bin]
  • w/reduced warnings
  • faster file system building
  • more internal documentation in the generated .h file
  • additional help information added

Windows EXE

  • Contact me by Private Email for a copy - the mbed site is not letting me upload it as a zip.

Files at this revision

API Documentation at this revision

Comitter:
WiredHome
Date:
Sat Jul 29 12:45:09 2017 +0000
Child:
1:689c997b57bb
Commit message:
FlashFileSystem - Read-only, but super fast. Requires external tool to prepare the data.

Changed in this revision

FlashFileSystem.cpp Show annotated file Show diff for this revision Revisions of this file
FlashFileSystem.h Show annotated file Show diff for this revision Revisions of this file
ffsformat.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FlashFileSystem.cpp	Sat Jul 29 12:45:09 2017 +0000
@@ -0,0 +1,627 @@
+/* Copyright 2011 Adam Green (http://mbed.org/users/AdamGreen/)
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+/* Specifies the classes used to implement the FlashFileSystem which is a
+   read-only file system that exists in the internal FLASH of the mbed
+   device.
+*/
+#include <mbed.h>
+#include <assert.h>
+#include "FlashFileSystem.h"
+#include "ffsformat.h"
+
+
+//#define DEBUG "ROFS"
+// ...
+// INFO("Stuff to show %d", var); // new-line is automatically appended
+//
+#if (defined(DEBUG) && !defined(TARGET_LPC11U24))
+#define INFO(x, ...) std::printf("[INF %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#define WARN(x, ...) std::printf("[WRN %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#define ERR(x, ...)  std::printf("[ERR %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+static void HexDump(const char * title, const uint8_t * p, int count)
+{
+    int i;
+    char buf[100] = "0000: ";
+
+    if (*title)
+        INFO("%s", title);
+    for (i=0; i<count; ) {
+        sprintf(buf + strlen(buf), "%02X ", *(p+i));
+        if ((++i & 0x0F) == 0x00) {
+            INFO("%s", buf);
+            if (i < count)
+                sprintf(buf, "%04X: ", i);
+            else
+                buf[0] = '\0';
+        }
+    }
+    if (strlen(buf))
+        INFO("%s", buf);
+}
+#else
+#define INFO(x, ...)
+#define WARN(x, ...)
+#define ERR(x, ...)
+#define HexDump(a, b, c)
+#endif
+
+
+
+/* Constructor for FlashFileSystemFileHandle which initializes to the specified
+   file entry in the image.
+
+   Parameters:
+    pFileStart is the beginning offset of this file in FLASH memory.
+    pFileEnd is the ending offset (1 bytes past last valid byte) of this file
+        FLASH memory.
+*/
+FlashFileSystemFileHandle::FlashFileSystemFileHandle(const char* pFileStart,
+        const char* pFileEnd)
+{
+    m_pFileStart = pFileStart;
+    m_pFileEnd = pFileEnd;
+    m_pCurr = pFileStart;
+}
+
+
+// Constructs a blank FlashFileSystemFileHandle object.
+FlashFileSystemFileHandle::FlashFileSystemFileHandle()
+{
+    FlashFileSystemFileHandle(NULL, NULL);
+}
+
+
+/* Write the contents of a buffer to the file
+
+   Parameters:
+    pBuffer is the buffer from which to write.
+    Length is the number of characters to write.
+
+   Returns
+    The number of characters written (possibly 0) on success, -1 on error.
+ */
+ssize_t FlashFileSystemFileHandle::write(const void* pBuffer, size_t Length)
+{
+    // This file system doesn't support writing.
+    return -1;
+}
+
+
+/* Close the file
+
+   Returns
+    Zero on success, -1 on error.
+*/
+int FlashFileSystemFileHandle::close()
+{
+    m_pFileStart = NULL;
+    m_pFileEnd = NULL;
+    m_pCurr = NULL;
+    INFO("close");
+    return 0;
+}
+
+/*  Reads the contents of the file into a buffer.
+
+   Parameters
+    pBuffer is the buffer into which the read should occur.
+    Length is the number of characters to read into pBuffer.
+
+   Returns
+    The number of characters read (zero at end of file) on success, -1 on error.
+*/
+ssize_t FlashFileSystemFileHandle::read(void* pBuffer, size_t Length)
+{
+    unsigned int    BytesLeft;
+
+    HexDump("Read", (uint8_t *)pBuffer, Length);
+    // Don't read more bytes than what are left in the file.
+    BytesLeft = m_pFileEnd - m_pCurr;
+    if (Length > BytesLeft) {
+        Length = BytesLeft;
+    }
+    // Copy the bytes from FLASH into the caller provided buffer.
+    memcpy(pBuffer, m_pCurr, Length);
+    // Update the file pointer.
+    m_pCurr += Length;
+    return Length;
+}
+
+
+/* Check if the handle is for a interactive terminal device .
+
+   Parameters
+    None
+   Returns
+    1 if it is a terminal, 0 otherwise
+*/
+int FlashFileSystemFileHandle::isatty()
+{
+    return 0;
+}
+
+
+/* Move the file position to a given offset from a given location.
+
+   Parameters
+    offset is the offset from whence to move to.
+    whence - SEEK_SET for the start of the file,
+             SEEK_CUR for the current file position, or
+             SEEK_END for the end of the file.
+
+   Returns
+    New file position on success, -1 on failure or unsupported
+*/
+off_t FlashFileSystemFileHandle::lseek(off_t offset, int whence)
+{
+    INFO("lseek(%d, %d)", offset, whence);
+    switch(whence) {
+        case SEEK_SET:
+            m_pCurr = m_pFileStart + offset;
+            break;
+        case SEEK_CUR:
+            m_pCurr += offset;
+            break;
+        case SEEK_END:
+            m_pCurr = (m_pFileEnd - 1) + offset;
+            break;
+        default:
+            INFO("Received unknown origin code (%d) for seek.", whence);
+            return -1;
+    }
+    return (m_pCurr - m_pFileStart);
+}
+
+
+/* Flush any buffers associated with the FileHandle, ensuring it
+   is up to date on disk.  Since the Flash file system is read-only, there
+   is nothing to do here.
+
+   Returns
+    0 on success or un-needed, -1 on error
+*/
+int FlashFileSystemFileHandle::fsync()
+{
+    return 0;
+}
+
+
+/* Returns the length of the file.
+
+   Parameters:
+    None
+   Returns:
+    Length of file.
+*/
+off_t FlashFileSystemFileHandle::flen()
+{
+    return (m_pFileEnd - m_pFileStart);
+}
+
+
+
+/* Construct and initialize a directory handle enumeration object.
+
+   Parameters:
+    pFLASHBase points to the beginning of the file system in FLASH memory.
+    pFirstFileEntry is a pointer to the first entry found in this directory.
+    DirectoryNameLength is the length of the directory name for which this
+        handle is being used to enumerate.
+
+   Returns:
+    Nothing.
+*/
+FlashFileSystemDirHandle::FlashFileSystemDirHandle(const char*              pFLASHBase,
+        const _SFileSystemEntry* pFirstFileEntry,
+        unsigned int             FileEntriesLeft,
+        unsigned int             DirectoryNameLength)
+{
+    m_pFLASHBase = pFLASHBase;
+    m_pFirstFileEntry = pFirstFileEntry;
+    m_pCurrentFileEntry = pFirstFileEntry;
+    m_FileEntriesLeft = FileEntriesLeft;
+    m_DirectoryNameLength = DirectoryNameLength;
+    m_DirectoryEntry.d_name[0] = '\0';
+}
+
+
+// Used to construct a closed directory handle.
+FlashFileSystemDirHandle::FlashFileSystemDirHandle()
+{
+    FlashFileSystemDirHandle(NULL, NULL, 0, 0);
+}
+
+
+/* Closes the directory enumeration object.
+
+   Parameters:
+    None.
+
+   Returns:
+    0 on success, or -1 on error.
+*/
+int FlashFileSystemDirHandle::closedir()
+{
+    m_pFLASHBase = NULL;
+    m_pFirstFileEntry = NULL;
+    m_pCurrentFileEntry = NULL;
+    m_FileEntriesLeft = 0;
+    m_DirectoryNameLength = 0;
+    m_DirectoryEntry.d_name[0] = '\0';
+
+    return 0;
+}
+
+
+/* Return the directory entry at the current position, and
+   advances the position to the next entry.
+
+   Parameters:
+    None.
+
+   Returns:
+    A pointer to a dirent structure representing the
+    directory entry at the current position, or NULL on reaching
+    end of directory or error.
+*/
+struct dirent* FlashFileSystemDirHandle::readdir() {
+    const char*  pPrevEntryName;
+    const char*  pCurrentEntryName;
+    char*        pSlash;
+    size_t       PrefixLength;
+    unsigned int FileEntriesUsed;
+    unsigned int FileEntriesLeft;
+
+    // Just return now if we have already finished enumerating the entries in
+    // the directory.
+    if (!m_pCurrentFileEntry) {
+        m_DirectoryEntry.d_name[0] = '\0';
+        return NULL;
+    }
+
+    // Calculate the number of valid entries are left in the file entry array.
+    FileEntriesUsed = m_pCurrentFileEntry - m_pFirstFileEntry;
+    FileEntriesLeft = m_FileEntriesLeft - FileEntriesUsed;
+
+    // Fill in the directory entry structure for the current entry.
+    pPrevEntryName = m_pFLASHBase +
+                     m_pCurrentFileEntry->FilenameOffset;
+    strncpy(m_DirectoryEntry.d_name,
+            pPrevEntryName + m_DirectoryNameLength,
+            sizeof(m_DirectoryEntry.d_name));
+    m_DirectoryEntry.d_name[sizeof(m_DirectoryEntry.d_name) - 1] = '\0';
+
+    // If the entry to be returned contains a slash then this is a directory
+    // entry.
+    pSlash = strchr(m_DirectoryEntry.d_name, '/');
+    if (pSlash) {
+        // I am truncating everything after the slash but leaving the
+        // slash so that I can tell it is a directory and not a file.
+        pSlash[1] = '\0';
+    }
+
+    // Skip entries that have the same prefix as the current entry.  This
+    // will skip the files in the same sub-tree.
+    PrefixLength = strlen(m_DirectoryEntry.d_name) + m_DirectoryNameLength;
+    do {
+        m_pCurrentFileEntry++;
+        FileEntriesLeft--;
+        pCurrentEntryName = m_pFLASHBase + m_pCurrentFileEntry->FilenameOffset;
+    } while (FileEntriesLeft &&
+             0 == strncmp(pPrevEntryName, pCurrentEntryName, PrefixLength));
+
+    // If we have walked past the end of all file entries in the file system or
+    // the prefix no longer matches this directory, then there are no more files
+    // for this directory enumeration.
+    if (0 == FileEntriesLeft ||
+            0 != strncmp(pPrevEntryName, pCurrentEntryName, m_DirectoryNameLength)) {
+        m_pCurrentFileEntry = NULL;
+    }
+
+    // Return a pointer to the directory entry structure that was previously
+    // setup.
+    return &m_DirectoryEntry;
+}
+
+
+//Resets the position to the beginning of the directory.
+void FlashFileSystemDirHandle::rewinddir()
+{
+    m_pCurrentFileEntry = m_pFirstFileEntry;
+}
+
+
+/* Returns the current position of the DirHandle.
+
+   Parameters:
+    None.
+
+   Returns:
+    The current position, or -1 on error.
+*/
+off_t FlashFileSystemDirHandle::telldir()
+{
+    return (off_t)m_pCurrentFileEntry;
+}
+
+
+/* Sets the position of the DirHandle.
+
+   Parameters:
+    Location is the location to seek to. Must be a value returned
+        by telldir.
+
+   Returns;
+    Nothing.
+*/
+void FlashFileSystemDirHandle::seekdir(off_t Location)
+{
+    SFileSystemEntry*   pLocation = (SFileSystemEntry*)Location;
+
+    assert ( NULL != pLocation &&
+             pLocation > m_pFirstFileEntry &&
+             (pLocation - m_pFirstFileEntry) < m_FileEntriesLeft );
+    m_pCurrentFileEntry = pLocation;
+}
+
+
+
+// Structure used to hold context about current filename search.
+struct SSearchContext {
+    // Name of file to be found in file system image.
+    const char* pKey;
+    // Base pointer for the file system image.
+    const char* pFLASHBase;
+};
+
+
+/* Internal routine used as callback for bsearch() when searching for a
+   requested filename in the FLASH file system image.
+
+   pvKey is a pointer to the SSearchContext object for this search.
+   pvEntry is a pointer to the current file system entry being checked by
+    bsearch().
+
+   Returns <0 if filename to find is lower in sort order than current entry.
+            0 if filename to find is the same as the current entry.
+           >0 if filename to find is higher in sort order than current entry.
+*/
+static int _CompareKeyToFileEntry(const void* pvKey, const void* pvEntry)
+{
+    const SSearchContext*       pContext = (const SSearchContext*)pvKey;
+    const char*                 pKey = pContext->pKey;
+    const SFileSystemEntry*     pEntry = (const SFileSystemEntry*)pvEntry;
+    const char*                 pEntryName = pContext->pFLASHBase + pEntry->FilenameOffset;
+
+    return strcmp(pKey, pEntryName);
+}
+
+
+/* Constructor for FlashFileSystem
+
+   Parameters:
+    pName is the root name to be used for this file system in fopen()
+        pathnames.
+    pFlashDrive (optional) is a pointer to the read-only file system (const char array).
+        When pFlashDrive is not specified, it is up to the user to append the
+        read-only file system file to the compiled binary.
+    FlashSize (optional) is the size of the FLASH (KB) on the device to
+        search through for the file system signature (default = 512).
+*/
+FlashFileSystem::FlashFileSystem(const char* pName, const uint8_t *pFlashDrive, const uint32_t FlashSize) : FileSystemLike(pName)
+{
+    static const char   FileSystemSignature[] = FILE_SYSTEM_SIGNATURE;
+    SFileSystemHeader*  pHeader = NULL;
+    char*               pCurr = (char*)(FlashSize * 1024) - sizeof(pHeader->FileSystemSignature);
+
+    // Initialize the members
+    m_pFLASHBase = NULL;
+    m_FileCount = 0;
+    m_pFileEntries = NULL;
+
+    INFO("constructor.");
+    wait_ms(200);
+    // Scan backwards through 512k FLASH looking for the file system signature
+    // NOTE: The file system image should be located after this code itself
+    //       so stop the search.
+    if (pFlashDrive == NULL) {
+        while (pCurr > FileSystemSignature) {
+            if (0 == memcmp(pCurr, FileSystemSignature, sizeof(pHeader->FileSystemSignature))) {
+                break;
+            }
+            pCurr--;
+        }
+        if (pCurr <= FileSystemSignature) {
+            INFO("Failed to find file system image in ROM.");
+            return;
+        } else {
+            INFO("found it at %p", pCurr);
+        }
+    } else {
+        pCurr = (char *)pFlashDrive;
+    }
+    if (((unsigned int)pCurr & 0x3) != 0) {
+        INFO("File system image at address %08X isn't 4-byte aligned.", pCurr);
+        return;
+    }
+
+    // Record the location of the file system image in the member fields.
+    m_pFLASHBase = pCurr;
+    pHeader = (SFileSystemHeader*)m_pFLASHBase;
+    m_FileCount = pHeader->FileCount;
+    m_pFileEntries = (SFileSystemEntry*)(m_pFLASHBase + sizeof(*pHeader));
+    INFO("  end constructor.");
+}
+
+
+/* Opens specified file in FLASH file system when an appropriate call to
+   fopen() is made.
+
+   pFilename is the name of the file to be opened within the file system.
+   Flags specify flags to determine open mode of file.  This file system only
+    support O_RDONLY.
+
+   Returns NULL if an error was encountered or a pointer to a FileHandle object
+    representing the requrested file otherwise.
+*/
+FileHandle* FlashFileSystem::open(const char* pFilename, int Flags)
+{
+    const SFileSystemEntry*     pEntry = NULL;
+    FlashFileSystemFileHandle*  pFileHandle = NULL;
+    SSearchContext              SearchContext;
+
+    INFO("Attempt to open file /FLASH/%s with flags:%x", pFilename, Flags);
+
+    // Can't find the file if file system hasn't been mounted.
+    if (!IsMounted()) {
+        INFO("not mounted.");
+        return NULL;
+    }
+
+    // Can only open files in FLASH for read.
+    if (O_RDONLY != Flags) {
+        INFO("Can only open files for reading.");
+    }
+
+    // Attempt to find the specified file in the file system image.
+    SearchContext.pKey = pFilename;
+    SearchContext.pFLASHBase = m_pFLASHBase;
+    pEntry = (const SFileSystemEntry*) bsearch(&SearchContext,
+             m_pFileEntries,
+             m_FileCount,
+             sizeof(*m_pFileEntries),
+             _CompareKeyToFileEntry);
+    if(!pEntry) {
+        // Create failure response.
+        INFO("Failed to find '%s' in file system image.", pFilename);
+        return NULL;
+    }
+
+    // Attempt to find a free file handle.
+    pFileHandle = FindFreeFileHandle();
+    if (!pFileHandle) {
+        INFO("File handle table is full.");
+        return NULL;
+    }
+
+    // Initialize the file handle and return it to caller.
+    pFileHandle->SetEntry(m_pFLASHBase + pEntry->FileBinaryOffset,
+                          m_pFLASHBase + pEntry->FileBinaryOffset + pEntry->FileBinarySize);
+    INFO("file opened ok.");
+    return pFileHandle;
+}
+
+DirHandle*  FlashFileSystem::opendir(const char *pDirectoryName)
+{
+    const SFileSystemEntry* pEntry = m_pFileEntries;
+    unsigned int            DirectoryNameLength;
+    unsigned int            i;
+
+    assert ( pDirectoryName);
+
+    // Removing leading slash since the file system image doesn't contain
+    // leading slashes.
+    if ('/' == pDirectoryName[0]) {
+        pDirectoryName++;
+    }
+
+    // Make sure that the directory name length would include the trailing
+    // slash.
+    DirectoryNameLength = strlen(pDirectoryName);
+    if (0 != DirectoryNameLength && '/' != pDirectoryName[DirectoryNameLength-1]) {
+        // Add the implicit slash to this count.
+        DirectoryNameLength++;
+    }
+
+    // Search through the file entries from the beginning to find the first
+    // entry which has pDirectoryName/ as the prefix.
+    for (i = 0 ; i < m_FileCount ; i++) {
+        const char* pEntryFilename = pEntry->FilenameOffset + m_pFLASHBase;
+
+        if (0 == DirectoryNameLength ||
+                (pEntryFilename == strstr(pEntryFilename, pDirectoryName) &&
+                 '/' == pEntryFilename[DirectoryNameLength-1]) ) {
+            // Found the beginning of the list of files/folders for the
+            // requested directory so return it to the caller.
+            FlashFileSystemDirHandle* pDirHandle = FindFreeDirHandle();
+            if (!pDirHandle) {
+                INFO("Dir handle table is full.");
+                return NULL;
+            }
+            pDirHandle->SetEntry(m_pFLASHBase,
+                                 pEntry,
+                                 m_FileCount - (pEntry - m_pFileEntries),
+                                 DirectoryNameLength);
+            return pDirHandle;
+        }
+        // Advance to the next file entry
+        pEntry++;
+    }
+    // Get here when the requested directory wasn't found.
+    WARN("Failed to find '%s' directory in file system image.",
+          pDirectoryName);
+    return NULL;
+}
+
+
+/* Protected method which attempts to find a free file handle in the object's
+   file handle table.
+
+   Parameters:
+    None
+
+   Returns:
+    Pointer to first free file handle entry or NULL if the table is full.
+*/
+FlashFileSystemFileHandle* FlashFileSystem::FindFreeFileHandle()
+{
+    size_t  i;
+
+    // Iterate through the file handle array, looking for a close file handle.
+    for (i = 0 ; i < sizeof(m_FileHandles)/sizeof(m_FileHandles[0]) ; i++) {
+        if (m_FileHandles[i].IsClosed()) {
+            return &(m_FileHandles[i]);
+        }
+    }
+    // If we get here, then no free entries were found.
+    WARN("no free entries found");
+    return NULL;
+}
+
+
+/* Protected method which attempts to find a free dir handle in the object's
+   directory handle table.
+
+   Parameters:
+    None
+
+   Returns:
+    Pointer to first free directory handle entry or NULL if the table is full.
+*/
+FlashFileSystemDirHandle* FlashFileSystem::FindFreeDirHandle()
+{
+    size_t  i;
+
+    // Iterate through the direcotry handle array, looking for a closed
+    // directory handle.
+    for (i = 0 ; i < sizeof(m_DirHandles)/sizeof(m_DirHandles[0]) ; i++) {
+        if (m_DirHandles[i].IsClosed()) {
+            return &(m_DirHandles[i]);
+        }
+    }
+    // If we get here, then no free entries were found.
+    WARN("no free entries found");
+    return NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FlashFileSystem.h	Sat Jul 29 12:45:09 2017 +0000
@@ -0,0 +1,317 @@
+/* Copyright 2011 Adam Green (http://mbed.org/users/AdamGreen/)
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+/* Specifies the classes used to implement the FlashFileSystem which is a
+   read-only file system that exists in the internal FLASH of the mbed
+   device.
+*/
+#ifndef _FLASHFILESYSTEM_H_
+#define _FLASHFILESYSTEM_H_
+
+#include "FileSystemLike.h"
+
+// Control the number of concurrently open files and directories.
+// Was originally 16 for each.
+//
+#define NUM_CONCURRENT_FILES 2
+#define NUM_CONCURRENT_DIRS  2
+
+
+// Forward declare file system entry structure used internally in 
+// FlashFileSystem.
+struct _SFileSystemEntry;
+
+
+
+// Represents an opened file object in the FlashFileSystem.
+class FlashFileSystemFileHandle : public FileHandle 
+{
+public:
+    FlashFileSystemFileHandle();
+    FlashFileSystemFileHandle(const char* pFileStart, const char* pFileEnd);
+    
+    // FileHandle interface methods.
+    virtual ssize_t write(const void* buffer, size_t length);
+    virtual int close();
+    virtual ssize_t read(void* buffer, size_t length);
+    virtual int isatty();
+    virtual off_t lseek(off_t offset, int whence);
+    virtual int fsync();
+    virtual off_t flen();
+
+    // Used by FlashFileSystem to maintain entries in its handle table.
+    void SetEntry(const char* pFileStart, const char* pFileEnd)
+    {
+        m_pFileStart = pFileStart;
+        m_pFileEnd = pFileEnd;
+        m_pCurr = pFileStart;
+    }
+    int IsClosed()
+    {
+        return (NULL == m_pFileStart);
+    }
+    
+protected:
+    // Beginning offset of file in FLASH memory.
+    const char*         m_pFileStart;
+    // Ending offset of file in FLASH memory.
+    const char*         m_pFileEnd;
+    // Current position in file to be updated by read and seek operations.
+    const char*         m_pCurr;
+};
+
+
+// Represents an open directory in the FlashFileSystem.
+class FlashFileSystemDirHandle : public DirHandle
+{
+ public:
+    // Constructors
+    FlashFileSystemDirHandle();
+    FlashFileSystemDirHandle(const char*              pFLASHBase,
+                             const _SFileSystemEntry* pFirstFileEntry,
+                             unsigned int             FileEntriesLeft,
+                             unsigned int             DirectoryNameLength);
+                             
+    // Used by FlashFileSystem to maintain DirHandle entries in its cache.
+    void SetEntry(const char*              pFLASHBase,
+                  const _SFileSystemEntry* pFirstFileEntry,
+                  unsigned int             FileEntriesLeft,
+                  unsigned int             DirectoryNameLength)
+    {
+        m_pFLASHBase = pFLASHBase;
+        m_pFirstFileEntry = pFirstFileEntry;
+        m_pCurrentFileEntry = pFirstFileEntry;
+        m_FileEntriesLeft = FileEntriesLeft;
+        m_DirectoryNameLength = DirectoryNameLength;
+    }
+    int IsClosed()
+    {
+        return (NULL == m_pFirstFileEntry);
+    }
+    
+    // Methods defined by DirHandle interface.
+    virtual int    closedir();
+    virtual struct dirent *readdir();
+    virtual void   rewinddir();
+    virtual off_t  telldir();
+    virtual void   seekdir(off_t location);
+
+protected:
+    // The first file entry for this directory.  rewinddir() takes the
+    // iterator back to here.
+    const _SFileSystemEntry*    m_pFirstFileEntry;
+    // The next file entry to be returned for this directory enumeration.
+    const _SFileSystemEntry*    m_pCurrentFileEntry;
+    // Pointer to where the file system image is located in the device's FLASH.
+    const char*                 m_pFLASHBase;
+    // Contents of previously return directory entry structure.
+    struct dirent               m_DirectoryEntry;
+    // This is the length of the directory name which was opened.  When the
+    // first m_DirectoryNameLength characters change then we have iterated
+    // through to a different directory.
+    unsigned int                m_DirectoryNameLength;
+    // The number of entries left in the file system file entries array.
+    unsigned int                m_FileEntriesLeft;
+};
+
+
+
+/** A filesystem for accessing a read-only file system placed in the internal\n
+ *  FLASH memory of the mbed board.
+ *\n
+ *  The file system to be mounted by this file system should be created through\n
+ *  the use of the fsbld utility on the PC.\n
+ *\n
+ *  As fsbld creates two output files (a binary and a header file), there are two\n
+ *  ways to add the resulting file system image:\n
+ *  -# Concatenate the binary file system to the end of the .bin file created\n
+ *     by the mbed online compiler before uploading to the mbed device.\n
+ *  -# Import the header file into your project, include this file in your main\n
+ *     file and add 'roFlashDrive' to the FlashfileSystem constructor call.\n
+ *     eg : static FlashFileSystem flash("flash", roFlashDrive);\n
+ *
+ *  A third (optional) parameter in the FlashfileSystem constructor call allows\n
+ *  you to specify the size of the FLASH (KB) on the device (default = 512).\n
+ *  eg (for a KL25Z device) : static FlashFileSystem flash("flash", NULL, 128);\n
+ *  Note that in this example, the pointer to the header file has been omitted,\n
+ *  so we need to append the binary file system ourselves (see above).\n
+ *  When you use the binary file system header in your main file, you can\n
+ *  use the roFlashDrive pointer.\n
+ *  eg (for a KL25Z device) : static FlashFileSystem flash("flash", roFlashDrive, 128);\n
+ *\n
+ *  NOTE: This file system is case-sensitive.  Calling fopen("/flash/INDEX.html")\n
+ *        won't successfully open a file named index.html in the root directory\n
+ *        of the flash file system.\n
+ *
+ * Example:
+ * @code
+#include <mbed.h>
+#include "FlashFileSystem.h"
+// Uncomment the line below when you imported the header file built with fsbld
+// and replace <Flashdrive> with its correct filename
+//#include "<FlashDrive>.h"
+
+static void _RecursiveDir(const char* pDirectoryName, DIR* pDirectory = NULL)
+{
+    DIR* pFreeDirectory = NULL;
+    
+    size_t DirectoryNameLength = strlen(pDirectoryName);
+ 
+    // Open the specified directory.
+    if (!pDirectory)
+    {
+        pDirectory = opendir(pDirectoryName);
+        if (!pDirectory)
+        {
+            error("Failed to open directory '%s' for enumeration.\r\n", 
+                  pDirectoryName);
+        }
+        
+        // Remember to free this directory enumerator.
+        pFreeDirectory = pDirectory;
+    }
+        
+    // Determine if we should remove a trailing slash from future *printf()
+    // calls.
+    if (DirectoryNameLength && '/' == pDirectoryName[DirectoryNameLength-1])
+    {
+        DirectoryNameLength--;
+    }
+    
+    // Iterate though each item contained within this directory and display
+    // it to the console.
+    struct dirent* DirEntry;
+    while((DirEntry = readdir(pDirectory)) != NULL) 
+    {
+        char RecurseDirectoryName[256];
+        DIR* pSubdirectory;
+
+        // Try opening this file as a directory to see if it succeeds or not.
+        snprintf(RecurseDirectoryName, sizeof(RecurseDirectoryName),
+                 "%.*s/%s",
+                 DirectoryNameLength,
+                 pDirectoryName,
+                 DirEntry->d_name);
+        pSubdirectory = opendir(RecurseDirectoryName);
+        
+        if (pSubdirectory)
+        {
+            _RecursiveDir(RecurseDirectoryName, pSubdirectory);
+            closedir(pSubdirectory);
+        }
+        else
+        {
+            printf("    %.*s/%s\n", 
+                   DirectoryNameLength, 
+                   pDirectoryName, 
+                   DirEntry->d_name);
+        }
+    }
+    
+    // Close the directory enumerator if it was opened by this call.
+    if (pFreeDirectory)
+    {
+        closedir(pFreeDirectory);
+    }
+}
+
+int main() 
+{
+    static const char* Filename = "/flash/index.html";
+    char*              ReadResult = NULL;
+    int                SeekResult = -1;
+    char               Buffer[128];
+
+    // Create the file system under the name "flash".
+    // NOTE : When you include the the header file built with fsbld,
+    //        disable the first static FlashFileSystem... line
+    //        and enable the second static FlashFileSystem... line.
+    static FlashFileSystem flash("flash");
+//    static FlashFileSystem flash("flash, roFlashDrive");
+    if (!flash.IsMounted())
+    {
+        error("Failed to mount FlashFileSystem.\r\n");
+    }
+
+    // Open "index.html" on the file system for reading.
+    FILE *fp = fopen(Filename, "r");
+    if (NULL == fp)
+    {
+        error("Failed to open %s\r\n", Filename);
+    }
+    
+    // Use seek to determine the length of the file
+    SeekResult = fseek(fp, 0, SEEK_END);
+    if (SeekResult)
+    {
+        error("Failed to seek to end of %s.\r\n", Filename);
+    }
+    long FileLength = ftell(fp);
+    printf("%s is %ld bytes in length.\r\n", Filename, FileLength);
+    
+    // Reset the file pointer to the beginning of the file
+    SeekResult = fseek(fp, 0, SEEK_SET);
+    if (SeekResult)
+    {
+        error("Failed to seek to beginning of %s.\r\n", Filename);
+    }
+    
+    // Read the first line into Buffer and then display to user.
+    ReadResult = fgets(Buffer, sizeof(Buffer)/sizeof(Buffer[0]), fp);
+    if (NULL == ReadResult)
+    {
+        error("Failed to read first line of %s.\r\n", Filename);
+    }
+    printf("%s:1  %s", Filename, Buffer);
+    
+    // Done with the file so close it.
+    fclose(fp);                               
+
+    // Enumerate all content on mounted file systems.
+    printf("\r\nList all files in /flash...\r\n");
+    _RecursiveDir("/flash");
+        
+    printf("\r\nFlashFileSystem example has completed.\r\n");
+}
+ * @endcode
+ */
+class FlashFileSystem : public FileSystemLike 
+{
+public:
+    FlashFileSystem(const char* pName, const uint8_t *pFlashDrive = NULL, const uint32_t FlashSize = 512);
+    
+    virtual FileHandle* open(const char* pFilename, int Flags);
+    virtual DirHandle*  opendir(const char *pDirectoryName);
+
+    virtual int         IsMounted() { return (m_FileCount != 0); }
+
+protected:
+    FlashFileSystemFileHandle*  FindFreeFileHandle();
+    FlashFileSystemDirHandle*   FindFreeDirHandle();
+
+    // File handle table used by this file system so that it doesn't need
+    // to dynamically allocate file handles at runtime.
+    FlashFileSystemFileHandle   m_FileHandles[NUM_CONCURRENT_FILES];
+    // Directory handle table used by this file system so that it doesn't need
+    // to dynamically allocate file handles at runtime.
+    FlashFileSystemDirHandle    m_DirHandles[NUM_CONCURRENT_DIRS];
+    // Pointer to where the file system image is located in the device's FLASH.
+    const char*                 m_pFLASHBase;
+    // Pointer to where the file entries are located in the device's FLASH.
+    const _SFileSystemEntry*    m_pFileEntries;
+    // The number of files in the file system image.
+    unsigned int                m_FileCount;
+};
+
+#endif // _FLASHFILESYSTEM_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ffsformat.h	Sat Jul 29 12:45:09 2017 +0000
@@ -0,0 +1,50 @@
+/* Copyright 2011 Adam Green (http://mbed.org/users/AdamGreen/)
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+/* Specifies constants and structures used within the FLASH File System.  The
+   header is used by both the runtime and the tool which builds the image on
+   the PC.
+*/
+#ifndef _FFSFORMAT_H_
+#define _FFSFORMAT_H_
+
+
+/* The signature to be placed in SFileSystemHeader::FileSystemSignature.
+   Only the first 8 bytes are used and the NULL terminator discarded. */
+#define FILE_SYSTEM_SIGNATURE "FFileSys"
+
+/* Header stored at the beginning of the file system image. */
+typedef struct _SFileSystemHeader
+{
+    /* Signature should be set to FILE_SYSTEM_SIGNATURE. */
+    char            FileSystemSignature[8];
+    /* Number of entries in this file system image. */
+    unsigned int    FileCount;
+    /* The SFileSystemEntry[SFileSystemHeader::FileCount] array will start here. 
+       These entries are to be sorted so that a binary search can be performed
+       at file open time. */
+} SFileSystemHeader;
+
+/* Information about each file added to the file system image. */
+typedef struct _SFileSystemEntry
+{
+    /* The 2 following offsets are relative to the beginning of the file 
+       image. */
+    unsigned int    FilenameOffset;
+    unsigned int    FileBinaryOffset;
+    unsigned int    FileBinarySize;
+} SFileSystemEntry;
+
+
+#endif /* _FFSFORMAT_H_ */