From 990090a4cc9070837d31e66b58d40f0c3d038741 Mon Sep 17 00:00:00 2001 From: Yuval Adam Date: Sun, 16 Mar 2014 14:41:11 +0200 Subject: Add usblib and utils --- utils/fswrapper.c | 860 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 860 insertions(+) create mode 100644 utils/fswrapper.c (limited to 'utils/fswrapper.c') diff --git a/utils/fswrapper.c b/utils/fswrapper.c new file mode 100644 index 0000000..74e80af --- /dev/null +++ b/utils/fswrapper.c @@ -0,0 +1,860 @@ +//***************************************************************************** +// +// fswrapper.c - File System Processing for lwIP Web Server Apps. +// +// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved. +// Software License Agreement +// +// Texas Instruments (TI) is supplying this software for use solely and +// exclusively on TI's microcontroller products. The software is owned by +// TI and/or its suppliers, and is protected under applicable copyright +// laws. You may not combine this software with "viral" open-source +// software in order to form a larger program. +// +// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS. +// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT +// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY +// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL +// DAMAGES, FOR ANY REASON WHATSOEVER. +// +// This is part of revision 2.1.0.12573 of the Tiva Utility Library. +// +//***************************************************************************** + +#include +#include +#include +#include "inc/hw_types.h" +#include "driverlib/debug.h" +#include "httpserver_raw/fs.h" +#include "httpserver_raw/fsdata.h" +#include "fatfs/src/ff.h" +#include "fatfs/src/diskio.h" +#include "utils/fswrapper.h" +#include "utils/lwiplib.h" +#include "utils/ustdlib.h" + +//***************************************************************************** +// +//! \addtogroup fswrapper_api +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Static file system images for use with this module may be created using +// the makefsfile.exe utility. Both position-independent (built using the -b +// command line option to makefsfile) and position dependent file system images +// may be used. +// +//***************************************************************************** +typedef struct +{ + // + // The index of the file system containing this file. + // + uint32_t ui32MountIndex; + + // + // The FatFs file structure allocated if the target file is in the FAT + // file system. + // + FIL *psFATFile; +} +fs_wrapper_data; + +//***************************************************************************** +// +// A marker used to indicate that a passed filename cannot be mapped to any of +// the configured mount points. +// +//***************************************************************************** +#define BAD_MOUNT_INDEX 0xFFFFFFFF + +//***************************************************************************** +// +// This macro is used to extract pointers from the file descriptors. We +// support files systems linked into the image as well as external, position +// independent file system images and this macro allows us to use the same code +// to extract pointers from file descriptors in each case. +// +//***************************************************************************** +#define FS_POINTER(ptTree, ptValue, bPosInd) \ + ((char *)((bPosInd) ? ((int8_t *)(ptTree) + (uint32_t)(ptValue)) : \ + (int8_t *)(ptValue))) + +//***************************************************************************** +// +// The pointer to the mount point table and the number of entries in the +// table. +// +//***************************************************************************** +static fs_mount_data *g_psMountPoints = NULL; +static uint32_t g_ui32NumMountPoints = 0; +static uint32_t g_ui32DefaultMountIndex = BAD_MOUNT_INDEX; +static bool g_bFatFsEnabled = false; + +//***************************************************************************** +// +// Given a filename, this function determine which of the configured mount +// points it resides under. It returns the index of the mount point in the +// g_psMountPoints array and also a pointer to the first character of the +// filename with the mount point name (directory) stripped from it. +// +//***************************************************************************** +static uint32_t +fs_find_mount_index(const char *pcName, char **ppcFSFilename) +{ + uint32_t ui32Loop; + int iLenDirName; + int iLenMountName; + char *pcSlash; + + // + // First extract the top level directory name which we need to match + // with the mount point name. For this to exist, the pcName string + // must start with a '/' character and must contain at least one more + // '/'. + // + if(pcName[0] == '/') + { + // + // The string starts with a '/'. Does it contain a second one? + // + pcSlash = strchr(pcName + 1, '/'); + + // + // Did we find another forward slash character? + // + if(pcSlash) + { + // + // Yes - the mount point name is between the start of the + // string and the slash we just found. How long is this string? + // + iLenDirName = (int)(pcSlash - (pcName + 1)); + } + else + { + // + // The mount point name is the whole string. + // + iLenDirName = ustrlen(pcName + 1); + pcSlash = (char *)pcName + 1 + iLenDirName; + } + + // + // Now figure out which, if any, of the mount points this matches. + // + for(ui32Loop = 0; ui32Loop < g_ui32NumMountPoints; ui32Loop++) + { + // + // Skip the default mount point if found. + // + if(!g_psMountPoints[ui32Loop].pcNamePrefix) + { + continue; + } + + // + // How long is the name of this mount point? + // + iLenMountName = ustrlen(g_psMountPoints[ui32Loop].pcNamePrefix); + + // + // Does the mount point name match the directory name extracted + // from the passed pcName? + // + if(iLenMountName == iLenDirName) + { + // + // The lengths match but are the strings the same? + // + if(!ustrncmp(g_psMountPoints[ui32Loop].pcNamePrefix, + pcName + 1, iLenDirName)) + { + // + // Yes - we have a match. Set the stripped filename to + // the second '/' and return the mount point index. + // + *ppcFSFilename = pcSlash; + return(ui32Loop); + } + } + } + } + + // + // If we drop out of the loop, we didn't find a specific mount point for + // this file so just return the filename passed and the default mount + // point. + // + *ppcFSFilename = (char *)pcName; + + return(g_ui32DefaultMountIndex); +} + +//***************************************************************************** +// +//! Initializes the file system wrapper. +//! +//! \param psMountPoints points to an array of fs_mount_data structures. Each +//! element in the array maps a top level directory name to a particular +//! file system image or to the FAT file system and a logical drive number. +//! \param ui32NumMountPoints provides the number of populated elements in the +//! \e psMountPoints array. +//! +//! This function should be called to initialize the file system wrapper and +//! provide it with the information required to access the files in multiple +//! file system images via a single filename space. +//! +//! Each entry in \e psMountPoints describes a top level directory in the +//! unified namespace and indicates to fswrapper where the files for that +//! directory can be found. Each entry can describe either a file system +//! image in system memory or a logical disk handled via the FatFs file system +//! driver. +//! +//! For example, consider the following 3 entry mount point table: +//! +//! \verbatim +//! { +//! { "internal", &g_pui8FSImage, 0, NULL, NULL }, +//! { "sdcard", NULL, 0, SDCardEnable, SDCardDisable }, +//! { NULL, &g_pui8FSDefault, 0, NULL, NULL} +//! } +//! \endverbatim +//! +//! Requests to open file ``/internal/index.html'' will be handled by +//! attempting to open ``/index.html'' in the internal file system pointed to +//! by \e g_pui8FSImage. Similarly, opening ``/sdcard/images/logo.gif'' will +//! result in a call to the FAT f_open function requesting +//! ``0:/images/logo.gif''. If a request to open ``index.htm'' is received, +//! this is handled by attempting to open ``index.htm'' in the default internal +//! file system image, \e g_pui8FSDefault. +//! +//! \return Returns \b true on success or \b false on failure. +// +//***************************************************************************** +bool +fs_init(fs_mount_data *psMountPoints, uint32_t ui32NumMountPoints) +{ + uint32_t ui32Loop; + + // + // Check for non-zero parameters in debug builds. + // + ASSERT(psMountPoints); + ASSERT(ui32NumMountPoints); + + // + // Remember the mount point information we have been given. + // + if(psMountPoints && ui32NumMountPoints) + { + // + // Remember the information passed. + // + g_psMountPoints = psMountPoints; + g_ui32NumMountPoints = ui32NumMountPoints; + + // + // Check to determine if any of the mount points refer to FAT file + // system drivers. We also hijack this loop to determine what the + // default mount point (if any) is. + // + g_bFatFsEnabled = false; + for(ui32Loop = 0; ui32Loop < g_ui32NumMountPoints; ui32Loop++) + { + // + // If the pui8FSImage field of a mount point structure is NULL, + // this implies that we are using the FAT file system for that + // node. + // + if(!g_psMountPoints[ui32Loop].pui8FSImage) + { + g_bFatFsEnabled = true; + } + + // + // Does this entry describe the default mount point? + // + if(g_psMountPoints[ui32Loop].pcNamePrefix == NULL) + { + g_ui32DefaultMountIndex = ui32Loop; + } + } + + return(true); + } + else + { + // + // Return an error due to being passed a bad parameter. + // + return(false); + } +} + +//***************************************************************************** +// +//! Provides a periodic tick for the file system. +//! +//! \param ui32TickMS is the number of milliseconds which have elapsed since +//! the last time this function was called. +//! +//! Applications making use of the file system wrapper with underlying FatFs +//! drives must call this function at least once every 10 milliseconds to +//! provide a time reference for use by the file system. It is typically +//! called in the context of the application's SysTick interrupt handler or +//! from the handler of some other timer interrupt. +//! +//! If only binary file system images are in use, this function need not be +//! called. +//! +//! \return None +// +// +//***************************************************************************** +void +fs_tick(uint32_t ui32TickMS) +{ + static uint32_t ui32TickCounter = 0; + + // + // Check if the file system has been enabled yet. + // + if(!g_bFatFsEnabled) + { + return; + } + + // + // Increment the tick counter. + // + ui32TickCounter += ui32TickMS; + + // + // Check to see if the FAT FS tick needs to run. + // + if(ui32TickCounter >= 10) + { + ui32TickCounter = 0; + disk_timerproc(); + } +} + +//***************************************************************************** +// +//! Opens a file. +//! +//! \param pcName points to a NULL terminated string containing the path and +//! file name to open. +//! +//! This function opens a file and returns a handle allowing it to be read. +//! +//! \return Returns a valid file handle on success or NULL on failure. +// +//***************************************************************************** +struct fs_file * +fs_open(const char *pcName) +{ + const struct fsdata_file *psTree; + const struct fsdata_file *psEnd = NULL; + struct fs_file *psFile = NULL; + fs_wrapper_data *psWrapper; + FRESULT fresult = FR_OK; + bool bPosInd = false; + char *pcFSFilename; + char *pcFilename; + uint32_t ui32Length; + + // + // Allocate memory for the file system structure. + // + psFile = mem_malloc(sizeof(struct fs_file)); + if(NULL == psFile) + { + return(NULL); + } + + // + // Allocate memory for our internal control structure. + // + psFile->pextension = mem_malloc(sizeof(fs_wrapper_data)); + psWrapper = (fs_wrapper_data *)psFile->pextension; + + if(NULL == psWrapper) + { + return(NULL); + } + + // + // Find which mount point we need to use to satisfy this file open request. + // + psWrapper->ui32MountIndex = fs_find_mount_index(pcName, &pcFSFilename); + if(psWrapper->ui32MountIndex == BAD_MOUNT_INDEX) + { + // + // We can't map the mount index so return an error. + // + mem_free(psWrapper); + mem_free(psFile); + return(NULL); + } + + // + // Enable access to the physical medium if we have been provided with + // a callback for this. + // + if(g_psMountPoints[psWrapper->ui32MountIndex].pfnEnable) + { + g_psMountPoints[psWrapper->ui32MountIndex]. + pfnEnable(psWrapper->ui32MountIndex); + } + + // + // Are we opening a file on an internal file system image? + // + if(g_psMountPoints[psWrapper->ui32MountIndex].pui8FSImage) + { + // + // Initialize the file system tree pointer to the root of the linked + // list for this mount point's file system image. + // + psTree = ((const struct fsdata_file *) + g_psMountPoints[psWrapper->ui32MountIndex].pui8FSImage); + + // + // Which type of file system are we dealing with? + // + if(psTree->next == FILE_SYSTEM_MARKER) + { + // + // If we found the marker, this is a position independent file + // system image. Remember this and fix up the pointer to the + // first descriptor by skipping over the 4 byte marker and the + // 4 byte image size entry. We also keep track of where the file + // system image ends since this allows us to do a bit more error + // checking later. + // + bPosInd = true; + ui32Length = *(uint32_t *)((uint8_t *)psTree + 4); + psTree = (struct fsdata_file *)((int8_t *)psTree + 8); + psEnd = (struct fsdata_file *)((int8_t *)psTree + ui32Length); + } + + // + // Begin processing the linked list, looking for the requested file + // name. + // + while(NULL != psTree) + { + // + // Compare the requested file "name" to the file name in the + // current node. + // + if(ustrncmp(pcFSFilename, + FS_POINTER(psTree, psTree->name, bPosInd), + psTree->len) == 0) + { + // + // Fill in the data pointer and length values from the + // linked list node. + // + psFile->data = FS_POINTER(psTree, psTree->data, bPosInd); + psFile->len = psTree->len; + + // + // For now, we setup the read index to the end of the file, + // indicating that all data has been read. This indicates that + // all the data is currently available in a contiguous block + // of memory (which is always the case with an internal file + // system image). + // + psFile->index = psTree->len; + + // + // We are not using a FAT file system file and don't need to + // remap the filename so set these pointers to NULL. + // + psWrapper->psFATFile = NULL; + + // + // Exit the loop and return the file system pointer. + // + break; + } + + // + // If we get here, we did not find the file at this node of the + // linked list. Get the next element in the list. We can't just + // assign psTree from psTree->next since this will give us the + // wrong pointer for a position independent image (where the values + // in the structure are offsets from the start of the file + // descriptor, not absolute pointers) but we do know that a 0 in + // the "next" field does indicate that this is the last file so we + // can use that info to force the loop to exit at the end. + // + if(psTree->next == 0) + { + psTree = NULL; + } + else + { + psTree = (struct fsdata_file *)FS_POINTER(psTree, psTree->next, + bPosInd); + + // + // If this is a position independent file system image, we can + // also check that the new node is within the image. If it + // isn't, the image is corrupted to stop the search. + // + if(bPosInd && (psTree >= psEnd)) + { + psTree = NULL; + } + } + } + + // + // If we didn't find the file, ptTee will be NULL. Make sure we + // return a NULL pointer if this happens. + // + if(NULL == psTree) + { + mem_free(psFile->pextension); + mem_free(psFile); + psFile = NULL; + } + } + else + { + // + // This file is on the FAT file system. + // + + // + // Allocate memory for the Fat File system handle. + // + psWrapper->psFATFile = mem_malloc(sizeof(FIL)); + if(NULL == psWrapper->psFATFile) + { + mem_free(psFile->pextension); + mem_free(psFile); + psFile = NULL; + } + else + { + // + // Reformat the filename to start with the FAT logical drive + // number. + // + ui32Length = ustrlen(pcFSFilename) + 16; + pcFilename = mem_malloc(ui32Length); + if(!pcFilename) + { + // + // Can't allocate temporary storage for the reformatted + // filename! + // + mem_free(psWrapper->psFATFile); + mem_free(psFile->pextension); + mem_free(psFile); + psFile = NULL; + } + else + { + usnprintf(pcFilename, ui32Length, "%d:%s", + g_psMountPoints[psWrapper->ui32MountIndex]. + ui32DriveNum, pcFSFilename); + // + // Attempt to open the file on the Fat File System. + // + fresult = f_open(psWrapper->psFATFile, pcFilename, FA_READ); + + // + // Free the filename storage + // + mem_free(pcFilename); + + // + // Did we open the file correctly? + // + if(FR_OK == fresult) + { + // + // Yes - fill in the file structure to indicate that a + // FAT file is in use. + // + psFile->data = NULL; + psFile->len = 0; + psFile->index = 0; + } + else + { + // + // If we get here, we failed to find the file on the FAT + // file system so free up the FAT handle/object. + // + mem_free(psWrapper->psFATFile); + mem_free(psWrapper); + mem_free(psFile); + psFile = NULL; + } + } + } + } + + // + // Disable access to the physical medium if we have been provided with + // a callback for this. + // + if(g_psMountPoints[psWrapper->ui32MountIndex].pfnDisable) + { + g_psMountPoints[psWrapper->ui32MountIndex]. + pfnDisable(psWrapper->ui32MountIndex); + } + + return(psFile); +} + +//***************************************************************************** +// +//! Closes a file. +//! +//! \param phFile is the handle of the file that is to be closed. This will +//! have been returned by an earlier call to fs_open(). +//! +//! This function closes the file identified by \e phFile and frees all +//! resources associated with the file handle. +//! +//! \return None. +// +//***************************************************************************** +void +fs_close(struct fs_file *phFile) +{ + fs_wrapper_data *psWrapper; + + psWrapper = (fs_wrapper_data *)phFile->pextension; + + // + // If a Fat file was opened, free its object. + // + if(psWrapper->psFATFile) + { + // + // Close the file. + // + f_close(psWrapper->psFATFile); + + // + // Free the file object. + // + mem_free(psWrapper->psFATFile); + } + + // + // Free our file wrapper control structure. + // + mem_free(phFile->pextension); + + // + // Free the main file system object. + // + mem_free(phFile); +} + +//***************************************************************************** +// +//! Reads data from an open file. +//! +//! \param phFile is the handle of the file which is to be read. This will +//! have been returned by a previous call to fs_open(). +//! \param pcBuffer points to the first byte of the buffer into which the +//! data read from the file will be copied. This buffer must be large enough +//! to hold \e iCount bytes. +//! \param iCount is the maximum number of bytes of data that are to be read +//! from the file. +//! +//! This function reads the next block of data from the given file into a +//! buffer and returns the number of bytes read or -1 if the end of the file +//! has been reached. +//! +//! \return Returns the number of bytes read from the file or -1 if the end of +//! the file has been reached and no more data is available. +// +//***************************************************************************** +int +fs_read(struct fs_file *phFile, char *pcBuffer, int iCount) +{ + int iAvailable, iRetcode; + fs_wrapper_data *psWrapper; + + psWrapper = (fs_wrapper_data *)phFile->pextension; + + // + // Call the application's enable function for this physical medium (if + // an enable function has been provided). + // + if(g_psMountPoints[psWrapper->ui32MountIndex].pfnEnable) + { + g_psMountPoints[psWrapper->ui32MountIndex]. + pfnEnable(psWrapper->ui32MountIndex); + } + + // + // Check to see if a Fat File was opened and process it. + // + if(psWrapper->psFATFile) + { + uint32_t ui32BytesRead; + FRESULT fresult; + + // + // Read the data. + // + fresult = f_read(psWrapper->psFATFile, pcBuffer, iCount, + (UINT*)&ui32BytesRead); + if((fresult != FR_OK) || (ui32BytesRead == 0)) + { + iRetcode = -1; + } + else + { + iRetcode = (int)ui32BytesRead; + } + } + else + { + // + // We are reading a file from a file system image. Check to see if + // more data is available. + // + if(phFile->len == phFile->index) + { + // + // There is no remaining data. Return a -1 for EOF indication. + // + return(-1); + } + + // + // Determine how much data we can copy. The minimum of the 'iCount' + // parameter or the available data in the file system buffer. + // + iAvailable = phFile->len - phFile->index; + if(iAvailable > iCount) + { + iAvailable = iCount; + } + + // + // Copy the data. + // + memcpy(pcBuffer, phFile->data + phFile->index, iAvailable); + phFile->index += iAvailable; + + // + // Return the count of data that we copied. + // + iRetcode = iAvailable; + } + + // + // Call the application's disable function now that we have finished + // accessing the file. + // + if(g_psMountPoints[psWrapper->ui32MountIndex].pfnDisable) + { + g_psMountPoints[psWrapper->ui32MountIndex]. + pfnDisable(psWrapper->ui32MountIndex); + } + + // + // Return the number of bytes read. + // + return(iRetcode); +} + +//***************************************************************************** +// +//! Maps a path string containing mount point names to a path suitable for +//! use in calls to the FatFs APIs. +//! +//! \param pcPath points to a string containing a path in the namespace +//! defined by the mount information passed to fs_init(). +//! \param pcMapped points to a buffer into which the mapped path string will +//! be written. +//! \param iLen is the size, in bytes, of the buffer pointed to by pcMapped. +//! +//! This function may be used by applications which want to make use of FatFs +//! functions which are not directly mapped by the fswrapper layer. A path +//! in the namespace defined by the mount points passed to function fs_init() +//! is translated to an equivalent path in the FatFs namespace and this may +//! then be used in a direct call to functions such as f_opendir() or +//! f_getfree(). +//! +//! \return Returns \b true on success or \b false if fs_init() has not +//! been called, if the path provided maps to an internal file system image +//! rather than a FatFs logical drive or if the buffer pointed to by +//! \e pcMapped is too small to fit the output string. +// +//***************************************************************************** +bool +fs_map_path(const char *pcPath, char *pcMapped, int iLen) +{ + char *pcFSFilename; + uint32_t ui32MountIndex; + int iCount; + + // + // If no mount points have been defined, return an error. + // + if(!g_psMountPoints) + { + return(false); + } + + // + // Find which mount point we need to use to satisfy this file open request. + // + ui32MountIndex = fs_find_mount_index(pcPath, &pcFSFilename); + + // + // If we got a bad mount index or the index returned represents a mount + // point that is not in the FAT file system, return an error. + // + if((ui32MountIndex == BAD_MOUNT_INDEX) || + (g_psMountPoints[ui32MountIndex].pui8FSImage)) + { + // + // We can't map the mount index so return an error. + // + return(false); + } + + // + // Now we can generate the FatFs namespace path string. + // + iCount = usnprintf(pcMapped, iLen, "%d:%s", + g_psMountPoints[ui32MountIndex].ui32DriveNum, + pcFSFilename); + + // + // Tell the user how we got on. The count returned by usnprintf is the + // number of characters that should have been written, excluding the + // terminating NULL so we use this to check for overflow of the output + // buffer. + // + return((iLen >= (iCount + 1)) ? true : false); +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** -- cgit v1.3.1