?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{FILE START}

library

?curdirlinks? - Rev 32

?prevdifflink? - Blame - ?getfile?

/*********************************************************************
 *
 *      Microchip File System (MPFS) File Access API
 *  Module for Microchip TCP/IP Stack
 *       -Provides single API for accessing web pages and other files 
 *    from internal program memory or an external serial EEPROM memory
 *       -Reference: AN833
 *
 *********************************************************************
 * FileName:        MPFS.c
 * Dependencies:    SPIEEPROM.c, SPIFlash.c, or MPFSImg2.c/.s
 * Processor:       PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32
 * Compiler:        Microchip C32 v1.05 or higher
 *                                      Microchip C30 v3.12 or higher
 *                                      Microchip C18 v3.30 or higher
 *                                      HI-TECH PICC-18 PRO 9.63PL2 or higher
 * Company:         Microchip Technology, Inc.
 *
 * Software License Agreement
 *
 * Copyright (C) 2002-2009 Microchip Technology Inc.  All rights
 * reserved.
 *
 * Microchip licenses to you the right to use, modify, copy, and
 * distribute:
 * (i)  the Software when embedded on a Microchip microcontroller or
 *      digital signal controller product ("Device") which is
 *      integrated into Licensee's product; or
 * (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h,
 *              ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device
 *              used in conjunction with a Microchip ethernet controller for
 *              the sole purpose of interfacing with the ethernet controller.
 *
 * You should refer to the license agreement accompanying this
 * Software for additional information regarding your rights and
 * obligations.
 *
 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
 *
 *
 * Author               Date        Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Elliott Wood                 07/2007         Complete rewrite as MPFS2
 * E. Wood                              04/2008         Updated as MPFS2.1
 ********************************************************************/
#define __MPFS2_C

#include "TCPIP Stack/TCPIP.h"

#if defined(STACK_USE_MPFS2)

//Supports long file names to 64 characters
#define MAX_FILE_NAME_LEN   (64u)

/*
 * MPFS Structure:
 *     [M][P][F][S]
 *     [BYTE Ver Hi][BYTE Ver Lo][WORD Number of Files]
 *     [Name Hash 0][Name Hash 1]...[Name Hash N]
 *     [File Record 0][File Record 1]...[File Record N]
 *     [String 0][String 1]...[String N]
 *     [File Data 0][File Data 1]...[File Data N]
 *
 * Name Hash (2 bytes):
 *     hash = 0
 *     for each(byte in name)
 *         hash += byte
 *         hash <<= 1
 *
 *     Technically this means the hash only includes the 
 *     final 15 characters of a name.
 *
 * File Record Structure (22 bytes):
 *     [DWORD String Ptr][DWORD Data Ptr]
 *     [DWORD Len][DWORD Timestamp][DWORD Microtime]
 *     [WORD Flags]
 *
 *     Pointers are absolute addresses within the MPFS image.
 *     Timestamp is the UNIX timestamp
 *     Microtime is currently unimplemented
 *
 * String Structure (1 to 64 bytes):
 *     ["path/to/file.ext"][0x00]
 *
 * File Data Structure (arbitrary length):
 *              [File Data]
 *
 * Unlike previous versions, there are no delimiters.
 *
 * Name hash is calculated as follows:
 *      hash = 0
 *      for each(byte in name)
 *          hash += byte, hash <<= 1
 *
 * When a file has an index, that index file has no file name,
 * but is accessible as the file immediately following in the image.
 *
 * Current version is 2.1
 */

/****************************************************************************
  Section:
        Module-Only Globals and Functions
  ***************************************************************************/
  
// Track the MPFS File Handles
// MPFSStubs[0] is reserved for internal use (FAT access)
static MPFS_STUB MPFSStubs[MAX_MPFS_HANDLES+1];

// Allows the MPFS to be locked, preventing access during updates
static BOOL isMPFSLocked;

// FAT record cache
static MPFS_FAT_RECORD fatCache;

// ID of currently loaded fatCache
static WORD fatCacheID;

// Number of files in this MPFS image
static WORD numFiles;


static void _LoadFATRecord(WORD fatID);
static void _Validate(void);

/****************************************************************************
  Section:
        EEPROM vs Flash Storage Settings
  ***************************************************************************/
  
#if defined(MPFS_USE_EEPROM)

        // Beginning address of MPFS Image
        #define MPFS_HEAD               MPFS_RESERVE_BLOCK

        // Track the last read address to prevent unnecessary
        // data overhead to switch locations.
        MPFS_PTR lastRead;


#elif defined(MPFS_USE_SPI_FLASH)

        // Beginning address of MPFS Image
        #define MPFS_HEAD               MPFS_RESERVE_BLOCK
        
#else

        // An address where MPFS data starts in program memory.
    #if defined(__18CXX) || defined(__C32__)
                extern ROM BYTE MPFS_Start[];
            #define MPFS_HEAD           ((DWORD)(&MPFS_Start[0]))
    #else
                extern DWORD MPFS_Start;
                #define MPFS_HEAD               MPFS_Start;
    #endif
    
#endif

/****************************************************************************
  Section:
        Stack-Level Functions
  ***************************************************************************/

/*****************************************************************************
  Function:
        void MPFSInit(void)

  Summary:
        Initializes the MPFS module.

  Description:
        Sets all MPFS handles to closed, and initializes access to the EEPROM
        if necessary.

  Precondition:
        None

  Parameters:
        None

  Returns:
        None
        
  Remarks:
        This function is called only one during lifetime of the application.
  ***************************************************************************/
void MPFSInit(void)
{
        BYTE i;
        
        for(i = 1; i <= MAX_MPFS_HANDLES; i++)
        {
                MPFSStubs[i].addr = MPFS_INVALID;
        }
        
        #if defined(MPFS_USE_EEPROM)
    // Initialize the EEPROM access routines.
    XEEInit();
        lastRead = MPFS_INVALID;
        #endif
        
        #if defined(MPFS_USE_SPI_FLASH)
        // Initialize SPI Flash access routines.
        SPIFlashInit();
        #endif

        // Validate the image and load numFiles
        _Validate();

        isMPFSLocked = FALSE;

}

/****************************************************************************
  Section:
        Handle Management Functions
  ***************************************************************************/

/*****************************************************************************
  Function:
        MPFS_HANDLE MPFSOpen(BYTE* cFile)

  Description:
        Opens a file in the MPFS2 file system.
        
  Precondition:
        None

  Parameters:
        cFile - a null terminated file name to open

  Returns:
        An MPFS_HANDLE to the opened file if found, or MPFS_INVALID_HANDLE
        if the file could not be found or no free handles exist.
  ***************************************************************************/
MPFS_HANDLE MPFSOpen(BYTE* cFile)
{
        MPFS_HANDLE hMPFS;
        WORD nameHash, i;
        WORD hashCache[8];
        BYTE *ptr, c;
        
        // Initialize c to avoid "may be used uninitialized" compiler warning
        c = 0;
        
        // Make sure MPFS is unlocked and we got a filename
        if(*cFile == '\0' || isMPFSLocked == TRUE)
                return MPFS_INVALID_HANDLE;

        // Calculate the name hash to speed up searching
        for(nameHash = 0, ptr = cFile; *ptr != '\0'; ptr++)
        {
                nameHash += *ptr;
                nameHash <<= 1;
        }
        
        // Find a free file handle to use
        for(hMPFS = 1; hMPFS <= MAX_MPFS_HANDLES; hMPFS++)
                if(MPFSStubs[hMPFS].addr == MPFS_INVALID)
                        break;
        if(hMPFS == MAX_MPFS_HANDLES)
                return MPFS_INVALID_HANDLE;
                
        // Read in hashes, and check remainder on a match.  Store 8 in cache for performance
        for(i = 0; i < numFiles; i++)
        {
                // For new block of 8, read in data
                if((i & 0x07) == 0u)
                {
                        MPFSStubs[0].addr = 8 + i*2;
                        MPFSStubs[0].bytesRem = 16;
                        MPFSGetArray(0, (BYTE*)hashCache, 16);
                }
                
                // If the hash matches, compare the full filename
                if(hashCache[i&0x07] == nameHash)
                {
                        _LoadFATRecord(i);
                        MPFSStubs[0].addr = fatCache.string;
                        MPFSStubs[0].bytesRem = 255;
                        
                        // Loop over filename to perform comparison
                        for(ptr = cFile; *ptr != '\0'; ptr++)
                        {
                                MPFSGet(0, &c);
                                if(*ptr != c)
                                        break;
                        }
                        
                        MPFSGet(0, &c);

                        if(c == '\0' && *ptr == '\0')
                        {// Filename matches, so return true
                                MPFSStubs[hMPFS].addr = fatCache.data;
                                MPFSStubs[hMPFS].bytesRem = fatCache.len;
                                MPFSStubs[hMPFS].fatID = i;
                                return hMPFS;
                        }
                }
        }
        
        // No file name matched, so return nothing
        return MPFS_INVALID_HANDLE;
}

/*****************************************************************************
  Function:
        MPFS_HANDLE MPFSOpenROM(ROM BYTE* cFile) 

  Description:
        Opens a file in the MPFS2 file system.
        
  Precondition:
        None

  Parameters:
        cFile - a null terminated file name to open

  Returns:
        An MPFS_HANDLE to the opened file if found, or MPFS_INVALID_HANDLE
        if the file could not be found or no free handles exist.

  Remarks:
        This function is aliased to MPFSOpen on non-PIC18 platforms.
  ***************************************************************************/
#if defined(__18CXX)
MPFS_HANDLE MPFSOpenROM(ROM BYTE* cFile) 
{
        MPFS_HANDLE hMPFS;
        WORD nameHash, i;
        WORD hashCache[8];
        ROM BYTE *ptr;
        BYTE c;
        
        // Make sure MPFS is unlocked and we got a filename
        if(*cFile == '\0' || isMPFSLocked == TRUE)
                return MPFS_INVALID_HANDLE;

        // Calculate the name hash to speed up searching
        for(nameHash = 0, ptr = cFile; *ptr != '\0'; ptr++)
        {
                nameHash += *ptr;
                nameHash <<= 1;
        }
        
        // Find a free file handle to use
        for(hMPFS = 1; hMPFS <= MAX_MPFS_HANDLES; hMPFS++)
                if(MPFSStubs[hMPFS].addr == MPFS_INVALID)
                        break;
        if(hMPFS == MAX_MPFS_HANDLES)
                return MPFS_INVALID_HANDLE;
                
        // Read in hashes, and check remainder on a match.  Store 8 in cache for performance
        for(i = 0; i < numFiles; i++)
        {
                // For new block of 8, read in data
                if((i & 0x07) == 0u)
                {
                        MPFSStubs[0].addr = 8 + i*2;
                        MPFSStubs[0].bytesRem = 16;
                        MPFSGetArray(0, (BYTE*)hashCache, 16);
                }
                
                // If the hash matches, compare the full filename
                if(hashCache[i&0x07] == nameHash)
                {
                        _LoadFATRecord(i);
                        MPFSStubs[0].addr = fatCache.string;
                        MPFSStubs[0].bytesRem = 255;
                        
                        // Loop over filename to perform comparison
                        for(ptr = cFile; *ptr != '\0'; ptr++)
                        {
                                MPFSGet(0, &c);
                                if(*ptr != c)
                                        break;
                        }
                        
                        MPFSGet(0, &c);

                        if(c == '\0' && *ptr == '\0')
                        {// Filename matches, so return true
                                MPFSStubs[hMPFS].addr = fatCache.data;
                                MPFSStubs[hMPFS].bytesRem = fatCache.len;
                                MPFSStubs[hMPFS].fatID = i;
                                return hMPFS;
                        }
                }
        }
        
        // No file name matched, so return nothing
        return MPFS_INVALID_HANDLE;
}
#endif

/*****************************************************************************
  Function:
        MPFS_HANDLE MPFSOpenID(WORD hFatID)

  Summary:
        Quickly re-opens a file.

  Description:
        Quickly re-opens a file in the MPFS2 file system.  Use this function
        along with MPFSGetID() to quickly re-open a file without tying up
        a permanent MPFSStub.
        
  Precondition:
        None

  Parameters:
        hFatID - the ID of a previous opened file in the FAT

  Returns:
        An MPFS_HANDLE to the opened file if found, or MPFS_INVALID_HANDLE
        if the file could not be found or no free handles exist.
  ***************************************************************************/
MPFS_HANDLE MPFSOpenID(WORD hFatID)
{
        MPFS_HANDLE hMPFS;
        
        // Make sure MPFS is unlocked and we got a valid id
        if(isMPFSLocked == TRUE || hFatID > numFiles)
                return MPFS_INVALID_HANDLE;

        // Find a free file handle to use
        for(hMPFS = 1; hMPFS <= MAX_MPFS_HANDLES; hMPFS++)
                if(MPFSStubs[hMPFS].addr == MPFS_INVALID)
                        break;
        if(hMPFS == MAX_MPFS_HANDLES)
                return MPFS_INVALID_HANDLE;
        
        // Load the FAT record
        _LoadFATRecord(hFatID);
                
        // Set up the file handle
        MPFSStubs[hMPFS].fatID = hFatID;
        MPFSStubs[hMPFS].addr = fatCache.data;
        MPFSStubs[hMPFS].bytesRem = fatCache.len;
        
        return hMPFS;
}

/*****************************************************************************
  Function:
        void MPFSClose(MPFS_HANDLE hMPFS)

  Summary:
        Closes a file.

  Description:
        Closes a file and releases its stub back to the pool of available 
        handles.
        
  Precondition:
        None

  Parameters:
        hMPFS - the file handle to be closed

  Returns:
        None
  ***************************************************************************/
void MPFSClose(MPFS_HANDLE hMPFS)
{
        if(hMPFS != 0u && hMPFS <= MAX_MPFS_HANDLES)
            MPFSStubs[hMPFS].addr = MPFS_INVALID;
}


/****************************************************************************
  Section:
        Data Reading Functions
  ***************************************************************************/

/*****************************************************************************
  Function:
        BOOL MPFSGet(MPFS_HANDLE hMPFS, BYTE* c)

  Description:
        Reads a byte from a file.
        
  Precondition:
        The file handle referenced by hMPFS is already open.

  Parameters:
        hMPFS - the file handle from which to read
        c - Where to store the byte that was read

  Return Values:
        TRUE - The byte was successfully read
        FALSE - No byte was read because either the handle was invalid or
                the end of the file has been reached.
  ***************************************************************************/
BOOL MPFSGet(MPFS_HANDLE hMPFS, BYTE* c)
{
        // Make sure we're reading a valid address
        if(hMPFS > MAX_MPFS_HANDLES)
                return FALSE;
        if(     MPFSStubs[hMPFS].addr == MPFS_INVALID ||
                MPFSStubs[hMPFS].bytesRem == 0u)
                return FALSE;

        if(c == NULL)
        {
                MPFSStubs[hMPFS].addr++;
                MPFSStubs[hMPFS].bytesRem--;
                return TRUE;
        }


    // Read function for EEPROM
    #if defined(MPFS_USE_EEPROM)
            // For performance, cache the last read address
                if(MPFSStubs[hMPFS].addr != lastRead+1)
                        XEEBeginRead(MPFSStubs[hMPFS].addr + MPFS_HEAD);
                *c = XEERead();
                lastRead = MPFSStubs[hMPFS].addr;
                MPFSStubs[hMPFS].addr++;
        #elif defined(MPFS_USE_SPI_FLASH)
                SPIFlashReadArray(MPFSStubs[hMPFS].addr + MPFS_HEAD, c, 1);
                MPFSStubs[hMPFS].addr++;
        #else
                #if defined(__C30__)
                {
                        DWORD addr;
                        DWORD_VAL read;
                        BYTE i;
        
                        // MPFS Images are addressed by the byte; Program memory by the word.
                        //
                        // Flash program memory is 24 bits wide and only even words are
                        // implemented.  The upper byte of the upper word is read as 0x00.
                        // Address in program memory of any given byte is (MPFSAddr * 2) / 3
                        //
                        // We will read 24 bits at a time, but need to support using only 
                        // fractions of the first and last byte.
                        
                        // Find the beginning address in program memory.
                        addr = (MPFSStubs[hMPFS].addr / 3) << 1;
                        
                        // Find where to start in that first 3 bytes
                        read.Val = (addr * 3) >> 1;
                        if(read.Val == MPFSStubs[hMPFS].addr)
                                i = 0;
                        else if(read.Val+1 == MPFSStubs[hMPFS].addr)
                                i = 1;
                        else
                                i = 2;
        
                        // Add in the MPFS starting address offset
                        addr += MPFS_HEAD;
                        
                        // Update the MPFS Handle
                        MPFSStubs[hMPFS].addr++;
                        
                        // Read the DWORD 
                        read.Val = ReadProgramMemory(addr & 0x00FFFFFF);
                        *c = read.v[i];
                        
                }
                #else
                {
                        DWORD dwHITECHWorkaround = MPFS_HEAD;
                *c = *((ROM BYTE*)(MPFSStubs[hMPFS].addr+dwHITECHWorkaround));
                    MPFSStubs[hMPFS].addr++;
                }
                #endif
        #endif
        
        MPFSStubs[hMPFS].bytesRem--;
        return TRUE;
}

/*****************************************************************************
  Function:
        WORD MPFSGetArray(MPFS_HANDLE hMPFS, BYTE* cData, WORD wLen)

  Description:
        Reads a series of bytes from a file.
        
  Precondition:
        The file handle referenced by hMPFS is already open.

  Parameters:
        hMPFS - the file handle from which to read
        cData - where to store the bytes that were read
        wLen - how many bytes to read

  Returns:
        The number of bytes successfully read.  If this is less than wLen, 
        an EOF occurred while attempting to read.
  ***************************************************************************/
WORD MPFSGetArray(MPFS_HANDLE hMPFS, BYTE* cData, WORD wLen)
{       
        // Make sure we're reading a valid address
        if(hMPFS > MAX_MPFS_HANDLES)
                return 0;
                
        // Determine how many we can actually read
        if(wLen > MPFSStubs[hMPFS].bytesRem)
                wLen = MPFSStubs[hMPFS].bytesRem;

        // Make sure we're reading a valid address
        if(MPFSStubs[hMPFS].addr == MPFS_INVALID || wLen == 0u)
                return 0;
                
        if(cData == NULL)
        {
                MPFSStubs[hMPFS].addr += wLen;
                MPFSStubs[hMPFS].bytesRem -= wLen;
                return wLen;
        }
        
        // Read the data
        #if defined(MPFS_USE_EEPROM)
                XEEReadArray(MPFSStubs[hMPFS].addr+MPFS_HEAD, cData, wLen);
                MPFSStubs[hMPFS].addr += wLen;
                MPFSStubs[hMPFS].bytesRem -= wLen;
                lastRead = MPFS_INVALID;
        #elif defined(MPFS_USE_SPI_FLASH)
                SPIFlashReadArray(MPFSStubs[hMPFS].addr+MPFS_HEAD, cData, wLen);
                MPFSStubs[hMPFS].addr += wLen;
                MPFSStubs[hMPFS].bytesRem -= wLen;
        #else
                #if defined(__C30__)
                {
                        DWORD addr;
                        DWORD_VAL read;
                        WORD count;
                        BYTE i;
        
                        // MPFS Images are addressed by the byte; Program memory by the word.
                        //
                        // Flash program memory is 24 bits wide and only even words are
                        // implemented.  The upper byte of the upper word is read as 0x00.
                        // Address in program memory of any given byte is (MPFSAddr * 2) / 3
                        //
                        // We will read 24 bits at a time, but need to support using only 
                        // fractions of the first and last byte.
                        
                        // Find the beginning address in program memory.
                        addr = (MPFSStubs[hMPFS].addr / 3) << 1;
                        
                        // Find where to start in that first 3 bytes
                        read.Val = (addr * 3) >> 1;
                        if(read.Val == MPFSStubs[hMPFS].addr)
                                i = 0;
                        else if(read.Val+1 == MPFSStubs[hMPFS].addr)
                                i = 1;
                        else
                                i = 2;
        
                        // Add in the MPFS starting address offset
                        addr += MPFS_HEAD;
                        
                        // Update the MPFS Handle
                        MPFSStubs[hMPFS].addr += wLen;
                        MPFSStubs[hMPFS].bytesRem -= wLen;
        
                        // Read the first DWORD 
                        read.Val = ReadProgramMemory(addr & 0x00FFFFFF);
                        addr += 2;
        
                        // Copy values as needed
                        for(count = wLen; count > 0; cData++, count--)
                        {
                                // Copy the next value in
                                *cData = read.v[i++];
                                
                                // Check if a new DWORD is needed
                                if(i == 3 && count != 1)
                                {// Read in a new DWORD
                                        read.Val = ReadProgramMemory(addr & 0x00FFFFFF);
                                        addr += 2;
                                        i = 0;
                                }
                        }
                        
                }
                #else
                {
                        DWORD dwHITECHWorkaround = MPFS_HEAD;
                        memcpypgm2ram(cData, (ROM void*)(MPFSStubs[hMPFS].addr + dwHITECHWorkaround), wLen);
                        MPFSStubs[hMPFS].addr += wLen;
                        MPFSStubs[hMPFS].bytesRem -= wLen;
                }
                #endif
        #endif
        
        return wLen;
}

/*****************************************************************************
  Function:
        BOOL MPFSGetLong(MPFS_HANDLE hMPFS, DWORD* ul)

  Description:
        Reads a DWORD or Long value from the MPFS.
        
  Precondition:
        The file handle referenced by hMPFS is already open.

  Parameters:
        hMPFS - the file handle from which to read
        ul - where to store the DWORD or long value that was read

  Returns:
        TRUE - The byte was successfully read
        FALSE - No byte was read because either the handle was invalid or
                the end of the file has been reached.
  ***************************************************************************/
BOOL MPFSGetLong(MPFS_HANDLE hMPFS, DWORD* ul)
{
        return ( MPFSGetArray(hMPFS, (BYTE*)ul, 4) == 4u );
}

/*****************************************************************************
  Function:
        BOOL MPFSSeek(MPFS_HANDLE hMPFS, DWORD dwOffset, MPFS_SEEK_MODE tMode)

  Description:
        Moves the current read pointer to a new location.
        
  Precondition:
        The file handle referenced by hMPFS is already open.

  Parameters:
        hMPFS - the file handle to seek with
        dwOffset - offset from the specified position in the specified direction
        tMode - one of the MPFS_SEEK_MODE constants

  Returns:
        TRUE - the seek was successful
        FALSE - either the new location or the handle itself was invalid
  ***************************************************************************/
BOOL MPFSSeek(MPFS_HANDLE hMPFS, DWORD dwOffset, MPFS_SEEK_MODE tMode)
{
        DWORD temp;
        
        // Make sure a valid file is open
        if(hMPFS > MAX_MPFS_HANDLES)
                return FALSE;
        if(MPFSStubs[hMPFS].addr == MPFS_INVALID)
                return FALSE;

        switch(tMode)
        {
                // Seek offset bytes from start
                case MPFS_SEEK_START:
                        temp = MPFSGetSize(hMPFS);
                        if(dwOffset > temp)
                                return FALSE;
                        
                        MPFSStubs[hMPFS].addr = MPFSGetStartAddr(hMPFS) + dwOffset;
                        MPFSStubs[hMPFS].bytesRem = temp - dwOffset;
                        return TRUE;
                
                // Seek forwards offset bytes
                case MPFS_SEEK_FORWARD:
                        if(dwOffset > MPFSStubs[hMPFS].bytesRem)
                                return FALSE;
                        
                        MPFSStubs[hMPFS].addr += dwOffset;
                        MPFSStubs[hMPFS].bytesRem -= dwOffset;
                        return TRUE;
                
                // Seek backwards offset bytes
                case MPFS_SEEK_REWIND:
                        temp = MPFSGetStartAddr(hMPFS);
                        if(MPFSStubs[hMPFS].addr < temp + dwOffset)
                                return FALSE;
                        
                        MPFSStubs[hMPFS].addr -= dwOffset;
                        MPFSStubs[hMPFS].bytesRem += dwOffset;
                        return TRUE;
                
                // Seek so that offset bytes remain in file
                case MPFS_SEEK_END:
                        temp = MPFSGetSize(hMPFS);
                        if(dwOffset > temp)
                                return FALSE;
                        
                        MPFSStubs[hMPFS].addr = MPFSGetEndAddr(hMPFS) - dwOffset;
                        MPFSStubs[hMPFS].bytesRem = dwOffset;
                        return TRUE;
                
                default:
                        return FALSE;
        }
}


/****************************************************************************
  Section:
        Data Writing Functions
  ***************************************************************************/

/*****************************************************************************
  Function:
        MPFS_HANDLE MPFSFormat(void)
        
  Summary:
        Prepares the MPFS image for writing.

  Description:
        Prepares the MPFS image for writing and locks the image so that other
        processes may not access it.
        
  Precondition:
        None

  Parameters:
        None

  Returns:
        An MPFS handle that can be used for MPFSPut commands, or 
        MPFS_INVALID_HANDLE when the EEPROM failed to initialize for writing.

  Remarks:
        In order to prevent misreads, the MPFS will be inaccessible until 
        MPFSClose is called.  This function is not available when the MPFS 
        is stored in internal Flash program memory.
  ***************************************************************************/
#if defined(MPFS_USE_EEPROM) || defined(MPFS_USE_SPI_FLASH)
MPFS_HANDLE MPFSFormat(void)
{

        BYTE i;
        
        // Close all files
        for(i = 0; i < MAX_MPFS_HANDLES; i++)
                MPFSStubs[i].addr = MPFS_INVALID;
        
        // Lock the image
        isMPFSLocked = TRUE;
        
        #if defined(MPFS_USE_EEPROM)
                // Set FAT ptr for writing
                MPFSStubs[0].addr = 0;
                MPFSStubs[0].fatID = 0xffff;
                MPFSStubs[0].bytesRem = MPFS_WRITE_PAGE_SIZE - ( ((BYTE)MPFSStubs[0].addr+MPFS_HEAD) & (MPFS_WRITE_PAGE_SIZE-1) );
                
                // Set up EEPROM for writing
                if( XEEBeginWrite(MPFSStubs[0].addr+MPFS_HEAD) == XEE_SUCCESS )
                        return 0x00;
        
                return MPFS_INVALID_HANDLE;
        #else
                // Set up SPI Flash for writing
                SPIFlashBeginWrite(MPFS_HEAD);
                return 0x00;
        #endif
}
#endif
        
/*****************************************************************************
  Function:
        WORD MPFSPutArray(MPFS_HANDLE hMPFS, BYTE *cData, WORD wLen)

  Description:
        Writes an array of data to the MPFS image.
        
  Precondition:
        MPFSFormat was sucessfully called.

  Parameters:
        hMPFS - the file handle for writing
        cData - the array of bytes to write
        wLen - how many bytes to write

  Returns:
        The number of bytes successfully written.

  Remarks:
        For EEPROM, the actual write may not initialize until the internal write 
        page is full.  To ensure that previously written data gets stored, 
        MPFSPutEnd must be called after the last call to MPFSPutArray.
  ***************************************************************************/
#if defined(MPFS_USE_EEPROM) || defined(MPFS_USE_SPI_FLASH)
WORD MPFSPutArray(MPFS_HANDLE hMPFS, BYTE* cData, WORD wLen)
{
        #if defined(MPFS_USE_EEPROM)
                // Write to the EEPROM
                WORD count;
                
                for(count = 0; count < wLen; count++)
                {
                        XEEWrite(cData[count]);
                        
                        MPFSStubs[hMPFS].addr++;
                        MPFSStubs[hMPFS].bytesRem--;
                        
                        if(MPFSStubs[hMPFS].bytesRem == 0u)
                        {
                                MPFSPutEnd(FALSE);
                                isMPFSLocked = TRUE;
                                XEEBeginWrite(MPFSStubs[hMPFS].addr+MPFS_HEAD);
                                MPFSStubs[hMPFS].bytesRem = MPFS_WRITE_PAGE_SIZE;
                        }
                }
                
                return count;
        
        #else
                // Write to the SPI Flash
                SPIFlashWriteArray(cData, wLen);
                return wLen;
        #endif
}
#endif

/*****************************************************************************
  Function:
        void MPFSPutEnd(void)

  Description:
        Finalizes an MPFS writing operation.
        
  Precondition:
        MPFSFormat and MPFSPutArray were sucessfully called.

  Parameters:
        final - TRUE if the application is done writing, FALSE if MPFS2 called
                this function locally.

  Returns:
        None
  ***************************************************************************/
#if defined(MPFS_USE_EEPROM) || defined(MPFS_USE_SPI_FLASH)
void MPFSPutEnd(BOOL final)
{
        isMPFSLocked = FALSE;
        
        #if defined(MPFS_USE_EEPROM)
            XEEEndWrite();
        while(XEEIsBusy());
    #endif
    
        if(final)
                _Validate();
}
#endif


/****************************************************************************
  Section:
        Meta Data Accessors
  ***************************************************************************/

/*****************************************************************************
  Function:
        static void _LoadFATRecord(WORD fatID)

  Description:
        Loads the FAT record for a specified handle.
        
  Precondition:
        None

  Parameters:
        fatID - the ID of the file whose FAT is to be loaded

  Returns:
        None

  Remarks:
        The FAT record will be stored in fatCache.
  ***************************************************************************/
static void _LoadFATRecord(WORD fatID)
{
        if(fatID == fatCacheID || fatID >= numFiles)
                return;
        
        // Read the FAT record to the cache
        MPFSStubs[0].bytesRem = 22;
        MPFSStubs[0].addr = 8 + numFiles*2 + fatID*22;
        MPFSGetArray(0, (BYTE*)&fatCache, 22);
        fatCacheID = fatID;
}

/*****************************************************************************
  Function:
        DWORD MPFSGetTimestamp(MPFS_HANDLE hMPFS)

  Description:
        Reads the timestamp for the specified file.
        
  Precondition:
        The file handle referenced by hMPFS is already open.

  Parameters:
        hMPFS - the file handle from which to read the metadata

  Returns:
        The timestamp that was read as a DWORD
  ***************************************************************************/
DWORD MPFSGetTimestamp(MPFS_HANDLE hMPFS)
{
        // Make sure a valid file is open
        if(hMPFS > MAX_MPFS_HANDLES)
                return 0x00000000;
        if(MPFSStubs[hMPFS].addr == MPFS_INVALID)
                return 0x00000000;
        
        // Move to the point for reading
        _LoadFATRecord(MPFSStubs[hMPFS].fatID);
        return fatCache.timestamp;
}

/*****************************************************************************
  Function:
        DWORD MPFSGetMicrotime(MPFS_HANDLE hMPFS)

  Description:
        Reads the microtime portion of a file's timestamp.
        
  Precondition:
        The file handle referenced by hMPFS is already open.

  Parameters:
        hMPFS - the file handle from which to read the metadata

  Returns:
        The microtime that was read as a DWORD
  ***************************************************************************/
DWORD MPFSGetMicrotime(MPFS_HANDLE hMPFS)
{
        // Make sure a valid file is open
        if(hMPFS > MAX_MPFS_HANDLES)
                return 0x00000000;
        if(MPFSStubs[hMPFS].addr == MPFS_INVALID)
                return 0x00000000;
        
        // Move to the point for reading
        _LoadFATRecord(MPFSStubs[hMPFS].fatID);
        return fatCache.microtime;
}

/*****************************************************************************
  Function:
        WORD MPFSGetFlags(MPFS_HANDLE hMPFS)

  Description:
        Reads a file's flags.
        
  Precondition:
        The file handle referenced by hMPFS is already open.

  Parameters:
        hMPFS - the file handle from which to read the metadata

  Returns:
        The flags that were associated with the file
  ***************************************************************************/
WORD MPFSGetFlags(MPFS_HANDLE hMPFS)
{
        // Make sure a valid file is open
        if(hMPFS > MAX_MPFS_HANDLES)
                return 0x0000;
        if(MPFSStubs[hMPFS].addr == MPFS_INVALID)
                return 0x0000;
        
        //move to the point for reading
        _LoadFATRecord(MPFSStubs[hMPFS].fatID);
        return fatCache.flags;
}

/*****************************************************************************
  Function:
        DWORD MPFSGetSize(MPFS_HANDLE hMPFS)

  Description:
        Reads the size of a file.
        
  Precondition:
        The file handle referenced by hMPFS is already open.

  Parameters:
        hMPFS - the file handle from which to read the metadata

  Returns:
        The size that was read as a DWORD
  ***************************************************************************/
DWORD MPFSGetSize(MPFS_HANDLE hMPFS)
{
        // Make sure a valid file is open
        if(hMPFS > MAX_MPFS_HANDLES)
                return 0x00000000;
        if(MPFSStubs[hMPFS].addr == MPFS_INVALID)
                return 0x00000000;
        
        // Move to the point for reading
        _LoadFATRecord(MPFSStubs[hMPFS].fatID);
        return fatCache.len;
}

/*****************************************************************************
  Function:
        DWORD MPFSGetBytesRem(MPFS_HANDLE hMPFS)

  Description:
        Determines how many bytes remain to be read.
        
  Precondition:
        The file handle referenced by hMPFS is already open.

  Parameters:
        hMPFS - the file handle from which to read the metadata

  Returns:
        The number of bytes remaining in the file as a DWORD
  ***************************************************************************/
DWORD MPFSGetBytesRem(MPFS_HANDLE hMPFS)
{
        // Make sure a valid file is open
        if(hMPFS > MAX_MPFS_HANDLES)
                return 0x00000000;
        if(MPFSStubs[hMPFS].addr == MPFS_INVALID)
                return 0x00000000;
                
        return MPFSStubs[hMPFS].bytesRem;       
}

/*****************************************************************************
  Function:
        MPFS_PTR MPFSGetStartAddr(MPFS_HANDLE hMPFS)

  Description:
        Reads the starting address of a file.
        
  Precondition:
        The file handle referenced by hMPFS is already open.

  Parameters:
        hMPFS - the file handle from which to read the metadata

  Returns:
        The starting address of the file in the MPFS image
  ***************************************************************************/
MPFS_PTR MPFSGetStartAddr(MPFS_HANDLE hMPFS)
{
        // Make sure a valid file is open
        if(hMPFS > MAX_MPFS_HANDLES)
                return 0;
        if(MPFSStubs[hMPFS].addr == MPFS_INVALID)
                return MPFS_INVALID;
        
        // Move to the point for reading
        _LoadFATRecord(MPFSStubs[hMPFS].fatID);
        return fatCache.data;
}

/*****************************************************************************
  Function:
        MPFS_PTR MPFSGetEndAddr(MPFS_HANDLE hMPFS)

  Description:
        Determines the ending address of a file.
        
  Precondition:
        The file handle referenced by hMPFS is already open.

  Parameters:
        hMPFS - the file handle from which to read the metadata

  Returns:
        The address just after the file ends (start address of next file)
  ***************************************************************************/
MPFS_PTR MPFSGetEndAddr(MPFS_HANDLE hMPFS)
{
        // Make sure a valid file is open
        if(hMPFS > MAX_MPFS_HANDLES)
                return MPFS_INVALID;
        if(MPFSStubs[hMPFS].addr == MPFS_INVALID)
                return MPFS_INVALID;
        
        // Move to the point for reading
        _LoadFATRecord(MPFSStubs[hMPFS].fatID);
        return fatCache.data + fatCache.len;
}

/*****************************************************************************
  Function:
        BOOL MPFSGetFilename(MPFS_HANDLE hMPFS, BYTE* cName, WORD wLen)

  Description:
        Reads the file name of a file that is already open.
        
  Precondition:
        The file handle referenced by hMPFS is already open.

  Parameters:
        hMPFS - the file handle from which to determine the file name
        cName - where to store the name of the file
        wLen - the maximum length of data to store in cName

  Return Values:
        TRUE - the file name was successfully located
        FALSE - the file handle provided is not currently open
  ***************************************************************************/
BOOL MPFSGetFilename(MPFS_HANDLE hMPFS, BYTE* cName, WORD wLen)
{
        DWORD addr;
        
        // Make sure a valid file is open
        if(hMPFS > MAX_MPFS_HANDLES)
                return FALSE;
        if(MPFSStubs[hMPFS].addr == MPFS_INVALID)
                return FALSE;
        
        // Move to the point for reading
        _LoadFATRecord(MPFSStubs[hMPFS].fatID);
        addr = fatCache.string;
        MPFSStubs[0].addr = addr;
        MPFSStubs[0].bytesRem = 255;
        
        // Read the value and return
        MPFSGetArray(0, cName, wLen);
        return TRUE;
}

/*****************************************************************************
  Function:
        DWORD MPFSGetPosition(MPFS_HANDLE hMPFS)

  Description:
        Determines the current position in the file
        
  Precondition:
        The file handle referenced by hMPFS is already open.

  Parameters:
        hMPFS - the file handle for which to determine position

  Returns:
        The position in the file as a DWORD (or MPFS_PTR)

  Remarks:
        Calling MPFSSeek(hMPFS, pos, MPFS_SEEK_START) will return the pointer
        to this position at a later time.  (Where pos is the value returned by
        this function.)
  ***************************************************************************/
DWORD MPFSGetPosition(MPFS_HANDLE hMPFS)
{
        return MPFSStubs[hMPFS].addr - MPFSGetStartAddr(hMPFS);
}

/*****************************************************************************
  Function:
        WORD MPFSGetID(MPFS_HANDLE hMPFS)

  Description:
        Determines the ID in the FAT for a file.
        
  Precondition:
        The file handle referenced by hMPFS is already open.

  Parameters:
        hMPFS - the file handle from which to read the metadata

  Returns:
        The ID in the FAT for this file

  Remarks:
        Use this function in association with MPFSOpenID to quickly access file
        without permanently reserving a file handle.
  ***************************************************************************/
WORD MPFSGetID(MPFS_HANDLE hMPFS)
{
        return MPFSStubs[hMPFS].fatID;
}


/****************************************************************************
  Section:
        Utility Functions
  ***************************************************************************/

/*****************************************************************************
  Function:
        void _Validate(void)

  Summary:
        Validates the MPFS Image

  Description:
        Verifies that the MPFS image is valid, and reads the number of 
        available files from the image header.  This function is called on
        boot, and again after any image is written.

  Precondition:
        None

  Parameters:
        None

  Returns:
        None
  ***************************************************************************/
static void _Validate(void)
{
        // If this function causes an Address Error Exception on 16-bit
        // platforms with code stored in internal Flash, make sure your
        // compiler memory model settings are correct.
        //
        // In MPLAB, choose Project Menu > Build Options > Project.
        // Select the MPLAB C30 tab and change Cagetory to Memory Model.
        // Ensure that Large Code Model is selected, and that the remaining
        //   options are set to Default.
        
        // Validate the image and update numFiles
        MPFSStubs[0].addr = 0;
        MPFSStubs[0].bytesRem = 8;
        MPFSGetArray(0, (BYTE*)&fatCache, 6);
        if(!memcmppgm2ram((void*)&fatCache, (ROM void*)"MPFS\x02\x01", 6))
                MPFSGetArray(0, (BYTE*)&numFiles, 2);
        else
                numFiles = 0;
        fatCacheID = MPFS_INVALID_FAT;
}       
#endif //#if defined(STACK_USE_MPFS2)
{FILE END}
{FOOTER START}

Powered by WebSVN v2.8.3