Subversion Repositories NaviCtrl

Compare Revisions

Ignore whitespace Rev 14 → Rev 15

/branches/V0.1 killagreg/fat16.c
54,7 → 54,7
// + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// + POSSIBILITY OF SUCH DAMAGE.
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//#include <stdio.h>
#include <stdio.h>
#include "91x_lib.h"
#include "fat16.h"
#include "sdc.h"
230,9 → 230,9
 
#define SLOT_EMPTY 0x00 // slot has never been used
#define SLOT_E5 0x05 // the real value is 0xe5
#define SLOT_DELETED 0xe5 // file in this slot deleted
#define SLOT_DELETED 0xE5 // file in this slot deleted
 
#define ATTR_NORMAL 0x00 // normal file
#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
289,6 → 289,7
u32 FirstFatSector; // sector of the start of the fat
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
} Partition_t;
 
Partition_t Partition; // Structure holds partition information
295,6 → 296,7
 
File_t FilePointer[FILE_MAX_OPEN]; // Allocate Memmoryspace for each filepointer used.
 
 
/****************************************************************************************************************************************/
/* Function: SeperateDirName(u8*, u8*, u8*); */
/* */
302,22 → 304,23
/* into the needed format ('test.txt' -> 'TEST TXT') */
/* The subpath is the pointer to the remaining substring if the filepath */
/* */
/* Returnvalue: Return 0 on error */
/* Returnvalue: Return 0 on error ot pointer to subpath */
/****************************************************************************************************************************************/
u8 SeperateDirName(const u8 *filepath, u8 *dirname, u8 *subpath)
u8* SeperateDirName(const u8 *filepath, u8 *dirname)
{
u8* readpointer = 0;
u8* subpath = 0;
u8 readpointer = 0;
u8 writepointer = 0;
 
// search subpath from beginning of filepath
subpath = 0;
readpointer = (u8*)filepath;
if(*readpointer == '/') readpointer++; // ignore first '/'
readpointer = 0;
if(filepath[0] == '/') readpointer = 1; // ignore first '/'
while(!subpath) // search the filepath until a subpath was found.
{
if(((*readpointer == 0) || (*readpointer == '/'))) // if '/' found or end of filepath reached
if(((filepath[readpointer] == 0) || (filepath[readpointer] == '/'))) // if '/' found or end of filepath reached
{
subpath = readpointer; // store the position of the first "/" found after the beginning of the filenpath
subpath = (u8*)&filepath[readpointer]; // store the position of the first "/" found after the beginning of the filenpath
}
readpointer++;
}
326,12 → 329,12
for(writepointer = 0; writepointer < 11; writepointer++) dirname[writepointer] = ' ';
writepointer = 0;
// start seperating the dirname from the filepath.
readpointer = (u8*)filepath;
if(*readpointer == '/') readpointer++; // ignore first '/'
while( readpointer < subpath)
readpointer = 0;
if(filepath[0] == '/') readpointer = 1; // ignore first '/'
while( &filepath[readpointer] < subpath)
{
if(writepointer >= 11) return 0; // dirname to long
if(*readpointer == '.') // seperating dirname and extension.
if(filepath[readpointer] == '.') // seperating dirname and extension.
{
if(writepointer<8)
{
342,19 → 345,19
}
else
{
if((0x60 < *readpointer) && (*readpointer < 0x7B))
if((0x60 < filepath[readpointer]) && (filepath[readpointer] < 0x7B))
{
dirname[writepointer] = (*readpointer - 0x20); // all characters must be upper case.
dirname[writepointer] = (filepath[readpointer] - 0x20); // all characters must be upper case.
}
else
{
dirname[writepointer] = *readpointer;
dirname[writepointer] = filepath[readpointer];
}
readpointer++;
writepointer++;
}
}
return (1);
return (subpath);
}
 
 
393,7 → 396,7
/* */
/* Returnvalue: The function returns "0" if the filesystem is initialized. */
/****************************************************************************************************************************************/
s16 InitFat16_Init(void)
s16 Fat16_Init(void)
{
u8 cnt = 0;
u32 PartitionFirstSector;
415,7 → 418,7
cnt = 0;
while(SD_SUCCESS != SDC_Init())
{
if(cnt > 200)
if(cnt > 5)
{
SerialPutString("SD-Card could not be initialized.\r\n");
return(1);
464,6 → 467,13
// Calculate the position of the first datacluster:
// Start + # of Reserved + (# of Sectors Per FAT * # of FAT Copies) + ((Maximum Root Directory Entries * 32) / Bytes per Sector)
Partition.FirstDataSector = Partition.FirstRootDirSector + (u32)(Partition.MaxRootEntries>>4); // assuming 512 Byte Per Sector
// Calculate the last data sector
if(VBR->NoSectors == 0)
{
SerialPutString("Bad nuber of sectors in this partition.\r\n");
return(4);
}
Partition.LastDataSector = Partition.FirstDataSector + VBR->NoSectors - 1;
// check for FAT16 in VBR of first partition
if(!((VBR->FATName[0]=='F') && (VBR->FATName[1]=='A') && (VBR->FATName[2]=='T') && (VBR->FATName[3]=='1')&&(VBR->FATName[4]=='6')))
{
499,10 → 509,26
return(returnvalue);
}
 
/****************************************************************************************************************************************/
/* Function: ClearCurrCluster(File_t file); */
/* */
/* Description: This function fills the current cluster with 0. */
/* */
/* Returnvalue: The function returns 1 on success else 0. */
/****************************************************************************************************************************************/
u8 ClearCurrCluster(File_t * File)
{
u8 retvalue = 1;
u32 i;
for(i = 0; i < BYTES_PER_SECTOR; i++) File->Cache[i] = 0; // clear file cache
for(i = 0; i < Partition.SectorsPerCluster; i++)
{
File->SectorInCache = File->FirstSectorOfCurrCluster + i;
if(SD_SUCCESS != SDC_PutSector(File->SectorInCache, File->Cache)) retvalue = 0;
}
return(retvalue);
}
 
 
 
 
/*****************************************************************************************************************************************/
/* Function: GetNextCluster(File_t file); */
/* */
518,7 → 544,7
if(File == 0) return(cluster);
// if sector is within the data area
if(Partition.FirstDataSector <= File->FirstSectorOfCurrCluster)
if((Partition.FirstDataSector <= File->FirstSectorOfCurrCluster)&& (File->FirstSectorOfCurrCluster <= Partition.LastDataSector))
{
// determine current file cluster
cluster = SectorToFat16Cluster(File->FirstSectorOfCurrCluster);
549,21 → 575,6
File->ByteOfCurrSector = 0;
}
}
// if sector is within the root directory
else if((Partition.FirstRootDirSector <= File->FirstSectorOfCurrCluster) && (File->FirstSectorOfCurrCluster < Partition.FirstDataSector))
{
if((File->FirstSectorOfCurrCluster + 1) == Partition.FirstDataSector)
{
cluster = 0;
}
else
{
File->FirstSectorOfCurrCluster++;
File->SectorOfCurrCluster = 0;
File->ByteOfCurrSector = 0;
cluster = 1;
}
}
return(cluster);
}
 
591,7 → 602,11
{
curr_sector = Partition.FirstFatSector + fat_sector; // calculate sector to read
File->SectorInCache = curr_sector; // upate the sector number of file cache.
SDC_GetSector(File->SectorInCache, File->Cache); // read sector of fat from sd-card.
if( SD_SUCCESS != SDC_GetSector(File->SectorInCache, File->Cache)) // read sector of fat from sd-card.
{
return(free_cluster);
}
 
Fat = (Fat16Entry_t *)File->Cache; // set fat pointer to file cache
 
for(fat_entry = 0; fat_entry < FAT16_ENTRIES_PER_SECTOR; fat_entry++) // look for an free cluster at all entries in this sector of the fat.
599,8 → 614,10
if(Fat[fat_entry].NextCluster == FAT16_CLUSTER_FREE) // empty cluster found!!
{
Fat[fat_entry].NextCluster = FAT16_CLUSTER_LAST_MAX; // mark this fat-entry as used
SDC_PutSector(File->SectorInCache, File->Cache); // and save the sector at the sd-card.
 
if(SD_SUCCESS != SDC_PutSector(File->SectorInCache, File->Cache)) // and save the sector at the sd-card.
{
return(free_cluster);
}
free_cluster = (u16)(fat_sector * FAT16_ENTRIES_PER_SECTOR + (u32)fat_entry);
fat_entry = FAT16_ENTRIES_PER_SECTOR; // terminate the search for a free cluster in this sector.
}
715,18 → 732,19
File->FirstSectorOfCurrCluster = Fat16ClusterToSector(new_cluster);
File->SectorOfCurrCluster = 0;
File->ByteOfCurrSector = 0;
ClearCurrCluster(File);
}
return(new_cluster);
}
 
/****************************************************************************************************************************************************/
/* Function: DirectoryEntryExist(u8 *, File_t *) */
/* Function: DirectoryEntryExist(u8 *, u8, u8, File_t *) */
/* */
/* Description: This function searches all possible dir entries until the file or directory is found or the end of thedirectory is reached */
/* Description: This function searches all possible dir entries until the file or directory is found or the end of the directory is reached */
/* */
/* Returnvalue: This function returns 1 if the directory entry specified was found. */
/****************************************************************************************************************************************************/
u8 DirectoryEntryExist(u8 *dirname, File_t *File)
u8 DirectoryEntryExist(u8 *dirname, u8 attribfilter, u8 attribmask, File_t *File)
{
u32 dir_sector, max_dir_sector, curr_sector;
u16 dir_entry = 0;
733,33 → 751,65
 
u16 end_of_directory_not_reached = 0;
u8 i = 0;
u8 retvalue = 0;
u8 direntry_exist = 0;
DirEntry_t * Dir;
 
if(File == 0) return(0);
// if incomming pointers are useless return immediatly
if((File == 0) || (dirname == 0)) return(direntry_exist);
 
// dir entries can be searched only in filesclusters that have
// the dir-flag set in its attribute or within the root directory
// within the root directory area its allways valid to search a directory entry
if((Partition.FirstRootDirSector <= File->DirectorySector) && (File->DirectorySector < Partition.FirstDataSector))
// a corresponding dir entry with adir-flag set in its attribute
// or direct within the root directory area
File->FirstSectorOfFirstCluster = 0;
// no current directory exist therefore assume searching in the root
if(File->DirectorySector == 0)
{
max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
File->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
}
// within the root directory area we can read sectors sequentially until the end of this area
else if((Partition.FirstRootDirSector <= File->DirectorySector) && (File->DirectorySector < Partition.FirstDataSector))
{
max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
}
// check if directory entry of current file has the dir-flag set
else if(Partition.FirstDataSector <= File->DirectorySector)
// within the data clusters we can read sectors sequentially only within the cluster
else if((Partition.FirstDataSector <= File->DirectorySector) && (File->DirectorySector <= Partition.LastDataSector))
{
max_dir_sector = Partition.SectorsPerCluster;
File->SectorInCache = File->DirectorySector; // upate the sector number of file cache.
max_dir_sector = Partition.SectorsPerCluster; // limit max secters before next cluster
}
else return (direntry_exist); // bad sector range for directory sector of the file
// if search area is not defined yet
if(File->FirstSectorOfFirstCluster == 0)
{
// check if the directory entry of current file is existent and has the dir-flag set
File->SectorInCache = File->DirectorySector; // update the sector number of file cache.
SDC_GetSector(File->SectorInCache, File->Cache); // read in the sector.
Dir = (DirEntry_t *)File->Cache; // set pointer to directory
if(Dir[File->DirectoryIndex].Attribute != ATTR_SUBDIRECTORY)
{ // current file is not a directory
return (0);
switch(Dir[File->DirectoryIndex].Name[0]) // check if current directory exist
{
case SLOT_EMPTY:
case SLOT_DELETED:
// the directrory pointer of this file points to a deleted or not existen directory
// therefore no file or subdirectory can be created
return (direntry_exist);
break;
default: // and is a real directory
if((Dir[File->DirectoryIndex].Attribute & ATTR_SUBDIRECTORY) != ATTR_SUBDIRECTORY)
{ // current file is not a directory therefore no file or subdirectory can be created here
return (direntry_exist);
}
break;
}
File->FirstSectorOfFirstCluster = Fat16ClusterToSector(Dir[File->DirectoryIndex].StartCluster);
}
else return (0); // bad sector range for directory sector of the file
 
do // loop over all clusters of the curernt directory
// update current file data area position to start of first cluster
File->FirstSectorOfCurrCluster = File->FirstSectorOfFirstCluster;
File->SectorOfCurrCluster = 0;
File->ByteOfCurrSector = 0;
 
do // loop over all data clusters of the current directory entry
{
dir_sector = 0; // reset sector counter within a new cluster
do // loop over all sectors of a cluster or all sectors of the root directory
766,11 → 816,11
{
curr_sector = File->FirstSectorOfCurrCluster + dir_sector; // calculate sector number
File->SectorInCache = curr_sector; // upate the sector number of file cache.
SDC_GetSector(File->SectorInCache, File->Cache); // read in the sector.
SDC_GetSector(File->SectorInCache, File->Cache); // read the sector
Dir = (DirEntry_t *)File->Cache; // set pointer to directory
// search all directory entries of a sector
// search all directory entries within that sector
for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
{
{ // check for existing dir entry
switch(Dir[dir_entry].Name[0])
{
case SLOT_EMPTY:
778,33 → 828,36
// ignore empty or deleted dir entries
break;
default:
// check attributes before names are compared will safe performance
if (Dir[dir_entry].Attribute != File->Attribute) break; // attribute must match
// compare the dirname to filename (first 9 characters including 8 char of the dirname and padded space char.)
// if existing check attributes before names are compared will safe performance
if ((Dir[dir_entry].Attribute & attribmask) != attribfilter) break; // attribute must match
// then compare the name to the giveb dirname (first 11 characters include 8 chars of basename and 3 chars extension.)
i = 0;
while((i < 11) && (Dir[dir_entry].Name[i] == dirname[i])) i++;
if (i < 10) break; // names does not match
File->Attribute = Dir[dir_entry].Attribute; // store attribute of dir entry
File->FirstSectorOfFirstCluster = Fat16ClusterToSector(Dir[dir_entry].StartCluster); // set start cluster sector
// if dirname and attribute have matched
File->Attribute = Dir[dir_entry].Attribute; // store attribute of found dir entry
File->FirstSectorOfFirstCluster = Fat16ClusterToSector(Dir[dir_entry].StartCluster); // set sector of first data cluster
File->FirstSectorOfCurrCluster = File->FirstSectorOfFirstCluster;
File->DirectorySector = File->SectorInCache; // store position of dir entry of that file
File->DirectoryIndex = dir_entry;
File->Size = Dir[dir_entry].Size;
retvalue = 1; // mark as found
dir_entry = DIRENTRIES_PER_SECTOR; // stop for-loop
File->SectorOfCurrCluster = 0;
File->ByteOfCurrSector = 0;
File->DirectorySector = curr_sector; // current sector
File->DirectoryIndex = dir_entry; // current direntry in current sector
File->Size = Dir[dir_entry].Size;
direntry_exist = 1; // mark as found
dir_entry = DIRENTRIES_PER_SECTOR; // stop for-loop
} // end of first byte of name check
}
dir_sector++; // search next sector
// stop if we reached the end of the cluster or the end of the root dir
}while((dir_sector < max_dir_sector) && (!retvalue));
}while((dir_sector < max_dir_sector) && (!direntry_exist));
 
// if we are seaching in the data area and the file not found in this cluster so take next cluster.
if(!retvalue && ( Partition.FirstDataSector <= File->FirstSectorOfCurrCluster))
if(!direntry_exist && ( Partition.FirstDataSector <= File->FirstSectorOfCurrCluster))
{
end_of_directory_not_reached = GetNextCluster(File); // updates File->FirstSectorOfCurrCluster
}
}while((end_of_directory_not_reached) && (!retvalue));
return(retvalue);
}while((end_of_directory_not_reached) && (!direntry_exist)); // repeat until a next cluster exist an no
return(direntry_exist);
}
 
 
816,99 → 869,260
/* */
/* Returnvalue: Return 0 on error */
/****************************************************************************************************************************************/
u8 CreateDirectoryEntry(u8 *name, File_t *File)
u8 CreateDirectoryEntry(u8 *dirname, u8 attrib, File_t *File)
{
u32 dir_sector, max_dir_sector, curr_sector;
u16 dir_entry = 0;
u16 cluster = 0;
u16 SubDirCluster, DirCluster = 0;
u16 end_of_directory_not_reached = 0;
u8 i = 0;
u8 retvalue = 0;
DirEntry_t *Dir;
 
 
if(File == 0) return (0);
if((File == 0) || (dirname == 0)) return (retvalue);
// It is not checked here that the dir entry that should be created is already existent!
// Dir entries can be created only in file-clusters that have
// the dir-flag set in its attribute or within the root directory
// within the root directory area its allways valid to create a directory entry
if((Partition.FirstRootDirSector <= File->DirectorySector) && (File->DirectorySector < Partition.FirstDataSector))
File->FirstSectorOfFirstCluster = 0;
// no current directory exist therefore assume creating in the root
if(File->DirectorySector == 0)
{
max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
DirCluster = 0;
File->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
}
// within the root directory area we can read sectors sequentially until the end of this area
else if((Partition.FirstRootDirSector <= File->DirectorySector) && (File->DirectorySector < Partition.FirstDataSector))
{
max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
}
// check if the directory entry of current file has the dir-flag set
else if(Partition.FirstDataSector <= File->DirectorySector)
// within the data clusters we can read sectors sequentially only within the cluster
else if((Partition.FirstDataSector <= File->DirectorySector) && (File->DirectorySector <= Partition.LastDataSector))
{
max_dir_sector = Partition.SectorsPerCluster;
}
else return (retvalue); // bad sector range for directory sector of the file
// if search area is not defined yet
if(File->FirstSectorOfFirstCluster == 0)
{
// check if the directory entry of current file is existent and has the dir-flag set
File->SectorInCache = File->DirectorySector; // update the sector number of file cache.
SDC_GetSector(File->SectorInCache, File->Cache); // read in the sector.
SDC_GetSector(File->SectorInCache, File->Cache); // read in the sector.
Dir = (DirEntry_t *)File->Cache; // set pointer to directory
if(Dir[File->DirectoryIndex].Attribute != ATTR_SUBDIRECTORY)
{ // current file is not a directory
return (0);
switch(Dir[File->DirectoryIndex].Name[0]) // check if current directory exist
{
case SLOT_EMPTY:
case SLOT_DELETED:
return (retvalue);
break;
default: // and is a real directory
if((Dir[File->DirectoryIndex].Attribute & ATTR_SUBDIRECTORY) != ATTR_SUBDIRECTORY)
{ // current file is not a directory therefore no file or subdirectory can be created here
return (retvalue);
}
break;
}
DirCluster = Dir[File->DirectoryIndex].StartCluster;
File->FirstSectorOfFirstCluster = Fat16ClusterToSector(DirCluster);
}
else return (0); // bad sector range for directory sector of the file
 
do // loop over all clusters of current directory
{
dir_sector = 0; // reset sector counter within a new cluster
do // loop over all sectors of a cluster or all sectors of the root directory
{
curr_sector = File->FirstSectorOfCurrCluster + dir_sector; // calculate sector number
File->SectorInCache = curr_sector; // upate the sector number of file cache.
SDC_GetSector(File->SectorInCache, File->Cache); // read in the sector.
Dir = (DirEntry_t *)File->Cache; // set pointer to directory
// search all directory entries of a sector
for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
{ // check if current direntry is available
if((Dir[dir_entry].Name[0] == SLOT_EMPTY) || (Dir[dir_entry].Name[0] == SLOT_DELETED))
{ // a free direntry was found
cluster = FindNextFreeCluster(File); // get the next free cluster on the disk.
if(cluster)
{
for(i = 0; i < 11; i++) Dir[dir_entry].Name[i] = name[i]; // Set dir name
Dir[dir_entry].Attribute = File->Attribute; // Set the fileattribute to archive to reserve the directoryentry.
Dir[dir_entry].StartCluster = cluster; // copy the location of the first datacluster to the directoryentry.
SubDirCluster = FindNextFreeCluster(File); // get the next free cluster on the disk and mark it as used.
if(SubDirCluster)
{
File->FirstSectorOfCurrCluster = File->FirstSectorOfFirstCluster;
File->SectorOfCurrCluster = 0;
do // loop over all clusters of current directory
{
dir_sector = 0; // reset sector counter within a new cluster
do // loop over all sectors of a cluster or all sectors of the root directory
{
curr_sector = File->FirstSectorOfCurrCluster + dir_sector; // calculate sector number
File->SectorInCache = curr_sector; // upate the sector number of file cache.
SDC_GetSector(File->SectorInCache, File->Cache);
Dir = (DirEntry_t *)File->Cache; // set pointer to directory
// search all directory entries of a sector
for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
{ // check if current direntry is available
if((Dir[dir_entry].Name[0] == SLOT_EMPTY) || (Dir[dir_entry].Name[0] == SLOT_DELETED))
{ // a free direntry was found
for(i = 0; i < 11; i++) Dir[dir_entry].Name[i] = dirname[i]; // Set dir name
Dir[dir_entry].Attribute = attrib; // Set the attribute of the new directoryentry.
Dir[dir_entry].StartCluster = SubDirCluster; // copy the location of the first datacluster to the directoryentry.
Dir[dir_entry].Size = 0; // the new createted file has no content yet.
SDC_PutSector(File->SectorInCache, File->Cache); // and save the sector containing new directory entry back to the sd-card.
File->FirstSectorOfFirstCluster = Fat16ClusterToSector(cluster); // Calculate absolute sectorposition of first datacluster.
SDC_PutSector(File->SectorInCache, File->Cache); // write back to card
File->FirstSectorOfFirstCluster = Fat16ClusterToSector(SubDirCluster); // Calculate absolute sectorposition of first datacluster.
File->FirstSectorOfCurrCluster = File->FirstSectorOfFirstCluster; // Start reading the file with the first sector of the first datacluster.
File->SectorOfCurrCluster = 0; // reset sector of cureen cluster
File->ByteOfCurrSector = 0; // reset byte location within the current sector
File->ByteOfCurrSector = 0; // reset the byte location within the current sector
File->Attribute = attrib; // set file attribute to dir attribute
File->Size = 0; // new file has no size
File->DirectorySector = curr_sector;
File->DirectoryIndex = dir_entry;
retvalue = 1;
dir_entry = DIRENTRIES_PER_SECTOR; // stop for-loop
if((attrib & ATTR_SUBDIRECTORY) == ATTR_SUBDIRECTORY) // if a new directory was created then initilize the data area
{
ClearCurrCluster(File); // fill cluster with zeros
File->SectorInCache = File->FirstSectorOfFirstCluster;
SDC_GetSector(File->SectorInCache, File->Cache);
Dir = (DirEntry_t *)File->Cache;
// create direntry "." to current dir
Dir[0].Name[0] = 0x2E;
for(i = 1; i < 11; i++) Dir[0].Name[i] = ' ';
Dir[0].Attribute = ATTR_SUBDIRECTORY;
Dir[0].StartCluster = SubDirCluster;
Dir[0].Size = 0;
// create direntry ".." to the upper dir
Dir[1].Name[0] = 0x2E;
Dir[1].Name[1] = 0x2E;
for(i = 2; i < 11; i++) Dir[1].Name[i] = ' ';
Dir[1].Attribute = ATTR_SUBDIRECTORY;
Dir[1].StartCluster = DirCluster;
Dir[1].Size = 0;
SDC_PutSector(File->SectorInCache, File->Cache);
}
retvalue = 1;
dir_entry = DIRENTRIES_PER_SECTOR; // stop for-loop
}
else
{ //no free cluster found in the fat
return (0);
}
}
dir_sector++; // search next sector
// stop if we reached the end of the cluster or the end of the root dir
}while((dir_sector < max_dir_sector) && (!retvalue));
// if we are seaching in the data area and the file not found in this cluster so take next cluster.
if(!retvalue && ( Partition.FirstDataSector <= File->FirstSectorOfCurrCluster))
{
end_of_directory_not_reached = GetNextCluster(File); // updates File->FirstSectorOfCurrCluster
}
}while((end_of_directory_not_reached) && (!retvalue));
// Perhaps we are at the end of the last cluster of a directory file an have no free direntry found.
// Then we would need to add a cluster to that file and create the new direntry there.
// This code is not implemented yet, because its occurs only if more that 32*32=1024 direntries are
// within a subdirectory of root.
}
return(retvalue); // return 1 if file has been created otherwise return 0.
}
 
/********************************************************************************************************************************************/
/* Function: FileExist(const u8* filename, u8 attribfilter, u8 attribmask, File_t *File); */
/* */
/* Description: This function looks for the specified filemincluding its subdirectories beginning */
/* in the rootdirectory of the drive. If the file is found the Filepointer properties are */
/* updated. */
/* */
/* Returnvalue: 1 if file is found else 0. */
/********************************************************************************************************************************************/
u8 FileExist(const u8* filename, const u8 attribfilter, const u8 attribmask, File_t *File)
{
u8 *path = 0, *subpath = 0;
u8 af, am, file_exist = 0;
u8 dirname[11];
 
// if incomming pointers are useless return immediatly
if ((filename == 0) || (File == 0)) return 0;
 
// trace along the filepath
path = (u8*)filename; // start a the beginning of the filename string
File->DirectorySector = 0; // start at RootDirectory with file search
File->DirectoryIndex = 0;
// 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
if((subpath = SeperateDirName(path, dirname)))
{
if(*subpath == 0)
{ // empty subpath indicates last element of dir chain
af = attribfilter;
am = attribmask;
}
else // it must be a subdirectory and no volume label
{
af = ATTR_SUBDIRECTORY;
am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;
}
if(!DirectoryEntryExist(dirname, af, am, File))
{
return (file_exist); // subdirectory does not exist
}
else
{
if (*subpath == 0)
{
file_exist = 1; // last element of path chain was found with the given attribute filter
}
}
dir_sector++; // search next sector
// stop if we reached the end of the cluster or the end of the root dir
}while((dir_sector < max_dir_sector) && (!retvalue));
// if we are seaching in the data area and the file not found in this cluster so take next cluster.
if(!retvalue && ( Partition.FirstDataSector <= File->FirstSectorOfCurrCluster))
}
}
else // error seperating the subpath
{
end_of_directory_not_reached = GetNextCluster(File); // updates File->FirstSectorOfCurrCluster
return file_exist; // bad subdir format
}
}while((end_of_directory_not_reached) && (!retvalue));
// Perhaps we are at the end of the last cluster of a directory file an have no free direntry found.
// Then we would need to add a cluster to that file and create the new direntry there.
// This code is not implemented yet, because its occurs only if more that 32*32=1024 direntries are
// within a subdirectory of root.
return(retvalue); // return 1 if file has been created otherwise return 0.
path = subpath;
subpath = 0;
}
return (file_exist);
}
 
 
/********************************************************************************************************************************************/
/* Function: FileCreate(const u8* filename, u8 attrib, File_t *File); */
/* */
/* Description: This function looks for the specified file including its subdirectories beginning */
/* in the rootdirectory of the partition. If the file is found the Filepointer properties are */
/* updated. If file or its subdirectories are not found they will be created */
/* */
/* Returnvalue: 1 if file was created else 0. */
/********************************************************************************************************************************************/
u8 FileCreate(const u8* filename, const u8 attrib, File_t *File)
{
u8 *path = 0;
u8 *subpath = 0;
u8 af, am, file_created = 0;
u8 dirname[11];
 
// if incomming pointers are useless return immediatly
if ((filename == 0) || (File == 0)) return 0;
 
// trace along the filepath
path = (u8*)filename; // start a the beginning of the filename string
File->DirectorySector = 0; // start at RootDirectory with file search
File->DirectoryIndex = 0;
// as long as the file was not created and the remaining file path is not empty
while((*path != 0) && !file_created)
{ // separate dirname and subpath from filepath string
if((subpath = SeperateDirName(path, dirname)))
{
if(*subpath == 0)
{ // empty subpath indicates last element of dir chain
af = ATTR_NONE;
am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL; // any file that is no subdir or volume label
}
else // it must be a subdirectory and no volume label
{
af = ATTR_SUBDIRECTORY;
am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;
}
if(!DirectoryEntryExist(dirname, af, am, File)) // if subdir or file is not existent
{ // try to create subdir or file
if(*subpath == 0) af = attrib; // if last element in dir chain take the given attribute
if(!CreateDirectoryEntry(dirname, af, File))
{ // could not be created
return(file_created);
}
else if (*subpath == 0) file_created = 1; // last element of path chain was created
}
}
else // error seperating the subpath
{
return file_created; // bad subdir format
}
path = subpath;
subpath = 0;
}
return (file_created);
}
 
 
/********************************************************************************************************************************************/
/* Function: File_t * fopen_(u8* filename, s8 mode); */
/* */
/* Description: This function looks for the specified file in the rootdirectory of the drive. If the file is found the number of the */
917,9 → 1131,7
/* Returnvalue: The filepointer to the file or 0 if faild. */
/********************************************************************************************************************************************/
File_t * fopen_(const u8 *filename, const s8 mode)
{
u8 name[11];
u8 *filepath = 0;
{
File_t *File = 0;
u8 i;
936,7 → 1148,8
// if no unused file pointer was found return 0
if(File == 0) return(File);
 
// initialize values
// now we have found a free filepointer and claimed it
// so let initiate its property values
File->FirstSectorOfFirstCluster = 0; // Sectorpointer to the first sector of the first datacluster of the file.
File->FirstSectorOfCurrCluster = 0; // Pointer to the cluster which is edited at the moment.
File->SectorOfCurrCluster = 0; // The sector which is edited at the moment (cluster_pointer + sector_index).
949,50 → 1162,66
File->DirectoryIndex = 0; // the index to the directoryentry within the specified sector.
File->Attribute = 0; // the attribute of the file opened.
 
// trace along the filepath by checking if the directories
filepath = (u8*)filename; // start a the beginning of the filename string
File->DirectorySector = Partition.FirstRootDirSector; // Root of RootDirectory is Root
File->FirstSectorOfCurrCluster = Partition.FirstRootDirSector; // start search in RootDirectory
File->Attribute = ATTR_SUBDIRECTORY; //check for directory
while(*filepath != 0)
{
if(SeperateDirName(filepath, name, filepath)) // separate dirname from filepath string
// check if a real file (no directory) to the given filename exist
if(FileExist(filename, ATTR_NONE, ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL, File))
{ // file exist
switch(mode) // check mode
{
if(!DirectoryEntryExist(name, File))
{
goto errorout; // subdirectory does not exist
}
case 'a': // if mode is: append to file
if((File->Attribute & ATTR_READONLY) == ATTR_READONLY)
{ // file is marked as readonly --> do not open this file
File->State = FSTATE_UNUSED; // release file pointer
File = 0;
}
else
{ // file is not marked as read only --> goto end of file
fseek_(File, 0, SEEK_END); // point to the end of the file
}
break;
case 'w': // if mode is: write to file
if((File->Attribute & ATTR_READONLY) == ATTR_READONLY)
{ // file is marked as readonly --> do not open this file
File->State = FSTATE_UNUSED; // release file pointer
File = 0;
}
else
{ // file is not marked as read only --> goto start of file
fseek_(File, 0, SEEK_SET);
}
break;
case 'r': // if mode is: read from to file
// goto end of file
fseek_(File, 0, SEEK_SET);
break;
default: // other modes are not supported
File->State = FSTATE_UNUSED; // release file pointer
File = 0;
break;
}
else // error seperating the subpath
{
goto errorout; // bad subdir format
}
}
// now name cointains the name of the file at the end of the filepath
File->Attribute = ATTR_ARCHIVE;
if(DirectoryEntryExist(name, File)) // file exist
{
if(mode == 'a') // if mode is: append to file
{
fseek_(File, 0, SEEK_END); // point to the end of the file
}
// else w /r ??
return(File);
}
else // file does not exist
{
if((mode == 'a') || (mode == 'w'))
switch(mode) // check mode
{
if(CreateDirectoryEntry(name, File)) // Could an entry for the new file in the directory be created?
{
return(File);
}
// else directory entry could be created at the current location --> error
case 'a':
case 'w': // if mode is write or append
// try to create the file
if(!FileCreate(filename, ATTR_ARCHIVE, File))
{ // if it could not be created
File->State = FSTATE_UNUSED; // release file pointer
File = 0;
}
break;
case 'r': // else opend for 'r'
default: // of unsupported mode
File->State = FSTATE_UNUSED; // release file pointer
File = 0;
break;
}
// else opend for 'r' and file is not existent --> error
return(File);
}
 
errorout:
// we should never come to this point
File->State = FSTATE_UNUSED; // release file pointer
File = 0;
return(File);
1132,7 → 1361,6
return(c);
}
 
 
/********************************************************************************************************************************************/
/* Function: fputc_( const s8 c, File *File); */
/* */
/branches/V0.1 killagreg/main.c
65,8 → 65,7
#include "i2c.h"
#include "timer.h"
#include "spi_slave.h"
#include "ssc.h"
#include "sdc.h"
#include "fat16.h"
#include "usb.h"
#include "sdc.h"
#include "main.h"
140,11 → 139,27
SPI0_Init();
// initialize i2c bus to MK3MAG
I2C1_Init();
// initialise SSC to the sdcard.
SSC_Init();
// try to initialize the sd card
SDC_Init();
//SDC_Init();
 
File_t *File = 0;
s16 c = 0;
u16 i;
if (0 == Fat16_Init())
{
File = fopen_("/dir/subdir/test.txt", 'a');
if(File != 0)
{
SerialPutString("File was opened.\r\n");
for(i=0;i<1000; i++)
{
fputs_("Das ist ein Test.\r\n", File);// 19 bytes
}
c = fclose_(File);
if (c != EOF) SerialPutString("File is closed.\r\n");
}
}
 
// get version from MK3MAG
I2C_Version.Major = 0xFF;
SendI2C_Command(I2C_CMD_VERSION);
156,9 → 171,7
TimerI2CReadDelay = SetDelay(5);
 
 
/*
InitFat16();
/*
ReadSetting(1);
*/
SerialPutString("Init done\n\r.");
216,3 → 229,25
}
 
 
//________________________________________________________________________________________________________________________________________
// Funtion: EXTIT1_IRQHandler(void);
//
// Description: This function handles the extnernal interrupts from port 5.3 (SD_SWITCH)
//
//
// Returnvalue: none
//________________________________________________________________________________________________________________________________________
void EXTIT1_IRQHandler(void)
{
VIC_ITCmd(EXTIT1_ITLine, DISABLE);
if(WIU_GetITStatus(WIU_Line11) != RESET)
{
BeepTime = 100;
Fat16_Init(); // initialize sd-card file system.
 
WIU_ClearFlag(WIU_Line1);
WIU_ClearITPendingBit(WIU_Line11);
}
VIC_ITCmd(EXTIT1_ITLine, ENABLE);
}
 
/branches/V0.1 killagreg/sdc.c
64,7 → 64,6
#include "main.h"
#include "crc16.h"
 
 
//________________________________________________________________________________________________________________________________________
// Module name: sdc.c
// Compiler used: avr-gcc 3.4.5
99,6 → 98,7
#define CMD_SEND_IF_COND 0x08 /* CMD08: response R7 */
#define CMD_SEND_CSD 0x09 /* CMD09: response R1 */
#define CMD_SEND_CID 0x0A /* CMD10: response R1 */
#define CMD_SEND_STATUS 0x0D /* CMD13: response R2 */
#define CMD_SET_BLOCKLEN 0x10 /* CMD16: arg0[31:0]: block length, response R1*/
#define CMD_READ_SINGLE_BLOCK 0x11 /* CMD17: arg0[31:0]: data address, response R1 */
#define CMD_WRITE_SINGLE_BLOCK 0x18 /* CMD24: arg0[31:0]: data address, response R1 */
107,16 → 107,26
#define CMD_CRC_ON_OFF 0x3B /* CMD59: arg0[31:1]: stuff bits, arg0[0:0]: crc option, response R1 */
#define ACMD_SEND_OP_COND 0x29 /* ACMD41: arg0[31]: stuff bits, arg0[30]: HCS, arg0[29:0] stuff bits*, response R1 */
 
#define R1_NO_ERROR 0x00
#define R1_NO_ERR 0x00
#define R1_IDLE_STATE 0x01
#define R1_ERASE_RESET 0x02
#define R1_ILLEGAL_CMD 0x04
#define R1_COM_CRC_ERROR 0x08
#define R1_ERASE_SEQUENCE_ERROR 0x10
#define R1_COM_CRC_ERR 0x08
#define R1_ERASE_SEQUENCE_ERR 0x10
#define R1_ADDRESS_ERR 0x20
#define R1_PARAMETER_ERR 0x40
#define R1_BAD_RESPONSE 0x80
 
#define R2_NO_ERR 0x00
#define R2_CARD_LOCKED 0x01
#define R2_ERASE_WRITE_PROT_ERR 0x02
#define R2_UNKOWN_ERR 0x04
#define R2_CARD_CTRL_ERR 0x08
#define R2_CARD_ECC_ERR 0x10
#define R2_WRITE_PROT_ERR 0x20
#define R2_ERASE_PARAM_ERR 0x40
#define R2_OUT_OF_RANGE_ERR 0x80
 
#define DATA_START_TOKEN 0xFE
#define DATA_RESPONSE_MASK 0x1F
#define DATA_RESPONSE_OK 0x05
171,6 → 181,21
return(crc);
}
 
u8 SDC_WaitForBusy()
{
u8 rsp = 0;
 
SSC_ClearRxFifo();
SSC_Enable(); // enable chipselect.
do
{
rsp = SSC_GetChar();
}while(rsp != 0xFF); // wait while card is busy (data out low)
return(rsp);
}
 
 
 
//________________________________________________________________________________________________________________________________________
// Function: SDC_SendCMDR1(u8 CmdNo, u32 arg);
//
181,7 → 206,7
//________________________________________________________________________________________________________________________________________
u8 SDC_SendCMDR1(u8 CmdNo, u32 arg)
{
u8 r1 = 0xFF;
u8 r1;
u16 Timeout = 0;
u16 a;
u8 cmd[6];
188,7 → 213,9
 
SSC_ClearRxFifo(); // clear the rx fifo
SSC_Enable(); // enable chipselect.
SSC_GetChar(); // send dummy
SDC_WaitForBusy();
SSC_ClearRxFifo(); // clear the rx fifo
SSC_GetChar(); // dummy to sync
 
/* Send cmd10 (SEND_CID) */;
cmd[0] = 0x40|CmdNo; // set command index
205,7 → 232,7
do
{
r1 = SSC_GetChar(); // get byte from sd-card
if (Timeout++ > 200) return(r1);
if (Timeout++ > 500) return(r1);
}while(r1 == 0xFF); // wait for the response byte from sd-card.
return(r1);
}
241,19 → 268,19
SD_Result_t SDC_GetData(u8 CmdNo, u32 addr, u8 *Buffer, u32 len)
{
u8 rsp;
u32 Timeout;
//u32 Timeout;
u16 a, Crc16;
SD_Result_t result = SD_ERROR_UNKNOWN;
 
// send the command
rsp = SDC_SendCMDR1(CmdNo, addr);
if (rsp != R1_NO_ERROR)
if (rsp != R1_NO_ERR)
{
result = SD_ERROR_BAD_RESPONSE;
goto end;
}
SSC_ClearRxFifo();
Timeout = SetDelay(200); // wait alt least 0.2 seconds for data ready
//Timeout = SetDelay(400); // wait alt least 0.2 seconds for data ready
do
{
rsp = SSC_GetChar();
262,11 → 289,11
result = SD_ERROR_READ_DATA;
goto end;
}
if(CheckDelay(Timeout))
/*if(CheckDelay(Timeout))
{
result = SD_ERROR_TIMEOUT;
goto end;
}
}*/
}while(rsp != DATA_START_TOKEN);
// data start token received
for (a = 0; a < len; a++) // read the block from the SSC
278,9 → 305,14
Crc16 = (Crc16<<8)|SSC_GetChar(); // lowbyte last
if(Crc16 != CRC16(Buffer, len)) result = SD_ERROR_CRC_DATA;
else result = SD_SUCCESS;
 
end:
SSC_Disable(); // disable sdcard.
//SSC_Disable(); // disable sdcard.
if(result != SD_SUCCESS)
{
sprintf(text,"Error %02X reading data from sd card (R1=%02X).\r\n", result, rsp);
SerialPutString(text);
}
return(result);
}
 
495,7 → 527,7
}
} while(rsp[0] & R1_IDLE_STATE); // loop until idle state
if(rsp[0] != R1_NO_ERROR)
if(rsp[0] != R1_NO_ERR)
{
SerialPutString("Init error.\r\n");
result = SD_ERROR_INITIALIZE;
502,7 → 534,7
goto end;
}
/* set block size to 512 bytes */
if(SDC_SendCMDR1(CMD_SET_BLOCKLEN, 512UL) != R1_NO_ERROR)
if(SDC_SendCMDR1(CMD_SET_BLOCKLEN, 512UL) != R1_NO_ERR)
{
SerialPutString("Error setting block length to 512.\r\n");
result = SD_ERROR_SET_BLOCKLEN;
645,18 → 677,18
{
u8 rsp;
u16 a, Crc16;
u32 Timeout = 0;
//u32 Timeout = 0;
SD_Result_t result = SD_ERROR_UNKNOWN;
 
addr = addr << 9; // convert sectoradress to byteadress
rsp = SDC_SendCMDR1(CMD_WRITE_SINGLE_BLOCK, addr);
if (rsp != R1_NO_ERROR)
if (rsp != R1_NO_ERR)
{
result = SD_ERROR_BAD_RESPONSE;
goto end;
}
SSC_ClearRxFifo();
for (a=0;a<10;a++) // at least one byte
for (a=0;a<20;a++) // at least one byte
{
SSC_GetChar();
}
671,15 → 703,15
SSC_PutChar((u8)(Crc16>>8)); // write high byte first
SSC_PutChar((u8)(0x00FF&Crc16)); // lowbyte last
SSC_ClearRxFifo();
Timeout = SetDelay(200);
//Timeout = SetDelay(200);
do // wait for data response token
{
rsp = SSC_GetChar();
if(CheckDelay(Timeout))
/*if(CheckDelay(Timeout))
{
result = SD_ERROR_TIMEOUT;
goto end;
}
}*/
}while((rsp & 0x11) != 0x01 );
// analyse data response token
switch(rsp & DATA_RESPONSE_MASK)
689,27 → 721,48
break;
case DATA_RESPONSE_CRC_ERR:
result = SD_ERROR_CRC_DATA;
goto end;
break;
case DATA_RESPONSE_WRITE_ERR:
result = SD_ERROR_WRITE_DATA;
goto end;
break;
default:
result = SD_ERROR_UNKNOWN;
goto end;
break;
 
}
// wait until the sdcard is not busy.
Timeout = SetDelay(200);
while (SSC_GetChar() != 0xFF)
// wait until the sdcard is busy.
rsp = SDC_WaitForBusy();
if(rsp != 0xFF)
{
if(CheckDelay(Timeout))
{
result = SD_ERROR_TIMEOUT;
goto end;
}
result = SD_ERROR_TIMEOUT;
goto end;
}
// check card status
rsp = SDC_SendCMDR1(CMD_SEND_STATUS, 0);
if(rsp != R1_NO_ERR)
{
result = SD_ERROR_BAD_RESPONSE;
SSC_GetChar();
goto end;
}
// 2nd byte of r2 response
rsp = SSC_GetChar();
if(rsp != R2_NO_ERR)
{
result = SD_ERROR_WRITE_DATA;
SSC_GetChar();
goto end;
}
end:
SSC_Disable(); // disable sdcard.
//SSC_Disable(); // disable sdcard.
if(result != SD_SUCCESS)
{
sprintf(text,"Error %02X writing data to sd card (R=%02X).\r\n", result, rsp);
SerialPutString(text);
}
return(result);
}
 
729,25 → 782,5
return SDC_GetData(CMD_READ_SINGLE_BLOCK, addr, Buffer, 512);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: EXTIT1_IRQHandler(void);
//
// Description: This function handles the extnernal interrupts from port 5.3 (SD_SWITCH)
//
//
// Returnvalue: none
//________________________________________________________________________________________________________________________________________
void EXTIT1_IRQHandler(void)
{
VIC_ITCmd(EXTIT1_ITLine, DISABLE);
if(WIU_GetITStatus(WIU_Line11) != RESET)
{
BeepTime = 100;
SDC_Init(); // initialize sd-card.
 
WIU_ClearFlag(WIU_Line1);
WIU_ClearITPendingBit(WIU_Line11);
}
VIC_ITCmd(EXTIT1_ITLine, ENABLE);
}
 
/branches/V0.1 killagreg/ssc.c
156,7 → 156,7
// Set Baud Rate (Prescaler)
// bit rate is BRCLK/SSP_ClockPrescaler/(1+SSP_ClockRate))
// With MSCLK = 48MHz/2 = BRCLK we get for the SPICLK = 24Mhz / 8 / (1+5) = 500 kHz
SSP_InitStructure.SSP_ClockRate = 5;
SSP_InitStructure.SSP_ClockRate = 5; //5
SSP_InitStructure.SSP_ClockPrescaler = 8;
SSP_Init(SSP1, &SSP_InitStructure);
SSC_Disable();
243,6 → 243,7
u8 SSC_GetChar (void)
{
u8 Byte = 0;
while(SSP_GetFlagStatus(SSP1, SSP_FLAG_TxFifoNotFull) != SET); // wait for space in the tx fifo
SSP_SendData(SSP1, 0xFF);// send dymmy byte (0xFF) as master to receive a byte from the slave
while(SSP_GetFlagStatus(SSP1, SSP_FLAG_TxFifoEmpty) != SET); // wait for the byte to be sent
Byte = SSP_ReceiveData(SSP1); // read the byte transmitted from the slave
/branches/V0.1 killagreg/uart.c
85,7 → 85,7
volatile u8 ReceivedBytes = 0;
 
volatile u8 CntCrcError = 0;
u8 text[20];
u8 text[50];
 
u8 PcAccess = 100;
u8 MotorTest[4] = {0,0,0,0};
/branches/V0.1 killagreg/uart.h
66,7 → 66,7
 
extern s16 uart_putchar (char c);
extern void SerialPutString(u8 *s);
extern u8 text[20];
extern u8 text[50];