Rev 24 |
Go to most recent revision |
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
// + 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
++;
}
}
}