Erick / Mbed 2 deprecated ICE-F412

Dependencies:   mbed-rtos mbed

Revision:
0:61364762ee0e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ICE-Application/src/add-ons/ConfigFS/mfs.cpp	Tue Jan 24 19:05:33 2017 +0000
@@ -0,0 +1,686 @@
+/** @file mfs.cpp */
+/*CPP**************************************************************************
+ * FILENAME :        mfs.cpp                                                  *
+ *                                                                            *
+ * DESCRIPTION :                                                              *
+ *       mFS file system implementation for mBED with external I2C EEEPROM.   *
+ *                                                                            *
+ * AUTHOR :    Olli Vanhoja        START DATE :    2011-02-21                 *
+ *****************************************************************************/
+ 
+#include "mbed.h"
+#include "mfs.h"
+#include "i2c_eeprom.h"
+ 
+#define BLOCK_LLEN 2        /**< Block number link length in bytes */
+#define RB 1+2*BLOCK_LLEN   /**< Reseved bytes per block (1 attrb B, 2 B for next/prev pointers */
+#define MFS_I2C_SPEED 100000    /**< I2C bus speed in Hz */
+#define DEBUG               /**< Adds extra safety in reading and writing */
+  
+mfs::mfs(int i2c_address)
+{
+    mem = new i2c_eeprom(i2c_address, MFS_I2C_SPEED);
+}
+ 
+char mfs::read(char *data, uint32_t block, uint32_t byte, uint32_t n)
+{
+    // Faster reading without DEBUG mode
+    #ifdef DEBUG
+    if ((byte+n-1 >= BS))
+        return 1;
+    #endif
+    mem->read(BS*block+byte, n, data);
+ 
+    return 0;
+}
+ 
+char mfs::write(char *data, uint32_t block, uint32_t byte, uint32_t n)
+{
+    // Faster writing without DEBUG mode
+    #ifdef DEBUG
+    if (byte+n >= BS)
+        return 1;
+    #endif
+    mem->write(data, BS*block+byte, n);
+    
+    return 0;
+}
+ 
+char mfs::getNextFreeBlock(uint32_t *blockOut)
+{    
+    // Locate free block by seeking EERPOM
+    char cFlags[1];
+    
+    for (*blockOut=0; *blockOut < BC; (*blockOut)++)
+    {
+        read(cFlags, *blockOut, 0, 1);
+        if (cFlags[0] == 0x04)
+            break;
+        if (*blockOut >= BC-1)
+            return 1;
+    }
+    
+    return 0;
+}
+ 
+char mfs::findNextFile(uint32_t block, char *filenameOut, uint32_t *blockOut)
+{
+    uint32_t i=block;
+    char cFlags[1];
+    
+    while (i < BC)
+    {
+        read(cFlags, i, 0, 1);
+        
+        if ((cFlags[0] & 0x8C) == 0x8C)
+            break; // File found
+        else
+            i++;
+    }
+    
+    if(i == BC)
+    {
+        strcpy(filenameOut, "");
+        return 1; // Empty fs
+    }
+    
+    // Read filename
+    read(filenameOut, i, RB, FILENAME_LENGTH);
+    *blockOut = i; // Return block number
+    return 0;
+}
+ 
+char mfs::getFirstBlockOfFile(char filename[FILENAME_LENGTH], uint32_t *blockOut)
+{
+    *blockOut=0;
+    char tmpFilename[FILENAME_LENGTH]="";
+ 
+    while (1)
+    {
+        if (findNextFile(*blockOut, tmpFilename, blockOut) == 0)
+        {
+            if(strcmp(tmpFilename, filename) == 0)
+                return 0; // File exists
+        }
+        else return 1; // File doesn't exist
+        (*blockOut)++;
+    }
+}
+ 
+char mfs::createFile(char filename[FILENAME_LENGTH])
+{
+    char tmpFilename[FILENAME_LENGTH];
+    uint32_t n;
+    uint32_t fb;
+ 
+    for (n=0; n < BC; n++)
+    {
+        if(findNextFile(n, tmpFilename, &n) == 0)
+        {
+            if(strcmp(tmpFilename, filename) == 0)
+                return 1; // File exist
+        }
+        else break; // We already reached the edge of the universe
+        n++;
+    }
+ 
+    if(getNextFreeBlock(&fb) != 0)
+        return 2; // Out of space
+    
+    char cData[RB+FILENAME_LENGTH+1];
+    cData[0] = '\xCC';   // Necessary flags for a file
+    cData[1] = '\0';     // No more blocks yet
+    cData[2] = '\0';
+    cData[3] = '\0';     // First block so there is no prev blocks
+    cData[4] = '\0';
+    cData[RB+FILENAME_LENGTH] = mEOF; // Set EOF at the begining
+    
+    for (char i=0; i < FILENAME_LENGTH; i++)
+        cData[RB+i] = filename[i];
+    
+    // Create file
+    write(cData, fb, 0, RB+FILENAME_LENGTH+1);
+        
+    return 0;
+}
+ 
+char mfs::removeFile(char filename[FILENAME_LENGTH])
+{
+    uint32_t block;
+    char cData[RB-BLOCK_LLEN];
+    char cDataNew[RB] = {'\x04', '\0', '\0', '\0', '\0'};
+    uint32_t i=0;
+ 
+    // Check if file exists
+    if (getFirstBlockOfFile(filename, &block) != 0)
+        return 1; // File not found
+    
+    read(cData, block, 0, RB-BLOCK_LLEN);
+    
+    // Check credentials
+     if (((cData[0] & 0x01)|((cData[0] & 0x10) >> 3)|((cData[0] & 0x20) >> 3) & 0x04) != 0)
+        return 2; // RO file
+    
+    // Clear blocks reserved by the file    
+    while(1)
+    {
+        write(cDataNew, block, 0, RB);
+        if ((cData[0] & 0x4C) == 0x4C)
+            break; // End of file found
+        else block = (uint32_t)(cData[1])<<8|cData[2]; // Set next block number
+        i++;
+        if (i > BC)
+            return 1; // fs is corrupted
+        read(cData, block, 0, RB-BLOCK_LLEN);
+    }
+    
+    return 0; // Everything went better than expected
+}
+ 
+char mfs::renameFile(char oldFilename[FILENAME_LENGTH], char newFilename[FILENAME_LENGTH])
+{
+    uint32_t block;
+    char cData[1];
+ 
+    // Check if file exists
+    if (getFirstBlockOfFile(oldFilename, &block) != 0)
+        return 1; // File not found
+    
+    // Check credentials
+    read(cData, block, 0, 1);
+     char flags = (cData[0] & 0x01)|((cData[0] & 0x10) >> 3)|((cData[0] & 0x20) >> 3);
+     if ((flags & 0x04) != 0)
+        return 2; // RO file
+    
+    write(newFilename, block, RB, FILENAME_LENGTH);
+    
+    return 0; // Everything went better than expected
+}
+ 
+char mfs::setFileFlags(char *flags, char filename[FILENAME_LENGTH])
+{
+    /* RO|HIDDEN|LOCK  *
+     * H            L */
+    
+    uint32_t n;
+    char cData[1] = {'\0'};
+    char cFlags;
+ 
+    // Check if file exists
+    if (getFirstBlockOfFile(filename, &n) != 0)
+        return 1; // File not found
+    
+    read(cData, n, 0, 1);
+    cFlags    = ((flags[0] & 0x01)|((flags[0] & 0x02) << 3)|((flags[0] & 0x04) << 3));
+    cData[0]  = cData[0] & (~0x31) | cFlags;
+    write(cData, n, 0, 1);
+    
+    return 0;
+}
+ 
+char mfs::getFileFlags(char *flags, char filename[FILENAME_LENGTH])
+{
+    /* RO|HIDDEN|LOCK  *
+     * H            L */
+    
+    uint32_t n;
+    char cData[1] = {'\0'};
+ 
+    // Check if file exists
+    if (getFirstBlockOfFile(filename, &n) != 0)
+        return 1; // File not found
+    
+    read(cData, n, 0, 1);
+    flags[0] = (cData[0] & 0x01)|((cData[0] & 0x10) >> 3)|((cData[0] & 0x20) >> 3);
+    
+    return 0;
+}
+ 
+// Return number of free blocks
+uint32_t mfs::free()
+{
+    uint32_t blocks=0;
+    uint32_t r;
+    char cFlags[1];
+    
+    for (r=0; r < BC; r++)
+    {
+        read(cFlags, r, 0, 1);
+        if (cFlags[0] == 0x04)
+            blocks++;
+        if (r >= BC-1)
+            return blocks;
+    }
+    
+    return 0;
+}
+ 
+uint32_t mfs::mkfs(bool createLabel)
+{
+    uint32_t iAddr = 0;
+    uint32_t i = 0;
+    uint32_t bad = 0; // For counting bad block headers
+    char cFlags[RB] = {'\0', '\0', '\0', '\0', '\0'}, o[1];
+    
+    if (createLabel == true)
+    {
+        // Write Volume label
+        cFlags[0] = '\x0E';
+        mem->write(cFlags, iAddr, RB);
+        iAddr = BS;
+        i = 1;
+    }
+    
+    cFlags[0] = '\x04';
+    for (; i < BC; i++)
+    {
+        mem->write(cFlags, iAddr, RB);
+        mem->read(iAddr, 1, o);
+        if (o[0] != cFlags[0])
+            bad++;
+        iAddr += BS;
+    }
+    
+    return bad;
+}
+ 
+file::file(mfs *fs_ref, char filename[FILENAME_LENGTH], FileOpenMode operation)
+{
+    fMode = operation;
+    
+    fs = fs_ref; // Don't forget this :)
+    
+    uint32_t n;
+    char cData[1] = {'\0'};
+ 
+    // Check if file exists
+    if (fs->getFirstBlockOfFile(filename, &n) != 0)
+        error("Oops, file \"%s\" not found! n=0x%X", filename, n); // File not found
+    
+    fs->read(cData, n, 0, 1);
+    char flags = (cData[0] & 0x01)|((cData[0] & 0x10) >> 3)|((cData[0] & 0x20) >> 3);
+    
+    if ((fMode != RO) && ((flags & 0x04) != 0))
+        error("Oops, cant open in RW mode!");
+ 
+    // Store FBOF number
+    firstBlock = n;
+    currBlock = n;
+    blockPos = RB+FILENAME_LENGTH; // skip flags + pointers + filename
+    byteCount = 0; // First byte of the file
+ 
+    // Initialize buffer
+    for (unsigned int i=0; i < BUF; i++)
+        buffer[i] = '\0';
+    bufPos = 0;
+}
+ 
+file::~file()
+{
+    flush();
+}
+ 
+char file::getBlockLink(BlockLinkType linkSelection, uint32_t *blockOut)
+{
+    char cData[1+BLOCK_LLEN];
+ 
+    if (linkSelection == NEXT)
+    {
+        // Fetch link to next block
+        fs->read(cData, currBlock, 0, 1+BLOCK_LLEN);
+        if ((cData[0] & 0x40) == 0)
+        {
+            *blockOut  = ((uint32_t)(cData[1])) << 8; // Hbyte of next block link
+            *blockOut |= (uint32_t)cData[2];          // Lbyte of next block link
+            return 0;
+        } else return 1; // Already at last block
+    } else if (linkSelection == PREV)
+    {
+        if (currBlock != firstBlock)
+        {
+            fs->read(cData, currBlock, 1+BLOCK_LLEN, BLOCK_LLEN);
+            *blockOut  = ((uint32_t)(cData[0])) << 8; // Hbyte of next block link
+            *blockOut |= (uint32_t)cData[1];          // Lbyte of next block link
+            return 0;
+        } else return 1; // Already at first block
+    }
+    
+    return 0;
+}
+ 
+char file::removeFollowingBlocks(uint32_t block)
+{
+    char cData[RB-BLOCK_LLEN];
+    char cDataNew[RB] = {'\x04', '\0', '\0', '\0', '\0'};
+    uint32_t i=0;
+    
+    while(1)
+    {
+        fs->read(cData, block, 0, RB-BLOCK_LLEN);
+        fs->write(cDataNew, block, 0, RB);
+        if ((cData[0] & 0x4C) == 0x4C)
+            break; // End of file found
+        else block = (uint32_t)(cData[0])<<8|cData[1]; // Set next block number
+        i++;
+        if (i > BC)
+            return 1; // fs is corrupted
+    }
+    
+    return 0;
+}
+ 
+void file::rewind()
+{
+    flush();
+    currBlock = firstBlock;
+    blockPos = RB+FILENAME_LENGTH; // skip flags & pointers + filename
+    byteCount = 0;
+}
+ 
+char file::rewind(uint32_t n)
+{
+    uint32_t i;
+    uint32_t block;
+    uint32_t varBlockOffset;
+    
+    flush(); // Check if flush is needed
+    
+    for (i=0; i < n; i++)
+    {
+        blockPos--;
+        byteCount--;
+    
+        // Change Block?
+        if (blockPos == firstBlock)
+            varBlockOffset = RB+FILENAME_LENGTH;
+        else
+            varBlockOffset = RB;
+        if ((blockPos < varBlockOffset) && (currBlock > firstBlock))
+        {
+            // Fetch link to previous block
+            if(getBlockLink(PREV, &block) == 0)
+            {
+                currBlock = block;
+                blockPos  = BS-1; // blockPos should be set at the end of block
+            } else {
+                blockPos++;
+                byteCount++;
+                return 1; // This is the first block and byte
+            }
+        }
+    }
+    
+    return 0; // OK
+}
+ 
+char file::forward()
+{
+    return forward(1);
+}
+ 
+char file::forward(uint32_t n)
+{
+    uint32_t i;
+    uint32_t block; // Next block number
+    char cData[1];
+ 
+    flush(); // Check if flush is needed
+    
+    for (i=0; i < n; i++)
+    {
+        // If this is empty file EOF will be at first byte
+        fs->read(cData, currBlock, blockPos, 1);
+        if (cData[0] == mEOF)
+        {
+            return 1;
+        }
+        
+        blockPos++;
+        byteCount++;
+    
+        // Change Block?
+        if (blockPos >= BS)
+        {
+            // Fetch link to next block
+            if (getBlockLink(NEXT, &block) == 0)
+            {
+                currBlock = block;
+                blockPos = RB; // Reset block position offset
+            } else {
+                blockPos--;
+                byteCount--;
+                return 1; // This is the last block & byte
+            }
+        }
+        fs->read(cData, currBlock, blockPos, 1);
+        if (cData[0] == mEOF)
+        {
+            rewind(1); // Get back to the byte before EOF
+            return 1;
+        }
+    }
+    
+    return 0; // OK
+}
+ 
+char file::seek(uint32_t byte)
+{
+    if (byte > byteCount)
+        return forward(byte-byteCount);
+    else if (byte < byteCount)
+        return rewind(byteCount-byte);
+    else return 0;
+}
+ 
+// Respects mEOF and automatically sets '\0' at the end of string
+void file::read(char *data, uint32_t n)
+{
+    uint32_t i;
+    uint32_t block;
+    char cData[1];
+    
+    if( flush() != 0 ) {
+        printf("(%s:%d): flush failed\r\n", __func__, __LINE__);
+    }
+    
+    for (i=0; i < n; i++)
+    {
+        // Change block?
+        if (blockPos >= BS-1)
+        {
+//            printf("(%s:%d): pos=%d, BS-1=%d\r\n", __func__, __LINE__, blockPos, BS-1);
+            // Fetch link to next block
+            if (getBlockLink(NEXT, &block) == 0)
+            {
+                currBlock = block;
+                blockPos  = RB; // Reset block position offset
+            } else goto stop;
+        }
+        
+        // Read data
+    
+        fs->read(cData, currBlock, blockPos, 1);
+        if (cData[0] == mEOF)
+        {
+//      printf("(%s:%d): Found EOF: currBlock=%d, blockPos=%d\r\n", __func__, __LINE__, currBlock, blockPos);
+            stop:
+            data[i]='\0';
+            return;
+        } else {
+            data[i] = cData[0];
+//      printf("(%s:%d): blk=%d, pos=%d, char=%c\r\n", __func__, __LINE__, currBlock, blockPos, data[i]);
+            blockPos++;
+            byteCount++;
+        }
+    }
+    if (data[n-1] != '\0') {
+    printf("(%s:%d): Adding NULL\r\n", __func__, __LINE__ );
+        data[n-1] = '\0';
+    }
+}
+ 
+// Ignores mEOF and doesn't set '\0' markings
+void file::readBin(char *data, uint32_t n)
+{
+    uint32_t i;
+    uint32_t block;
+    char cData[1];
+    
+    for (i=0; i < n; i++)
+    {
+        // Change block?
+        if (blockPos == BS-1)
+        {
+            // Fetch link to next block
+            if (getBlockLink(NEXT, &block) == 0)
+            {
+                currBlock = block;
+                blockPos = RB; // Reset block position offset
+            } else return;
+        }
+        
+        // Read data
+        fs->read(cData, currBlock, blockPos, 1);
+        data[i] = cData[0];
+        
+        blockPos++;
+        byteCount++;
+    }
+}
+ 
+// Always binary
+char file::write(char *data, uint32_t n)
+{
+    if (fMode == RO) return 1;
+    
+    for (uint32_t i=0; i < n; i++)
+    {
+        // write to the buffer
+        buffer[bufPos] = data[i];
+        bufPos++;
+        
+        // If the buffer is full then flush
+        if(bufPos == BUF)
+        {
+        printf("(%s:%d): flushing buffer: bufPos=%d\r\n", __func__, __LINE__, bufPos);
+            if(flush() != 0);
+                return 1; // Flush failed
+        }
+    }
+    
+    return 0;
+}
+ 
+char file::flush()
+{
+    char cData[RB], cDataOB[RB-BLOCK_LLEN], c[1];
+    uint32_t nextFree;
+    uint32_t i;
+    uint32_t leftSpaceEOF;
+    
+    bool destructiveFlag = false; // Set this true if there is any data to be removed
+    uint32_t destructiveBlock=0;  // First block to be removed by DWRITE
+    
+    static bool fEOFow = false;   /* END of file found while appending (and overwritten).
+                                     Must be static because we don't want to found many EOF's. */
+    
+    
+    if (bufPos == 0) return 0; // File up-to date
+    if (fMode == RO) return 1;
+    
+    for (i=0; i <= bufPos; i++)
+    {
+     if( blockPos == 255 )
+     {
+//       printf("%s:%d:\r\n",__func__, __LINE__);
+     }
+
+        // Change Block?
+        if ((bufPos - i) == 1)
+            leftSpaceEOF = 1;
+        else
+            leftSpaceEOF = 0;
+        if (blockPos+1 >= BS-leftSpaceEOF)
+        {
+//      printf("(%s:%d): fetching unused block: currBlock=%d, blockPos=%d, bufPos=%d\r\n", __func__, __LINE__, currBlock, blockPos, bufPos );
+            // Fetch new unused block number
+            if(fs->getNextFreeBlock(&nextFree) != 0)
+                return 2; // No free space left
+            
+            // Read flags from current block
+            fs->read(cDataOB, currBlock, 0, RB-BLOCK_LLEN);
+            
+            /* If destructive write is set then check if there is something
+               to be marked for removal */
+            if (((cDataOB[0] & 0x40) != 0x40) && (fMode == DWRITE))
+            {
+                destructiveFlag = true;
+                destructiveBlock = (uint32_t)cDataOB[1]<<8|cDataOB[2];
+//          printf("(%s:%d): destructive flag set: currBlock=%d, blockPos=%d, bufPos=%d\r\n", __func__, __LINE__, currBlock, blockPos, bufPos );
+                goto allocate_new_block;
+            } else if ((cDataOB[0] & 0x40) != 0x40) // fMode == AWRITE
+            {
+                // Update current block info
+                currBlock = (uint32_t)cDataOB[1]<<8|cDataOB[2];
+                blockPos  = RB; // Reset block position offset
+//          printf("(%s:%d): resetting block position: currBlock=%d, blockPos=%d, bufPos=%d\r\n", __func__, __LINE__, currBlock, blockPos, bufPos );
+            } else // There is no block to append so we allocate a new one
+            {
+                allocate_new_block:
+                // Allocate new block for use
+                cData[0] = 0x4C;                              // New flags
+                cData[1] = '\0';                              // Hbyte of Next Block link
+                cData[2] = '\0';                              // Lbyte of Next Block link
+                cData[3] = (char)((currBlock & 0xff00) >> 8); // Hbyte of Prev Block link
+                cData[4] = (char)(currBlock & 0x00ff);        // Lbyte of Prev Block link
+                fs->write(cData, nextFree, 0, RB);            // Update Block Data
+            
+                // Link old block with new block
+                cDataOB[0] &= ~0x40;                             // Clear LBOF flag if set
+                cDataOB[1]  = (char)((nextFree & 0xff00) >> 8);  // Hbyte of Next Block link
+                cDataOB[2]  = (char)(nextFree & 0x00ff);         // Lbyte of Next Block link
+                fs->write(cDataOB, currBlock, 0, RB-BLOCK_LLEN); // Update Block Data
+
+                // Update current block info
+                currBlock = nextFree;
+                blockPos  = RB; // Reset block position offset
+
+//          printf("(%s:%d): allocating new block: currBlock=%d, blockPos=%d, bufPos=%d\r\n", __func__, __LINE__, currBlock, blockPos, bufPos );
+            }
+        }
+        
+        if (fMode == AWRITE) // Check if EOF is here
+        {
+            fs->read(c, currBlock, blockPos, 1);
+            if ((c[0] == mEOF) && (fEOFow == false))
+                fEOFow = true;
+        }
+        
+        // Write file
+        c[0]=buffer[i];
+        fs->write(c, currBlock, blockPos, 1);
+//  printf("(%s:%d): blk=%d, pos=%d, char=%c\r\n", __func__, __LINE__, currBlock, blockPos, c[0] );
+        blockPos++;
+        byteCount++;
+        
+        // For fail safe, write EOF now
+        if ((fMode == DWRITE)||(fEOFow == true))
+        {
+          char fs_data[] = { mEOF };
+          fs->write(fs_data, currBlock, blockPos, 1); // Write mEOF
+//          printf("(%s:%d): Writing EOF, blk=%d, pos=%d, char=0x%x\r\n", __func__, __LINE__, currBlock, blockPos, fs_data[0] );
+        }
+    }
+    
+    bufPos = 0; // Reset buffer position counter
+    
+    /* If destructive write flag is set
+       and there is data to be removed then remove data now */
+    if (destructiveFlag == true) {
+        if(removeFollowingBlocks(destructiveBlock) != 0) {
+            return 3;
+        }
+    }
+        
+    return 0;
+}