//******************************************************************************
//* FAT filesystem driver.                                                     *
//* Written by   : Tamas Raikovich                                             *
//* Version      : 1.0                                                         *
//* Last modified: 2012.10.11.                                                 *
//******************************************************************************
//******************************************************************************
//*                                                                            *
//* This file is based on the Petit FatFs by ChaN (http://elm-chan.org).       *
//*                                                                            *
//* Petit FatFs module is an open source software to implement FAT file system *
//* to small embedded systems. This is a free software and is opened for       *
//* education, research and commercial developments under license policy of    *
//* following trems.                                                           *
//*                                                                            *
//* Copyright (C) 2009, ChaN, all right reserved.                              *
//*                                                                            *
//* - The Petit FatFs module is a free software and there is NO WARRANTY.      *
//* - No restriction on use. You can use, modify and redistribute it for       *
//*   personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY.        *
//* - Redistributions of source code must retain the above copyright notice.   *
//******************************************************************************
#ifndef FAT_FILESYSTEM_H_INCLUDED
#define FAT_FILESYSTEM_H_INCLUDED


//******************************************************************************
//* Configuration options.                                                     *
//******************************************************************************
//Enable or disable file read support (pf_read() function).
#define	FATFS_USE_READ      1
//Enable or disable directory support (pf_opendir(), pf_readdir() functions).
#define	FATFS_USE_DIR       0
//Enable or disable file pointer change support (pf_ltell(), pf_lseek() functions).
#define	FATFS_USE_LSEEK     1
//Enable or disable file write support (pf_write() function).
#define	FATFS_USE_WRITE     0


//******************************************************************************
//* Disk handler functions.                                                    *
//******************************************************************************
#define DiskInitialize              MemCardInitialize
#define DiskGetSectorBuffer         MemCardGetSectorBuffer
#define DiskReadPartialSector       MemCardReadPartialSector
#define DiskReadMultipleSectors     MemCardReadMultipleSectors
#define DiskWritePartialSector      MemCardWritePartialSector
#define DiskWriteMultipleSectors    MemCardWriteMultipleSectors


//******************************************************************************
//* FAT boot record.                                                           *
//******************************************************************************
#pragma pack(push, 1)

//Partition table element.
typedef struct _PARTITION_TABLE_ENTRY
{
    //Boot indicator.
    unsigned char           bootIndicator;
    //Starting head.
    unsigned char           startingHead;
    //Starting sector/cylinder.
    unsigned short          startingSector;
    //System identifier.
    unsigned char           systemID;
    //Ending head.
    unsigned char           endingHead;
    //Ending sector/cylinder.
    unsigned short          endingSector;
    //Number of sectors before the starting sector of this partition.
    unsigned long           relativeSector;
    //Number of sectors on this partition.
    unsigned long           totalSector;
} PARTITION_TABLE_ENTRY, *PPARTITION_TABLE_ENTRY;


//FAT12/16 specific data in the boot sector starting at offset 36.
typedef struct _FAT12_FAT16_DATA
{
    //Drive number (OS specific).
    unsigned char           BS_DrvNum;
    //Reserved, should always be set to 0.
    unsigned char           BS_Reserved1;
    //Extended boot signature.
    unsigned char           BS_BootSig;
    //Volume serial number.
    unsigned long           BS_VolID;
    //Volume label.
    unsigned char           BS_VolLab[11];
    //Filesystem type string (not related to FAT type).
    unsigned char           BS_FilSysType[8];
} FAT12_FAT16_DATA, *PFAT12_FAT16_DATA;


//FAT32 specific data in the boot sector starting at offset 36.
typedef struct _FAT32_DATA
{
    //Number of sectors occupied by one FAT.
    unsigned long           BPB_FATSz32;
    //Flags.
    unsigned short          BPB_ExtFlags;
    //FAT32 version number.
    unsigned short          BPB_FSVer;
    //First cluster of the root directory.
    unsigned long           BPB_RootClus;
    //Sector number of FSINFO structure in the reserved area.
    unsigned short          BPB_FSInfo;
    //Sector number of a copy of the boot record in the reserved area.
    unsigned short          BPB_BkBootSec;
    //Reserved, should always be filled with 0.
    unsigned char           BPB_Reserved[12];
    //Drive number (OS specific).
    unsigned char           BS_DrvNum;
    //Reserved, should always be set to 0.
    unsigned char           BS_Reserved1;
    //Extended boot signature.
    unsigned char           BS_BootSig;
    //Volume serial number.
    unsigned long           BS_VolID;
    //Volume label.
    unsigned char           BS_VolLab[11];
    //Filesystem type string (not related to the FAT type).
    unsigned char           BS_FilSysType[8];
} FAT32_DATA, *PFAT32_DATA;


//Union that contains the FAT specific data.
typedef union _FAT_SPECIFIC_DATA
{
    //FAT12/16 specific data.
    FAT12_FAT16_DATA        fat12Fat16Data;
    //FAT32 specific data.
    FAT32_DATA              fat32Data;
} FAT_SPECIFIC_DATA, *PFAT_SPECIFIC_DATA;


//Boot sector structure.
typedef struct _BOOT_SECTOR
{
    //Jump instruction to boot code.
    unsigned char           BS_jmpBoot[3];
    //OEM name string.
    unsigned char           BS_OEMName[8];
    //Bytes per sector.
    unsigned short          BPB_BytsPerSec;
    //Number of sectors per allocation unit.
    unsigned char           BPB_SecPerClus;
    //Number of sectors in the reserved region.
    unsigned short          BPB_RsvdSecCnt;
    //Number of the FAT data structures on the volume.
    unsigned char           BPB_NumFATs;
    //Number of the root directory entries (FAT12/16 only).
    unsigned short          BPB_RootEntCnt;
    //Total number of sectors on the volume (16-bit).
    unsigned short          BPB_TotSec16;
    //Media type.
    unsigned char           BPB_Media;
    //Number of sectors occupied by one FAT (16-bit, FAT12/16 only).
    unsigned short          BPB_FATSz16;
    //Sectors per track (only relevant for media that have geometry).
    unsigned short          BPB_SecPerTrk;
    //Number of heads (only relevant for media that have geometry).
    unsigned short          BPB_NumHeads;
    //Number of hidden sectors preceeding the partition that contains this FAT volume.
    unsigned long           BPB_HiddSec;
    //Total number of sectors on the volume (32-bit).
    unsigned long           BPB_TotSec32;
    //FAT specific data starting at offset 36.
    FAT_SPECIFIC_DATA       fatSpecificData;
    //Fill.
    unsigned char           fill[356];
    //Partition table.
    PARTITION_TABLE_ENTRY   partitionData[4];
    //Signature word (0x55, 0xAA).
    unsigned short          BS_SignatureWord;
} BOOT_SECTOR, *PBOOT_SECTOR;

#pragma pack(pop)


//******************************************************************************
//* FAT directory entry structure.                                             *
//******************************************************************************
#pragma pack(push, 1)

typedef struct _FAT_DIR_ENTRY
{
    //Short (8.3) file name.
    unsigned char   DIR_Name[11];
    //File attributes.
    unsigned char   DIR_Attr;
    //Reserved (set to 0 when the file is created, do not modify).
    unsigned char   DIR_NTRes;
    //File creation time (milliseconds part).
    unsigned char   DIR_CrtTimeTenth;
    //File creation time.
    unsigned short  DIR_CrtTime;
    //File creation date.
    unsigned short  DIR_DrtDate;
    //Last access date.
    unsigned short  DIR_LstAccDate;
    //First cluster number (high word).
    unsigned short  DIR_FstClusHI;
    //Time of last write.
    unsigned short  DIR_WrtTime;
    //Date of last write.
    unsigned short  DIR_WrtDate;
    //First cluster number (low word).
    unsigned short  DIR_FstClusLO;
    //File size.
    unsigned long   DIR_FileSize;
} FAT_DIR_ENTRY, *PFAT_DIR_ENTRY;

#pragma pack(pop)

//File attribute bits.
#define AM_RDO      0x01	//Read only.
#define	AM_HID      0x02	//Hidden.
#define	AM_SYS      0x04	//System.
#define	AM_VOL      0x08	//Volume label.
#define AM_LFN      0x0f	//Long filename (LFN) entry.
#define AM_DIR      0x10	//Directory.
#define AM_ARC      0x20	//Archive.
#define AM_MASK     0x3f	//Mask of the defined bits.


//******************************************************************************
//* Filesystem object structure.                                               *
//******************************************************************************
typedef struct _FATFS
{
    //FAT type (FAT12, FAT16 or FAT32).
    unsigned char   fs_type;
    //Number of sectors per cluster.
    unsigned char   csize;
    unsigned char   log2csize;
    //File status flags.
    unsigned char   flag;
    //File sector offset in the cluster.
    unsigned char   csect;
    //Number of root directory entries (0 on FAT32).
    unsigned short  n_rootdir;
    //Pointer to the disk access buffer.
    unsigned char   *buf;
    //Maximum cluster number + 1. Number of clusters is max_clust - 2.
    unsigned long   max_clust;
    //FAT start sector.
    unsigned long   fatbase;
    //Root directory start sector (cluster number on FAT32).
    unsigned long   dirbase;
    //Data start sector.
    unsigned long   database;
    //File read/write pointer.
    unsigned long   fptr;
    //File size.
    unsigned long   fsize;
    //File start cluster.
    unsigned long   org_clust;
    //File current cluster.
    unsigned long   curr_clust;
    //File current data sector.
    unsigned long   dsect;
} FATFS, *PFATFS;

//File status flags.
#define	FA_OPENED   0x01
#define	FA_WPRT	    0x02
#define	FA__WIP     0x40

//FAT type
#define FS_FAT12    1
#define FS_FAT16    2
#define FS_FAT32    3


//******************************************************************************
//* Directory object structure.                                                *
//******************************************************************************
typedef struct _DIR
{
    //Current read/write index number.
    unsigned short  index;
    //Pointer to the short file name (file[8], ext[3], status[1]).
    unsigned char   *fn;
    //Table start cluster (0: static table).
    unsigned long   sclust;
    //Current cluster.
    unsigned long   clust;
    //Current sector.
    unsigned long   sect;
} DIR, *PDIR;


//******************************************************************************
//* File object structure.                                                     *
//******************************************************************************
typedef struct _FILINFO
{
    //File size.
    unsigned long	fsize;
    //Last modified date.
    unsigned short	fdate;
    //Last modified time,
    unsigned short	ftime;
    //File attributes.
    unsigned char	fattrib;
    //File name (8.3 format, null-terminated).
    unsigned char	fname[13];
} FILINFO, *PFILINFO;


//******************************************************************************
//* File function status codes.                                                *
//******************************************************************************
#define FR_OK               0
#define FR_DISK_ERR         1
#define FR_NOT_READY        2
#define FR_NO_FILE          3
#define FR_NO_PATH          4
#define FR_NOT_OPENED       5
#define FR_NOT_ENABLED      6
#define FR_NO_FILESYSTEM    7


//******************************************************************************
//* Function prototypes.                                                       *
//******************************************************************************
unsigned char pf_mount(PFATFS);
unsigned char pf_open(const char*);
unsigned char pf_read(void *, unsigned short, unsigned short *);
unsigned char pf_write(const void *, unsigned short, unsigned short *);
unsigned char pf_lseek(unsigned long);
unsigned char pf_opendir(PDIR, const char *);
unsigned char pf_readdir(PDIR, PFILINFO);


#endif //FAT_FILESYSTEM_H_INCLUDED
