414 lines
11 KiB
C
414 lines
11 KiB
C
/**
|
|
* @file fat32.c
|
|
* Functions to give an API to a Fat32 storage device which is compatible
|
|
* with the fs_int module.
|
|
* It uses the FatFS as FAT32.
|
|
* For more information about FatFS see:
|
|
* http://elm-chan.org/fsw/ff/00index_e.html
|
|
*/
|
|
|
|
/*********************
|
|
* INCLUDES
|
|
*********************/
|
|
#include "misc_conf.h"
|
|
#if USE_FAT32 != 0
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include "fat32.h"
|
|
#include "ff.h"
|
|
#include "hw/dev/ext_mem/sdcard.h"
|
|
|
|
/*********************
|
|
* DEFINES
|
|
*********************/
|
|
|
|
/**********************
|
|
* TYPEDEFS
|
|
**********************/
|
|
|
|
/**********************
|
|
* STATIC PROTOTYPES
|
|
**********************/
|
|
static fs_res_t fat32_res_trans(FRESULT fat32_res);
|
|
|
|
/**********************
|
|
* STATIC VARIABLES
|
|
**********************/
|
|
|
|
/**********************
|
|
* MACROS
|
|
**********************/
|
|
|
|
/**********************
|
|
* GLOBAL FUNCTIONS
|
|
**********************/
|
|
/**
|
|
* Create a driver for the fat32 device and initilaize it.
|
|
*/
|
|
void fat32_init(void)
|
|
{
|
|
/*Create the driver*/
|
|
fs_drv_t fat_drv;
|
|
memset(&fat_drv, 0, sizeof(fs_drv_t)); /*Initialization*/
|
|
|
|
fat_drv.file_size = sizeof(FIL);
|
|
fat_drv.rddir_size = sizeof(DIR);
|
|
fat_drv.letter = FAT32_LETTER;
|
|
fat_drv.ready = fat32_ready;
|
|
|
|
fat_drv.open = fat32_open;
|
|
fat_drv.close = fat32_close;
|
|
#if _FS_MINIMIZE < 1
|
|
fat_drv.remove = fat32_remove;
|
|
#else
|
|
fat_drv.remove = NULL;
|
|
#endif
|
|
fat_drv.read = fat32_read;
|
|
#if _FS_READONLY == 0
|
|
fat_drv.write = fat32_write;
|
|
#else
|
|
fat_drv.write = NULL;
|
|
#endif
|
|
#if _FS_MINIMIZE < 3
|
|
fat_drv.seek = fat32_seek;
|
|
#else
|
|
fat_drv.seek = NULL;
|
|
#endif
|
|
fat_drv.tell = fat32_tell;
|
|
fat_drv.size = fat32_size;
|
|
fat_drv.trunc = fat32_trunc;
|
|
#if _FS_MINIMIZE < 2
|
|
fat_drv.rddir_init = fat32_readdir_init;
|
|
fat_drv.rddir = fat32_readdir;
|
|
fat_drv.rddir_close = fat32_readdir_close;
|
|
#else
|
|
fat_drv.rddir_init = NULL;
|
|
fat_drv.rddir = NULL;
|
|
fat_drv.rddir_close = NULL;
|
|
#endif
|
|
|
|
#if _FS_MINIMIZE == 0
|
|
fat_drv.free = fat32_free;
|
|
#else
|
|
fat_drv.free = NULL;
|
|
#endif
|
|
fs_add_drv(&fat_drv);
|
|
}
|
|
|
|
/**
|
|
* Give the state of the fat32 storage device
|
|
* @return true if the device is initialized and can be used else false
|
|
*/
|
|
bool fat32_ready(void)
|
|
{
|
|
return sdcard_ready();
|
|
}
|
|
|
|
/**
|
|
* Open a file
|
|
* @param file_p pointer to a FIL type variable
|
|
* @param path path of the file (e.g. "dir1/dir2/file1.txt")
|
|
* @param mode open mode (FS_MODE_RD or FS_MODE_WR or both with | (or connection))
|
|
* @return FS_RES_OK or any error from 'fs_res_t'
|
|
*/
|
|
fs_res_t fat32_open (void * file_p, const char * path, fs_mode_t mode)
|
|
{
|
|
uint8_t fat32_mode = 0;
|
|
if(mode & FS_MODE_RD) fat32_mode |= FA_READ;
|
|
#if _FS_READONLY == 0
|
|
if(mode & FS_MODE_WR) fat32_mode |= FA_WRITE | FA_OPEN_ALWAYS;
|
|
#endif
|
|
|
|
/*In ready only mode the write is not implemented*/
|
|
if(mode == 0) return FS_RES_NOT_IMP;
|
|
|
|
|
|
FRESULT fat32_res;
|
|
fat32_res = f_open(file_p, path, fat32_mode);
|
|
return fat32_res_trans(fat32_res);
|
|
|
|
}
|
|
|
|
/**
|
|
* Close an already opened file
|
|
* @param file_p pointer to a FIL type variable
|
|
* @return FS_RES_OK or any error from fs_res_t
|
|
*/
|
|
fs_res_t fat32_close (void * file_p)
|
|
{
|
|
FRESULT fat32_res;
|
|
fat32_res = f_close(file_p);
|
|
return fat32_res_trans(fat32_res);
|
|
}
|
|
|
|
/**
|
|
* Remove (delete) a file
|
|
* @param path the path of the file ("dir1/file1.txt")
|
|
* @return FS_RES_OK or any error from 'fs_res_t'
|
|
*/
|
|
fs_res_t fat32_remove(const char * path)
|
|
{
|
|
#if _FS_MINIMIZE < 1
|
|
FRESULT fat32_res;
|
|
fat32_res = f_unlink(path);
|
|
return fat32_res_trans(fat32_res);
|
|
#else
|
|
return FS_RES_NOT_IMP;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Read data from an opened file
|
|
* @param file_p pointer to a FIL type variable
|
|
* @param buf pointer a buffer to store the read bytes
|
|
* @param btr the number of Bytes To Read
|
|
* @param br the number of real read bytes (Bytes Read)
|
|
* @return FS_RES_OK or any error from 'fs_res_t'
|
|
*/
|
|
fs_res_t fat32_read (void * file_p, void * buf, uint32_t btr, uint32_t * br)
|
|
{
|
|
FRESULT fat32_res;
|
|
fat32_res = f_read(file_p, buf, btr, (UINT *)br);
|
|
return fat32_res_trans(fat32_res);
|
|
}
|
|
|
|
/**
|
|
* Write data to an opened file
|
|
* @param file_p pointer to a FIL type variable
|
|
* @param buf pointer to buffer where the data to write is located
|
|
* @param btw the number of Bytes To Write
|
|
* @param bw the number of real written bytes (Bytes Written)
|
|
* @return FS_RES_OK or any error from 'fs_res_t'
|
|
*/
|
|
fs_res_t fat32_write (void * file_p, const void * buf, uint32_t btw, uint32_t * bw)
|
|
{
|
|
#if _FS_READONLY == 0
|
|
FRESULT fat32_res;
|
|
fat32_res = f_write(file_p, buf, btw, (UINT *)bw);
|
|
return fat32_res_trans(fat32_res);
|
|
#else
|
|
return FS_RES_NOT_IMP;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Position the read write pointer to given position
|
|
* @param file_p pointer to a FIL type variable
|
|
* @param pos the new position expressed in bytes index (0: start of file)
|
|
* @return FS_RES_OK or any error from 'fs_res_t'
|
|
*/
|
|
fs_res_t fat32_seek (void * file_p, uint32_t pos)
|
|
{
|
|
#if _FS_MINIMIZE < 3
|
|
FRESULT fat32_res;
|
|
fat32_res = f_lseek(file_p, pos);
|
|
return fat32_res_trans(fat32_res);
|
|
#else
|
|
return FS_RES_NOT_IMP;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Give the position of the read write pointer
|
|
* @param file_p pointer to a FIL type variable
|
|
* @param pos_p pointer to store the position of the read write pointer
|
|
* @return FS_RES_OK or any error from 'fs_res_t'
|
|
*/
|
|
fs_res_t fat32_tell (void * file_p, uint32_t * pos_p)
|
|
{
|
|
*pos_p = f_tell((FIL *)file_p);
|
|
|
|
return FS_RES_OK;
|
|
}
|
|
|
|
/**
|
|
* Truncate the file size to the current position of read write pointer
|
|
* @param file_p pointer to a FIL type variable
|
|
* @return FS_RES_OK or any error from 'fs_res_t'
|
|
*/
|
|
fs_res_t fat32_trunc (void * file_p)
|
|
{
|
|
#if _FS_MINIMIZE < 1
|
|
FRESULT fat32_res;
|
|
fat32_res = f_truncate(file_p);
|
|
return fat32_res_trans(fat32_res);
|
|
#else
|
|
return FS_RES_NOT_IMP;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Give the size of a file
|
|
* @param file_p pointer to a FIL type variable
|
|
* @param size_p pointer to store the size
|
|
* @return FS_RES_OK or any error from 'fs_res_t'
|
|
*/
|
|
fs_res_t fat32_size (void * file_p, uint32_t * size_p)
|
|
{
|
|
*size_p = f_size((FIL *)file_p);
|
|
return FS_RES_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
* Initialize a variable for directory reading
|
|
* @param rddir_p pointer to a 'DIR' variable
|
|
* @param path path to a directory
|
|
* @return FS_RES_OK or any error from fs_res_t enum
|
|
*/
|
|
fs_res_t fat32_readdir_init(void * rddir_p, const char * path)
|
|
{
|
|
#if _FS_MINIMIZE < 2
|
|
FRESULT res = f_opendir(rddir_p, path);
|
|
|
|
return fat32_res_trans(res);
|
|
#else
|
|
return FS_RES_NOT_IMP;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Read the next filename form a directory.
|
|
* The name of the directories will begin with '/'
|
|
* @param rddir_p pointer to an initialized 'DIR' variable
|
|
* @param fn pointer to a buffer to store the filename
|
|
* @return FS_RES_OK or any error from fs_res_t enum
|
|
*/
|
|
fs_res_t fat32_readdir(void * rddir_p, char * fn)
|
|
{
|
|
|
|
#if _FS_MINIMIZE < 2
|
|
FRESULT res;
|
|
FILINFO fno;
|
|
char lfn_buf[FSINT_MAX_FN_LENGTH];
|
|
fno.lfname = lfn_buf;
|
|
fno.lfsize = FSINT_MAX_FN_LENGTH;
|
|
res = f_readdir(rddir_p, &fno);
|
|
if(res == FR_OK && fno.fname[0] != '\0') {
|
|
if (fno.fattrib & AM_DIR) { /* It is a directory */
|
|
#if _USE_LFN != 0
|
|
sprintf(fn, "/%s", fno.lfname[0] != '\0' ? fno.lfname : fno.fname);
|
|
#else
|
|
sprintf(fn, "/%s", fno.fname);
|
|
#endif
|
|
} else { /* It is a file. */
|
|
#if _USE_LFN != 0
|
|
strcpy(fn, fno.lfname[0] != '\0' ? fno.lfname : fno.fname);
|
|
#else
|
|
strcpy(fn, fno.fname);
|
|
#endif
|
|
}
|
|
} else {
|
|
fn[0] = '\0';
|
|
}
|
|
|
|
return fat32_res_trans(res);
|
|
#else
|
|
return FS_RES_NOT_IMP;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Close the directory reading
|
|
* @param rddir_p pointer to an initialized 'DIR' variable
|
|
* @return FS_RES_OK or any error from fs_res_t enum
|
|
*/
|
|
fs_res_t fat32_readdir_close(void * rddir_p)
|
|
{
|
|
#if _FS_MINIMIZE < 2
|
|
f_closedir(rddir_p);
|
|
return FS_RES_OK;
|
|
#else
|
|
return FS_RES_NOT_IMP;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Give the size of a drive
|
|
* @param total_p pointer to store the total size [kB]
|
|
* @param free_p pointer to store the free size [kB]
|
|
* @return FS_RES_OK or any error from 'fs_res_t'
|
|
*/
|
|
fs_res_t fat32_free (uint32_t * total_p, uint32_t * free_p)
|
|
{
|
|
#if _FS_READONLY == 0 && _FS_MINIMIZE == 0
|
|
FATFS *fs;
|
|
FRESULT fat32_res;
|
|
uint32_t fre_clust = 0;
|
|
uint32_t fre_sect=0;
|
|
uint32_t tot_sect=0;
|
|
|
|
fat32_res = f_getfree("", (unsigned long*)&fre_clust, &fs);
|
|
tot_sect=(fs->n_fatent - 2) * fs->csize;
|
|
fre_sect=fre_clust*fs->csize;
|
|
#if _MAX_SS!=512
|
|
tot_sect*=fs1->ssize / 512;
|
|
fre_sect*=fs1->ssize / 512;
|
|
#endif
|
|
*total_p=tot_sect >> 1;
|
|
*free_p=fre_sect >> 1;
|
|
return fat32_res_trans(fat32_res);
|
|
#else
|
|
return FS_RES_NOT_IMP;
|
|
#endif
|
|
}
|
|
|
|
/**********************
|
|
* STATIC FUNCTIONS
|
|
**********************/
|
|
|
|
/**
|
|
* Translate the return codes to fs_res_t
|
|
* @param fat32_res the original fat_32 result
|
|
* @return the converted, fs_res_t return code
|
|
*/
|
|
|
|
static fs_res_t fat32_res_trans(FRESULT fat32_res)
|
|
{
|
|
switch(fat32_res) {
|
|
case FR_OK: /* (0) Succeeded */
|
|
return FS_RES_OK;
|
|
|
|
case FR_DISK_ERR: /* (1) A hard error occurred in the low level disk I/O layer */
|
|
case FR_NOT_READY: /* (3) The physical drive cannot work */
|
|
return FS_RES_HW_ERR;
|
|
|
|
case FR_INT_ERR: /* (2) Assertion failed */
|
|
case FR_NOT_ENABLED: /* (12) The volume has no work area */
|
|
case FR_NO_FILESYSTEM: /* (13) There is no valid FAT volume */
|
|
return FS_RES_FS_ERR;
|
|
|
|
case FR_NO_FILE: /* (4) Could not find the file */
|
|
case FR_NO_PATH: /* (5) Could not find the path */
|
|
case FR_INVALID_NAME: /* (6) The path name format is invalid */
|
|
case FR_INVALID_DRIVE: /* (11) The logical drive number is invalid */
|
|
return FS_RES_NOT_EX;
|
|
|
|
case FR_DENIED: /* (7) Access denied due to prohibited access or directory full */
|
|
case FR_EXIST: /* (8) Access denied due to prohibited access */
|
|
case FR_WRITE_PROTECTED: /* (10) The physical drive is write protected */
|
|
case FR_LOCKED: /* (16) The operation is rejected according to the file sharing policy */
|
|
return FS_RES_DENIED;
|
|
|
|
case FR_INVALID_OBJECT: /* (9) The file/directory object is invalid */
|
|
case FR_INVALID_PARAMETER: /* (19) Given parameter is invalid */
|
|
return FS_RES_INV_PARAM;
|
|
|
|
case FR_TIMEOUT: /* (15) Could not get a grant to access the volume within defined period */
|
|
return FS_RES_TOUT;
|
|
|
|
case FR_TOO_MANY_OPEN_FILES:/* (18) Number of open files > _FS_LOCK */
|
|
case FR_NOT_ENOUGH_CORE: /* (17) LFN working buffer could not be allocated */
|
|
return FS_RES_OUT_OF_MEM;
|
|
|
|
case FR_MKFS_ABORTED: /* (14) The f_mkfs() aborted due to any parameter error */
|
|
return FS_RES_UNKNOWN;
|
|
|
|
}
|
|
|
|
return FS_RES_UNKNOWN;
|
|
}
|
|
|
|
#endif
|