55,6 → 55,7 |
// + POSSIBILITY OF SUCH DAMAGE. |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
#include <stdio.h> |
#include <string.h> |
#include "91x_lib.h" |
#include "timer1.h" |
#include "fat16.h" |
61,6 → 62,7 |
#include "sdc.h" |
#include "uart1.h" |
|
void Test(void); |
//________________________________________________________________________________________________________________________________________ |
// Module name: fat16.c |
// Compiler used: avr-gcc 3.4.5 |
126,6 → 128,8 |
u32 NoSectorsPartition ; // Number of Sectors in the Partition |
} __attribute__((packed)) PartitionEntry_t; |
|
|
|
/* |
Coding of Cylinder/Sector words |
|
309,10 → 313,12 |
u32 FirstRootDirSector; // sector of the rootdirectory |
u32 FirstDataSector; // sector of the first cluster containing data (cluster2). |
u32 LastDataSector; // the last data sector of the partition |
u8 VolumeLabel[12]; // the volume label |
} Partition_t; |
u8 VolumeLabel[12]; // the volume label |
u32 CurrentWorkingDirectory;// A pointer to the directory we are actual using |
s8 PathToCwd[256]; // a string containing the complete path to the current working directory |
} __attribute__((packed)) Partition_t; |
|
Partition_t Partition; // Structure holds partition information |
Partition_t Partition; // Structure holds partition information |
|
File_t FilePointer[FILE_MAX_OPEN]; // Allocate Memmoryspace for each filepointer used. |
|
571,7 → 577,6 |
|
UART1_PutString("\r\n FAT16 init..."); |
Partition.IsValid = 0; |
|
// declare the filepointers as unused. |
for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++) |
{ |
654,7 → 659,11 |
goto end; |
} |
Partition.IsValid = 1; // mark data in partition structure as valid |
Partition.CurrentWorkingDirectory = Partition.FirstRootDirSector; |
strcpy(Partition.PathToCwd,"/"); |
result = 0; |
|
// Test(); |
end: |
if(result != 0) Fat16_Deinit(); |
else UART1_PutString("ok"); |
1037,7 → 1046,6 |
// dir entries can be searched only in filesclusters that have |
// a corresponding dir entry with adir-flag set in its attribute |
// or direct within the root directory area |
|
file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED; |
// no current directory exist therefore assume searching in the root |
if(file->DirectorySector == SECTOR_UNDEFINED) |
1092,7 → 1100,7 |
|
do // loop over all data clusters of the current directory entry |
{ |
dir_sector = 0; // reset sector counter within a new cluster |
dir_sector = 0; |
do // loop over all sectors of a cluster or all sectors of the root directory |
{ |
curr_sector = file->FirstSectorOfCurrCluster + dir_sector; // calculate sector number |
1350,6 → 1358,14 |
path = (s8*)filename; // start a the beginning of the filename string |
file->DirectorySector = 0; // start at RootDirectory with file search |
file->DirectoryIndex = 0; |
/* if a path begins with a '/' at index 0 the search starts at the rootdirectory otherwise we will start relative to the cwd */ |
if(path[0] != '/') |
{ |
/* is the current working directory the rootdirectory? */ |
if(Partition.CurrentWorkingDirectory == Partition.FirstRootDirSector) file->DirectorySector = 0; |
/* otherwise we are working in an subdirectory */ |
else file->DirectorySector = Partition.CurrentWorkingDirectory; |
} |
// as long as the file was not found and the remaining path is not empty |
while((*path != 0) && !file_exist) |
{ // separate dirname and subpath from filepath string |
1559,7 → 1575,7 |
{ // if it could not be created |
fclose_(file); |
file = NULL; |
} |
} |
break; |
case 'r': // else opened for 'r' |
default: // if unsupported mode |
1662,7 → 1678,7 |
|
if( (!Partition.IsValid) || (file == NULL)) return(c); |
// if the end of the file is not reached, get the next character. |
if((0 < file->Size) && ((file->Position+1) < file->Size) ) |
if((0 < file->Size) && ((file->Position) < file->Size) ) |
{ |
curr_sector = file->FirstSectorOfCurrCluster; // calculate the sector of the next character to be read. |
curr_sector += file->SectorOfCurrCluster; |
2041,3 → 2057,486 |
UnlockFilePointer(file); |
return(pVolumeLabel); |
} |
|
|
|
#define ATTR_NONE 0x00 // normal file |
#define ATTR_READONLY 0x01 // file is readonly |
#define ATTR_HIDDEN 0x02 // file is hidden |
#define ATTR_SYSTEM 0x04 // file is a system file |
#define ATTR_VOLUMELABEL 0x08 // entry is a volume label |
#define ATTR_LONG_FILENAME 0x0F // this is a long filename entry |
#define ATTR_SUBDIRECTORY 0x10 // entry is a directory name |
#define ATTR_ARCHIVE 0x20 // file is new or modified |
|
|
/********************************************************************************************************************************************/ |
/* Function: u8 FindItem(Find_t); */ |
/* */ |
/* Description: This function looks for the item specified by global structure FindElement in the actual directory */ |
/* */ |
/* */ |
/* Returnvalue: TRUE if an matching element was found */ |
/********************************************************************************************************************************************/ |
|
u8 FindItem(Find_t *findelement) |
{ |
u16 index = 0; |
u16 end_of_directory_not_reached = 1; // the directory has been read completely without a result. |
u8 i = 0; |
u8 readpointer = 0; |
u8 writepointer = 0; |
u8 retvalue = 0; |
DirEntry_t *DirectoryEntry; |
File_t file; |
|
file.FirstSectorOfCurrCluster = findelement->fp.FirstSectorOfCurrCluster; |
file.SectorOfCurrCluster = findelement->fp.SectorOfCurrCluster; |
index = findelement->fp.DirectoryIndex; |
|
|
do |
{ // search the next 16 rootentries in this sector of the roordirectory. |
SDC_GetSector(((u32) file.FirstSectorOfCurrCluster + (u32)file.SectorOfCurrCluster), file.Cache); // Read the Rootdirectory. |
DirectoryEntry = (DirEntry_t *)file.Cache; |
|
while((!retvalue)&&(index<16)) |
{ |
i=0; |
if((u8) DirectoryEntry[index].Name[0] != 0xe5) // ignore deleted items. |
{ |
while((i<=10)&&((DirectoryEntry[index].Name[i] == findelement->searchstring[i]) || (findelement->searchstring[i]=='*') || findelement->searchstring[i]=='?')) |
{ |
i++; |
} |
} |
if((DirectoryEntry[index].Attribute <= 0x30) && (DirectoryEntry[index].Attribute & findelement->attribmask) && (i==11)) |
{ |
for(readpointer=0;readpointer<=10;readpointer++) |
{ |
if((DirectoryEntry[index].Name[readpointer] != ' ') && (readpointer!=8)) |
{ |
findelement->name[writepointer] = DirectoryEntry[index].Name[readpointer]; // copy the name of the item found to the find_structure. |
writepointer++; |
} |
else |
{ |
if(DirectoryEntry[index].Attribute == ATTR_ARCHIVE) |
{ |
if(readpointer < 8) readpointer=8; |
if(DirectoryEntry[index].Name[readpointer] != ' ') |
{ |
findelement->name[writepointer] = '.'; // then seperate the name and the extension by a '.' at index 8. |
writepointer++; |
findelement->name[writepointer] = DirectoryEntry[index].Name[readpointer]; // copy the name of the item found to the find_structure. |
writepointer++; |
} |
else break; |
} |
else break; |
} |
/* terminate the namestring with 0 for debugpurposes*/ |
findelement->name[12] = 0; |
} |
findelement->fp.FirstSectorOfFirstCluster = (u32) DirectoryEntry[index].StartCluster; |
findelement->fp.DirectoryIndex = index; |
findelement->fp.FirstSectorOfCurrCluster = file.FirstSectorOfCurrCluster; |
findelement->fp.DirectorySector = (file.FirstSectorOfCurrCluster + file.SectorOfCurrCluster); |
findelement->fp.SectorOfCurrCluster = file.SectorOfCurrCluster; |
findelement->fp.Size = DirectoryEntry[index].Size; |
findelement->fp.Attribute = DirectoryEntry[index].Attribute; |
retvalue = 1; |
} |
index++; |
} |
if(!retvalue) // file not found in this sector so take next sector. |
{ |
file.SectorOfCurrCluster++; |
if(file.SectorOfCurrCluster >= Partition.SectorsPerCluster) |
{ |
file.SectorOfCurrCluster=0; |
end_of_directory_not_reached = GetNextCluster(&file); |
} |
} |
index = 0; |
} |
while((end_of_directory_not_reached) && (!retvalue)); |
|
return(retvalue); |
} |
|
|
/********************************************************************************************************************************************/ |
/* Function: findnext_(Find_t *); */ |
/* */ |
/* Description: This function looks for the next item in the specified directory with a matching filename and fileattributes specified */ |
/* by function findfirst() */ |
/* */ |
/* Returnvalue: */ |
/********************************************************************************************************************************************/ |
u8 findnext_(Find_t * findelement) |
{ |
u8 itemfound = 0; |
u8 index = 0; |
|
findelement->fp.DirectoryIndex++; |
|
/* before we start searching an element we clear the complete namestring within the structure FindElement */ |
for(index=0;index<11;index++) findelement->name[index] = 0; |
|
if(FindItem(findelement)) |
{ |
itemfound = 1; |
} |
|
return(itemfound); |
} |
|
|
|
/********************************************************************************************************************************************/ |
/* Function: findfirst_(s8* filename, u8 attribfilter, u8 attribmask, Find_t *); */ |
/* */ |
/* Description: This function looks for the first item in the specified directory with a matching filename and fileattributes */ |
/* The filename of the element found is transformed from 8.3 to a string */ |
/* */ |
/* */ |
/* Returnvalue: (1) if Element was found. (0) if no valid element was found */ |
/********************************************************************************************************************************************/ |
u8 findfirst_(const s8* name, u8 attribmask, Find_t *findelement) |
{ |
u8 itemfound = 0; |
u8 index = 0; |
|
/* initialize the FindElement structure */ |
findelement->fp.FirstSectorOfFirstCluster = 0; // First sector of the first cluster of the file. |
findelement->fp.FirstSectorOfCurrCluster = Partition.CurrentWorkingDirectory; // First sector of the cluster which is edited at the moment. |
findelement->fp.SectorOfCurrCluster = 0; // The sector within the current cluster. |
findelement->fp.ByteOfCurrSector = 0; // The byte location within the current sector. |
findelement->fp.Size = 0; // The size of the opend file in bytes. |
findelement->fp.Position = 0; // Pointer to a character within the file 0 < fileposition < filesize |
findelement->fp.DirectorySector = 0; // the sectorposition where the directoryentry has been made. |
findelement->fp.DirectoryIndex = 0; // The index to the directoryentry within the specified sector. |
findelement->attribfilter = 0; |
findelement->attribmask = attribmask; |
findelement->searchstring[0]=0; |
|
/* seperate the name of the element to be found from the filepath and bring it to the 8.3*/ |
SeperateDirName(name, findelement->searchstring); |
/* after the name of the element is in 8.3 we process the wildcards (*). After an * all following character are wildcards to */ |
for(index=0;index<8;index++) |
{ |
/* if we find an wildcard within the name of the searchstring all remaining character after the wildcard shall be wildcards also */ |
if(findelement->searchstring[index] == '*') |
{ |
/* */ |
while(++index <8) findelement->searchstring[index] = '*'; |
} |
} |
for(index=8;index<11;index++) |
{ |
/* if we find an wildcard within the name of the searchstring all remaining character after the wildcard shall be wildcards also */ |
if(findelement->searchstring[index] == '*') |
{ |
/* */ |
while(++index <11) findelement->searchstring[index] = '*'; |
} |
} |
|
/* the value of ...DirectoryIndex will be incremented in findnext_() thererfore it has to be decremented in findfirst_() */ |
findelement->fp.DirectoryIndex--; |
/* now lets search for the item within the direcory */ |
itemfound = findnext_(findelement); |
|
return(itemfound); |
} |
|
|
/********************************************************************************************************************************************/ |
/* Function: u8 GetDirCount(s8* filepath); */ |
/* */ |
/* Description: This function counts the number of subdirectories the dirpath contains */ |
/* */ |
/* */ |
/* Returnvalue: then number of subdirectories within the specified path */ |
/********************************************************************************************************************************************/ |
u8 GetDirCount(u8 *dirpath) |
{ |
u8 i=0; |
u8 cnt=0; |
|
while(dirpath[i] != 0) |
{ |
if(dirpath[i]=='/') |
{ |
if(dirpath[i+1]!=0) cnt++; // ignore last'/' |
} |
i++; |
} |
i=0; |
return(cnt); |
} |
|
|
/********************************************************************************************************************************************/ |
/* Funtion: char *GetSubDirectory (char *dirpath, char *directory) */ |
/* */ |
/* Description: this function returns a pointer to the beginning of the next subdirectory or NULL */ |
/* */ |
/* */ |
/* returnvalue: number of subdirectories in the filepath */ |
/********************************************************************************************************************************************/ |
u8 * GetSubDirectory(u8 *dirpath, u8 *directory) |
{ |
u8 *cptr = dirpath; |
u8 *dptr = directory; |
u8 *retvalue = NULL; |
|
/* if the first character of the path is an '/' we go to the next character */ |
if(*cptr == '/') cptr++; |
/* search end of path or subdirectory*/ |
while((*cptr != 0) && (*cptr != '/')) |
{ |
*dptr = *cptr; |
dptr++; |
cptr++; |
} |
if(*cptr!=0) retvalue = ++cptr; |
*dptr = 0; |
|
return(retvalue); |
} |
|
/********************************************************************************************************************************************/ |
/* Function: s8 *GetPath(void); */ |
/* */ |
/* Description: This function function returns a pointer to the absolute path of the active partition */ |
/* */ |
/* */ |
/* Returnvalue: */ |
/********************************************************************************************************************************************/ |
|
s8 *GetPath(void) |
{ |
return(Partition.PathToCwd); |
} |
|
/********************************************************************************************************************************************/ |
/* Function: void SetPathToRoot(void); */ |
/* */ |
/* Description: This function sets the path to the rootdirectory */ |
/* */ |
/* */ |
/* Returnvalue: */ |
/********************************************************************************************************************************************/ |
|
void SetPathToRoot(void) |
{ |
/* lets point to the rootdirectory */ |
strcpy(Partition.PathToCwd, "/"); |
} |
|
/********************************************************************************************************************************************/ |
/* Function: void AppendDirToPath(s8* directory); */ |
/* */ |
/* Description: This function function appends the name of an directory to the Path to the CWD */ |
/* */ |
/* */ |
/* Returnvalue: */ |
/********************************************************************************************************************************************/ |
|
void AppendDirToPath(s8* directory) |
{ |
/* append the name of the directory to the path */ |
strcat(Partition.PathToCwd, directory); |
/* append a '/' after the directoryname */ |
strcat(Partition.PathToCwd, "/"); |
} |
|
/********************************************************************************************************************************************/ |
/* Function: RemoveLastDirFromPath(void); */ |
/* */ |
/* Description: This function removes the last directory from the path to the cwd */ |
/* */ |
/* */ |
/* Returnvalue: */ |
/********************************************************************************************************************************************/ |
|
void RemoveLastDirFromPath(void) |
{ |
/* a pointer to the beginning of the absolute path to the cwd */ |
s8 * cptr = Partition.PathToCwd; |
/* lets find the end of the path to the cwd */ |
while(*cptr++ != 0); |
/* now lets find the beginning of the last directorientry */ |
while(*cptr-- != '/'); |
/* we delete the direntry by terminating the path with 0 */ |
*++cptr = 0; |
} |
|
/********************************************************************************************************************************************/ |
/* Function: chdir_(s8* filepath); */ |
/* */ |
/* Description: This function changed the current working directory to the directory specified by the filepath */ |
/* by function findfirst() */ |
/* */ |
/* Returnvalue: */ |
/********************************************************************************************************************************************/ |
/* |
#define ATTR_NONE 0x00 // normal file |
#define ATTR_READONLY 0x01 // file is readonly |
#define ATTR_HIDDEN 0x02 // file is hidden |
#define ATTR_SYSTEM 0x04 // file is a system file |
#define ATTR_VOLUMELABEL 0x08 // entry is a volume label |
#define ATTR_LONG_FILENAME 0x0F // this is a long filename entry |
#define ATTR_SUBDIRECTORY 0x10 // entry is a directory name |
#define ATTR_ARCHIVE 0x20 // file is new or modified |
*/ |
|
u8 chdir_(s8 *path) |
{ |
u8 retvalue = 0; // the value returned by this function |
u32 ultemp = 0; // temp. variable |
u8 *directory = path; // pointer to a directoryname within the path |
u8 dircount = 0; // the number of subdirectoryentries within the path |
u8 cache[64]; // a buffer containing the name of the subdirectory we are actually looking for |
Find_t fe; // The findelement needed for function findfirst to find the subdirectoryentry |
s8 tp[256]; // temporarily we remember the actual path until the operation has finished successfully |
u32 cwdt = 0; |
|
/* lets remember the actual path */ |
strcpy(tp, Partition.PathToCwd); |
cwdt = Partition.CurrentWorkingDirectory; |
/* if the path is absolute we begin at the rootdirectory */ |
strcpy(Partition.PathToCwd, "/"); |
/* how many subdirectories are there within the path? */ |
dircount = GetDirCount(path); |
/* now we parse through all the subdirectories within the path */ |
do |
{ |
/* until all the subdirectories within the path have been processed */ |
if(dircount) dircount--; |
/* this is the name of the next subdirectory we are looking for */ |
directory = GetSubDirectory(directory, cache); |
/* search for the next subdirectory within the path */ |
if(findfirst_(cache, ATTR_SUBDIRECTORY, &fe)) |
{ |
/* we try to change into the directory "..". Now we have to delete the last direntry from the path */ |
if(strcmp(cache,"..") == 0) RemoveLastDirFromPath(); |
/* we try to change into the actual directory so there's nothing todo */ |
else if(cache[0] == '.') return(1); |
/* otherwise we append the name of the directory we are changing in to the path */ |
else AppendDirToPath(cache); |
/* The startcluster within an directoryentry specifies the position within the fat where the file or directory starts */ |
ultemp = (u32) fe.fp.FirstSectorOfFirstCluster; |
/* the first 2 entries are reserved for '.' and '..' */ |
ultemp -= 2; |
/* now we have to transform the position within the fat into the corrosponding sectoraddress relative to the beginning of the datasection of the active partition*/ |
ultemp *= Partition.SectorsPerCluster; |
/* at least we make the sectoraddress absolute by adding the relative address to the beginning of the datasection of the active partition */ |
ultemp += Partition.FirstDataSector; |
/* the cwd now points to the specified directory */ |
Partition.CurrentWorkingDirectory = ultemp; |
/* we found the folder specified by the foldername */ |
retvalue = 1; |
} |
} |
/* do this until all subdirectories have been found or a subdirectory is missing */ |
while(dircount && retvalue); |
|
/* if we could not change to the specified directory we restore the actual path */ |
if(!retvalue) |
{ |
Partition.CurrentWorkingDirectory = cwdt; |
strcpy(Partition.PathToCwd, tp); |
} |
return(retvalue); |
} |
|
/********************************************************************************************************************************************/ |
/* Function: void Test(void); */ |
/* */ |
/* Description: Diese Funktion demonstriert die Möglichkeiten der Funktionen findfirst_() findnext_() und changedir_() */ |
/* */ |
/* */ |
/* Returnvalue: */ |
/********************************************************************************************************************************************/ |
|
void Test(void) |
{ |
File_t *fp = NULL; |
Find_t fe; |
u32 cwd = 0; |
|
|
cwd = Partition.CurrentWorkingDirectory; |
sprintf(text,"\r\n Path: %s\r\n",Partition.PathToCwd); UART1_PutString(text); |
/* Als Erstes suchen wir uns das erste Unterverzeichnis (ATTR_SUBDIRECTORY) auf der Speicherkarte */ |
if(findfirst_("*.*", ATTR_SUBDIRECTORY, &fe)) |
{ |
/* Danach wechseln wir in in dieses Unterverzeichnis auf der speicherkarte */ |
if(chdir_(fe.name)) |
{ |
sprintf(text,"\r\n Path: %s\r\n",Partition.PathToCwd); UART1_PutString(text); |
/* Dann finden wir die erste Datei (ATTR_ARCIVE) in diesem Unterverzeichnis */ |
if(findfirst_("*.*", ATTR_ARCHIVE, &fe)) |
{ |
/* Der Name der gefundenen Datei wird ausgegeben */ |
UART1_PutString("\r\n"); |
UART1_PutString(fe.name); |
/* nun wir die erste gefundene Datei im Unterverzeichnis lesend geöffnet */ |
fp = fopen_(fe.name, 'r'); |
if(fp != NULL){ |
/* und die erste Zeile aus dem Inhalt ausgegeben */ |
fgets_(text,60,fp); |
UART1_PutString("\r\n"); |
UART1_PutString(text); |
fclose_(fp); |
} |
else { |
UART1_PutString("\r\nfile not found"); |
} |
|
/* anschließend suchen wir alle weiteren Dateien im aktuellen Unterverzeichnis */ |
while(findnext_(&fe)) |
{ |
/* und geben ebenfalls deren Namen */ |
UART1_PutString("\r\n"); |
UART1_PutString(fe.name); |
/* sowie nach dem Öffnen ihren Inhalt aus */ |
fp = fopen_(fe.name, 'r'); |
if(fp != NULL) |
{ |
fgets_(text,60,fp); |
UART1_PutString("\r\n"); |
UART1_PutString(text); |
fclose_(fp); |
} |
} |
} |
} |
} |
Partition.CurrentWorkingDirectory = cwd; |
sprintf(text,"\r\n Path: %s\r\n",Partition.PathToCwd); UART1_PutString(text); |
if(chdir_("/ordner1/ordner12/ordner13")) |
{ |
sprintf(text,"\r\n Path: %s\r\n",Partition.PathToCwd); UART1_PutString(text); |
fp = fopen_("Datei13.txt", 'r'); |
if(fp != NULL){ |
/* und die erste Zeile aus dem Inhalt ausgegeben */ |
fgets_(text,60,fp); |
UART1_PutString("\r\n"); |
UART1_PutString(text); |
fclose_(fp); |
} |
else { |
UART1_PutString("\r\nfile not found"); |
} |
} |
else |
UART1_PutString("\r\ndirectory not found"); |
/* jetzt sind wir wieder im Rootverzeichnis */ |
Partition.CurrentWorkingDirectory = cwd; |
sprintf(text,"\r\n Path: %s\r\n",Partition.PathToCwd); UART1_PutString(text); |
} |
|