Subversion Repositories NaviCtrl

Compare Revisions

Ignore whitespace Rev 22 → Rev 23

/tags/V0.1/fat16.c
0,0 → 1,1007
/*#######################################################################################*/
/* !!! THIS IS NOT FREE SOFTWARE !!! */
/*#######################################################################################*/
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Copyright (c) 2008 Ingo Busker, Holger Buss
// + Nur für den privaten Gebrauch
// + FOR NON COMMERCIAL USE ONLY
// + www.MikroKopter.com
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Es gilt für das gesamte Projekt (Hardware, Software, Binärfiles, Sourcecode und Dokumentation),
// + dass eine Nutzung (auch auszugsweise) nur für den privaten (nicht-kommerziellen) Gebrauch zulässig ist.
// + Sollten direkte oder indirekte kommerzielle Absichten verfolgt werden, ist mit uns (info@mikrokopter.de) Kontakt
// + bzgl. der Nutzungsbedingungen aufzunehmen.
// + Eine kommerzielle Nutzung ist z.B.Verkauf von MikroKoptern, Bestückung und Verkauf von Platinen oder Bausätzen,
// + Verkauf von Luftbildaufnahmen, usw.
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Werden Teile des Quellcodes (mit oder ohne Modifikation) weiterverwendet oder veröffentlicht,
// + unterliegen sie auch diesen Nutzungsbedingungen und diese Nutzungsbedingungen incl. Copyright müssen dann beiliegen
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Sollte die Software (auch auszugesweise) oder sonstige Informationen des MikroKopter-Projekts
// + auf anderen Webseiten oder sonstigen Medien veröffentlicht werden, muss unsere Webseite "http://www.mikrokopter.de"
// + eindeutig als Ursprung verlinkt werden
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Keine Gewähr auf Fehlerfreiheit, Vollständigkeit oder Funktion
// + Benutzung auf eigene Gefahr
// + Wir übernehmen keinerlei Haftung für direkte oder indirekte Personen- oder Sachschäden
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Die PORTIERUNG der Software (oder Teile davon) auf andere Systeme (ausser der Hardware von www.mikrokopter.de) ist nur
// + mit unserer Zustimmung zulässig
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Die Funktion printf_P() unterliegt ihrer eigenen Lizenz und ist hiervon nicht betroffen
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Redistributions of source code (with or without modifications) must retain the above copyright notice,
// + this list of conditions and the following disclaimer.
// + * Neither the name of the copyright holders nor the names of contributors may be used to endorse or promote products derived
// + from this software without specific prior written permission.
// + * The use of this project (hardware, software, binary files, sources and documentation) is only permitted
// + for non-commercial use (directly or indirectly)
// + Commercial use (for excample: selling of MikroKopters, selling of PCBs, assembly, ...) is only permitted
// + with our written permission
// + * If sources or documentations are redistributet on other webpages, out webpage (http://www.MikroKopter.de) must be
// + clearly linked as origin
// + * PORTING this software (or part of it) to systems (other than hardware from www.mikrokopter.de) is NOT allowed
//
// + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// + POSSIBILITY OF SUCH DAMAGE.
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
#include "main.h"
 
//________________________________________________________________________________________________________________________________________
// Module name: fat16.c
// Compiler used: avr-gcc 3.4.5
// Last Modifikation: 24.07.2007
// Version: 1.24
// Authors: Stephan Busker
// Description: Source files for FAT16 implementation with read and write-access using AVR-Mikrocontrollers
// Copyright (C) 2007 Stephan Busker
//........................................................................................................................................
// Functions: extern u8 InitFat16(void);
// u8 fopen_(u8 *fname,s8 mode, File *file);
// void fclose_(File *file);
// u32 fread_(void *buffer, u32 size, u32 count, File *file);
// u32 fwrite_(void *buffer, u32 size, u32 count, File *file);
// s16 fseek_(File *file, s32 offset, s16 origin);
// s8 fgets8_(File *file);
// u8 fputchar_(File *file,s8 c);
// u8 fputs_(File *file,s8 *string);
// s8 * fgets(s8 *, s16, File);
// u8 fexist_(u8*, File *file);
//........................................................................................................................................
// ext. functions: extern u8 SDC_GetSector (u32,u8 *);
// extern u8 SDC_PutSector (u32,u8 *);
//........................................................................................................................................
//
// URL: www.Mikro-Control.de
// mailto: stephan.busker@mikro-control.de
//________________________________________________________________________________________________________________________________________
 
 
 
 
//________________________________________________________________________________________________________________________________________
//
// Global variables needed for read- or write-acces to the FAT16- filesystem.
//
//________________________________________________________________________________________________________________________________________
 
u8 SectorsPerCluster = 0; // how many sectors does a cluster contain?
u8 FatCopies = 0; // Numbers of copies of the FAT
u16 PossibleRootEntries = 0; // Possible number of entries in the root directory.
u16 SectorsPerFat = 0; // how many sectors does a fat16 contain?
u32 ReservedSectors = 0; // Sectors reserved by the filesystem.
u32 FirstPartitionSector = 0; // Distance in sectors between the first partition and the master bootrecord.
u32 FileAllocationTable = 0; // pointer to the first FAT
u32 RootDirectory = 0; // Pointer to the rootdirectory of the first partition.
u32 FirstDataCluster = 0; // Pointer to the first cluster containing data (cluster0).
//u8 FileBuffer[512]; // Buffer for read and write operation from or to the mmc.
 
struct DirEntry *DirectoryEntry; // Pointer to an entry of the directory.
struct FatEntry *Fat; // Pointer to an entry of the fat (next clusterposition).
 
File FilePointer[__MAX_FILES_USED]; // Allocate Memmoryspace for each filepointer used.
 
 
 
 
//________________________________________________________________________________________________________________________________________
// Funtion: InitFat16(void);
//
// Description: This function reads the Masterbootrecord and finds the position of the Volumebootrecord, the FAT and the Rootdirectory
// and stores the information in global variables.
//
// Returnvalue: The function returns "0" if the filesystem could not be initialized because no partition was found on the disc.
//________________________________________________________________________________________________________________________________________
 
u8 InitFat16(void)
{
u8 retvalue = 0;
u8 cnt = 0;
struct VBR_Entry *VBR; // Pointer to the VolumeBootRecord.
struct MBR_Entry *MBR; // Pointer to the masterbootrecord.
File *file;
 
for(cnt=0;cnt<__MAX_FILES_USED;cnt++)
{
FilePointer[cnt].state = _UNUSED; // declare the filepointers as unused.
}
file = &FilePointer[0];
 
while((SDC_Init() != 0) && (cnt++<200)); // initialise the sdcard.
if(cnt <200) //sdcard initialised succesfully
{
SDC_GetSector((u32)MBR_SECTOR,file->buffer); // Read the MasterBootRecord from mmc.
MBR = (struct MBR_Entry *) file->buffer;
FirstPartitionSector = MBR->PartitionEntry1.NoSectorsBeforePartition;
SDC_GetSector(FirstPartitionSector,file->buffer); // Read the volume bootrecord from mmc.
 
VBR = (struct VBR_Entry *) file->buffer; // Enter the VBR using the structure VBR_Entry.
SectorsPerCluster = VBR->SectorsPerCluster; // Number of sectors per cluster. Depends on the memorysize of the sd-card.
FatCopies = VBR->NoFATCopies; // Number of fatcopies.
PossibleRootEntries = VBR->MaxRootEntries; // How many Entries are possible in the rootdirectory (FAT16 allows max. 512 entries).
SectorsPerFat = VBR->SectorsPerFAT; // The number of sectors per FAT.
ReservedSectors = VBR->ReservedSectors; // calculate the sectorpositon of the FAT, the Rootdirectory and the first Datacluster.
 
FileAllocationTable = (u32)(FirstPartitionSector + (u32)ReservedSectors); // Calculate the position of the FileAllocationTable.
RootDirectory = (u32)((u32)FileAllocationTable + (u32)((u32)SectorsPerFat*(u32)FatCopies)); // Calculate the position of the Rootdirectory.
FirstDataCluster = (u32)((u32)RootDirectory + ((u32)(PossibleRootEntries>>4))); // Calculate the position of the first datacluster.
if((file->buffer[0x36]=='F') &&(file->buffer[0x37]=='A')&&(file->buffer[0x38]=='T')&&(file->buffer[0x39]=='1')&&(file->buffer[0x3A]=='6'))
{
retvalue = 1;
}
}
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: File * fopen_(u8*, u8 *, File *file);
//
// Description: This function looks for the specified file in the rootdirectory of the drive. If the file is found the number of the
// corrosponding datacluster is returned to main. Only modes 'r' (reading) and 'a' append are implemented yet.
//
// Return: 0 = faild to open speicified file
// 1 = file opened
//________________________________________________________________________________________________________________________________________
 
File * fopen_(u8 *fname, s8 mode)
{
u32 cluster_temp = 0;
u8 name[11] = " ";
u16 temp = 0;
File *file;
file=0;
for(temp = 0;temp<__MAX_FILES_USED;temp++)
{
if(FilePointer[temp].state == _UNUSED) // free filepointer found?
{
file = &FilePointer[temp];
FilePointer[temp].state = _USED; // mark as used.
break;
}
}
if(file == 0) return(file); // no valid pointer
 
file->start_cluster = 0; // Sectorpointer to the first sector of the first datacluster of the file.
file->cluster_pointer = 0; // Pointer to the cluster which is edited at the moment.
file->sector_index = 0; // The sector which is edited at the moment (cluster_pointer + sector_index).
file->byte_index = 0; // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
file->mode = mode; // mode of fileoperation (read,write)
file->filesize = 0; // the size of the opend file in bytes.
file->fileposition = 0; // pointer to a character within the file 0 < fileposition < filesize
file->sector_in_buffer = 0; // the last sector read, wich is still in the sectorbuffer.
file->directory_sector = 0; // the sectorposition where the directoryentry has been made.
file->directory_index = 0; // the index to the directoryentry within the specified sector.
file->attribute = 0; // the attribute of the file opened.
 
if(ScanSubDirectories(&fname[0], file)) // Is the specified filepath available?
{
SeperateFileName(&fname[0], &name[0]); // seperate the filename and attribute from the filepath and bring them in the correct format.
file->attribute = _FILE;
if(SeekDirectoryEntry(&name[0], file)) // if file was found
{
if(mode == 'a') // open existing file for writing (append data at the end of the file)
{
fseek_(file, 0, SEEK_END); // fseek points to the end of the file
}
return(file);
}
else
{
if((mode == 'a') || (mode == 'w')) // specified file doesn't exist so create new file for writing data.
{
cluster_temp = (u32)FindNextFreeCluster(file); // the next free cluster on the disk.
if(cluster_temp) // if a free cluster is available:
{
temp = (u16)cluster_temp; // remember the index of the free datacluster found for the directory entry.
cluster_temp -=2; // Clusterposition is ((position in FAT)-2). first two entries in FAT are reserved.
cluster_temp *= SectorsPerCluster; // Calculate relative sectorindex of first datacluster.
file->start_cluster = (FirstDataCluster + cluster_temp); // Calculate absolute sectorposition of first datacluster.
file->cluster_pointer = file->start_cluster; // start reading the file with the first sector of the first datacluster.
if(CreateDirectoryEntry(&name[0],temp,file,_FILE)) // Could an entry for the new file in the rootdirectory be created?
{
return(file);
}
}
}
}
}
return(0);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: fflush_(File *file);
//
// Description: This function writes the data already in the buffer but not yet written to the file.
//
//________________________________________________________________________________________________________________________________________
 
s16 fflush_(File *file)
{
u16 time=0;
u16 date=0;
 
#ifdef __USE_TIME_DATE_ATTRIBUTE // has the date and time attribute of the file to be set?
time = (((rtctime.hour)<<11) | ((rtctime.minute)<<5) | rtctime.second);
date = ((((rtctime.year)-1980) <<9) | ((rtctime.month) <<5) | rtctime.day);
 
#endif
if(file && file->mode =='a')
{
if(file->byte_index > 0) // has data been added to the file?
{
SDC_PutSector((u32)(file->cluster_pointer + file->sector_index),file->buffer); // save the data still in the buffer
}
SDC_GetSector((u32)file->directory_sector,file->buffer); // read the directoryentry for this file.
DirectoryEntry = (struct DirEntry *)file->buffer;
DirectoryEntry[file->directory_index].size = (u32) file->filesize;
DirectoryEntry[file->directory_index].time = (u16) time;
DirectoryEntry[file->directory_index].date = (u16) date;
SDC_PutSector((u32)file->directory_sector,file->buffer);
}
return(0);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: fclose_(File *file);
//
// Description: This function closes the open file by writing the remaining data from the buffer to the device and entering the filesize
// in the directory entry.
//________________________________________________________________________________________________________________________________________
 
void fclose_(File *file)
{
u8 cnt = 0;
for(cnt=0;cnt<__MAX_FILES_USED;cnt++)
{
if(&FilePointer[cnt] == file) // filepointer to be freed found?
{
FilePointer[cnt].state = _UNUSED;
}
 
fflush_(file); // save buffercontent to the sdcard
 
file->start_cluster = 0; // Sectorpointer to the first sector of the first datacluster of the file.
file->cluster_pointer = 0; // Pointer to the cluster which is edited at the moment.
file->sector_index = 0; // The sector which is edited at the moment (cluster_pointer + sector_index).
file->byte_index = 0; // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
file->mode = 0; // mode of fileoperation (read,write)
file->filesize = 0; // the size of the opend file in bytes.
file->fileposition = 0; // pointer to a character within the file 0 < fileposition < filesize
file->sector_in_buffer = 0; // the last sector read, wich is still in the sectorbuffer.
file->directory_sector = 0; // the sectorposition where the directoryentry has been made.
file->directory_index = 0; // the index to the directoryentry within the specified sector.
file->attribute = 0; // the attribute of the file opened.
}
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: s32 fread_(void *buffer, s32 size, s32 count, File *file);
//
// Description: This function reads count objects of the specified size from the actual position of the file to the specified buffer.
//
// Returnvalue: The function returns the number of objects (not bytes) read from the file.
//
//________________________________________________________________________________________________________________________________________
 
u32 fread_(void *buffer, u32 size, u32 count, File *file)
{
u32 object_cnt = 0; // count the number of objects read from the file.
u32 object_size = 0; // count the number of bytes read from the actual object.
u8 *buff_pnt = 0; // a pointer to the actual bufferposition.
u8 success = 1; // no error occured during read operation to the file.
buff_pnt = (u8 *) buffer; // cast the void pointer to an u8 *
while((object_cnt < count) && success)
{
object_size = size;
while((size > 0) && success)
{
*buff_pnt = (u8) fgetchar_(file); // read a byte from the buffer to the opened file.
buff_pnt++;
size--;
}
if(success) object_cnt++;
}
return(object_cnt); // return the number of objects succesfully read from the file
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: s32 fwrite_(void *buffer, s32 size, s32 count, File *file);
//
// Description: This function writes count objects of the specified size from the buffer to the actual positon within the file.
//
// Returnvalue: The function returns the number of objects (not bytes) written to the file.
//
//________________________________________________________________________________________________________________________________________
 
u32 fwrite_(void *buffer, u32 size, u32 count, File *file)
{
u32 object_cnt = 0; // count the number of objects written to the file.
u32 object_size = 0; // count the number of bytes written from the actual object.
u8 *buff_pnt = 0; // a pointer to the actual bufferposition.
u8 success = 1; // no error occured during write operation to the file.
buff_pnt = (u8 *) buffer; // cast the void pointer to an u8 *
while((object_cnt < count) && success)
{
object_size = size;
while((size > 0) && success)
{
success = fputchar_(file, *buff_pnt); // write a byte from the buffer to the opened file.
buff_pnt++;
size--;
}
if(success) object_cnt++;
}
return(object_cnt); // return the number of objects succesfully written to the file
} // (!!!!! objects and not bytes !!!!)
 
//________________________________________________________________________________________________________________________________________
// Funtion: s16 fseek_(File *, s32, s16)
//
// Description: This function sets the pointer of the stream relative to the position
// specified by origin (SEEK_SET, SEEK_CUR, SEEK_END).
//
//________________________________________________________________________________________________________________________________________
 
s16 fseek_(File *file, s32 offset, s16 origin)
{
s32 fposition = 0;
s16 retvalue = 1;
u32 temp = 0;
//......................................................
if(origin == SEEK_SET) // Fileposition relative to the beginning of the file.
{
fposition = 0;
}
//......................................................
else if(origin == SEEK_END) // Fileposition relative to the end of the file.
{
fposition = (s32) file->filesize;
}
//......................................................
else if(origin == SEEK_CUR) // Fileposition relative to the current position of the file.
{
fposition = file->fileposition;
}
 
fposition += offset;
 
if((fposition >= 0) && (fposition <= (s32)file->filesize)) // is the pointer still within the file?
{
retvalue = 0;
file->sector_index = 0;
file->byte_index = 0;
file->fileposition = 0;
file->cluster_pointer = file->start_cluster;
while(file->fileposition < fposition)
{
file->fileposition++;
if(file->byte_index < 511)
{
file->byte_index++;
}
else
{
file->byte_index=0; // reading at the beginning of new sector.
file->sector_index++; // continue reading in next sector
if(file->sector_index >= SectorsPerCluster) // When end of cluster is reached, the next datacluster has to be searched in the FAT.
{
if(file->fileposition < fposition)
{
file->sector_index = 0; // start reading new cluster at first sector of the cluster.
GetNextCluster(file); // Sets the clusterpointer of the file to the next datacluster.
}
}
}
}
if(file->byte_index)
{
temp = (u32)((u32)file->cluster_pointer + (u32)file->sector_index);
SDC_GetSector((u32)temp,file->buffer); // FileBuffer will be written at once at the end of the cluster and has to be updated.
}
}
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: fgetchar_(File *file);
//
// Description: This function reads and returns one character from the specified file. Is the end of the actual sector reached the
// next sector of the cluster is read. Is the last sector of the cluster read the next cluster will be searched in FAT.
// Returnvalue: The function returns the character read from the specified memorylocation as u8 casted to s16 or EOF.
//________________________________________________________________________________________________________________________________________
 
s16 fgetchar_(File *file)
{
s16 c = EOF;
u32 temp1;
if(file->filesize > 0) // wen the end of the file is not reached, get the next character.
{
temp1 = (u32)file->cluster_pointer; // calculate the adress of the next character to be read.
temp1 += (u32)file->sector_index;
if(file->sector_in_buffer != temp1) // Has the content of the buffer been modified and has to be updated?
{
SDC_GetSector((u32)temp1,file->buffer); // Read the calculated cluster.
file->sector_in_buffer = (u32)temp1;
}
c = (s16) file->buffer[file->byte_index];
file->filesize--; // decrement the number of characters available.
if(file->byte_index < 511) // continue reading from this sector until the end of the sector is reached.
{
file->byte_index++;
}
else // has the end of an sector been reached->
{
file->byte_index=0; // continue reading at the beginning -
file->sector_index++; // of new sector.
if(file->sector_index >= SectorsPerCluster) // When the end of an cluster is reached, the next datacluster has to be searched in the FAT.
{
file->sector_index = 0; // start reading new cluster at first sector of the cluster.
GetNextCluster(file); // Sets the clusterpointer of the file to the next datacluster.
}
}
}
return(c);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: fputchar_(File *file);
//
// Description: This function writes a byte to the specified file and takes care of writing the necessary FAT- Entries.
//
// Returnvalue: The function returns a value of 0 if the data could not be written.
//________________________________________________________________________________________________________________________________________
 
u8 fputchar_(File *file,s8 c)
{
u32 ul_temp = 0;
u8 retvalue = 1;
if(file->sector_index >= SectorsPerCluster) // if end of the cluster is reached, find next free cluster
{
file->sector_index = 0;
if(!AppendCluster(file)) retvalue = 0; // append a new and free cluster at the end of the file.
}
 
file->buffer[file->byte_index] = c; // write databyte into the buffer. The byte will be written to the device at once
if(file->filesize == file->fileposition) file->filesize++; // a character has been written to the file so the size is inkremented but only when the character has been added at the end of the file.
file->fileposition++; // the actual positon within the file.
// if the buffer contains the complete sectordata.
if(file->byte_index < 511) // if the end of this sector is not reached yet
{
file->byte_index++; // the next byte will be written to the next byteposition in this sector.
}
else // otherwise the data in the sectorbuffer will be written to the device and the next sector will be selected.
{
ul_temp = (u32)file->cluster_pointer;
ul_temp += (u32)file->sector_index;
SDC_PutSector((u32)ul_temp,file->buffer);
file->byte_index=0; // and the next byte will be written at the beginning of this new sector.
file->sector_index++;
if(file->sector_index >= SectorsPerCluster) // if end of the cluster is reached, find next free cluster
{
file->sector_index = 0;
if(!AppendCluster(file)) retvalue = 0; // append a new and free cluster at the end of the file.
}
}
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: fputs_(File *file);
//
// Description: This function writes a string to the specified file.
//
//________________________________________________________________________________________________________________________________________
 
u8 fputs_(File *file,s8 * string)
{
u8 i=0;
while(string[i] != 0)
{
fputchar_(file,string[i]);
i++;
}
return(0);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: fgets_(File *file);
//
// Description: This function reads a string from the file to the specifies string.
//
// Returnvalue: A pointer to the string written from the file.
//________________________________________________________________________________________________________________________________________
 
s8 * fgets_(s8 *string, s16 count, File *file)
{
s16 buff_pnt = 0;
s16 buff_tmp = 0;
u8 state = 0; // Variable used for a statemachine to recognize the end of a line.
while(count > 1) // read the count-1 characters from the file to the string.
{
buff_tmp = fgetchar_(file); // read a character from the opened file.
switch(state)
{
case 0:
if(buff_tmp == 0x0A)// state++;
{
count = 1;
}
state = 0;
break;
case 1:
if(buff_tmp == 0x0A)
{
count = 1;
}
state = 0;
break;
}
if(buff_tmp == EOF) {buff_tmp = 0; count = 1;} // is the end of the file reached, terminate the string with zero.
string[buff_pnt] = (s8) buff_tmp;
count--;
buff_pnt++;
}
string[buff_pnt] = 0;
return(string);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: u8 fexist_(u8*, File *file);
//
// Description: This function searches the specified file and returns 0 if the file was not found.
//
//
// Return: 0 = file does not exist
// 1 = file exists
//________________________________________________________________________________________________________________________________________
 
u8 fexist_(u8 *fname)
{
File *file;
if((file = fopen_(fname,'r')) != 0)
{
fclose_(file);
return(1);
}
else
{
return(0);
}
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: GetNextCluster(File *file);
//
// Description: This function finds the next datacluster of the file specified with File *file.
//
// Returnvalue: The function returns "0" if the last cluster has already been reached.
//________________________________________________________________________________________________________________________________________
 
u16 GetNextCluster(File *file)
{
u32 fat_pointer = 0;
u32 fat_sector_offset = 0;
u32 ul_tmp = 0;
u8 retvalue = 0; // no new cluster found yet.
if((file->cluster_pointer >= RootDirectory) && (file->cluster_pointer < (RootDirectory + 31)))
{ // Is the next cluster searched within the rootdirectory and available?
file->cluster_pointer++; // the rootdirectory is a linear adress space of 32 clusters.
retvalue = 1; // and the next cluster has been found.
}
else if(file->cluster_pointer > (RootDirectory + 31)) // The specified cluster is within the FAT.
{
fat_sector_offset = ((file->cluster_pointer) - (FirstDataCluster)); // Calculate index of actual cluster within the FAT.
fat_sector_offset /= SectorsPerCluster; // calculate the index of the actual sector within the FAT.
fat_sector_offset += 2; // In Fat16 clusterpositions have an offset of two.
fat_pointer = (fat_sector_offset%0x100); // Calculate the sector within the cluster.
fat_sector_offset = (fat_sector_offset>>8); // and the position within the sector.
 
SDC_GetSector((u32)(FileAllocationTable + fat_sector_offset),file->buffer);
file->sector_in_buffer = (FileAllocationTable + fat_sector_offset); // Mark that new sector has been read.
ul_tmp = (u32)file->buffer[((fat_pointer << 1)+1)]; // Read next sector information from calculated clusterposition.
ul_tmp = (ul_tmp << 8);
ul_tmp |= (u32)file->buffer[(fat_pointer << 1)];
ul_tmp -=2; // next datacluster is clusterposition in fat - 2.
ul_tmp *= SectorsPerCluster; // calculate sectorposition of new cluster
ul_tmp += FirstDataCluster; // in relation to first datacluster of the disk.
if(ul_tmp < 0xfff7) // has a new cluster been read or was the end of the fat reached?
{
file->cluster_pointer = (u32) ul_tmp; // continue reading the file at the beginning of new datacluster.
retvalue = 1; // a new cluster was found.
}
}
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: u16 FindNextFreeCluster(void)
//
// Description: This function looks in the FAT to find the next free datacluster
//
// Returnvalue: The function returns the adress of the next free cluster found within the fAT.
//________________________________________________________________________________________________________________________________________
 
u16 FindNextFreeCluster(File *file)
{
u32 fat_pointer = 0; // Pointer to the first sector of the FAT.
u32 ul_tmp = 0; // temporary variable used to calculate a sectornumber.
u16 fat_sector_offset = 0; // index to a sector within the FAT.
u16 fat_entry = 0; // index to an fatentry within the actual sector (256 fatentries are possible within one sector).
u16 free_cluster = 0; // a pointer to the first sector of the next free cluster.
fat_pointer = (u32) FileAllocationTable; // start searching for empty cluster at the beginning of the fat.
// if the end of the fat is not reached yet and no free cluster has been found
while((fat_sector_offset < SectorsPerFat) && (!free_cluster))
{
ul_tmp = (u32) ((u32)fat_pointer + (u32)fat_sector_offset);
SDC_GetSector((u32)ul_tmp,file->buffer); // read next sector of FAT.
file->sector_in_buffer = ul_tmp; // remember the number of the sector in FileBuffer.
Fat = (struct FatEntry *)file->buffer;
for(fat_entry=0;fat_entry<256;fat_entry++) // look for an free cluster at all entries in this sector of the fat.
{
if(Fat[fat_entry].next_cluster == 0x0000) // empty cluster found!!
{
Fat[fat_entry].next_cluster = 0xffff; // mark this fat-entry as used and save it to the device.
SDC_PutSector((u32)file->sector_in_buffer,file->buffer);
free_cluster = fat_entry; // the relative position of the free cluster found in this sector of the FAT.
free_cluster += (fat_sector_offset << 8); // calculate the absolute position of the free cluster in the FAT;
fat_entry = 256; // terminate the search for a free cluster in this sector.
}
}
fat_sector_offset++;
}
return(free_cluster);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: u16 AppendCluster(File *file);
//
// Description: This function finds the next free datacluster on the disk and appends it to the specified file.
//
// Returnvalue: This funktion returns 1 if a cluster was appended to the specified file.
//________________________________________________________________________________________________________________________________________
 
u8 AppendCluster(File *file)
{
u16 free_cluster = 0;
u32 fat_pointer = 0;
u8 retvalue = 0;
free_cluster = FindNextFreeCluster(file); // the next free cluster found on the disk.
if(free_cluster) retvalue = 1; // A free cluster was found and can be added to the end of the file.
fat_pointer = FileAllocationTable; // Set Pointer to the beginnig of the FAT.
fat_pointer += (u32)((u32)GetFatClusterOffset(file) >> 8); // find the sector in the FAT with 256 entries per sector.
SDC_GetSector(fat_pointer,file->buffer);
Fat = (struct FatEntry *)file->buffer;
Fat[GetFatSectorIndex(file)].next_cluster = free_cluster; // append the free cluster to the end of the file in the FAT.
SDC_PutSector((u32)fat_pointer,file->buffer); // save the modified sector to the FAT.
 
fat_pointer = (u32)free_cluster;
fat_pointer -= 2;
fat_pointer *= SectorsPerCluster;
fat_pointer += FirstDataCluster;
 
file->cluster_pointer = fat_pointer; // continue wrtiting to the file in the new and free datacluster.
return(retvalue); // return 1 when a new cluster was appended to the file
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: u16 GetFatClusterIndex(File *file);
//
// Description: This function returns the clusterindex of the cluster specified by file->cluster_pointer of the specified file.
//
//________________________________________________________________________________________________________________________________________
 
u16 GetFatClusterOffset(File *file)
{
u32 fat_sector_offset = 0;
 
fat_sector_offset = ((file->cluster_pointer) - (FirstDataCluster)); // Calculate index of actual cluster in FAT.
fat_sector_offset /= SectorsPerCluster;
fat_sector_offset += 2; // In Fat16 clusterpositions have an offset of two.
return((u16)fat_sector_offset);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: u16 GetFatSectorIndex(File *file);
//
// Description: This function returns the sectorindex of the cluster specified by file->cluster_pointer of the specified file.
//
//________________________________________________________________________________________________________________________________________
 
u16 GetFatSectorIndex(File *file)
{
u16 fat_pointer = 0;
fat_pointer = GetFatClusterOffset(file);
fat_pointer = fat_pointer % 0x100; // Calculate the clusterposition in the fat
return(fat_pointer);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: u16 CreateDirectoryEntry(u8 *, u16, u8 attrib)
//
// Description: This function looks for the next free position in the directory and creates an entry. The type of an directoryentry is
// specified by the attribute.
// bit0: unused
// bit1: archive
// bit2: read_only
// bit3: system
// bit4: directory
// bit5: volume
//________________________________________________________________________________________________________________________________________
 
u8 CreateDirectoryEntry(u8 *fname, u16 cluster, File *file,u8 attrib)
{
u16 rootentry = 0; // index to an entry in the rootdirectory.
u16 cnt_enries_searched = 0; // count the number of rootentries which have been searched already.
u8 i = 0;
u16 sector_offset = 0; // index to the sector of the Rootentry which is searched momentarily
u8 retvalue = 0;
// directory starts at sector specified by dir_sector. This can be the rootdirectory or any other directory.
do
{ // search the next 16 rootentries in this sector of the roordirectory.
rootentry=0;
SDC_GetSector((u32)(RootDirectory + sector_offset),file->buffer); // Read the Rootdirectory.
DirectoryEntry = (struct DirEntry *)file->buffer;
while((rootentry<16) && (!retvalue))
{
if((DirectoryEntry[rootentry].attribute == 0) || (DirectoryEntry[rootentry].attribute == 0xE5)) // empty directory entry found
{
for(i=0;i<11;i++) DirectoryEntry[rootentry].name[i] = fname[i]; // Kopie the filename and the file extension to the directoryentry.
DirectoryEntry[rootentry].attribute = attrib; // Set the fileattribute to archive to reserve the directoryentry.
DirectoryEntry[rootentry].startcluster = cluster; // copy the location of the first datacluster to the directoryentry.
DirectoryEntry[rootentry].size = 0; // the new createted file has no content yet.
file->directory_sector = (u32) (RootDirectory + sector_offset);
file->directory_index = (u8) rootentry;
retvalue = 1;
SDC_PutSector((u32)(RootDirectory + sector_offset),file->buffer);
}
rootentry++;
cnt_enries_searched++;
}
if(!retvalue) // file not found in this sector so take next sector.
{
rootentry = 0;
sector_offset++;
}
}
while((cnt_enries_searched< PossibleRootEntries) && (!retvalue));
 
return(retvalue); // return 1 if file has been created otherwise return 0.
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: u16 SeekDirectoryEntry(u8*, File *, u8)
//
// Description: this function searches all possible rootentries until the file or directory is found or the end of the rootdirectory is reached
//
// Returnvalue: This function returns 1 if the directoryentry specified was found.
//________________________________________________________________________________________________________________________________________
 
u8 SeekDirectoryEntry(u8 *fname, File *file)
{
u16 rootentry=0;
u16 end_of_directory_not_reached = 0; // the directory has been read completely without a result.
u8 i=0;
u8 retvalue = 0;
u32 cluster_temp = 0;
u16 cnt=0;
 
// directory starts at sector specified by dir_sector. This can be the rootdirectory or any other directory.
do
{ // search the next 16 rootentries in this sector of the roordirectory.
rootentry=0;
SDC_GetSector((u32) file->cluster_pointer,file->buffer); // Read the Rootdirectory.
DirectoryEntry = (struct DirEntry *)file->buffer;
 
while((!retvalue)&&(rootentry<16))
{
cnt++;
 
i=0;
while((i<10)&&(DirectoryEntry[rootentry].name[i] == fname[i]))
{
i++;
}
if((i==10) && (DirectoryEntry[rootentry].attribute == file->attribute)) // entry found!! -> reading startcluster of entry from offset 26.
{
cluster_temp = (u32)DirectoryEntry[rootentry].startcluster;
cluster_temp -=2; // Clusterposition is ((position in FAT)-2). first two entries in FAT are reserved.
cluster_temp *= (u32)SectorsPerCluster; // Calculate positon of first cluster.
file->start_cluster = (FirstDataCluster + cluster_temp);
file->directory_sector = (u32) file->cluster_pointer;
file->cluster_pointer = file->start_cluster; // start reading the file with the first cluster.
file->filesize = (u32) DirectoryEntry[rootentry].size;
file->directory_index = (u8) rootentry;
retvalue = 1;
}
rootentry++;
}
if(!retvalue) // file not found in this sector so take next sector.
{
end_of_directory_not_reached = GetNextCluster(file);
}
}
while((end_of_directory_not_reached) && (!retvalue));
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: void ScanSubDirectories(u8*, File *file);
//
// Description: This function scans the filename for subdirectories and changes the directory until the last directory is reached.
// here the specified file is searched.
//
// Returnvalue:
//________________________________________________________________________________________________________________________________________
 
u8 ScanSubDirectories(u8 *fname, File *file)
{
u8 readpointer = 0; // pointer to read a character within the filepath.
u8 writepointer = 0; // pointer to write a character into the string dirname.
u8 dircnt = 0; // the number of subdirectories found in filepath.
u8 dirname[11]; // temporary variable containing the name of a directory within the filepath.
u8 retvalue = 1; // no error opening a subdirectory occured yet.
u8 cnt = 0; // maximun number of characters in a path is 256;
 
while((fname[readpointer]!=0) && (cnt < 255)) // search the string until the end is reached.
{
cnt++;
if((fname[readpointer] == '/') && readpointer) // subdirectory found. ignore first "/" as directory.
{
dircnt++; // count the number of subdirectories found within the filepath.
}
readpointer++;
}
for(writepointer=0;writepointer<10;writepointer++) dirname[writepointer] = ' ';
writepointer = 0;
readpointer = 0; // start scanning the string at the beginning.
 
file->cluster_pointer = RootDirectory; // always start searching in the rootdirectory.
file->attribute = _DIRECTORY; // the attribute of the item to be searched in the specified directory.
while(dircnt && retvalue) // scan all subdirectories found before.
{
if(fname[readpointer] != '/') // is the end of the subdirectory entry not reached yet?
{
if((fname[readpointer]>96) && (fname[readpointer]<123))
{ // all characters must be upper case.
dirname[writepointer]=(fname[readpointer] - 32);
}
else
{
dirname[writepointer]=fname[readpointer];
}
writepointer++;
}
else
{
dircnt--;
if(!(SeekDirectoryEntry(dirname, file))) // was the seperated subdirectory not found?
{
retvalue = 0; // leave the function with return(0) otherwise continue with the next subdirectory until all directories have been searched.
}
for(writepointer=0;writepointer<10;writepointer++) dirname[writepointer] = ' ';
writepointer = 0;
}
readpointer++;
}
file->attribute = _FILE; // All subdirectories have been searched. the next thing to find is the specified file.
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: void SeperateFileName(u8*);
//
// Description: This function seperates the filename and the fileattribute and brings them into the needed format ('test.txt' -> 'TEST TXT');
//
//________________________________________________________________________________________________________________________________________
 
void SeperateFileName(u8 *fname, u8 *name)
{
u8 readpointer = 0;
u8 writepointer = 0;
u8 dircnt = 0; // the number of subdirectories found in filepath.
u8 fileindex = 0; // the position in the filenamestring where the last "/" is found.
while(fname[readpointer]!=0) // search the string until the end is reached.
{
if((fname[readpointer] == '/') && readpointer) // subdirectory found. ignore first "/" as directory.
{
dircnt++; // subdirectory entry found.
fileindex = (readpointer + 1); // store the index of the last slash found as the beginning of the filename.
}
readpointer++;
}
readpointer = fileindex; // start seperating the filename from the directory at the stored position.
dircnt = 0;
 
while((writepointer<=10) && (fname[readpointer]!=0)) // the rootdirectoryentry is 8bytes for filename and 3bytes for fileattribute.
{ // the filename in the rootdirectory is in the format "TEST TXT" without the dot.
if(fname[readpointer]=='.') // seperating filename and attribute.
{
readpointer++;
writepointer=8;
}
else
{
if((fname[readpointer]>96) && (fname[readpointer]<123))
{
name[writepointer]=(fname[readpointer] - 32); // all characters must be upper case.
}
else
{
name[writepointer]=fname[readpointer];
}
readpointer++;
writepointer++;
}
}
}