Subversion Repositories NaviCtrl

Rev

Rev 23 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*#######################################################################################*/
/* !!! THIS IS NOT FREE SOFTWARE !!!                                                     */
/*#######################################################################################*/
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Copyright (c) 2008 Ingo Busker, Holger Buss
// + Nur für den privaten Gebrauch / NON-COMMERCIAL USE ONLY
// + 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 oder Nutzung 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 the sources to other systems or using the software on other systems (except 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++;
                }
        }      
}