www.pudn.com > UDiskFileSystem.rar > FAT.c


 
#include  
#include  
 
#include "fat.h" 
#include "fattime.h" 
#include "HAL.h" 
#include "global.h" 
 
#ifdef FOR_WIN 
#include "UFI_Layer.h" 
#else 
#include "2410lib.h" 
#define printf Uart_Printf  
#endif 
 
// globals variable 
 
// This buffer is used to put data read from NANDFlash 
u_8 SECTOR_BUFFER_ADDR[512]; 
 
// This buffer is used to put the fat data read from NANDFlash 
u_8 FAT_CACHE_ADDR[512]; 
 
u_8 *SectorBuffer  	=			(u_8 *) SECTOR_BUFFER_ADDR;	// Sector Buffer address 
u_8 *FatCache 		=			(u_8 *) FAT_CACHE_ADDR;		// Fat Buffer address 
char VolLabel[12] = {0};									// Volume Label 
 
u_8 DiskIndex; 
 
struct partrecord PartInfo;			// Partition Information 
TFILE File;							// File Information 
u_32 FSInfo;						// File System Information 
u_8  Fat32Enabled;					// Indicates if is FAT32 or FAT16 
u_32 FirstDataSector;				// First Data Sector Address , the first sector of cluster 2 . 
u_16 SectorsPerCluster;				// Number of Sectors per Cluster 
u_32 FirstFATSector;				// First FAT Sector Address 
u_32 FirstFAT2Sector;				// First FAT2 Sector Address 
u_32 FirstDirCluster;				// Root Directory Cluster Address 
u_32 RootDirSectors; 				// Justin add for The count of sectors occupied by the root directory for FAT16  
u_32 FatInCache = 0xFFFFFFFF;		// Address of the FAT Cluster in FatCache 
u_32 FatSectors;					// Number of FAT Sectors 
u_32 currentDirCluster;				// Actual Dir Cluster Number 
u_32 NumClusters;					// NANDFlash Cluster Numbers 
u_32 SectorInCache = 0xFFFFFFFF;	// Address of the Sector Cluster in SectorBuffer 
 
//Some compiler doesn't have this non-ansi C function ,  
//It is for fatNormalize() use. 
char * MX_strupr (char *a) 
{ 
	char *ret = a; 
 
	while (*ret != 0) 
	{ 
		if ((0x61 <= *ret) && (*ret <= 0x7A)) 
		{ 
			*ret = *ret - 0x20; 
		} 
		ret+=1; 
    } 
 
	return ret; 
} 
 
//***************************************************************************** 
// Function: fatClustToSect 
// Parameters: cluster 
// Returns: sector 
// 
// Description: Converts Sectors in Clusters 
//***************************************************************************** 
u_32 fatClustToSect(u_32 clust) 
{ 
	//if (clust == 0) 
	//		clust=2; 
	//Justin modify for FAT16 
	if (Fat32Enabled) 
	{ 
		if (clust == 0) 
			clust=2; 
	} 
	else 
	{ 
		if (clust == 0) 
			return FirstDataSector - RootDirSectors; 
	} 
	return ((clust-2) * SectorsPerCluster) + FirstDataSector; 
} 
 
 
//***************************************************************************** 
// Function: fatInit 
// Parameters: none 
// Returns: 0 if a FAT drive was found, FALSE otherwise 
// 
// Description: Get FAT info from NANDFlash and initialize internal variables 
//***************************************************************************** 
u_8 fatInit(u_8 index) 
{ 
	struct bpb710 *bpb; 
	u_32 TotalSectors;	//Total sectors of this Volume 
	u_8 i,j=0; 
	 
	DiskIndex = index; 
	PartInfo.prStartLBA = 0;//Boot Sector Start LBA 
	 
	if(HAL_ReadSector( DiskIndex, PartInfo.prStartLBA, SectorBuffer, &SectorInCache )) 
		return 1; 
 
	for(i=0;i<512;i++) 
	{ 
		if(i%16==0) 
		{ 
			printf("\n"); 
			j++; 
		} 
		if(j==7) 
			break; 
		printf("%2x  ",SectorBuffer[i]); 
		 
	} 
	 
	bpb = (struct bpb710 *) ((struct bootsector710 *) SectorBuffer)->bsBPB; 
 
	// setup global disk constants 
	FirstDataSector	= PartInfo.prStartLBA; 
	if(bpb->bpbFATsecs) 
	{ 
		FatSectors			= bpb->bpbFATsecs; 
	} 
	else 
	{ 
		FatSectors			= bpb->bpbBigFATsecs; 
	} 
	 
	RootDirSectors = ((bpb->bpbRootDirEnts * 32) + (bpb->bpbBytesPerSec -1))/bpb->bpbBytesPerSec; 
		 
	FirstDataSector	+= (bpb->bpbResSectors + bpb->bpbFATs * FatSectors) + RootDirSectors; 
	//FirstDataSector	+= (bpb->bpbResSectors + bpb->bpbFATs * FatSectors) ; 
 
	if(bpb->bpbSectors) 
	{ 
		TotalSectors = bpb->bpbSectors; 
	} 
	else 
	{ 
		TotalSectors = bpb->bpbHugeSectors; 
	} 
//	bpb->bpbSecPerClust=1; 
	printf("bpb->bpbSecPerClust=%d\n\n",bpb->bpbSecPerClust); 
	NumClusters = (TotalSectors - (bpb->bpbResSectors + (bpb->bpbFATs * FatSectors) + RootDirSectors))/ bpb->bpbSecPerClust; 
	printf("aaaa\n\n"); 
 
	//FAT Type Determination by count of Clusters 
	if(NumClusters < 4085) 
	{ 
		PartInfo.prPartType = PART_TYPE_FAT12; 
	} 
	else if(NumClusters < 65525) 
	{ 
		PartInfo.prPartType = PART_TYPE_FAT16; 
	} 
	else 
	{ 
		PartInfo.prPartType = PART_TYPE_FAT32; 
	} 
 
	SectorsPerCluster	= bpb->bpbSecPerClust; 
	printf("SectorsPerCluster = %d\n",SectorsPerCluster); 
 
	FirstFATSector		= bpb->bpbResSectors + PartInfo.prStartLBA; 
 
	switch (PartInfo.prPartType) 
	{ 
		case PART_TYPE_FAT16: 
			FirstDirCluster	= 0;//first legal cluster number for FAT16 , the First Data Cluster is 2 , the Root Entry is fixed   
			Fat32Enabled = FALSE; 
			break; 
		case PART_TYPE_FAT32: 
			FirstDirCluster = bpb->bpbRootClust; 
			Fat32Enabled = TRUE; 
			break; 
		default: 
			//Found: No Partition! 
			return 1; 
	} 
	printf("bbb\n\n"); 
	if (Fat32Enabled) 
	{ 
		FirstFAT2Sector=FirstFATSector+bpb->bpbBigFATsecs; 
		// initialize Volume Label 
		memcpy(&VolLabel, (u_8*)(bpb->bpbVolLabel), 11); 
		VolLabel[11]='\0'; 
	} 
	else 
	{ 
		FirstFAT2Sector=FirstFATSector+bpb->bpbFATsecs; 
	} 
	 
	FSInfo=bpb->bpbFSInfo+PartInfo.prStartLBA; 
 
	currentDirCluster= FirstDirCluster; 
 
	return 0; 
} 
 
//***************************************************************************** 
// Function: fatNextCluster 
// Parameters: cluster 
// Returns: the next cluster 
// 
// Description: Find next cluster in the FAT chain 
//***************************************************************************** 
u_32 fatNextCluster(u_32 cluster) 
{ 
	u_32 nextCluster; 
	u_32 fatMask; 
	u_32 fatOffset; 
	u_32 sector; 
	u_32 offset; 
 
	// get fat offset in bytes 
	if(Fat32Enabled) 
	{ 
		// four FAT bytes (32 bits) for every cluster 
		fatOffset = cluster << 2; 
		// set the FAT bit mask 
		fatMask = FAT32_MASK; 
	} 
	else 
	{ 
		// two FAT bytes (16 bits) for every cluster 
		fatOffset = cluster << 1; 
		// set the FAT bit mask 
		fatMask = FAT16_MASK; 
	} 
 
	// calculate the FAT sector that we're interested in 
	sector = FirstFATSector + (fatOffset / BYTES_PER_SECTOR); 
	// calculate offset of the our entry within that FAT sector 
	offset = fatOffset % BYTES_PER_SECTOR; 
 
	// if we don't already have this FAT chunk loaded, go get it 
	//Justin modify on 20060518 
	if(sector != FatInCache) 
	{ 
		//printf("\nFAT chunk loaded\n"); 
		HAL_ReadSector( DiskIndex, sector, (u_8*)FAT_CACHE_ADDR, &FatInCache); 
	} 
 
	// read the nextCluster value 
	nextCluster = (*((u_32*) &((char*)FAT_CACHE_ADDR)[offset])) & fatMask; 
 
	// check to see if we're at the end of the chain 
	if (nextCluster == (CLUST_EOFE & fatMask)) 
		nextCluster = 0; 
 
	return nextCluster; 
} 
 
 
 
 
//***************************************************************************** 
// Function: fatGetFileInfo 
// Parameters: address of direntry struct, short name of the file 
// Returns: On SUSCEFULL, return the direntry struct filled out with the file info, 
//          otherwise returns NULL; 
// 
// Description: return the direntry struct of a short name file given 
//              this function will search for a filename only in the current 
//              directory, given by currentDirCluster 
//***************************************************************************** 
struct direntry *fatGetFileInfo(struct direntry *rde, char *shortName) 
{ 
	u_32 sector=0, cluster; 
	struct direntry *de; 
	u_16 index, isetor; 
	char Name[13]; 
 
	strncpy(Name, shortName,12); 
	 
	Name[12]='\0'; 
 
	fatNormalize(Name); // adjust the name to the FAT format 
 
	cluster= currentDirCluster;	// start the search in the current cluster 
	do 
	{ 
		for (isetor=0; isetor< SectorsPerCluster; isetor++)		// clusters 
		{ 
			// read dir data 
			sector = fatClustToSect(cluster) + (u_32)isetor; 
			HAL_ReadSector( DiskIndex, sector, SectorBuffer, &SectorInCache); 
			de = (struct direntry *) SectorBuffer; 
 
			for (index=1; index<=FAT_DIRENTRIES_PER_SECTOR; index++) 
			{ 
				if (*de->deName == 0x00) 
				{ 
					return NULL;		// there is no more direntries 
				} 
				if((*de->deName != SLOT_DELETED) && (de->deAttributes != ATTR_LONG_FILENAME)) 
				{ 
					if (strncmp((const char*)(de->deName), Name, 11) == 0) 
					{ 
						memcpy((u_8*)rde, (u_8*)de, DIRENTRY_SIZE); 
						return(de); 
					} 
				} 
				de++; 
			}	// end of sector 
		}	// end of cluster 
		cluster= fatNextCluster(cluster); 
	}while  (sector < FirstFATSector+FatSectors); // end of FatDirentries 
 
	return NULL; 
} 
 
 
//***************************************************************************** 
// Function: fatNormalize 
// Parameters: file name to be normalized 
// Returns: the normalized file name 
// 
// Description: normalize the file name. Insert spaces betwen the name and the extension. 
//              The file name will be 11 caracters 
//***************************************************************************** 
void fatNormalize(char *str_dest) 
{ 
	u_8 o=0, d=0; 
	char str_ori[12]; 
 
	strncpy(str_ori, str_dest, 12); 
 
	if (str_ori[0] == '.') 		// if the file name is "." or ".." 
	{ 
		d=1; 
		if (str_ori[1] == '.') 
			d=2; 
		for (;d<11; d++) 
			str_dest[d]=' ';	// complete with spaces 
		str_dest[11]='\0'; 
		return;					// finish 
	} 
 
	for (d=0; d<8; d++)			// for all the other file name 
	{ 
		if (str_ori[o] == '.')	// if we found the '.' 
		{ 
			o++; 
			break;				//		break the loop 
		} 
		if (str_ori[o] == '\0')	// if we find the file name end 
			break;				//		break the loop 
		str_dest[d]= str_ori[o++]; 
	} 
 
	for (; d<8; d++)			// complete the eight caracters file name with spaces 
		str_dest[d]= ' '; 
 
	if (str_ori[o]=='.')		// eliminate the '.' 
		o++; 
 
	for (; d<11; d++)			// copy the extension 
	{ 
		if (str_ori[o] == '\0') 
			break; 
		str_dest[d]= str_ori[o++]; 
	} 
 
	for (; d<11; d++)			// complete the three caracters extension file name with spaces 
		str_dest[d]= ' '; 
	 
	MX_strupr(str_dest); 
 
	str_dest[11]='\0'; 
} 
 
//***************************************************************************** 
// Function: fatFcreate 
// Parameters: File short name 
// Returns: A TFILE struct filled with the created file information, or NULL 
//          if an error has ocurred 
// 
// Description: Create a file and open it in the current directory 
TFILE* fatFcreate(char *shortName) 
{ 
	struct direntry *de, rde; 
	u_32 freeCluster, newDirEntrySector, lastCluster; 
	u_16 date, time; 
	char string[12]; 
	TTime t; 
 
	// if the file already exist 
	if (fatGetFileInfo(&rde, shortName) != NULL) 
		return NULL; 
 
 
	// Find a free direntry, returns a pointer to the direntry struct inside SectorBuffer, 
	// until to the end of the FAT chain !! 
	de=fatNextFreeDirEntry(currentDirCluster); 
 
	// Saves the sector address of this new DirEntry to write it back to the NANDFlah 
	newDirEntrySector= SectorInCache; 
 
 
	// if goes until the end of the cluster and don't find a free direntry 
	// needs to create a new direntry in a new cluster to put this new file. 
	if (de == NULL) 
	{ 
		freeCluster=fatNextFreeCluster(0); // Find the Free Cluster from cluster0. 
		if (freeCluster == 0)	// if disk is full 
			return (FALSE);		// returns ERROR 
 
 
		lastCluster= fatLastCluster(currentDirCluster);	// find the last cluster of the current dir 
		fatWrite(lastCluster, freeCluster);				// creates a connection between the last cluster of the current directory and the new cluster created 
		fatWriteEOC(freeCluster);						// mark the new cluster with an END OF CLUSTER mark 
		memset (SectorBuffer, '\0', BYTES_PER_SECTOR); 	// fill the SectorBuffer with ZEROS to informate to the FAT that don't have more direntries after this one that we are creating 
		de= (struct direntry *)SectorBuffer;			// de points to the first address in the SectorBuffer 
		newDirEntrySector= fatClustToSect(freeCluster); // Calculate the start sector address of this new cluster 
		SectorInCache= newDirEntrySector;				// the sector in memory is this new direntry allocated 
	} 
 
	// find a free fat cluster to put the content of this new file 
	freeCluster=fatNextFreeCluster(0); 
 
	// fill with file data information 
	strcpy(string, shortName); 
	string[11]='\0'; 
	fatNormalize(string); 
 
 
	fatGetCurTime(&t); 
	time= (u_16)((t.hour)<>DT_2SECONDS_SHIFT);		// create time 
	date= (u_16)((t.year-1980)<deName), string, 11); 
	de->deAttributes= ATTR_ARCHIVE; 
	de->deLowerCase=0;   				// lowercase Names 
	de->deCHundredth= 0x00;				// hundredth of seconds in CTime 
 
	de->deCTime[0]=(u_8)time&0x00FF; 
	de->deCTime[1]=(u_8)((time&0xFF00)>>8); 
	de->deCDate[0]=(u_8)date&0x00FF; 
	de->deCDate[1]=(u_8)((date&0xFF00)>>8); 
	de->deADate[0]=de->deCDate[0];     	// access date 
	de->deADate[1]=de->deCDate[1];     	// access date 
	de->deHighClust= (u_16)(freeCluster>>16); // high bytes of starting cluster no. 
	de->deMTime[0]=de->deCTime[0];     	// last update time 
	de->deMTime[1]=de->deCTime[1];     	// last update time 
	de->deMDate[0]=de->deCDate[0];     	// last update date 
	de->deMDate[1]=de->deCDate[1];     	// last update date 
	de->deStartCluster= (u_16)freeCluster; 	// low bytes of starting cluster no. of file 
	de->deFileSize=0;  					// size of file in bytes 
 
	// write direntry with the file information 
	HAL_WriteSector( DiskIndex, newDirEntrySector, SectorBuffer); 
 
	// mark the cluster with the content off the new directory created with an END OF CLUSTER mark 
	fatWriteEOC(freeCluster); 
 
	// open the file to read and write 
	return(fatFopen(shortName)); 
} 
//***************************************************************************** 
// Function: fatNextFreeDirEntry 
// Parameters: start cluster 
// Returns: On SUSCEFULL returns the next free dir entry found, NULL otherwise 
// 
// Description:   Find a free dir entry in the directory started in cluster address 
//                If found a free dir entry, returns the address of this dir entry 
//                The SectorInCache variable will be filled with the sector address 
//              of the free dir entry found. 
//                If goes until the end of the clusters and don't found a free dir 
//              entry, returns NULL. Will be necessary alocate a new cluster 
//***************************************************************************** 
struct direntry *fatNextFreeDirEntry(u_32 cluster) 
{ 
	u_16 s,index=0; 
	u_32 sector; 
	struct direntry *de; 
 
	do 
	{ 
		sector = fatClustToSect(cluster); 
		for(s=0; s< SectorsPerCluster ; s++) 
		{ 
			HAL_ReadSector(DiskIndex, sector+s, SectorBuffer, &SectorInCache); 
			de = (struct direntry *) SectorBuffer; 
			for (index=0; indexdeName == SLOT_DELETED) || (*de->deName == 0x00)) 
					return(de); 
				de++; 
			} 
		} 
		cluster=fatNextCluster(cluster); 
		if (cluster == 0)//at the end of the chain 
			return NULL; 
    }while  (cluster <  NumClusters ); // end of FatDirentries 
 	return NULL; 
} 
 
//***************************************************************************** 
// Function: fatNextFreeCluster 
// Parameters: start cluster 
// Returns: On SUSCEFULL returns the next free cluster found, 0 otherwise 
// 
// Description: Returns the first free cluster found in Fat table. 
//              If goes until the end of the FAT table and don't found a free cluster. 
//              return 0. 
//***************************************************************************** 
u_32 fatNextFreeCluster(u_32 cluster) 
{ 
	u_16 index; 
	u_32 sector; 
	u_32 *fat32Buffer; 
	u_16 *fat16Buffer; 
 
	fat32Buffer= (u_32 *)FatCache; 
	fat16Buffer= (u_16 *)FatCache; 
 
	//Calculate the FAT LBA of this cluster no. 
	if (Fat32Enabled) 
		sector= (cluster>>7) + FirstFATSector;// 128 structures of 4 bytes each as a pointer to a cluster 
	else 
		sector= (cluster>>8) + FirstFATSector;// 256 structures of 2 bytes each as a pointer to a cluster 
 
	index=0; 
	do 
	{ 
		HAL_ReadSector( DiskIndex, sector, FatCache, &FatInCache); 
		if (Fat32Enabled) 
		{ 
			for (index=0; index < FAT32_STRUCTS_PER_SECTOR; index++) //Read all Clusters in a sector 
			{ 
				if ((fat32Buffer[index]&FAT32_MASK) == 0x00000000) 
					return (index + ((sector - FirstFATSector)*FAT32_STRUCTS_PER_SECTOR)); 
			} 
		} 
		else //FAT16 
		{ 
			for (index=0; index < FAT16_STRUCTS_PER_SECTOR; index++) //Read all Clusters in a sector  
			{ 
				if ((fat16Buffer[index]&FAT16_MASK) == 0x0000) 
				{ 
					return (index + ((sector - FirstFATSector)*FAT16_STRUCTS_PER_SECTOR)); 
				} 
					 
			} 
		} 
		sector++; 
    } 
	while  (sector < FirstFATSector+FatSectors); // end of FatDirentries 
 	return 0; 
} 
 
//***************************************************************************** 
// Function: fatLastCluster 
// Parameters: cluster 
// Returns: last cluster of the file started in cluster 
// 
// Description: Find the last cluster of a file started in "cluster" in fat table 
//***************************************************************************** 
u_32 fatLastCluster(u_32 cluster) 
{ 
	u_32 lastCluster; 
 
	do 
	{ 
		lastCluster=cluster; 
		cluster = fatNextCluster(lastCluster); 
    } 
	while  (cluster != 0); 
	return lastCluster; 
} 
 
//***************************************************************************** 
// Function: fatWrite 
// Parameters: cluster, data to write 
// Returns: none 
// 
// Description: Write the data in FAT in cluster position 
//***************************************************************************** 
void fatWrite(u_32 cluster, u_32 data) 
{ 
	u_16 offset; 
	u_32 *Fat32CacheLong, sector; 
	u_16 *Fat16CacheInt; 
 
	// calculate offset of the our entry within that FAT sector 
	if(Fat32Enabled) 
		offset = (u_16)( cluster % FAT32_STRUCTS_PER_SECTOR ); 
	else 
		offset = (u_16)( cluster % FAT16_STRUCTS_PER_SECTOR ); 
 
	// read the FAT sector, with has information about the cluster that we are interested in. 
	sector= fatTableClustToSect(cluster); 
 
	HAL_ReadSector( DiskIndex,	sector, FatCache, &FatInCache); 
 
	// write the data to Fat Cache 
	if (Fat32Enabled) 
	{ 
		Fat32CacheLong= (u_32 *)FatCache; 
		Fat32CacheLong[offset]= (Fat32CacheLong[offset]&(~FAT32_MASK)) | (data&FAT32_MASK); 
	} 
	else 
	{ 
		Fat16CacheInt= (u_16 *)FatCache; 
		Fat16CacheInt[offset]= (Fat16CacheInt[offset]&(~FAT16_MASK)) | (u_16)(data&FAT16_MASK); 
	} 
	// write Fat Cache in the NANDFlash 
	HAL_WriteSector( DiskIndex, sector, FatCache);	// FAT1 
	HAL_WriteSector( DiskIndex, sector+(FirstFAT2Sector-FirstFATSector), FatCache); // FAT2 
} 
 
//***************************************************************************** 
// Function: fatTableClustToSect 
// Parameters: cluster 
// Returns: the FAT sector address with has cluster information 
// 
// Description: Calculate the FAT sector address with has cluster information 
//***************************************************************************** 
u_32 fatTableClustToSect(u_32 cluster) 
{ 
	u_32 sector, fatOffset; 
 
	// get fat offset in bytes 
	if(Fat32Enabled) 
		fatOffset = cluster << 2; 
	else 
		fatOffset = cluster << 1; 
 
	// calculate the FAT sector that we're interested in 
	sector = FirstFATSector + (fatOffset / BYTES_PER_SECTOR); 
	return (sector); 
} 
 
//***************************************************************************** 
// Function: fatWriteEOC 
// Parameters: cluster 
// Returns: none 
// 
// Description: Write in FAT in cluster position, the END OF CLUSTER mark 
//***************************************************************************** 
void fatWriteEOC(u_32 cluster) 
{ 
	fatWrite(cluster, FAT32_MASK & CLUST_EOFE);//Justin modify 
	//fatWrite(cluster, FAT16_MASK & CLUST_EOFE); 
} 
 
//***************************************************************************** 
// Function: fatFopen 
// Parameters: File or Directory short name 
// Returns: A TFILE struct filled with the opened file information, or NULL 
//          if an error has ocurred 
// 
// Description: Open a file to read and write. The File struct is filled and 
//              the Sector Buffer in memory is filled with the first sector 
//              of the file opened 
//***************************************************************************** 
TFILE* fatFopen(char *shortName) 
{ 
	// if the file don't exist 
	if (fatGetFileInfo(&File.de, shortName) == NULL) 
		return NULL; 
 
	File.currentSector = fatClustToSect(((u_32)File.de.deHighClust << 16) + File.de.deStartCluster); 
	File.buffer=SectorBuffer; 
	File.bytePointer=0; 
	File.sectorHasChanged=FALSE; 
	HAL_ReadSector( DiskIndex, File.currentSector, File.buffer, &SectorInCache); // read the first file sector 
 
	return (&File); 
} 
 
//***************************************************************************** 
// Function: fatGetVolLavel 
// Parameters: none 
// Returns: the FAT Volume Name 
// 
// Description: Return the FAT Volume Name read in fatInit 
//***************************************************************************** 
char* fatGetVolLabel(void) 
{ 
	return VolLabel; 
} 
 
//***************************************************************************** 
// Function: fatDir 
// Parameters: initial cluster, offset(sectors) 
// Returns: On SUSCEFULL returns the sector with direntries info, otherwise 
//          returns NULL 
// 
// Description: return the sector with direntries info starting in the cluster, 
//              and with offset sectors from the begining cluster sector 
//***************************************************************************** 
u_8 *fatDir(u_32 cluster, u_32 offset) 
{ 
	u_32 index; 
 
	for (index=0; index < offset/SectorsPerCluster; index++) 
		cluster=fatNextCluster(cluster); 
 
	//Justin modify for FAT 16 , in FAT16 , cluster 0 means Root dir . 
	if (cluster == 0) 
	{ 
		if(Fat32Enabled) 
			return NULL; 
	} 
		 
 
	HAL_ReadSector(DiskIndex, fatClustToSect(cluster)+ offset%SectorsPerCluster, SectorBuffer, &SectorInCache); 
	return SectorBuffer; 
} 
 
//***************************************************************************** 
// Function: fatGetCurDirCluster 
// Parameters: none 
// Returns: The current dir cluster 
// 
// Description: Return the current directory cluster number 
//***************************************************************************** 
u_32 fatGetCurDirCluster(void) 
{ 
	return currentDirCluster; 
} 
 
 
//***************************************************************************** 
// Function: fatGetFirstDirCluster 
// Parameters: none 
// Returns: the cluster number of the first dir entry in FAT 
// 
// Description: return the first dir entry cluster in FAT 
//***************************************************************************** 
u_32 fatGetFirstDirCluster(void) 
{ 
	return(FirstDirCluster); 
} 
 
//***************************************************************************** 
// Function: fatMkdir 
// Parameters: path 
// Returns: TRUE if the path was created, otherwise FALSE 
// 
// Description: Create a new directory on the current directory 
//***************************************************************************** 
u_8 fatMkdir(char *path) 
{ 
	struct direntry *de, rde; 
	u_32 freeCluster, newDirEntrySector, lastCluster; 
	u_16 i, date, time; 
	char string[12]; 
	TTime t; 
 
	// if the file already exist 
	if (fatGetFileInfo(&rde, path) != NULL) 
	{ 
		return FALSE; 
	} 
 
	// Find a free direntry, returns a pointer to the direntry struct inside SectorBuffer, 
	de=fatNextFreeDirEntry(currentDirCluster); 
 
	// Saves the sector address of this new DirEntry to write it back to the NANDFlah 
	newDirEntrySector= SectorInCache; 
 
 
	// if goes until the end of the cluster and don't find a free direntry 
	// needs to create a new direntry in a new cluster to put this new directory. 
	if (de == NULL) 
	{ 
		freeCluster=fatNextFreeCluster(0); 	// find a new free cluster 
		if (freeCluster == 0)				// If the disk is full 
			return (FALSE);					//		return ERROR 
 
		lastCluster= fatLastCluster(currentDirCluster);	// find the last cluster of the current dir 
		fatWrite(lastCluster, freeCluster);				// creates a connection between the last cluster of the current directory and the new cluster created 
		fatWriteEOC(freeCluster);						// mark the new cluster with an END OF CLUSTER mark 
		memset (SectorBuffer, '\0', BYTES_PER_SECTOR); 	// fill the SectorBuffer with ZEROS to informate to the FAT that don't have more direntries after this one that we are creating 
		de= (struct direntry *)SectorBuffer;			// de points to the first address in the SectorBuffer 
		newDirEntrySector= fatClustToSect(freeCluster); // Calculate the start sector address of this new cluster 
		SectorInCache= newDirEntrySector;				// the sector in memory is this new direntry allocated 
		for (i=1; i< SectorsPerCluster; i++)	// write zeros in all the new cluster allocated 
			HAL_WriteSector( DiskIndex, newDirEntrySector+i, SectorBuffer); 
	} 
 
	// in this point we have a direntry in SectorBuffer, and de point to the address of the informations about the new directory 
 
 
	// find a FAT free cluster to write the directory content 
	freeCluster=fatNextFreeCluster(0); 
 
	// fill the direntry 
	strcpy(string, path); 
	string[11]='\0'; 
	 
	fatNormalize(string); 
 
	fatGetCurTime(&t); 
	time= (u_16)((t.hour)<>DT_2SECONDS_SHIFT);		// create time 
	date= (u_16)((t.year-1980)<deName), string, 11);		// name of the directory 
	de->deAttributes= ATTR_DIRECTORY; 
	de->deLowerCase=0;   	 			// lowercase Names 
	de->deCHundredth= 0x00;	 			// hundredth of seconds in CTime 
 
	de->deCTime[0]=(u_8)time&0x00FF; 
	de->deCTime[1]=(u_8)((time&0xFF00)>>8); 
	de->deCDate[0]=(u_8)date&0x00FF; 
	de->deCDate[1]=(u_8)((date&0xFF00)>>8); 
	de->deADate[0]=de->deCDate[0];     	// access date 
	de->deADate[1]=de->deCDate[1];     	// access date 
	de->deHighClust= (u_16)(freeCluster>>16); // high bytes of cluster number 
	de->deMTime[0]=de->deCTime[0];     	// last update time 
	de->deMTime[1]=de->deCTime[1];     	// last update time 
	de->deMDate[0]=de->deCDate[0];     	// last update date 
	de->deMDate[1]=de->deCDate[1];     	// last update date 
	de->deStartCluster= (u_16)freeCluster; 	// starting cluster of file 
	de->deFileSize=0;  					// size of file in bytes, is a directory, so the size is 0 
 
 
	// write SectorBuffer filled with the new directory information 
	HAL_WriteSector( DiskIndex, newDirEntrySector, SectorBuffer); 
 
 
	// create the files "." and ".." 
	de= (struct direntry *)SectorBuffer; 
	//strncpy(de->deName, ".          ", 11); 
	memcpy((u_8*)(de->deName), ".          ", 11); 
	de->deAttributes= ATTR_DIRECTORY; 
	de->deLowerCase=0;   				// lowercase Names 
	de->deCHundredth= 0x00;	 			// hundredth of seconds in CTime 
	de->deCTime[0]=(u_8)time&0x00FF; 
	de->deCTime[1]=(u_8)((time&0xFF00)>>8); 
	de->deCDate[0]=(u_8)date&0x00FF; 
	de->deCDate[1]=(u_8)((date&0xFF00)>>8);	de->deADate[0]=de->deCDate[0];     	// access date 
	de->deADate[1]=de->deCDate[1];     	// access date 
	de->deHighClust= (u_16)(freeCluster>>16); // high bytes of cluster number 
	de->deMTime[0]=de->deCTime[0];     	// last update time 
	de->deMTime[1]=de->deCTime[1];     	// last update time 
	de->deMDate[0]=de->deCDate[0];     	// last update date 
	de->deMDate[1]=de->deCDate[1];     	// last update date 
	de->deStartCluster= (u_16)freeCluster; // starting cluster of file 
	de->deFileSize=0;  					// size of file in bytes 
 
	de++; 
	//strncpy(de->deName, "..         ", 11); 
	memcpy((u_8*)(de->deName), "..         ", 11); 
	de->deAttributes= ATTR_DIRECTORY; 
	de->deLowerCase=0;   				// lowercase Names 
	de->deCHundredth= 0x00;	 			// hundredth of seconds in CTime 
	de->deCTime[0]=(u_8)time&0x00FF; 
	de->deCTime[1]=(u_8)((time&0xFF00)>>8); 
	de->deCDate[0]=(u_8)date&0x00FF; 
	de->deCDate[1]=(u_8)((date&0xFF00)>>8); 
	de->deADate[0]=de->deCDate[0];     	// access date 
	de->deADate[1]=de->deCDate[1];     	// access date 
	de->deHighClust= (u_16)(currentDirCluster>>16); // high bytes of cluster number 
	de->deMTime[0]=de->deCTime[0];     	// last update time 
	de->deMTime[1]=de->deCTime[1];     	// last update time 
	de->deMDate[0]=de->deCDate[0];     	// last update date 
	de->deMDate[1]=de->deCDate[1];     	// last update date 
	de->deStartCluster= (u_16)currentDirCluster; // starting cluster of file 
	de->deFileSize=0;  					// size of file in bytes 
	de++; 
 
	// fill the rest with zeros 
	for (i= (u_16)(((u_8 *)de) - SectorBuffer); i < 512; i++) 
		SectorBuffer[i]= 0; 
 
	// write the content of the new directory created, including "." and ".." files 
	HAL_WriteSector( DiskIndex, fatClustToSect(freeCluster), SectorBuffer); 
 
 
	// fill the entire sector buffer with zeros 
	memset (SectorBuffer, '\0', BYTES_PER_SECTOR); 
 
	// write all the others sectors of this new cluster. 
	for (i=1; i< SectorsPerCluster; i++) 
		HAL_WriteSector( DiskIndex, fatClustToSect(freeCluster)+i, SectorBuffer); 
 
	// actualize the sector address in cache 
	SectorInCache= fatClustToSect(freeCluster)+SectorsPerCluster-1; 
 
 
	// mark the cluster with the content off the new directory created with an END OF CLUSTER mark 
	fatWriteEOC(freeCluster); 
	return TRUE; 
} 
 
//***************************************************************************** 
// Function: fatFputc 
// Parameters: TFILE struct of the file opened, character to be writed 
// Returns: On SUSCEFULL returns TRUE, and FALSE otherwise 
// 
// Description: Write a character to the file. Return false if the disk is full 
//***************************************************************************** 
u_8 fatFputc(TFILE *fp, char c) 
{ 
	u_16 bufferPointer; 
	u_32 freeCluster; 
 
	bufferPointer= (u_16)(fp->bytePointer & 0x001FF); // equal (fp->bytePointer % 512) 
	fp->bytePointer++; 
 
 
	if ((fp->bytePointer != 1) && (bufferPointer == 0))	// if we need to allocate a new sector to the file 
	{ 
		HAL_WriteSector(DiskIndex, fp->currentSector, fp->buffer); 
 
		if(fp->de.deFileSize > fp->bytePointer)	// sector already exist 
		{ 
			// Next Sector is in current Cluster 
			if (fatSectToClust(fp->currentSector) == fatSectToClust(fp->currentSector+1)) 
			{ 
				fp->currentSector++; 
			} 
			else // Next Sector is in next Cluster 
			{ 
				u_32 cluster; 
 
				cluster= fatNextCluster(fatSectToClust(fp->currentSector)); 
				fp->currentSector= fatClustToSect(cluster); 
			} 
			HAL_ReadSector( DiskIndex, fp->currentSector, fp->buffer, &SectorInCache); 
		} 
		else 	// sector isn't used or the cluster isn't allocated 
		{ 
 
			if (fatSectToClust(fp->currentSector) == fatSectToClust(fp->currentSector+1))//the next sector is in current cluster 
			{ 
				fp->currentSector++; 
			} 
			else 
			{ 
				freeCluster=fatNextFreeCluster(0); 
				if (freeCluster == 0)		// if disk is full 
					return (FALSE); 
				fatWrite(fatSectToClust(fp->currentSector), freeCluster); 
				fatWriteEOC(freeCluster); 
				fp->currentSector = fatClustToSect(freeCluster); 
			} 
		} 
	} 
	fp->buffer[bufferPointer]=c; 
	fp->sectorHasChanged=TRUE; 
	if(fp->bytePointer > fp->de.deFileSize) 
		fp->de.deFileSize = fp->bytePointer; 
 
	return (TRUE); 
} 
 
//***************************************************************************** 
// Function: fatSectToClust 
// Parameters: sector 
// Returns: cluster 
// 
// Description: Converts Clusters in Sectors 
//***************************************************************************** 
u_32 fatSectToClust(u_32 sect) 
{ 
	return (((sect - FirstDataSector) / SectorsPerCluster) + 2); 
} 
 
 
//***************************************************************************** 
// Function: fatFflush 
// Parameters: TFILE struct of the file to be flushed 
// Returns: TRUE if the file was corrected flushed, and FALSE otherwise 
// 
// Description: write current sector file to hard disk if necessary 
//***************************************************************************** 
u_8 fatFflush(TFILE *fp) 
{ 
	if (fp->sectorHasChanged) 
	{ 
		HAL_WriteSector( DiskIndex, fp->currentSector, fp->buffer); 
		fp->sectorHasChanged=FALSE; 
	} 
	return TRUE; 
} 
 
//***************************************************************************** 
// Function: fatFseek 
// Parameters: TFILE struct of the file opened, offSet, seek mode 
// Returns: On SUSCEFULL returns TRUE, and FALSE otherwise 
// 
// Description: find a byte position in the file and load the corresponded sector in buffer 
//              Modes: SEEK_CUR: from the current position of the file pointer; 
//                     SEEK_SET: from the beggining of the file 
//                     SEEK_END: from the end of file to back. 
//***************************************************************************** 
u_8 fatFseek(TFILE *fp, u_32 offSet, u_8 mode) 
{ 
 
	u_32 numClusters, curCluster, numSector; 
 
	// calculate the new byte pointer 
	switch (mode) 
	{ 
		case SEEK_END: fp->bytePointer= fp->de.deFileSize - offSet;	break; 
		case SEEK_SET: fp->bytePointer= offSet;                     break; 
		case SEEK_CUR: fp->bytePointer= fp->bytePointer + offSet;   break; 
		default: return FALSE; 
	} 
 
	// calculate the current file cluster 
	curCluster=((u_32)fp->de.deHighClust<<16)+(fp->de.deStartCluster); 
	numClusters=fp->bytePointer/(BYTES_PER_SECTOR*SectorsPerCluster); 
	numSector=(fp->bytePointer/BYTES_PER_SECTOR)%SectorsPerCluster; 
 
	// calculate the cluster address of the new byte pointer 
	while (numClusters > 0) 
	{ 
		curCluster=fatNextCluster(curCluster); 
		numClusters--; 
	} 
 
	// calculate the Sector address of the new byte pointer 
	fp->currentSector=fatClustToSect(curCluster) + numSector; 
 
	// read that sector 
	HAL_ReadSector( DiskIndex, fp->currentSector, fp->buffer, &SectorInCache); 
 
	return TRUE; 
} 
 
 
//***************************************************************************** 
// Function: fatFgetc 
// Parameters: TFILE struct of the file opened 
// Returns: On SUSCEFULL returns the next character from file, and 0 otherwise 
// 
// Description: Get the next character from file, and actualize the byte pointer 
//***************************************************************************** 
char fatFgetc(TFILE *fp) 
{ 
	u_16 bufferPointer; 
 
	if (fatFeof(fp))	// if is the end of file 
		return 0; 
 
 
	bufferPointer= (u_16)(fp->bytePointer & 0x001FF); // equal (fp->bytePointer % 512) 
	fp->bytePointer++; 
 
 
	//if(fp->bytePointer == 1) , it means reading first char after fopen , 
	//when fopen , it has read the first file sector into fp->buffer. 
	//if(bufferPointer == 0) , it means that the next char is in next sector . 
	if ((fp->bytePointer == 1) || (bufferPointer != 0)) 
	{ 
		return(fp->buffer[bufferPointer]); 
	} 
	else 
	{ 
		// Next Sector is in current Cluster 
		if (fatSectToClust(fp->currentSector) == fatSectToClust(fp->currentSector+1)) 
		{ 
			fp->currentSector++; 
		} 
		else // Next Sector is in next Cluster 
		{ 
			u_32 cluster; 
 
			cluster= fatNextCluster(fatSectToClust(fp->currentSector)); 
			fp->currentSector= fatClustToSect(cluster); 
		} 
		HAL_ReadSector( DiskIndex, fp->currentSector, fp->buffer, &SectorInCache); 
		return(fp->buffer[bufferPointer]); 
	} 
} 
 
//***************************************************************************** 
// Function: fatFeof 
// Parameters: TFILE struct of the file opened 
// Returns: On END OF FILE returns TRUE, and FALSE otherwise 
// 
// Description: return TRUE if the byte pointer points to the end of the file 
//***************************************************************************** 
u_8 fatFeof(TFILE *fp) 
{ 
	if ((fp->bytePointer) >= (fp->de.deFileSize)) 
		return TRUE; 
	return FALSE; 
} 
 
 
 
//***************************************************************************** 
// Function: fatFclose 
// Parameters: TFILE struct of the file to be closed 
// Returns: TRUE if the file was corrected closed, and FALSE otherwise 
// 
// Description: write current file to the FAT file system 
//              refresh the file size 
//***************************************************************************** 
u_8 fatFclose(TFILE *fp) 
{ 
	struct direntry *de, rde; 
	u_32 fileSize; 
	u_16 date, time; 
	TTime t; 
 
	fileSize= fp->de.deFileSize; 
	fp->bytePointer=0; 
	if (fatFflush(fp)) 
	{ 
		if ((de=fatGetFileInfo(&rde, (char*)(fp->de.deName))) == NULL) // if the file don't exist 
			return FALSE; 
		de->deFileSize= fileSize; // refresh the file size ?? 
		fatGetCurTime(&t); 
		time= (u_16)((t.hour)<>DT_2SECONDS_SHIFT);		// create time 
		date= (u_16)((t.year-1980)<deMTime[0]=(u_8)time&0x00FF;			// last update time 
		de->deMTime[1]=(u_8)((time&0xFF00)>>8);	// last update time 
		de->deMDate[0]=(u_8)date&0x00FF;			// last update date 
		de->deMDate[1]=(u_8)((date&0xFF00)>>8);	// last update date 
		de->deADate[0]=de->deMDate[0];     					// access date 
		de->deADate[1]=de->deMDate[1];     					// access date 
 
 
		HAL_WriteSector( DiskIndex, SectorInCache, SectorBuffer); 
 
		 
		HAL_ReadSector( DiskIndex, FSInfo, SectorBuffer, &SectorInCache); // Read FSInfo 
		((struct fsinfo *)SectorBuffer)->fsinfree[0]=0xFF; // change to Operation System don't to try to correct this field and the FAT 
		((struct fsinfo *)SectorBuffer)->fsinfree[1]=0xFF; 
		((struct fsinfo *)SectorBuffer)->fsinfree[2]=0xFF; 
		((struct fsinfo *)SectorBuffer)->fsinfree[3]=0xFF; 
 
		((struct fsinfo *)SectorBuffer)->fsinxtfree[0]=0xFF; 
		((struct fsinfo *)SectorBuffer)->fsinxtfree[1]=0xFF; 
		((struct fsinfo *)SectorBuffer)->fsinxtfree[2]=0xFF; 
		((struct fsinfo *)SectorBuffer)->fsinxtfree[3]=0xFF; 
		HAL_WriteSector( DiskIndex, SectorInCache, SectorBuffer); 
		 
		 
		return(TRUE); 
	} 
	return (FALSE); 
} 
 
//***************************************************************************** 
// Function: fatCddir 
// Parameters: path 
// Returns: On SUSCEFULL returns TRUE, otherwise returns FALSE 
// 
// Description: Change the current directory. Only one level path 
//              ex: cd \test 
//              cd \test\test2  IS INVALID, use cd \test cd\test2 instead 
//***************************************************************************** 
u_8 fatCddir(char *path) 
{ 
	struct direntry de; 
 
	// if the path doesn't exist return FALSE 
	if (fatGetFileInfo(&de, path) == NULL) 
		return FALSE; 
 
	// if the path is a directory 
	if ((de.deAttributes & ATTR_DIRECTORY) == ATTR_DIRECTORY) 
	{ 
		// change the current dir cluster to the path information 
		currentDirCluster= (de.deStartCluster) + ((unsigned long)de.deHighClust<<16); 
		//Justin modify for FAT16 
		if (currentDirCluster == 0 && Fat32Enabled) 
			currentDirCluster = 2; 
		return TRUE; 
	} 
	return FALSE; 
} 
 
//***************************************************************************** 
// Function: fatRename 
// Parameters: old name, new name 
// Returns: TRUE if the name was chanched, otherwise FALSE 
// 
// Description: Change the name of a directory or file 
//***************************************************************************** 
u_8 fatRename(char *oldShortName, char *newShortName) 
{ 
	struct direntry *de, rde; 
	char string[12]; 
 
	// if the new file name already exist 
	de=fatGetFileInfo(&rde, newShortName); 
	if (de != NULL) 
		return FALSE; 
 
	// if the file don't exist 
	de=fatGetFileInfo(&rde, oldShortName); 
	if (de == NULL) 
		return FALSE; 
 
 
	strcpy(string, newShortName); 
	string[11]='\0'; 
	fatNormalize(string); 
	memcpy((u_8*)(de->deName), string, 11); 
	HAL_WriteSector( DiskIndex, SectorInCache, SectorBuffer); 
	return TRUE; 
 
} 
 
//***************************************************************************** 
// Function: fatRemoveAll 
// Parameters: none 
// Returns: none 
// 
// Description: Remove all files in currentDirCluster 
//***************************************************************************** 
void fatRemoveAll(void) 
{ 
	u_32 offset=0; 
	struct direntry *de = 0;	// avoid compiler warning by initializing 
	s_16 index; 
 
	for (offset=0; ; offset++) 
	{ 
		de = (struct direntry *) fatDir(currentDirCluster, offset); 
		if (de == NULL) 
			return; 
		for (index=0; indexdeName == SLOT_EMPTY) 
				return;		// there is no more direntries 
 
			if (( de->deAttributes & ATTR_VOLUME ) != ATTR_VOLUME) 
				if ((*de->deName != SLOT_DELETED) && (*de->deName != '.')) 
					fatRemove((char*)(de->deName)); 
			de++; 
		}	// end of sector 
	}	// end of cluster 
} 
 
//***************************************************************************** 
// Function: fatRemove 
// Parameters: File or Directory short name 
// Returns: TRUE if the file was removed, otherwise FALSE 
// 
// Description: remove a file or directory 
//***************************************************************************** 
u_8 fatRemove(char *shortName) 
{ 
	struct direntry *de, rde; 
	u_32 CurrentDirCluster, NextCluster, fileSector; 
 
 
	de=fatGetFileInfo(&rde, shortName);	// get file information 
	if (de == NULL)						// if the file doesn't exist 
		return FALSE;					//	 	return ERROR 
 
	fileSector=SectorInCache;			// save the File sector address 
 
	// calculate the cluster address of this file 
	CurrentDirCluster = ((u_32)de->deHighClust << 16) + de->deStartCluster; 
 
	// if the file is a directory 
	if ( de->deAttributes == ATTR_DIRECTORY ) 
	{ 
		if (!fatDirectoryIsEmpty(CurrentDirCluster))	// if there are files in the directory 
			return FALSE;								//		return ERROR 
	} 
 
	// Read the direntry information about the file 
	HAL_ReadSector( DiskIndex, fileSector, SectorBuffer, &SectorInCache); 
 
	// mark the file name as deleted 
	*de->deName = SLOT_DELETED; 
 
	// write the direntry back to the NANDFlash 
	HAL_WriteSector( DiskIndex, SectorInCache, SectorBuffer); 
 
	// erase fat table 
	do{ 
		NextCluster=fatNextCluster(CurrentDirCluster); 
		fatWrite(CurrentDirCluster,CLUST_FREE);	// free the current dir cluster 
		CurrentDirCluster=NextCluster; 
	}while( NextCluster != 0 ); 
 
	//file erased 
	return TRUE; 
} 
 
//***************************************************************************** 
// Function: fatDirectoryIsEmpty 
// Parameters: Start Directory Cluster 
// Returns: TRUE if the directory is empty, FALSE otherwise 
// 
// Description: check to the existance of files in the directory started in DirCluster 
//***************************************************************************** 
u_8 fatDirectoryIsEmpty(u_32 DirCluster) 
{ 
	struct direntry *de; 
	u_32 sector, isector; 
	s_16 index; 
 
	do 
	{ 
		sector=fatClustToSect(DirCluster);	//read directory clusters 
		for (isector=0; isector < SectorsPerCluster ;isector++)	// read one cluster 
		{ 
			HAL_ReadSector( DiskIndex, sector + isector, SectorBuffer, &SectorInCache); 
			de= (struct direntry *)SectorBuffer; 
			for (index=0; indexdeName != '.' ) 
				{ 
					if ( *de->deName == SLOT_EMPTY ) 
						return TRUE; 
					if ( *de->deName != SLOT_DELETED) 
						return FALSE; 
				} 
				// If goes until here it's because de->Name is equal '.' or is equal SLOT_DELETED 
				de++; 
			} 
		} 
		DirCluster=fatNextCluster(DirCluster); 
	}while ( DirCluster != 0 ); 
	// if goes until here it's because the all file (directory) is filled with SLOT_DELETED 
	return  TRUE; 
} 
 
//***************************************************************************** 
// Function: fatGetPartInfo 
// Parameters: none 
// Returns: FAT partition information 
// 
// Description: return the partition information read in fatInit routine 
//***************************************************************************** 
struct partrecord *fatGetPartInfo(void) 
{ 
	return (&PartInfo); 
} 
 
//***************************************************************************** 
// Justin added on 20060517 
// Function: fatFread 
// Parameters: buffer is address of BUFFER to be write into, size is the size of BUFFER , TFILE struct of the file opened 
// Returns: On SUSCEFULL returns the size has been read, and 0 otherwise 
// 
// Description: Get the datas from file and write into BUFFER , and actualize the byte pointer 
//***************************************************************************** 
u_16 fatFread(u_8* buffer,u_16 size,TFILE *fp) 
{ 
	u_16 buffer_idx = 0; 
 
	if (fatFeof(fp))	// if is the end of file 
		return 0; 
	if(!size) 
		return 0; 
 
	while(buffer_idx < size) 
	{ 
		//if(fp->bytePointer == 0) , it means reading first char after fopen , 
		//when fopen , it has read the first file sector into fp->buffer. 
		if (fp->bytePointer != 0 && (fp->bytePointer%512 == 0)) 
		{ 
			// Next Sector is in current Cluster 
			if (fatSectToClust(fp->currentSector) == fatSectToClust(fp->currentSector+1)) 
			{ 
				fp->currentSector++; 
			} 
			else // Next Sector is in next Cluster 
			{ 
				u_32 cluster; 
				cluster= fatNextCluster(fatSectToClust(fp->currentSector)); 
				fp->currentSector= fatClustToSect(cluster); 
			} 
			//Fill one sector into SectorBuffer(fp->buffer) 
			HAL_ReadSector( DiskIndex, fp->currentSector, fp->buffer, &SectorInCache); 
		} 
 
		if(buffer_idx+512 <= size)//buffer's empty size is enough to fill 512 byte data 
		{ 
			if((fp->bytePointer + 512) >= (fp->de.deFileSize))//arriving EOF  
			{ 
				u_16 len; 
				if((fp->de.deFileSize - fp->bytePointer) > (512 - fp->bytePointer%512)) 
					len = (u_16)(512 - fp->bytePointer%512); 
				else 
					len = (u_16)(fp->de.deFileSize - fp->bytePointer); 
				 
				memcpy((buffer+buffer_idx), &(fp->buffer[fp->bytePointer%512]), len); 
				buffer_idx += len; 
				fp->bytePointer += len; 
 
				if(fp->bytePointer == fp->de.deFileSize) 
					break; 
			 
			} 
			else 
			{ 
				u_16 len = (u_16)(512-(fp->bytePointer%512)); 
				memcpy((buffer+buffer_idx), &(fp->buffer[fp->bytePointer%512]), len); 
				buffer_idx += len; 
				fp->bytePointer += len; 
			} 
		} 
		else 
		{ 
			if((fp->bytePointer + (size-buffer_idx)) >= (fp->de.deFileSize))//arriving EOF  
			{ 
				u_16 len; 
				if((fp->de.deFileSize - fp->bytePointer) > (512 - fp->bytePointer%512)) 
					len = (u_16)(512 - fp->bytePointer%512); 
				else 
					len = (u_16)(fp->de.deFileSize - fp->bytePointer); 
				 
				memcpy((buffer+buffer_idx), &(fp->buffer[fp->bytePointer%512]), len); 
				buffer_idx += len; 
				fp->bytePointer += len; 
				 
				if(fp->bytePointer == fp->de.deFileSize) 
					break; 
				 
			} 
			else 
			{ 
				u_16 len; 
				if((size - buffer_idx) > (u_16)(512 - fp->bytePointer%512))//arriving end of sector , the remainder sector datas is larger than the buffer empty size. 
					len = (u_16)(512 - fp->bytePointer%512); 
				else 
					len = (u_16)(size - buffer_idx); 
 
				memcpy((buffer+buffer_idx), &(fp->buffer[fp->bytePointer%512]), len); 
				buffer_idx += len; 
				fp->bytePointer += len; 
 
				break; 
			} 
 
			 
			 
		} 
	} 
 
	return buffer_idx; 
	 
	 
} 
 
#if 0 
u_16 fatFread(u_8* buffer,u_16 size,TFILE *fp) 
{ 
 
	if (fatFeof(fp))	// if is the end of file 
		return 0; 
 
 
	//if(fp->bytePointer == 0) , it means reading first char after fopen , 
	//when fopen , it has read the first file sector into fp->buffer. 
	if (fp->bytePointer != 0) 
	{ 
 
		// Next Sector is in current Cluster 
		if (fatSectToClust(fp->currentSector) == fatSectToClust(fp->currentSector+1)) 
		{ 
			fp->currentSector++; 
		} 
		else // Next Sector is in next Cluster 
		{ 
			u_32 cluster; 
 
			cluster= fatNextCluster(fatSectToClust(fp->currentSector)); 
			fp->currentSector= fatClustToSect(cluster); 
		} 
		HAL_ReadSector( DiskIndex, fp->currentSector, fp->buffer, &SectorInCache); 
 
	} 
 
	if((fp->bytePointer + 512) > (fp->de.deFileSize)) 
	{ 
		memcpy(buffer, &(fp->buffer[0]), (fp->de.deFileSize % 512)); 
		fp->bytePointer = fp->de.deFileSize; 
		return (fp->de.deFileSize % 512); 
	} 
	else 
	{ 
		memcpy(buffer, &(fp->buffer[0]), 512); 
		fp->bytePointer += 512; 
		return 512; 
	} 
} 
#endif