/* * This file is subject to the terms of the GFX License. If a copy of * the license was not distributed with this file, you can obtain one at: * * http://ugfx.org/license.html */ /******************************************************** * The FATFS file-system ********************************************************/ #include "../../gfx.h" #if GFX_USE_GFILE && GFILE_NEED_FATFS #include "gfile_fs.h" #include "gfile_fatfs_wrapper.h" /******************************************************** * The FAT file-system VMT ********************************************************/ static bool_t fatfsDel(const char* fname); static bool_t fatfsExists(const char* fname); static long int fatfsFileSize(const char* fname); static bool_t fatfsRename(const char* oldname, const char* newname); static bool_t fatfsOpen(GFILE* f, const char* fname); static void fatfsClose(GFILE* f); static int fatfsRead(GFILE* f, void* buf, int size); static int fatfsWrite(GFILE* f, const void* buf, int size); static bool_t fatfsSetPos(GFILE* f, long int pos); static long int fatfsGetSize(GFILE* f); static bool_t fatfsEOF(GFILE* f); static bool_t fatfsMount(const char* drive); static bool_t fatfsUnmount(const char* drive); static bool_t fatfsSync(GFILE* f); #if GFILE_NEED_FILELISTS && _FS_MINIMIZE <= 1 static gfileList *fatfsFlOpen(const char *path, bool_t dirs); static const char *fatfsFlRead(gfileList *pfl); static void fatfsFlClose(gfileList *pfl); #endif const GFILEVMT FsFatFSVMT = { GFSFLG_WRITEABLE | GFSFLG_SEEKABLE, 'F', fatfsDel, fatfsExists, fatfsFileSize, fatfsRename, fatfsOpen, fatfsClose, fatfsRead, fatfsWrite, fatfsSetPos, fatfsGetSize, fatfsEOF, fatfsMount, fatfsUnmount, fatfsSync, #if GFILE_NEED_FILELISTS #if _FS_MINIMIZE <= 1 fatfsFlOpen, fatfsFlRead, fatfsFlClose #else 0, 0, 0 #endif #endif }; // Our directory list structure typedef struct fatfsList { gfileList fl; // This must be the first element. DIR dir; FILINFO fno; #if _USE_LFN char lfn[_MAX_LFN + 1]; /* Buffer to store the LFN */ #endif } fatfsList; // optimize these later on. Use an array to have multiple FatFS static bool_t fatfs_mounted = FALSE; static FATFS fatfs_fs; static BYTE fatfs_flags2mode(GFILE* f) { BYTE mode = 0; if (f->flags & GFILEFLG_READ) mode |= FA_READ; if (f->flags & GFILEFLG_WRITE) mode |= FA_WRITE; if (f->flags & GFILEFLG_APPEND) mode |= 0; // ToDo if (f->flags & GFILEFLG_TRUNC) mode |= FA_CREATE_ALWAYS; /* ToDo - Complete */ return mode; } static bool_t fatfsDel(const char* fname) { FRESULT ferr; ferr = f_unlink( (const TCHAR*)fname ); if (ferr != FR_OK) return FALSE; return TRUE; } static bool_t fatfsExists(const char* fname) { FRESULT ferr; FILINFO fno; ferr = f_stat( (const TCHAR*)fname, &fno); if (ferr != FR_OK) return FALSE; return TRUE; } static long int fatfsFileSize(const char* fname) { FRESULT ferr; FILINFO fno; ferr = f_stat( (const TCHAR*)fname, &fno ); if (ferr != FR_OK) return 0; return (long int)fno.fsize; } static bool_t fatfsRename(const char* oldname, const char* newname) { FRESULT ferr; ferr = f_rename( (const TCHAR*)oldname, (const TCHAR*)newname ); if (ferr != FR_OK) return FALSE; return TRUE; } static bool_t fatfsOpen(GFILE* f, const char* fname) { FIL* fd; #if !GFILE_NEED_NOAUTOMOUNT if (!fatfs_mounted && !fatfsMount("")) return FALSE; #endif if (!(fd = gfxAlloc(sizeof(FIL)))) return FALSE; if (f_open(fd, fname, fatfs_flags2mode(f)) != FR_OK) { gfxFree(fd); f->obj = 0; return FALSE; } f->obj = (void*)fd; #if !GFILE_NEED_NOAUTOSYNC // no need to sync when not opening for write if (f->flags & GFILEFLG_WRITE) { f_sync( (FIL*)f->obj ); } #endif return TRUE; } static void fatfsClose(GFILE* f) { if ((FIL*)f->obj != 0) { f_close( (FIL*)f->obj ); gfxFree( (FIL*)f->obj ); } } static int fatfsRead(GFILE* f, void* buf, int size) { int br; f_read( (FIL*)f->obj, buf, size, (UINT*)&br); return br; } static int fatfsWrite(GFILE* f, const void* buf, int size) { int wr; f_write( (FIL*)f->obj, buf, size, (UINT*)&wr); #if !GFILE_NEED_NOAUTOSYNC f_sync( (FIL*)f->obj ); #endif return wr; } static bool_t fatfsSetPos(GFILE* f, long int pos) { FRESULT ferr; ferr = f_lseek( (FIL*)f->obj, (DWORD)pos ); if (ferr != FR_OK) return FALSE; return TRUE; } static long int fatfsGetSize(GFILE* f) { return (long int)f_size( (FIL*)f->obj ); } static bool_t fatfsEOF(GFILE* f) { if ( f_eof( (FIL*)f->obj ) != 0) return TRUE; else return FALSE; } static bool_t fatfsMount(const char* drive) { FRESULT ferr; if (!fatfs_mounted) { ferr = f_mount(&fatfs_fs, drive, 1); if (ferr != FR_OK) return FALSE; fatfs_mounted = TRUE; return TRUE; } return FALSE; } static bool_t fatfsUnmount(const char* drive) { (void)drive; if (fatfs_mounted) { // FatFS does not provide an unmount routine. fatfs_mounted = FALSE; return TRUE; } return FALSE; } static bool_t fatfsSync(GFILE *f) { FRESULT ferr; ferr = f_sync( (FIL*)f->obj ); if (ferr != FR_OK) { return FALSE; } return TRUE; } #if GFILE_NEED_FILELISTS && _FS_MINIMIZE <= 1 static gfileList *fatfsFlOpen(const char *path, bool_t dirs) { fatfsList *p; (void) dirs; if (!(p = gfxAlloc(sizeof(fatfsList)))) return 0; if (f_opendir(&p->dir, path) != FR_OK) { gfxFree(p); return 0; } return &p->fl; } static const char *fatfsFlRead(gfileList *pfl) { #define ffl ((fatfsList *)pfl) while(1) { #if _USE_LFN ffl->fno.lfname = ffl->lfn; ffl->fno.lfsize = sizeof(ffl->lfn); #endif // Read the next entry if (f_readdir(&ffl->dir, &ffl->fno) != FR_OK || !ffl->fno.fname[0]) return 0; /* Ignore dot entries */ if (ffl->fno.fname[0] == '.') continue; /* Is it a directory */ if (ffl->fl.dirs) { if ((ffl->fno.fattrib & AM_DIR)) break; } else { if (!(ffl->fno.fattrib & AM_DIR)) break; } } #if _USE_LFN return ffl->fno.lfname[0] ? ffl->fno.lfname : ffl->fno.fname; #else return ffl->fno.fname; #endif #undef ffl } static void fatfsFlClose(gfileList *pfl) { f_closedir(&((fatfsList *)pfl)->dir); gfxFree(pfl); } #endif #endif //GFX_USE_GFILE && GFILE_NEED_FATFS