Subversion Repositories NaviCtrl

Compare Revisions

Ignore whitespace Rev 210 → Rev 211

/trunk/fat16.c
61,12 → 61,11
#include "sdc.h"
#include "uart1.h"
 
 
//________________________________________________________________________________________________________________________________________
// Module name: fat16.c
// Compiler used: avr-gcc 3.4.5
// Last Modifikation: 16.06.2008
// Version: 2.00
// Last Modifikation: 20.03.2010
// Version: 2.10
// Authors: Stephan Busker & Gregor Stobrawa
// Description: Source files for FAT16 implementation with read and write-access
// Copyright (C) 2008 Stephan Busker & Gregor Stobrawa
73,8 → 72,10
//........................................................................................................................................
// Functions: extern s16 Fat16_Init(void);
// extern s16 Fat16_Deinit(void);
// extern s8* FAT16_GetVolumeLabel(void);
// extern File_t * fopen_(const u8 *filename, const s8 mode);
// extern s16 fclose_(File_t *File);
// extern u8 fexist_(s8 * const filename);
// extern s16 fflush_(File_t *File);
// extern s16 fseek_(File_t *File, s32 offset, s16 origin);
// extern s16 fgetc_(File_t *File);
83,6 → 84,7
// extern u32 fwrite_(void *buffer, u32 size, u32 count, File_t *File);
// extern s16 fputs_(const u8 *string, File_t *File);
// extern u8 * fgets_(u8 *string, s16 length, File_t *File);
// extern u8 feof_(File_t * const file);
//........................................................................................................................................
// ext. functions: extern SD_Result_t SDC_Init(void;)
// extern SD_Result_t SDC_Deinit(void);
230,8 → 232,14
s8 Name[8]; // 8 bytes name, padded with spaces.
u8 Extension[3]; // 3 bytes extension, padded with spaces.
u8 Attribute; // attribute of the directory entry (unused,archive,read-only,system,directory,volume)
u8 Reserved[10]; // reserved bytes within the directory entry.
u32 DateTime; // date and time of last write access to the file or directory.
u8 Res1; // should be zero
u8 CreationTime10ms; // subsecond resolution of creation time
u16 CreationTime; // Time of creation h:m:s
u16 CreationDate; // Date of creation Y.M.D
u16 LastAccessDate; // The date where the file was last accessed
u8 Res2[2]; // should be zero
u16 ModTime; // date of last write access
u16 ModDate; // date of last write access to the file or directory.
u16 StartCluster; // first cluster of the file or directory.
u32 Size; // size of the file or directory in bytes.
} __attribute__((packed)) DirEntry_t;
284,6 → 292,9
#define FAT16_BYTES 2
#define FAT16_ENTRIES_PER_SECTOR BYTES_PER_SECTOR/FAT16_BYTES
 
#define SECTOR_UNDEFINED 0x00000000L
#define CLUSTER_UNDEFINED 0x0000
 
#define FSTATE_UNUSED 0
#define FSTATE_USED 1
 
307,28 → 318,44
 
 
/****************************************************************************************************************************************/
/* Function: FileDateTime(DateTime_t *); */
/* Function: FileDate(DateTime_t *); */
/* */
/* Description: This function calculates the DOS date time from a pointer to a time structure. */
/* Description: This function calculates the DOS date from a pointer to a time structure. */
/* */
/* Returnvalue: Returns the DOS date time. */
/* Returnvalue: Returns the DOS date. */
/****************************************************************************************************************************************/
u16 FileDate(DateTime_t * pTimeStruct)
{
u16 date = 0;
if(pTimeStruct == NULL) return date;
if(!(pTimeStruct->Valid)) return date;
 
u32 FileDateTime(DateTime_t * pTimeStruct)
date |= (0x007F & (u16)(pTimeStruct->Year - 1980))<<9; // set year
date |= (0x000F & (u16)(pTimeStruct->Month))<<5; // set month
date |= (0x001F & (u16)(pTimeStruct->Day));
return date;
}
 
/****************************************************************************************************************************************/
/* Function: FileTime(DateTime_t *); */
/* */
/* Description: This function calculates the DOS time from a pointer to a time structure. */
/* */
/* Returnvalue: Returns the DOS time. */
/****************************************************************************************************************************************/
 
u16 FileTime(DateTime_t * pTimeStruct)
{
u32 datetime = 0;
if((pTimeStruct == 0) || !(pTimeStruct->Valid)) return datetime;
u16 time = 0;
if(pTimeStruct == NULL) return time;
if(!(pTimeStruct->Valid)) return time;
 
datetime |= (0x0000007FL & (u32)(pTimeStruct->Year - 1980))<<25; // set year
datetime |= (0x0000000FL & (u32)(pTimeStruct->Month))<<21; // set month
datetime |= (0x0000001FL & (u32)(pTimeStruct->Day))<<16;
datetime |= (0x0000001FL & (u32)(pTimeStruct->Hour))<<11;
datetime |= (0x0000003FL & (u32)(pTimeStruct->Min))<<5;
datetime |= (0x0000001FL & (u32)(pTimeStruct->Sec/2));
return datetime;
time |= (0x001F & (u16)(pTimeStruct->Hour))<<11;
time |= (0x003F & (u16)(pTimeStruct->Min))<<5;
time |= (0x001F & (u16)(pTimeStruct->Sec/2));
return time;
}
 
 
/****************************************************************************************************************************************/
/* Function: LockFilePointer(); */
/* */
368,16 → 395,15
if(&FilePointer[cnt] == file) // filepointer to be freed found?
{
file->State = FSTATE_UNUSED;
file->FirstSectorOfFirstCluster = 0; // Sectorpointer to the first sector of the first datacluster of the file.
file->FirstSectorOfCurrCluster = 0;
file->SectorOfCurrCluster = 0; // Pointer to the cluster which is edited at the moment.
file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED; // Sectorpointer to the first sector of the first datacluster of the file.
file->FirstSectorOfCurrCluster = SECTOR_UNDEFINED; // Pointer to the cluster which is edited at the moment.
file->SectorOfCurrCluster = 0; // The sector which is edited at the moment (cluster_pointer + sector_index).
file->ByteOfCurrSector = 0; // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
file->Mode = 0; // mode of fileoperation (read,write)
file->Size = 0; // the size of the opend file in bytes.
file->Position = 0; // pointer to a character within the file 0 < fileposition < filesize
file->SectorInCache = 0; // the last sector read, wich is still in the sectorbuffer.
file->DirectorySector = 0; // the sectorposition where the directoryentry has been made.
file->SectorInCache = SECTOR_UNDEFINED; // the last sector read, wich is still in the sectorbuffer.
file->DirectorySector = SECTOR_UNDEFINED; // the sectorposition where the directoryentry has been made.
file->DirectoryIndex = 0; // the index to the directoryentry within the specified sector.
file->Attribute = 0; // the attribute of the file opened.
file = NULL;
462,9 → 488,15
/****************************************************************************************************************************************/
u32 Fat16ClusterToSector(u16 cluster)
{
if(!Partition.IsValid) return 0;
if (cluster < 2) cluster = 2; // the 0. and 1. cluster in the fat are used for the media descriptor
return ( (cluster - 2) * Partition.SectorsPerCluster) + Partition.FirstDataSector; // the first data sector is represented by the 2nd cluster
if(!Partition.IsValid) return SECTOR_UNDEFINED;
if (cluster < 2)
{
return SECTOR_UNDEFINED;
}
else
{
return ( (cluster - 2) * Partition.SectorsPerCluster) + Partition.FirstDataSector; // the first data sector is represented by the 2nd cluster
}
}
 
/****************************************************************************************************************************************/
477,8 → 509,9
/****************************************************************************************************************************************/
u16 SectorToFat16Cluster(u32 sector)
{
if(!Partition.IsValid) return 0;
return ((u16)((sector - Partition.FirstDataSector) / Partition.SectorsPerCluster) + 2);
if(!Partition.IsValid) return CLUSTER_UNDEFINED;
if((sector == SECTOR_UNDEFINED) || (sector < Partition.FirstDataSector)) return CLUSTER_UNDEFINED;
else return ((u16)((sector - Partition.FirstDataSector) / Partition.SectorsPerCluster) + 2);
}
 
 
514,6 → 547,7
{
returnvalue += fclose_(&FilePointer[cnt]); // try to close open file pointers
}
else UnlockFilePointer(&FilePointer[cnt]);
 
}
SDC_Deinit(); // uninitialize interface to sd-card
546,12 → 580,12
// declare the filepointers as unused.
for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
{
FilePointer[cnt].State = FSTATE_UNUSED;
UnlockFilePointer(&FilePointer[cnt]);
}
// set current file pinter to first position in list
file = &FilePointer[0];
 
// try to initialise the sd-card.
// try to initialize the sd-card.
if(SD_SUCCESS != SDC_Init())
{
UART1_PutString("SD-Card could not be initialized.");
649,6 → 683,7
if((!Partition.IsValid) || (file == NULL)) return(0);
 
for(i = 0; i < BYTES_PER_SECTOR; i++) file->Cache[i] = 0; // clear file cache
if(file->FirstSectorOfCurrCluster == SECTOR_UNDEFINED) return (0); // nothing to do
for(i = 0; i < Partition.SectorsPerCluster; i++)
{
file->SectorInCache = file->FirstSectorOfCurrCluster + i;
670,11 → 705,12
/*****************************************************************************************************************************************/
u16 GetNextCluster(File_t * file)
{
u16 cluster = 0;
u16 cluster = CLUSTER_UNDEFINED;
u32 fat_byte_offset, sector, byte;
Fat16Entry_t * fat;
 
if((!Partition.IsValid) || (file == NULL)) return(cluster);
if(file->FirstSectorOfCurrCluster == SECTOR_UNDEFINED) return(cluster);
// if sector is within the data area
if((Partition.FirstDataSector <= file->FirstSectorOfCurrCluster)&& (file->FirstSectorOfCurrCluster <= Partition.LastDataSector))
{
699,10 → 735,10
// read the next cluster from cache
fat = (Fat16Entry_t *)(&(file->Cache[byte]));
cluster = fat->NextCluster;
// if last cluster fat entry
// if no next cluster exist
if(FAT16_CLUSTER_LAST_MIN <= cluster)
{
cluster = 0;
cluster = CLUSTER_UNDEFINED; // next cluster is undefined
}
else
{
727,7 → 763,7
u32 fat_sector; // current sector within the fat relative to the first sector of the fat.
u32 curr_sector; // current sector
u16 fat_entry; // index to an fatentry within the actual sector (256 fatentries are possible within one sector).
u16 free_cluster = 0; // next free cluster number.
u16 free_cluster = CLUSTER_UNDEFINED; // next free cluster number.
Fat16Entry_t * fat;
 
if((!Partition.IsValid) || (file == NULL)) return(0);
772,7 → 808,7
/* */
/* Description: This function sets the pointer of the stream relative to the position */
/* specified by origin (SEEK_SET, SEEK_CUR, SEEK_END) */
/* Returnvalue: Is 1 if seek was successful */
/* Returnvalue: Is 0 if seek was successful */
/****************************************************************************************************************************************************/
s16 fseek_(File_t *file, s32 offset, s16 origin)
{
779,7 → 815,7
s32 fposition = 0;
s16 retvalue = 1;
 
if((!Partition.IsValid) || (file == NULL)) return(0);
if((!Partition.IsValid) || (file == NULL)) return(retvalue);
switch(origin)
{
case SEEK_SET: // Fileposition relative to the beginning of the file.
803,7 → 839,7
file->SectorOfCurrCluster = 0;
file->ByteOfCurrSector = 0;
file->Position = 0;
 
if(file->FirstSectorOfCurrCluster == SECTOR_UNDEFINED) return(retvalue);
while(file->Position < fposition) // repeat until the current position is less than target
{
file->Position++; // increment file position
820,7 → 856,7
}
else // the last cluster was allready reached
{
file->SectorOfCurrCluster--; // jump back to the ast sector in the last cluster
file->SectorOfCurrCluster--; // jump back to the last sector in the last cluster
file->ByteOfCurrSector = BYTES_PER_SECTOR; // set ByteOfCurrSector one byte over sector end
}
}
847,10 → 883,11
u32 sector_in_buffer = 0;
u8 repeat = 0;
 
if(!Partition.IsValid) return 0;
if(!Partition.IsValid) return(0);
if(StartCluster == CLUSTER_UNDEFINED) return(0);
cluster = StartCluster; // init chain trace
// if start cluster is equal to the last cluster we are done
if(FAT16_CLUSTER_LAST_MIN <= cluster) return 1;
// if start cluster is no real cluster
if(FAT16_CLUSTER_LAST_MIN <= cluster) return 1;
 
// calculate byte offset in the fat for corresponding entry
fat_byte_offset = ((u32)cluster)<<1; // two FAT bytes (16 bits) for every cluster
869,16 → 906,20
// read the next cluster from cache
fat = (Fat16Entry_t *)(&(buffer[byte]));
cluster = fat->NextCluster;
if((FAT16_CLUSTER_USED_MIN <= cluster) && (cluster <= FAT16_CLUSTER_USED_MAX) ) repeat = 1;
fat->NextCluster = FAT16_CLUSTER_FREE; // mark current cluster as free
 
if((FAT16_CLUSTER_USED_MIN <= cluster) && (cluster <= FAT16_CLUSTER_USED_MAX) )
{
repeat = 1;
// calculate sector byte and byte offset in the fat for the next cluster
fat_byte_offset = ((u32)cluster)<<1; // two FAT bytes (16 bits) for every cluster
// calculate the sector that contains the current cluster within the fat
sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
// calculate byte offset of the current cluster within that fat sector
byte = fat_byte_offset % BYTES_PER_SECTOR;
}
else repeat = 0;
 
fat->NextCluster = FAT16_CLUSTER_FREE; // mark current cluster as free
// calculate byte offset in the fat for corresponding entry
fat_byte_offset = ((u32)cluster)<<1; // two FAT bytes (16 bits) for every cluster
// calculate the sector that contains the current cluster within the fat
sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
// calculate byte offset of the current cluster within that fat sector
byte = fat_byte_offset % BYTES_PER_SECTOR;
// if new sector is not the sector in buffer or the last cluster in the chain was traced
if((sector != sector_in_buffer) || !repeat)
{ // write sector in buffer
885,7 → 926,7
if(SD_SUCCESS != SDC_PutSector(sector_in_buffer,buffer))
{
Fat16_Deinit();
return 0;
return(0);
}
}
}
900,11 → 941,11
/* */
/* Description: This function looks in the fat to find the next free cluster and appends it to the file. */
/* */
/* Returnvalue: The function returns the appened cluster number or 0 of no cluster was appended. */
/* Returnvalue: The function returns the appened cluster number or CLUSTER_UNDEFINED of no cluster was appended. */
/****************************************************************************************************************************************/
u16 AppendCluster(File_t *file)
{
u16 last_cluster, new_cluster = 0;
u16 last_cluster, new_cluster = CLUSTER_UNDEFINED;
u32 fat_byte_offset, sector, byte;
Fat16Entry_t * fat;
 
911,30 → 952,65
if((!Partition.IsValid) || (file == NULL)) return(new_cluster);
 
new_cluster = FindNextFreeCluster(file); // the next free cluster found on the disk.
if(new_cluster)
if(new_cluster != CLUSTER_UNDEFINED)
{ // A free cluster was found and can be added to the end of the file.
fseek_(file, 0, SEEK_END); // jump to the end of the file
last_cluster = SectorToFat16Cluster(file->FirstSectorOfCurrCluster); // determine current file cluster
fat_byte_offset = ((u32)last_cluster)<<1;
sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
byte = fat_byte_offset % BYTES_PER_SECTOR;
 
if(file->SectorInCache != sector)
if(last_cluster != CLUSTER_UNDEFINED)
{
file->SectorInCache = sector; // update sector stored in buffer
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache)) // read sector from sd-card
// update FAT entry of last cluster
fat_byte_offset = ((u32)last_cluster)<<1;
sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
byte = fat_byte_offset % BYTES_PER_SECTOR;
// read the sector containing the last cluster of the file
if(file->SectorInCache != sector)
{
file->SectorInCache = sector; // update sector stored in buffer
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache)) // read sector from sd-card
{
Fat16_Deinit();
return(0);
}
}
fat = (Fat16Entry_t *)(&(file->Cache[byte]));
fat->NextCluster = new_cluster; // append the free cluster to the end of the file in the FAT.
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache)) // save the modified sector to the FAT.
{
Fat16_Deinit();
return(0);
return(0);
}
}
fat = (Fat16Entry_t *)(&(file->Cache[byte]));
fat->NextCluster = new_cluster; // append the free cluster to the end of the file in the FAT.
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache)) // save the modified sector to the FAT.
{
Fat16_Deinit();
return(0);
else // last cluster of the file is undefined
{ // then the new cluster must be the first one of the file
// and its cluster number must be set in the direntry
DirEntry_t * dir;
file->SectorInCache = file->DirectorySector; // update the sector number of file cache.
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
{
Fat16_Deinit();
return(CLUSTER_UNDEFINED);
}
dir = (DirEntry_t *)file->Cache; // set pointer to directory
dir[file->DirectoryIndex].Res1 = 0;
dir[file->DirectoryIndex].Res2[0] = 0;
dir[file->DirectoryIndex].Res2[1] = 0;
dir[file->DirectoryIndex].StartCluster = new_cluster; // update startcluster
dir[file->DirectoryIndex].ModTime = FileTime(&SystemTime);// set time
dir[file->DirectoryIndex].ModDate = FileDate(&SystemTime);// and date of modification
dir[file->DirectoryIndex].LastAccessDate = dir[file->DirectoryIndex].ModDate;
dir[file->DirectoryIndex].Size = 0;
// write sector containing the direntry
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
{
Fat16_Deinit();
return(CLUSTER_UNDEFINED);
}
// update file info
file->FirstSectorOfFirstCluster = Fat16ClusterToSector(new_cluster);
file->Size = 0;
file->Position = 0;
}
// update file pointes
file->FirstSectorOfCurrCluster = Fat16ClusterToSector(new_cluster);
file->SectorOfCurrCluster = 0;
file->ByteOfCurrSector = 0;
966,9 → 1042,9
// a corresponding dir entry with adir-flag set in its attribute
// or direct within the root directory area
 
file->FirstSectorOfFirstCluster = 0;
file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;
// no current directory exist therefore assume searching in the root
if(file->DirectorySector == 0)
if(file->DirectorySector == SECTOR_UNDEFINED)
{
max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
985,7 → 1061,7
}
else return (direntry_exist); // bad sector range for directory sector of the file
// if search area is not defined yet
if(file->FirstSectorOfFirstCluster == 0)
if(file->FirstSectorOfFirstCluster == SECTOR_UNDEFINED)
{
// check if the directory entry of current file is existent and has the dir-flag set
file->SectorInCache = file->DirectorySector; // update the sector number of file cache.
995,7 → 1071,7
return(direntry_exist);
}
dir = (DirEntry_t *)file->Cache; // set pointer to directory
switch((u8)dir[file->DirectoryIndex].Name[0]) // check if current directory exist
switch((u8)dir[file->DirectoryIndex].Name[0]) // check if current directory exist
{
case SLOT_EMPTY:
case SLOT_DELETED:
1098,9 → 1174,9
// Dir entries can be created only in file-clusters that have
// the dir-flag set in its attribute or within the root directory
 
file->FirstSectorOfFirstCluster = 0;
file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;
// no current directory exist therefore assume creating in the root
if(file->DirectorySector == 0)
if(file->DirectorySector == SECTOR_UNDEFINED)
{
max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
dircluster = 0;
1118,7 → 1194,7
}
else return (retvalue); // bad sector range for directory sector of the file
// if search area is not defined yet
if(file->FirstSectorOfFirstCluster == 0)
if(file->FirstSectorOfFirstCluster == SECTOR_UNDEFINED)
{
// check if the directory entry of current file is existent and has the dir-flag set
file->SectorInCache = file->DirectorySector; // update the sector number of file cache.
1145,97 → 1221,113
file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dircluster);
}
 
subdircluster = FindNextFreeCluster(file); // get the next free cluster on the disk and mark it as used.
if(subdircluster)
file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
file->SectorOfCurrCluster = 0;
do // loop over all clusters of current directory
{
file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
file->SectorOfCurrCluster = 0;
do // loop over all clusters of current directory
dir_sector = 0; // reset sector counter within a new cluster
do // loop over all sectors of a cluster or all sectors of the root directory
{
dir_sector = 0; // reset sector counter within a new cluster
do // loop over all sectors of a cluster or all sectors of the root directory
curr_sector = file->FirstSectorOfCurrCluster + dir_sector; // calculate sector number
file->SectorInCache = curr_sector; // upate the sector number of file cache.
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
{
curr_sector = file->FirstSectorOfCurrCluster + dir_sector; // calculate sector number
file->SectorInCache = curr_sector; // upate the sector number of file cache.
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
{
Fat16_Deinit();
return(retvalue);
}
dir = (DirEntry_t *)file->Cache; // set pointer to directory
// search all directory entries of a sector
for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
{ // check if current direntry is available
if(((u8)dir[dir_entry].Name[0] == SLOT_EMPTY) || ((u8)dir[dir_entry].Name[0] == SLOT_DELETED))
{ // a free direntry was found
for(i = 0; i < 11; i++) dir[dir_entry].Name[i] = dirname[i]; // Set dir name
dir[dir_entry].Attribute = attrib; // Set the attribute of the new directoryentry.
dir[dir_entry].StartCluster = subdircluster; // copy the location of the first datacluster to the directoryentry.
dir[dir_entry].DateTime = FileDateTime(&SystemTime); // set date/time
dir[dir_entry].Size = 0; // the new createted file has no content yet.
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache)) // write back to card
Fat16_Deinit();
return(retvalue);
}
 
dir = (DirEntry_t *)file->Cache; // set pointer to directory
// search all directory entries of a sector
for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
{ // check if current direntry is available
if(((u8)dir[dir_entry].Name[0] == SLOT_EMPTY) || ((u8)dir[dir_entry].Name[0] == SLOT_DELETED))
{ // a free direntry was found
for(i = 0; i < 11; i++) dir[dir_entry].Name[i] = dirname[i]; // Set dir name
dir[dir_entry].Attribute = attrib;
dir[dir_entry].Res1 = 0;
dir[dir_entry].CreationTime10ms = (u8)(SystemTime.mSec/10);
dir[dir_entry].CreationTime = FileTime(&SystemTime);
dir[dir_entry].CreationDate = FileDate(&SystemTime);
dir[dir_entry].LastAccessDate = dir[dir_entry].CreationDate;
dir[dir_entry].Res2[0] = 0;
dir[dir_entry].Res2[1] = 0;
dir[dir_entry].ModTime = dir[dir_entry].CreationTime;
dir[dir_entry].ModDate = dir[dir_entry].CreationDate;
// if the new direntry is a subdirectory
if((attrib & ATTR_SUBDIRECTORY) == ATTR_SUBDIRECTORY)
{ // get a free clutser for its content
subdircluster = FindNextFreeCluster(file); // get the next free cluster on the disk and mark it as used.
file->FirstSectorOfFirstCluster = Fat16ClusterToSector(subdircluster); // Calculate absolute sectorposition of first datacluster.
}
else // normal file
{ // has no data cluster after creation
subdircluster = CLUSTER_UNDEFINED;
file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;
}
// Set the attribute of the new directoryentry.
dir[dir_entry].StartCluster = subdircluster; // copy the location of the first datacluster to the directoryentry.
dir[dir_entry].Size = 0; // the new createted file has no content yet.
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache)) // write back to card
{
Fat16_Deinit();
return(retvalue);
}
file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster; // Start reading the file with the first sector of the first datacluster.
file->SectorOfCurrCluster = 0; // reset sector of cureen cluster
file->ByteOfCurrSector = 0; // reset the byte location within the current sector
file->Attribute = attrib; // set file attribute to dir attribute
file->Size = 0; // new file has no size
file->DirectorySector = curr_sector;
file->DirectoryIndex = dir_entry;
// prepare subdirectory data cluster
if((attrib & ATTR_SUBDIRECTORY) == ATTR_SUBDIRECTORY) // if a new directory was created then initilize the data area
{
ClearCurrCluster(file); // fill cluster with zeros
file->SectorInCache = file->FirstSectorOfFirstCluster;
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
{
Fat16_Deinit();
Fat16_Deinit();
return(retvalue);
}
file->FirstSectorOfFirstCluster = Fat16ClusterToSector(subdircluster); // Calculate absolute sectorposition of first datacluster.
file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster; // Start reading the file with the first sector of the first datacluster.
file->SectorOfCurrCluster = 0; // reset sector of cureen cluster
file->ByteOfCurrSector = 0; // reset the byte location within the current sector
file->Attribute = attrib; // set file attribute to dir attribute
file->Size = 0; // new file has no size
file->DirectorySector = curr_sector;
file->DirectoryIndex = dir_entry;
if((attrib & ATTR_SUBDIRECTORY) == ATTR_SUBDIRECTORY) // if a new directory was created then initilize the data area
dir = (DirEntry_t *)file->Cache;
// create direntry "." to current dir
dir[0].Name[0] = 0x2E;
for(i = 1; i < 11; i++) dir[0].Name[i] = ' ';
dir[0].Attribute = ATTR_SUBDIRECTORY;
dir[0].StartCluster = subdircluster;
dir[0].Size = 0;
// create direntry ".." to the upper dir
dir[1].Name[0] = 0x2E;
dir[1].Name[1] = 0x2E;
for(i = 2; i < 11; i++) dir[1].Name[i] = ' ';
dir[1].Attribute = ATTR_SUBDIRECTORY;
dir[1].StartCluster = dircluster;
dir[1].Size = 0;
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))// read in the sector.
{
ClearCurrCluster(file); // fill cluster with zeros
file->SectorInCache = file->FirstSectorOfFirstCluster;
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
{
Fat16_Deinit();
return(retvalue);
}
dir = (DirEntry_t *)file->Cache;
// create direntry "." to current dir
dir[0].Name[0] = 0x2E;
for(i = 1; i < 11; i++) dir[0].Name[i] = ' ';
dir[0].Attribute = ATTR_SUBDIRECTORY;
dir[0].StartCluster = subdircluster;
dir[0].DateTime = 0;
dir[0].Size = 0;
// create direntry ".." to the upper dir
dir[1].Name[0] = 0x2E;
dir[1].Name[1] = 0x2E;
for(i = 2; i < 11; i++) dir[1].Name[i] = ' ';
dir[1].Attribute = ATTR_SUBDIRECTORY;
dir[1].StartCluster = dircluster;
dir[1].DateTime = 0;
dir[1].Size = 0;
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))// read in the sector.
{
Fat16_Deinit();
return(retvalue);
}
}
retvalue = 1;
dir_entry = DIRENTRIES_PER_SECTOR; // stop for-loop
}
Fat16_Deinit();
return(retvalue);
}
}
retvalue = 1;
dir_entry = DIRENTRIES_PER_SECTOR; // stop for-loop
}
dir_sector++; // search next sector
// stop if we reached the end of the cluster or the end of the root dir
}while((dir_sector < max_dir_sector) && (!retvalue));
}
dir_sector++; // search next sector
// stop if we reached the end of the cluster or the end of the root dir
}while((dir_sector < max_dir_sector) && (!retvalue));
 
// if we are seaching in the data area and the file not found in this cluster so take next cluster.
if(!retvalue && ( Partition.FirstDataSector <= file->FirstSectorOfCurrCluster))
{
end_of_directory_not_reached = GetNextCluster(file); // updates File->FirstSectorOfCurrCluster
}
}while((end_of_directory_not_reached) && (!retvalue));
// Perhaps we are at the end of the last cluster of a directory file an have no free direntry found.
// Then we would need to add a cluster to that file and create the new direntry there.
// This code is not implemented yet, because its occurs only if more that 32*32=1024 direntries are
// within a subdirectory of root.
}
// if we are seaching in the data area and the file not found in this cluster so take next cluster.
if(!retvalue && ( Partition.FirstDataSector <= file->FirstSectorOfCurrCluster))
{
end_of_directory_not_reached = GetNextCluster(file); // updates File->FirstSectorOfCurrCluster
}
}while((end_of_directory_not_reached) && (!retvalue));
// Perhaps we are at the end of the last cluster of a directory file and have no free direntry found.
// Then we would need to add a cluster to that file and create the new direntry there.
// This code is not implemented yet, because its occurs only if more that 32*32=1024 direntries are
// within a subdirectory of root.
 
return(retvalue); // return 1 if file has been created otherwise return 0.
}
 
1382,15 → 1474,15
 
// now we have found a free filepointer and claimed it
// so let initiate its property values
file->FirstSectorOfFirstCluster = 0; // Sectorpointer to the first sector of the first datacluster of the file.
file->FirstSectorOfCurrCluster = 0; // Pointer to the cluster which is edited at the moment.
file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED; // Sectorpointer to the first sector of the first datacluster of the file.
file->FirstSectorOfCurrCluster = SECTOR_UNDEFINED; // Pointer to the cluster which is edited at the moment.
file->SectorOfCurrCluster = 0; // The sector which is edited at the moment (cluster_pointer + sector_index).
file->ByteOfCurrSector = 0; // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
file->Mode = mode; // mode of fileoperation (read,write)
file->Size = 0; // the size of the opened file in bytes.
file->Position = 0; // pointer to a byte within the file 0 < fileposition < filesize
file->SectorInCache = 0; // the last sector read, wich is still in the sectorbuffer.
file->DirectorySector = 0; // the sectorposition where the directoryentry has been made.
file->SectorInCache = SECTOR_UNDEFINED; // the last sector read, wich is still in the sectorbuffer.
file->DirectorySector = SECTOR_UNDEFINED; // the sectorposition where the directoryentry has been made.
file->DirectoryIndex = 0; // the index to the directoryentry within the specified sector.
file->Attribute = 0; // the attribute of the file opened.
 
1417,11 → 1509,30
file = NULL;
}
else
{ // file is not marked as read only --> goto start of file
{ // file is not marked as read only
DirEntry_t * dir;
// free all clusters of that file
DeleteClusterChain(SectorToFat16Cluster(file->FirstSectorOfFirstCluster));
// mark an empy cluster as the last one and store the corresponding sector
file->FirstSectorOfFirstCluster = Fat16ClusterToSector(FindNextFreeCluster(file));
// update directory entry of that file
file->SectorInCache = file->DirectorySector; // update the sector number of file cache.
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
{
Fat16_Deinit();
return(NULL);
}
dir = (DirEntry_t *)file->Cache; // set pointer to directory
dir[file->DirectoryIndex].ModTime = FileTime(&SystemTime); // set modification time
dir[file->DirectoryIndex].ModDate = FileDate(&SystemTime); // set modification date
dir[file->DirectoryIndex].LastAccessDate = dir[file->DirectoryIndex].ModDate;
dir[file->DirectoryIndex].StartCluster = CLUSTER_UNDEFINED; // update startcluster
dir[file->DirectoryIndex].Size = 0;
// write sector containing the direntry
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
{
Fat16_Deinit();
return(NULL);
}
file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;
file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
file->SectorOfCurrCluster = 0;
file->ByteOfCurrSector = 0;
1501,8 → 1612,11
}
 
dir = (DirEntry_t *)file->Cache;
// update dile size and modification time & date
dir[file->DirectoryIndex].ModTime = FileTime(&SystemTime);
dir[file->DirectoryIndex].ModDate = FileDate(&SystemTime);
dir[file->DirectoryIndex].LastAccessDate = dir[file->DirectoryIndex].ModDate;
dir[file->DirectoryIndex].Size = file->Size; // update file size
dir[file->DirectoryIndex].DateTime = FileDateTime(&SystemTime); // update date time
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache)) // write back to sd-card
{
Fat16_Deinit();
1511,6 → 1625,7
break;
case 'r':
default:
// do nothing!
return(EOF);
break;
 
1603,57 → 1718,68
u32 curr_sector = 0;
 
if((!Partition.IsValid) || (file == NULL)) return(EOF);
 
// If file position equals to file size, then the end of file has reached.
// In this chase it has to be checked that the ByteOfCurrSector is BYTES_PER_SECTOR
// and a new cluster should be appended.
if((file->Position >= file->Size) && (file->ByteOfCurrSector >= BYTES_PER_SECTOR))
switch(file->Mode)
{
if(!AppendCluster(file)) return(EOF);
}
 
curr_sector = file->FirstSectorOfCurrCluster;
curr_sector += file->SectorOfCurrCluster;
if(file->SectorInCache != curr_sector)
{
file->SectorInCache = curr_sector;
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))
{
Fat16_Deinit();
return(EOF);
}
}
 
file->Cache[file->ByteOfCurrSector] = (u8)c; // write databyte into the buffer. The byte will be written to the device at once
if(file->Size == file->Position) file->Size++; // a character has been written to the file so the size is incremented only when the character has been added at the end of the file.
file->Position++; // the actual positon within the file.
file->ByteOfCurrSector++; // goto next byte in sector
if(file->ByteOfCurrSector >= BYTES_PER_SECTOR) // if the end of this sector is reached yet
{ // save the sector to the sd-card
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
{
Fat16_Deinit();
return(EOF);
}
file->ByteOfCurrSector = 0; // reset byte location
file->SectorOfCurrCluster++; // next sector
if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster)// if end of cluster is reached, the next datacluster has to be searched in the FAT.
{
if(!GetNextCluster(file)) // Sets the clusterpointer of the file to the next datacluster.
{ // if current cluster was the last cluster of the file
if(!AppendCluster(file)) // append a new and free cluster at the end of the file.
case 'w':
case 'a':
// If file position equals to file size, then the end of file has been reached.
// In this case it has to be checked that the ByteOfCurrSector is BYTES_PER_SECTOR
// and a new cluster should be appended.
// If the first sector of first cluster is unvalid, then the file claims no data clusters
// and size should be zero, therefore append a new Cluster too.
if(((file->Position >= file->Size) && (file->ByteOfCurrSector >= BYTES_PER_SECTOR)) || (file->FirstSectorOfFirstCluster == SECTOR_UNDEFINED))
{
if(CLUSTER_UNDEFINED == AppendCluster(file)) return(EOF);
}
curr_sector = file->FirstSectorOfCurrCluster;
curr_sector += file->SectorOfCurrCluster;
if(file->SectorInCache != curr_sector)
{
file->SectorInCache = curr_sector;
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))
{
file->SectorOfCurrCluster--; // jump back to last sector of last cluster
file->ByteOfCurrSector = BYTES_PER_SECTOR; // set byte location to 1 byte over sector len
return(EOF);
Fat16_Deinit();
return(EOF);
}
}
else // next cluster
{
file->SectorOfCurrCluster = 0; // start reading new cluster at first sector of the cluster.
file->Cache[file->ByteOfCurrSector] = (u8)c; // write databyte into the buffer. The byte will be written to the device at once
if(file->Size == file->Position) file->Size++; // a character has been written to the file so the size is incremented only when the character has been added at the end of the file.
file->Position++; // the actual positon within the file.
file->ByteOfCurrSector++; // goto next byte in sector
if(file->ByteOfCurrSector >= BYTES_PER_SECTOR) // if the end of this sector is reached yet
{ // save the sector to the sd-card
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
{
Fat16_Deinit();
return(EOF);
}
file->ByteOfCurrSector = 0; // reset byte location
file->SectorOfCurrCluster++; // next sector
if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster)// if end of cluster is reached, the next datacluster has to be searched in the FAT.
{
if(!GetNextCluster(file)) // Sets the clusterpointer of the file to the next datacluster.
{ // if current cluster was the last cluster of the file
if(!AppendCluster(file)) // append a new and free cluster at the end of the file.
{
file->SectorOfCurrCluster--; // jump back to last sector of last cluster
file->ByteOfCurrSector = BYTES_PER_SECTOR; // set byte location to 1 byte over sector len
return(EOF);
}
}
else // next cluster
{
file->SectorOfCurrCluster = 0; // start reading new cluster at first sector of the cluster.
}
}
}
}
}
break;
case 'r':
default:
return(EOF);
break;
} // EOF switch(file->Mode)
return(0);
}
 
1718,7 → 1844,7
s16 c;
 
if((!Partition.IsValid) || (file == NULL) || (buffer == NULL)) return(0);
 
if(file->Mode == 'r') return (0); // opened read only
pbuff = (u8 *) buffer; // cast the void pointer to an u8 *
 
while((object_cnt < count) && success)
1756,8 → 1882,8
u8 i=0;
s16 c = 0;
 
if((!Partition.IsValid) || (file == NULL) || (string == NULL)) return(0);
 
if((!Partition.IsValid) || (file == NULL) || (string == NULL)) return(EOF);
if(file->Mode == 'r') return(EOF);
while((string[i] != 0)&& (c != EOF))
{
c = fputc_(string[i], file);
/trunk/fat16.h
9,7 → 9,7
//________________________________________________________________________________________________________________________________________
 
//#define __USE_TIME_DATE_ATTRIBUTE
#define FILE_MAX_OPEN 3 // The number of files that can accessed simultaneously.
#define FILE_MAX_OPEN 4 // The number of files that can accessed simultaneously.
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2