/*
* Author: Pawel Jablonski
* E-mail: pj@xirx.net
* WWW: xirx.net
* GIT: git.xirx.net
*
* License: You can use this code however you like
* but leave information about the original author.
* Code is free for non-commercial and commercial use.
*/
#include "fatfs/ff_gen_drv.h"
#include "type.h"
#include "flash.h"
#include "fs.h"
//! File system block type list
enum FSReadBlockType
{
FS_READ_BLOCK_UNKNOWN = 0, //!< Unknown type
FS_READ_BLOCK_FILE, //!< File type
FS_READ_BLOCK_DIR, //!< Directory type
};
static void fsMakePath(char *path, const char *dirName, const char *fileName);
static DSTATUS fsFatInit(BYTE pdrv);
static DSTATUS fsFatGetStatus(BYTE pdrv);
static DRESULT fsFatRead(BYTE pdrv, BYTE *buf, DWORD sector, UINT count);
//! File system handlers to functions
static Diskio_drvTypeDef fatDriver =
{
fsFatInit,
fsFatGetStatus,
fsFatRead
};
static char fatDiskPath[4]; //!< Path to the FAT file system
static FATFS fatFS; //!< Descriptor of the FAT file system
static FRESULT fatMountStatus = FR_NOT_READY; //!< Mount status of the physical drive
static FRESULT fatOpenStatus = FR_NOT_READY; //!< Open status of the file
static FIL fatFile; //!< Descriptor of the file
static int readBlockType = FS_READ_BLOCK_UNKNOWN; //!< Type of reading block
static unsigned char dirBuffer[FS_DIR_ENTRY_SIZE * FS_DIR_MAX_QUANTITY]; //!< Directory entrys buffer
//! Init file system and set up the FAT
void fsInit(void)
{
if(!FATFS_LinkDriver(&fatDriver, fatDiskPath))
{
fatMountStatus = f_mount(&fatFS, fatDiskPath, 1);
}
}
/**
* Open a file from the file system
*
* @param dirName Name of the directory. "app" or "file".
* @param fileName Name of the file to open
* @param size Struct where size of the file will be written
*
* @return Status of the open operation
*/
bool fsOpen(const char *dirName, const struct FSName *fileName, struct FSSize *size)
{
size->low = 0;
size->high = 0;
readBlockType = FS_READ_BLOCK_FILE;
if(!fatMountStatus)
{
char path[FS_PATH_MAX_LENGTH + 1];
fsMakePath(path, dirName, (const char *)(fileName->data));
fatOpenStatus = f_open(&fatFile, path, FA_READ);
if(!fatOpenStatus)
{
DWORD fileSize = f_size(&fatFile);
size->low = (fileSize % 256);
size->high = ((fileSize / 256) & 0xff);
return(TRUE);
}
}
return(FALSE);
}
/**
* Create a list of files in the directory from the file system
*
* @param dirName Name of the directory. "app" or "file".
* @param size Struct where size of the buffer with description of the files will be written
*
* @return Status of the list operation
*/
bool fsList(const char *dirName, struct FSSize *size)
{
size->low = 0;
size->high = 0;
readBlockType = FS_READ_BLOCK_DIR;
if(!fatMountStatus)
{
char path[FS_PATH_MAX_LENGTH + 1];
DIR dir;
FILINFO info;
fsMakePath(path, dirName, NULL);
if(!f_opendir(&dir, path))
{
int dirSize = 0;
while(1)
{
if(f_readdir(&dir, &info) != FR_OK)
{
break;
}
if(info.fname[0] == 0)
{
break;
}
for(int i = 0; i < FS_NAME_MAX_LENGTH; i++)
{
dirBuffer[dirSize + i] = info.fname[i];
}
dirBuffer[dirSize + FS_NAME_MAX_LENGTH] = 0;
dirBuffer[dirSize + FS_DIR_ENTRY_SIZE - 2] = (info.fsize % 256);
dirBuffer[dirSize + FS_DIR_ENTRY_SIZE - 1] = ((info.fsize / 256) & 0xff);
dirSize += FS_DIR_ENTRY_SIZE;
if(dirSize >= (FS_DIR_ENTRY_SIZE * FS_DIR_MAX_QUANTITY))
{
break;
}
}
size->low = ((dirSize) % 256);
size->high = (((dirSize) / 256) & 0xff);
return(TRUE);
}
}
return(FALSE);
}
/**
* Read data from buffer to block based on offset
*
* @param block Struct where the data from the buffer will be written
* @param number Number of the block selected to read
*/
void fsReadBlock(struct FSBlock *block, int number)
{
if((!fatMountStatus) && (!fatOpenStatus))
{
if(readBlockType == FS_READ_BLOCK_FILE)
{
if(!f_lseek(&fatFile, (number * FS_BLOCK_SIZE)))
{
UINT read;
f_read(&fatFile, block->data, 256, &read);
}
}
else if(readBlockType == FS_READ_BLOCK_DIR)
{
for(int i = 0; i < FS_BLOCK_SIZE; i++)
{
block->data[i] = 0;
}
if(((number * FS_BLOCK_SIZE) / FS_DIR_ENTRY_SIZE) < (FS_DIR_MAX_QUANTITY))
{
int offset = (number * FS_BLOCK_SIZE);
for(int i = 0; i < FS_BLOCK_SIZE; i++)
{
block->data[i] = dirBuffer[offset + i];
}
}
}
}
}
/**
* Generate a full path to file
*
* @param path Buffer to write
* @param dirName
* @param fileName
*/
static void fsMakePath(char *path, const char *dirName, const char *fileName)
{
path[0] = '/';
int i = 1;
for(int j = 0; dirName[j]; j++, i++)
{
path[i] = dirName[j];
}
if(fileName)
{
path[i] = '/';
i++;
for(int j = 0; fileName[j]; j++, i++)
{
path[i] = fileName[j];
}
}
path[i] = 0;
}
/**
* Get status of init
*
* @param pdrv Physical drive number
*
* @return Status of init
*/
static DSTATUS fsFatInit(BYTE pdrv)
{
return(0);
}
/**
* Get status of the physical drive
*
* @param pdrv Physical drive number
*
* @return Status of the physical drive
*/
static DSTATUS fsFatGetStatus(BYTE pdrv)
{
return(0);
}
/**
* Read sector of the physical drive
*
* @param pdrv Physical drive number
* @param buf Buffer to write
* @param sector Sector number to read
* @param count Count of sectors to read
*
* @return Status of the reading process
*/
static DRESULT fsFatRead(BYTE pdrv, BYTE *buf, DWORD sector, UINT count)
{
for(uint32_t i = 0; i < count; i++)
{
if(!flashRead((sector + i), (buf + (FLASH_SECTOR_SIZE * i))))
{
return(RES_ERROR);
}
}
return(RES_OK);
}