Subversion Repositories Projects

Compare Revisions

Ignore whitespace Rev 296 → Rev 297

/FollowMe/FollowMe.pnproj
0,0 → 1,0
<Project name="FollowMe"><Folder name="Sources"><File path="ubx.c"></File><File path="analog.c"></File><File path="button.c"></File><File path="crc16.c"></File><File path="fat16.c"></File><File path="led.c"></File><File path="main.c"></File><File path="menu.c"></File><File path="printf_P.c"></File><File path="sdc.c"></File><File path="ssc.c"></File><File path="timer0.c"></File><File path="uart0.c"></File><File path="uart1.c"></File></Folder><Folder name="Header"><File path="ubx.h"></File><File path="analog.h"></File><File path="button.h"></File><File path="crc16.h"></File><File path="fat16.h"></File><File path="led.h"></File><File path="main.h"></File><File path="menu.h"></File><File path="printf_P.h"></File><File path="sdc.h"></File><File path="ssc.h"></File><File path="timer0.h"></File><File path="uart0.h"></File><File path="uart1.h"></File></Folder></Project>
/FollowMe/FollowMe.pnps
0,0 → 1,0
<pd><ViewState><e p="FollowMe" x="true"></e><e p="FollowMe\Header" x="true"></e><e p="FollowMe\Sources" x="true"></e></ViewState></pd>
/FollowMe/fat16.c
1,1482 → 1,1729
#include <stdio.h>
#include <avr/io.h>
#include <string.h>
#include "printf_P.h"
#include "timer0.h"
#include "fat16.h"
#include "sdc.h"
#include "printf_P.h"
#include "uart1.h"
 
 
//________________________________________________________________________________________________________________________________________
// Module name: fat16.c
// Compiler used: avr-gcc 3.4.5
// Last Modifikation: 28.03.2008
// Version: 1.25
// 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 FAT16_Init(void);
// u8 fopen_(s8 *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 fgets_(s8 *string, s16 count, File *file);
// u8 fputchar_(File *file,s8 c);
// u8 fputs_(File *file,s8 *string);
// s8 * fgets(s8 *, s16, File);
// u8 fexist_(u8*, File *file);
// u8 mkdir__(s8 *name);
// u8 chdir__(s8 *name);
// u8 findfirst_(s8 *fname, Find *item, u8 attribute);
// u8 findnext_(Find *item);
// u8 fdelete_(s8 *fname)
// u8 rmdir_(s8 *dname)
//........................................................................................................................................
// 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
//________________________________________________________________________________________________________________________________________
/*
FAT16 Drive Layout:
Description Offset
Volume Boot Sector Start of Partition
Fat Tables Start + # of Reserved Sectors
Root Directory Entry Start + # of Reserved + (# of Sectors Per FAT * 2)
Data Area (Starts with Cluster #2) Start + # of Reserved + (# of Sectors Per FAT * 2) + ((Maximum Root Directory Entries * 32) / Bytes per Sector)
*/
 
u8 text[80];
 
/*
________________________________________________________________________________________________________________________________________
 
//________________________________________________________________________________________________________________________________________
//
// Global variables needed for read- or write-acces to the FAT16- filesystem.
//
//________________________________________________________________________________________________________________________________________
Structure of an partition entry
________________________________________________________________________________________________________________________________________
 
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).
u32 CWD = 0; // Pointer startcluster to the current working directory
Partition Entry is 16 bytes long
*/
typedef struct
{
uint8_t PartitionState; // Current State of Partition (00h=Inactive, 80h=Active)
uint8_t BeginningHead; // Beginning of Partition - Head
uint16_t BeginningCylSec; // Beginning of Partition - Cylinder/Sector (See Below)
uint8_t Type; // Type of Partition (See List Below)
uint8_t EndHead; // End of Partition - Head
uint16_t EndCylSec; // End of Partition - Cylinder/Sector
uint32_t NoSectorsBeforePartition; // Number of Sectors between the MBR and the First Sector in the Partition
uint32_t NoSectorsPartition ; // Number of Sectors in the Partition
} __attribute__((packed)) PartitionEntry_t;
 
/*
Coding of Cylinder/Sector words
 
struct DirEntry *DirectoryEntry; // Pointer to an entry of the directory.
struct FatEntry *Fat; // Pointer to an entry of the fat (next clusterposition).
Cylinder is 10 bits: [7:0] at [15:8] and [9:8] at [7:6]
Sector is 5 bits: [5:0] at [5:0]
*/
 
File FilePointer[__MAX_FILES_USED]; // Allocate Memmoryspace for each filepointer used.
// Partition Types:
#define PART_TYPE_UNKNOWN 0x00
#define PART_TYPE_FAT12 0x01
#define PART_TYPE_XENIX 0x02
#define PART_TYPE_FAT16_ST_32_MB 0x04
#define PART_TYPE_EXTDOS 0x05
#define PART_TYPE_FAT16_LT_32_MB 0x06
#define PART_TYPE_NTFS 0x07
#define PART_TYPE_FAT32 0x0B
#define PART_TYPE_FAT32LBA 0x0C
#define PART_TYPE_FAT16LBA 0x0E
#define PART_TYPE_EXTDOSLBA 0x0F
#define PART_TYPE_EISA 0x12
#define PART_TYPE_ONTRACK 0x33
#define PART_TYPE_NOVELL 0x40
#define PART_TYPE_DYNAMIC 0x42
#define PART_TYPE_PCIX 0x4B
#define PART_TYPE_LINUX_SWAP 0x82
#define PART_TYPE_LINUX_NATIVE 0x83
#define PART_TYPE_LINUX_LVM 0x8E
#define PART_TYPE_PHOENIXSAVE 0xA0
#define PART_TYPE_FREEBSD 0xA5
#define PART_TYPE_OPENBSD 0xA6
#define PART_TYPE_NETNBSD 0xA9
#define PART_TYPE_CPM 0xDB
#define PART_TYPE_DBFS 0xE0
#define PART_TYPE_BBT 0xFF
 
 
//________________________________________________________________________________________________________________________________________
// 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 FAT16_Init(void)
Structure of the MasterBootRecord
________________________________________________________________________________________________________________________________________
 
Master Boot Record is 512 bytes long
The Master Boot Record is the same for pretty much all Operating Systems.
It is located on the first Sector of the Hard Drive, at Cylinder 0, Head 0, Sector 1
*/
typedef struct
{
u8 retvalue = 0;
u8 cnt = 0;
struct VBR_Entry *VBR; // Pointer to the VolumeBootRecord.
struct MBR_Entry *MBR; // Pointer to the masterbootrecord.
File *file;
uint8_t ExecutableCode[446]; // 446 bytes for machine start code
PartitionEntry_t PartitionEntry1; // 16 bytes for partition entry 1
PartitionEntry_t PartitionEntry2; // 16 bytes for partition entry 2
PartitionEntry_t PartitionEntry3; // 16 bytes for partition entry 3
PartitionEntry_t PartitionEntry4; // 16 bytes for partition entry 4
uint16_t ExecutableMarker; // BIOS-Signature (0x55 0xAA)
} __attribute__((packed)) MBR_Entry_t;
 
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;
if((MBR->PartitionEntry1.Type == _FAT16_32_MB_BIOS_Extension) ||
(MBR->PartitionEntry1.Type == _FAT16_ST_32_MB) ||
(MBR->PartitionEntry1.Type == _FAT16_LT_32_MB))
{
SDC_GetSector(FirstPartitionSector,file->buffer); // Read the volume bootrecord from mmc.
Structure of the VolumeBootRecord
________________________________________________________________________________________________________________________________________
 
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.
The Volume Boot Record is 512 bytes long
This information is located in the first sector of every partition.
*/
typedef struct
{
uint8_t JumpCode[3]; // Jump Code + NOP
int8_t OEMName[8]; // OEM Name
uint16_t BytesPerSector; // Bytes Per Sector
uint8_t SectorsPerCluster; // Sectors Per Cluster
uint16_t ReservedSectors; // Reserved Sectors
uint8_t NoFATCopies; // Number of Copies of FAT
uint16_t MaxRootEntries; // Maximum Root Directory Entries
uint16_t NoSectorsInPartSml32MB; // Number of Sectors in Partition Smaller than 32 MB
uint8_t MediaDescriptor; // Media Descriptor (0xF8 for Hard Disks)
uint16_t SectorsPerFAT; // Sectors Per FAT
uint16_t SectorsPerTrack; // Sectors Per Track
uint16_t NoHeads; // Number of Heads
uint32_t NoHiddenSectors; // Number of Hidden Sectors in Partition
uint32_t NoSectors; // Number of Sectors in Partition
uint16_t DriveNo; // Logical Drive Number of Partition
uint8_t ExtendedSig; // Extended Signature (0x29)
uint32_t SerialNo; // Serial Number of the Partition
int8_t VolumeName[11]; // Volume Name of the Partititon
int8_t FATName[8]; // FAT Name (FAT16)
uint8_t ExecutableCode[446]; // 446 bytes for machine start code
uint16_t ExecutableMarker; // Executable Marker (0x55 0xAA)
} __attribute__((packed)) VBR_Entry_t;
 
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.
CWD = RootDirectory; // The actual directory is the rootdirectory.
retvalue = 1;
}
}
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: File * fopen_(u8*, u8 *);
//
// Description: This function looks for the file in the directory specified by the variable "CWD" 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_(s8 *fname, s8 mode)
/*
________________________________________________________________________________________________________________________________________
 
Structure of an directory entry
________________________________________________________________________________________________________________________________________
 
Directory entry is 32 bytes.
*/
typedef struct
{
File *file;
int8_t Name[8]; // 8 bytes name, padded with spaces.
uint8_t Extension[3]; // 3 bytes extension, padded with spaces.
uint8_t Attribute; // attribute of the directory entry (unused,archive,read-only,system,directory,volume)
uint8_t Reserved[10]; // reserved bytes within the directory entry.
uint32_t DateTime; // date and time of last write access to the file or directory.
uint16_t StartCluster; // first cluster of the file or directory.
uint32_t Size; // size of the file or directory in bytes.
} __attribute__((packed)) DirEntry_t;
 
file = ReserveFilePointer(); // reserve a filepointer.
#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
 
if(file != NULL) // A free filepointer was found.
{
file->mode = mode; // mode of fileoperation (read,write)
#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
 
if(SeekFileInDirectory(fname, 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
}
else if(mode == 'r')
{
return(file);
}
else
{
fclose_(file);
file = NULL;
}
 
}
else
{
if((mode == 'a') || (mode == 'w')) // specified file doesn't exist so create new file for writing data.
{
if(CreateFileInDirectory(fname,file)) // Could an entry for the new file in the rootdirectory be created?
{
return(file);
}
else
{
fclose_(file);
file = NULL;
}
}
}
}
return(file);
}
/*
________________________________________________________________________________________________________________________________________
 
Structure of an entry within the fileallocationtable.
________________________________________________________________________________________________________________________________________
*/
typedef struct
{
uint16_t NextCluster; // the next cluster of the file.
} __attribute__((packed)) Fat16Entry_t;
 
// secial fat entries
#define FAT16_CLUSTER_FREE 0x0000
#define FAT16_CLUSTER_RESERVED 0x0001
#define FAT16_CLUSTER_USED_MIN 0x0002
#define FAT16_CLUSTER_USED_MAX 0xFFEF
#define FAT16_CLUSTER_ROOTDIR_MIN 0xFFF0
#define FAT16_CLUSTER_ROOTDIR_MAX 0xFFF6
#define FAT16_CLUSTER_BAD 0xFFF7
#define FAT16_CLUSTER_LAST_MIN 0xFFF8
#define FAT16_CLUSTER_LAST_MAX 0xFFFF
 
//________________________________________________________________________________________________________________________________________
// Funtion: fflush_(File *file);
//
// Description: This function writes the data already in the buffer but not yet written to the file.
//
//________________________________________________________________________________________________________________________________________
/*****************************************************************************************************************************************/
/* */
/* Global variables needed for read- or write-acces to the FAT16- filesystem. */
/* */
/*****************************************************************************************************************************************/
 
s16 fflush_(File *file)
#define MBR_SECTOR 0x00 // the masterboot record is located in sector 0.
#define DIRENTRY_SIZE 32 //bytes
#define DIRENTRIES_PER_SECTOR BYTES_PER_SECTOR/DIRENTRY_SIZE
#define FAT16_BYTES 2
#define FAT16_ENTRIES_PER_SECTOR BYTES_PER_SECTOR/FAT16_BYTES
 
#define FSTATE_UNUSED 0
#define FSTATE_USED 1
 
typedef struct
{
u16 time=0;
u16 date=0;
uint8_t IsValid; // 0 means invalid, else valid
uint8_t SectorsPerCluster; // how many sectors does a cluster contain?
uint8_t FatCopies; // Numbers of copies of the FAT
uint16_t MaxRootEntries; // Possible number of entries in the root directory.
uint16_t SectorsPerFat; // how many sectors does a fat16 contain?
uint32_t FirstFatSector; // sector of the start of the fat
uint32_t FirstRootDirSector; // sector of the rootdirectory
uint32_t FirstDataSector; // sector of the first cluster containing data (cluster2).
uint32_t LastDataSector; // the last data sector of the partition
} Partition_t;
 
Partition_t Partition; // Structure holds partition information
 
if(file && ((file->mode =='a') || (file->mode =='w')))
{
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);
}
File_t FilePointer[FILE_MAX_OPEN]; // Allocate Memmoryspace for each filepointer used.
 
//________________________________________________________________________________________________________________________________________
// 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)
/****************************************************************************************************************************************/
/* Function: FileDateTime(DateTime_t *); */
/* */
/* Description: This function calculates the DOS date time from a pointer to a time structure. */
/* */
/* Returnvalue: Returns the DOS date time. */
/****************************************************************************************************************************************/
 
uint32_t FileDateTime(DateTime_t * pTimeStruct)
{
if(file != NULL)
{
fflush_(file); // save buffered data to the disk
}
FreeFilePointer(file); // and free the filepointer.
uint32_t datetime = 0;
if((pTimeStruct == 0) || !(pTimeStruct->Valid)) return datetime;
 
datetime |= (0x0000007FL & (uint32_t)(pTimeStruct->Year - 1980))<<25; // set year
datetime |= (0x0000000FL & (uint32_t)(pTimeStruct->Month))<<21; // set month
datetime |= (0x0000001FL & (uint32_t)(pTimeStruct->Day))<<16;
datetime |= (0x0000001FL & (uint32_t)(pTimeStruct->Hour))<<11;
datetime |= (0x0000003FL & (uint32_t)(pTimeStruct->Min))<<5;
datetime |= (0x0000001FL & (uint32_t)(pTimeStruct->Sec/2));
return datetime;
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: u32 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)
/****************************************************************************************************************************************/
/* Function: LockFilePointer(); */
/* */
/* Description: This function trys to lock a free file pointer. */
/* */
/* Returnvalue: Returns the Filepointer on success or 0. */
/****************************************************************************************************************************************/
File_t * LockFilePointer(void)
{
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)
uint8_t i;
File_t * File = 0;
for(i = 0; i < FILE_MAX_OPEN; i++)
{
object_size = size;
while((size > 0) && success)
if(FilePointer[i].State == FSTATE_UNUSED) // found an unused one
{
*buff_pnt = (u8) fgetchar_(file); // read a byte from the buffer to the opened file.
buff_pnt++;
size--;
File = &FilePointer[i]; // set pointer to that entry
FilePointer[i].State = FSTATE_USED; // mark it as used
break;
}
if(success) object_cnt++;
}
 
return(object_cnt); // return the number of objects succesfully read from the file
return(File);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: u32 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)
/****************************************************************************************************************************************/
/* Function: UnlockFilePointer(file_t *); */
/* */
/* Description: This function trys to unlock a file pointer. */
/* */
/* Returnvalue: Returns 1 if file pointer was freed else 0. */
/****************************************************************************************************************************************/
uint8_t UnlockFilePointer(File_t * 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)
uint8_t cnt;
if(file == NULL) return(0);
for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
{
object_size = size;
while((size > 0) && success)
if(&FilePointer[cnt] == file) // filepointer to be freed found?
{
success = fputchar_(file, *buff_pnt); // write a byte from the buffer to the opened file.
buff_pnt++;
size--;
file->State = FSTATE_UNUSED;
file->FirstSectorOfFirstCluster = 0; // Sectorpointer to the first sector of the first datacluster of the file.
file->FirstSectorOfCurrCluster = 0;
file->SectorOfCurrCluster = 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).
file->ByteOfCurrSector = 0; // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
file->Mode = 0; // mode of fileoperation (read,write)
file->Size = 0; // the size of the opend file in bytes.
file->Position = 0; // pointer to a character within the file 0 < fileposition < filesize
file->SectorInCache = 0; // the last sector read, wich is still in the sectorbuffer.
file->DirectorySector = 0; // the sectorposition where the directoryentry has been made.
file->DirectoryIndex = 0; // the index to the directoryentry within the specified sector.
file->Attribute = 0; // the attribute of the file opened.
file = NULL;
return(1);
}
if(success) object_cnt++;
}
return(0);
}
 
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)
/****************************************************************************************************************************************/
/* Function: SeperateDirName(int8_t*, int8_t*); */
/* */
/* Description: This function seperates the first dirname from filepath and brings them */
/* into the needed format ('test.txt' -> 'TEST TXT') */
/* The subpath is the pointer to the remaining substring if the filepath */
/* */
/* Returnvalue: Return NULL on error or pointer to subpath */
/****************************************************************************************************************************************/
int8_t* SeperateDirName(const int8_t *filepath, int8_t *dirname)
{
s32 fposition = 0;
s16 retvalue = 1;
u32 temp = 0;
int8_t* subpath = NULL;
uint8_t readpointer = 0;
uint8_t writepointer = 0;
 
//......................................................
if(origin == SEEK_SET) // Fileposition relative to the beginning of the file.
// search subpath from beginning of filepath
subpath = NULL;
readpointer = 0;
if(filepath[0] == '/') readpointer = 1; // ignore first '/'
while(subpath == NULL) // search the filepath until a subpath was found.
{
fposition = 0;
if(((filepath[readpointer] == 0) || (filepath[readpointer] == '/'))) // if '/' found or end of filepath reached
{
subpath = (int8_t*)&filepath[readpointer]; // store the position of the first "/" found after the beginning of the filenpath
}
readpointer++;
}
//......................................................
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?
// clear dirname with spaces
dirname[11] = 0; // terminate dirname
for(writepointer = 0; writepointer < 11; writepointer++) dirname[writepointer] = ' ';
writepointer = 0;
// start seperating the dirname from the filepath.
readpointer = 0;
if(filepath[0] == '/') readpointer = 1; // ignore first '/'
while( &filepath[readpointer] < subpath)
{
retvalue = 0;
file->sector_index = 0;
file->byte_index = 0;
file->fileposition = 0;
file->cluster_pointer = file->start_cluster;
 
while(file->fileposition < fposition)
if(writepointer >= 11) return(NULL); // dirname to long
if(filepath[readpointer] == '.') // seperating dirname and extension.
{
file->fileposition++;
if(file->byte_index < 511)
if(writepointer <= 8)
{
file->byte_index++;
readpointer++; // next character in filename
writepointer = 8; // jump to start of extension
}
else return(NULL); // dirbasename to long
}
else
{
if((0x60 < filepath[readpointer]) && (filepath[readpointer] < 0x7B))
{
dirname[writepointer] = (filepath[readpointer] - 0x20); // all characters must be upper case.
}
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.
}
}
dirname[writepointer] = filepath[readpointer];
}
readpointer++;
writepointer++;
}
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);
return(subpath);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: fgetchar_(File *file);
//
// Description: This function reads and returns one character from the specified file.
//
// Returnvalue: The function returns the character read from the specified memorylocation as u8 casted to s16 or EOF.
//________________________________________________________________________________________________________________________________________
 
s16 fgetchar_(File *file)
/**************************************************************************************************************************************+*/
/* Function: Fat16ClusterToSector( uint16_t cluster); */
/* */
/* Description: This function converts a cluster number given by the fat to the corresponding */
/* sector that points to the start of the data area that is represented by the cluster number. */
/* */
/* Returnvalue: The sector number with the data area of the given cluster */
/****************************************************************************************************************************************/
uint32_t Fat16ClusterToSector(uint16_t cluster)
{
s16 c = EOF;
u32 temp1;
if(!Partition.IsValid) return 0;
if (cluster < 2) cluster = 2; // the 0. and 1. cluster in the fat are used for the media descriptor
return ( (cluster - 2) * Partition.SectorsPerCluster) + Partition.FirstDataSector; // the first data sector is represented by the 2nd cluster
}
 
if(file->filesize > 0) // wen the end of the file is not reached, get the next character.
/****************************************************************************************************************************************/
/* Function: SectorToFat16Cluster( uint32_t sector); */
/* */
/* Description: This function converts a given sector number given to the corresponding */
/* cluster number in the fat that represents this data area. */
/* */
/* Returnvalue: The cluster number representing the data area of the sector. */
/****************************************************************************************************************************************/
uint16_t SectorToFat16Cluster(uint32_t sector)
{
if(!Partition.IsValid) return 0;
return ((uint16_t)((sector - Partition.FirstDataSector) / Partition.SectorsPerCluster) + 2);
}
 
 
/****************************************************************************************************************************************/
/* Function: Fat16_Deinit(void); */
/* */
/* Description: This function uninitializes the fat 16 api */
/* */
/* Returnvalue: The function returns "0" on success */
/****************************************************************************************************************************************/
uint8_t Fat16_Deinit(void)
{
int16_t returnvalue = 0;
uint8_t cnt;
// declare the filepointers as unused.
for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
{
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?
if(FilePointer[cnt].State == FSTATE_USED)
{
SDC_GetSector((u32)temp1,file->buffer); // Read the calculated cluster.
file->sector_in_buffer = (u32)temp1;
returnvalue += fclose_(&FilePointer[cnt]); // try to close open file pointers
}
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);
SDC_Deinit(); // uninitialize interface to sd-card
Partition.IsValid = 0; // mark data in partition structure as invalid
return(returnvalue);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: fputchar_(File *file, s8 *);
//
// 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)
/****************************************************************************************************************************************/
/* Function: Fat16_Init(void); */
/* */
/* Description: This function reads the Masterbootrecord and finds the position of the Volumebootrecord, the FAT and the Rootdir */
/* and stores the information in global variables. */
/* */
/* Returnvalue: The function returns "0" if the filesystem is initialized. */
/****************************************************************************************************************************************/
uint8_t Fat16_Init(void)
{
u32 ul_temp = 0;
u8 retvalue = 1;
uint8_t cnt = 0;
uint32_t partitionfirstsector;
VBR_Entry_t *VBR;
MBR_Entry_t *MBR;
File_t *file;
uint8_t result = 0;
 
if(file->sector_index >= SectorsPerCluster) // if end of the cluster is reached, find next free cluster
printf("\r\n FAT16 init...");
Partition.IsValid = 0;
 
// declare the filepointers as unused.
for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
{
file->sector_index = 0;
if(!AppendCluster(file)) retvalue = 0; // append a new and free cluster at the end of the file.
FilePointer[cnt].State = FSTATE_UNUSED;
}
// set current file pinter to first position in list
file = &FilePointer[0];
 
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
// try to initialise the sd-card.
if(SD_SUCCESS != SDC_Init())
{
file->byte_index++; // the next byte will be written to the next byteposition in this sector.
printf("SD-Card could not be initialized.");
result = 1;
goto end;
}
else // otherwise the data in the sectorbuffer will be written to the device and the next sector will be selected.
 
// SD-Card is initialized successfully
if(SD_SUCCESS != SDC_GetSector((uint32_t)MBR_SECTOR,file->Cache)) // Read the MasterBootRecord
{
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
printf("Error reading the MBR.");
result = 2;
goto end;
}
MBR = (MBR_Entry_t *)file->Cache; // Enter the MBR using the structure MBR_Entry_t.
if((MBR->PartitionEntry1.Type == PART_TYPE_FAT16_ST_32_MB) ||
(MBR->PartitionEntry1.Type == PART_TYPE_FAT16_LT_32_MB) ||
(MBR->PartitionEntry1.Type == PART_TYPE_FAT16LBA))
{
// get sector offset 1st partition
partitionfirstsector = MBR->PartitionEntry1.NoSectorsBeforePartition;
// Start of Partition is the Volume Boot Sector
if(SD_SUCCESS != SDC_GetSector(partitionfirstsector,file->Cache)) // Read the volume boot record
{
file->sector_index = 0;
if(!AppendCluster(file)) retvalue = 0; // append a new and free cluster at the end of the file.
printf("Error reading the VBR.");
result = 3;
goto end;
}
}
return(retvalue);
}
else // maybe the medium has no partition assuming sector 0 is the vbr
{
partitionfirstsector = 0;
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: fputs_(File *file, s8 *string);
//
// Description: This function writes a string to the specified file.
//
//________________________________________________________________________________________________________________________________________
VBR = (VBR_Entry_t *) file->Cache; // Enter the VBR using the structure VBR_Entry_t.
if(VBR->BytesPerSector != BYTES_PER_SECTOR)
{
printf("VBR: Sector size not supported.");
result = 4;
goto end;
}
Partition.SectorsPerCluster = VBR->SectorsPerCluster; // Number of sectors per cluster. Depends on the memorysize of the sd-card.
Partition.FatCopies = VBR->NoFATCopies; // Number of fatcopies.
Partition.MaxRootEntries = VBR->MaxRootEntries; // How many Entries are possible in the rootdirectory (FAT16 allows max. 512 entries).
Partition.SectorsPerFat = VBR->SectorsPerFAT; // The number of sectors per FAT.
 
u8 fputs_(File *file,s8 * string)
{
u8 i=0;
 
while(string[i] != 0)
/* Calculate the sectorpositon of the FAT, the Rootdirectory and the first Datacluster. */
// Calculate the position of the FileAllocationTable:
// Start + # of Reserved Sectors
Partition.FirstFatSector = (uint32_t)(partitionfirstsector + (uint32_t)(VBR->ReservedSectors));
// Calculate the position of the Rootdirectory:
// Start + # of Reserved Sectors + (# of Sectors Per FAT * # of FAT Copies)
Partition.FirstRootDirSector = Partition.FirstFatSector + (uint32_t)((uint32_t)Partition.SectorsPerFat*(uint32_t)Partition.FatCopies);
// 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 + (uint32_t)(Partition.MaxRootEntries>>4); // assuming 512 Byte Per Sector
// Calculate the last data sector
if(VBR->NoSectors == 0)
{
fputchar_(file,string[i]);
i++;
printf("VBR: Bad number of sectors.");
result = 5;
goto end;
}
return(0);
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')))
{
printf("VBR: Partition ist not FAT16 type.");
result = 6;
goto end;
}
Partition.IsValid = 1; // mark data in partition structure as valid
result = 0;
end:
if(result != 0) Fat16_Deinit();
else printf(" ...ok");
return(result);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: s8 * fgets_(s8 *string, s16 count, 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)
 
/****************************************************************************************************************************************/
/* Function: ClearCurrCluster(File_t*); */
/* */
/* Description: This function fills the current cluster with 0. */
/* */
/* Returnvalue: The function returns 1 on success else 0. */
/****************************************************************************************************************************************/
uint8_t ClearCurrCluster(File_t * file)
{
s16 buff_pnt = 0;
s16 buff_tmp = 0;
u8 state = 0; // Variable used for a statemachine to recognize the end of a line.
uint8_t retvalue = 1;
uint32_t i;
 
while(count > 1) // read the count-1 characters from the file to the string.
if((!Partition.IsValid) || (file == NULL)) return(0);
 
for(i = 0; i < BYTES_PER_SECTOR; i++) file->Cache[i] = 0; // clear file cache
for(i = 0; i < Partition.SectorsPerCluster; i++)
{
buff_tmp = fgetchar_(file); // read a character from the opened file.
switch(state)
file->SectorInCache = file->FirstSectorOfCurrCluster + i;
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
{
case 0:
if(buff_tmp == 0x0D) state++;
break;
 
case 1:
if(buff_tmp == 0x0A)
{
count = 1;
}
state = 0;
break;
Fat16_Deinit();
retvalue = 0;
}
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);
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// 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_(s8 *fname)
/*****************************************************************************************************************************************/
/* Function: GetNextCluster(File_t* ); */
/* */
/* Description: This function finds the next datacluster of the file specified with File *File. */
/* */
/* Returnvalue: The function returns the next cluster or 0 if the last cluster has already reached. */
/*****************************************************************************************************************************************/
uint16_t GetNextCluster(File_t * file)
{
File *file;
uint16_t cluster = 0;
uint32_t fat_byte_offset, sector, byte;
Fat16Entry_t * fat;
 
file = ReserveFilePointer();
 
if(file != NULL)
if((!Partition.IsValid) || (file == NULL)) return(cluster);
// if sector is within the data area
if((Partition.FirstDataSector <= file->FirstSectorOfCurrCluster)&& (file->FirstSectorOfCurrCluster <= Partition.LastDataSector))
{
if((file = fopen_(fname,'r'))!= NULL)
// determine current file cluster
cluster = SectorToFat16Cluster(file->FirstSectorOfCurrCluster);
// calculate byte offset in the fat for corresponding entry
fat_byte_offset = ((uint32_t)cluster)<<1; // two FAT bytes (16 bits) for every cluster
// calculate the sector that contains the current cluster within the fat
sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
// calculate byte offset of the current cluster within that fat sector
byte = fat_byte_offset % BYTES_PER_SECTOR;
// read this sector to the file cache
if(file->SectorInCache != sector)
{
fclose_(file);
return(1);
file->SectorInCache = sector; // update sector stored in buffer
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache)) // read sector from sd-card
{
Fat16_Deinit();
return (cluster);
}
}
// read the next cluster from cache
fat = (Fat16Entry_t *)(&(file->Cache[byte]));
cluster = fat->NextCluster;
// if last cluster fat entry
if(FAT16_CLUSTER_LAST_MIN <= cluster)
{
cluster = 0;
}
else
{
return(0);
file->FirstSectorOfCurrCluster = Fat16ClusterToSector(cluster);
file->SectorOfCurrCluster = 0;
file->ByteOfCurrSector = 0;
}
}
else
{
return(0);
}
return(cluster);
}
 
//________________________________________________________________________________________________________________________________________
// 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)
/****************************************************************************************************************************************/
/* Function: FindNextFreeCluster(File_t *); */
/* */
/* Description: This function looks in the fat to find the next free cluster */
/* */
/* Returnvalue: The function returns the cluster number of the next free cluster found within the fat. */
/****************************************************************************************************************************************/
uint16_t FindNextFreeCluster(File_t *file)
{
u32 fat_pointer = 0;
u32 fat_sector_offset = 0;
u32 ul_tmp = 0;
u8 retvalue = 0; // no new cluster found yet.
uint32_t fat_sector; // current sector within the fat relative to the first sector of the fat.
uint32_t curr_sector; // current sector
uint16_t fat_entry; // index to an fatentry within the actual sector (256 fatentries are possible within one sector).
uint16_t free_cluster = 0; // next free cluster number.
Fat16Entry_t * fat;
 
if((!Partition.IsValid) || (file == NULL)) return(0);
 
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.
// start searching for an empty cluster at the beginning of the fat.
fat_sector = 0;
do
{
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.
curr_sector = Partition.FirstFatSector + fat_sector; // calculate sector to read
file->SectorInCache = curr_sector; // upate the sector number of file cache.
if( SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache)) // read sector of fat from sd-card.
{
Fat16_Deinit();
return(free_cluster);
}
 
SDC_GetSector((u32)(FileAllocationTable + fat_sector_offset),file->buffer);
file->sector_in_buffer = (FileAllocationTable + fat_sector_offset); // Mark that new sector has been read.
fat = (Fat16Entry_t *)file->Cache; // set fat pointer to file cache
 
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?
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.
{
file->cluster_pointer = (u32) ul_tmp; // continue reading the file at the beginning of new datacluster.
retvalue = 1; // a new cluster was found.
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
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache)) // and save the sector at the sd-card.
{
Fat16_Deinit();
return(free_cluster);
}
free_cluster = (uint16_t)(fat_sector * FAT16_ENTRIES_PER_SECTOR + (uint32_t)fat_entry);
fat_entry = FAT16_ENTRIES_PER_SECTOR; // terminate the search for a free cluster in this sector.
}
}
}
return(retvalue);
fat_sector++; // continue the search in next fat sector
// repeat until the end of the fat is reached and no free cluster has been found so far
}while((fat_sector < Partition.SectorsPerFat) && (!free_cluster));
return(free_cluster);
}
 
//________________________________________________________________________________________________________________________________________
// 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)
/****************************************************************************************************************************************************/
/* Function: int16_t fseek_(File_t *, int32_t *, uint8_t) */
/* */
/* Description: This function sets the pointer of the stream relative to the position */
/* specified by origin (SEEK_SET, SEEK_CUR, SEEK_END) */
/* Returnvalue: Is 1 if seek was successful */
/****************************************************************************************************************************************************/
int16_t fseek_(File_t *file, int32_t offset, int16_t origin)
{
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.
int32_t fposition = 0;
int16_t retvalue = 1;
 
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))
if((!Partition.IsValid) || (file == NULL)) return(0);
switch(origin)
{
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.
case SEEK_SET: // Fileposition relative to the beginning of the file.
fposition = 0;
break;
case SEEK_END: // Fileposition relative to the end of the file.
fposition = (int32_t)file->Size;
break;
case SEEK_CUR: // Fileposition relative to the current position of the file.
default:
fposition = file->Position;
break;
}
 
fposition += offset;
 
if((fposition >= 0) && (fposition <= (int32_t)file->Size)) // is the pointer still within the file?
{
// reset file position to start of the file
file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
file->SectorOfCurrCluster = 0;
file->ByteOfCurrSector = 0;
file->Position = 0;
 
while(file->Position < fposition) // repeat until the current position is less than target
{
if(Fat[fat_entry].next_cluster == 0x0000) // empty cluster found!!
file->Position++; // increment file position
file->ByteOfCurrSector++; // next byte in current sector
if(file->ByteOfCurrSector >= BYTES_PER_SECTOR)
{
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.
file->ByteOfCurrSector = 0; // reading at the beginning of new sector.
file->SectorOfCurrCluster++; // continue reading in next sector
if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster) // if end of cluster is reached, the next datacluster has to be searched in the FAT.
{
if(GetNextCluster(file)) // Sets the clusterpointer of the file to the next datacluster.
{
file->SectorOfCurrCluster = 0;
}
else // the last cluster was allready reached
{
file->SectorOfCurrCluster--; // jump back to the ast sector in the last cluster
file->ByteOfCurrSector = BYTES_PER_SECTOR; // set ByteOfCurrSector one byte over sector end
}
}
}
}
fat_sector_offset++;
}
return(free_cluster);
if(file->Position == fposition) retvalue = 0;
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// 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)
/****************************************************************************************************************************************/
/* Function: uint16_t DeleteClusterChain(File *file); */
/* */
/* Description: This function trances along a cluster chain in the fat and frees all clusters visited. */
/* */
/****************************************************************************************************************************************/
uint8_t DeleteClusterChain(uint16_t StartCluster)
{
u16 free_cluster = 0;
u32 fat_pointer = 0;
u8 retvalue = 0;
uint16_t cluster;
uint32_t fat_byte_offset, sector, byte;
Fat16Entry_t * fat;
uint8_t buffer[BYTES_PER_SECTOR];
uint32_t sector_in_buffer = 0;
uint8_t repeat = 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.
if(!Partition.IsValid) return 0;
 
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.
cluster = StartCluster; // init chain trace
// calculate byte offset in the fat for corresponding entry
fat_byte_offset = ((uint32_t)cluster)<<1; // two FAT bytes (16 bits) for every cluster
// calculate the sector that contains the current cluster within the fat
sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
// calculate byte offset of the current cluster within that fat sector
byte = fat_byte_offset % BYTES_PER_SECTOR;
do
{
if(sector != sector_in_buffer)
{
// read this sector to buffer
sector_in_buffer = sector;
if(SD_SUCCESS != SDC_GetSector(sector_in_buffer, buffer)) return 0; // read sector from sd-card
}
// read the next cluster from cache
fat = (Fat16Entry_t *)(&(buffer[byte]));
cluster = fat->NextCluster;
if((FAT16_CLUSTER_USED_MIN <= cluster) && (cluster <= FAT16_CLUSTER_USED_MAX) ) repeat = 1;
else repeat = 0;
 
fat_pointer = (u32)free_cluster;
fat_pointer -= 2;
fat_pointer *= SectorsPerCluster;
fat_pointer += FirstDataCluster;
fat->NextCluster = FAT16_CLUSTER_FREE; // mark current cluster as free
// calculate byte offset in the fat for corresponding entry
fat_byte_offset = ((uint32_t)cluster)<<1; // two FAT bytes (16 bits) for every cluster
// calculate the sector that contains the current cluster within the fat
sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
// calculate byte offset of the current cluster within that fat sector
byte = fat_byte_offset % BYTES_PER_SECTOR;
// if new sector is not the sector in buffer or the last cluster in the chain was traced
if((sector != sector_in_buffer) || !repeat)
{ // write sector in buffer
if(SD_SUCCESS != SDC_PutSector(sector_in_buffer,buffer)) return 0;
}
}
while(repeat);
 
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
return 1;
}
 
 
//________________________________________________________________________________________________________________________________________
// Funtion: void DeleteClusterChain(u16 startcluster);
//
// Description: This function frees all the clusters used for file from the fat.
//
// Returnvalue: none
//________________________________________________________________________________________________________________________________________
 
void DeleteClusterChain(u16 startcluster)
/****************************************************************************************************************************************/
/* Function: uint16_t AppendCluster(File *file); */
/* */
/* Description: This function looks in the fat to find the next free cluster and appends it to the file. */
/* */
/* Returnvalue: The function returns the appened cluster number or 0 of no cluster was appended. */
/****************************************************************************************************************************************/
uint16_t AppendCluster(File_t *file)
{
u16 fat_index = 0;
u16 fat_sector_offset = 0;
u32 sector_in_buffer = 0;
u32 ul_temp = 0;
u8 buffer[512];
uint16_t last_cluster, new_cluster = 0;
uint32_t fat_byte_offset, sector, byte;
Fat16Entry_t * fat;
 
fat_index = (startcluster % 0x100); // Calculate the sector within the cluster.
fat_sector_offset = (startcluster >> 8); // and the position within the sector.
ul_temp = (u32)(FileAllocationTable + fat_sector_offset);
if((!Partition.IsValid) || (file == NULL)) return(new_cluster);
 
new_cluster = FindNextFreeCluster(file); // the next free cluster found on the disk.
if(new_cluster)
{ // A free cluster was found and can be added to the end of the file.
fseek_(file, 0, SEEK_END); // jump to the end of the file
last_cluster = SectorToFat16Cluster(file->FirstSectorOfCurrCluster); // determine current file cluster
fat_byte_offset = ((uint32_t)last_cluster)<<1;
sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
byte = fat_byte_offset % BYTES_PER_SECTOR;
 
do
{
if(sector_in_buffer != ul_temp)
if(file->SectorInCache != sector)
{
sector_in_buffer = ul_temp;
SDC_GetSector(ul_temp,buffer);
file->SectorInCache = sector; // update sector stored in buffer
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache)) // read sector from sd-card
{
Fat16_Deinit();
return(0);
}
}
Fat = (struct FatEntry *)buffer;
 
startcluster = Fat[fat_index].next_cluster;
Fat[fat_index].next_cluster = 0x0000; // free the cluster within the fat.
 
fat_index = (startcluster % 0x100); // Calculate the sector within the cluster.
fat_sector_offset = (startcluster >> 8); // and the position within the sector.
ul_temp = (u32)(FileAllocationTable + fat_sector_offset);
if((sector_in_buffer != ul_temp) || (startcluster == 0xffff))
fat = (Fat16Entry_t *)(&(file->Cache[byte]));
fat->NextCluster = new_cluster; // append the free cluster to the end of the file in the FAT.
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache)) // save the modified sector to the FAT.
{
SDC_PutSector(sector_in_buffer,buffer);
Fat16_Deinit();
return(0);
}
file->FirstSectorOfCurrCluster = Fat16ClusterToSector(new_cluster);
file->SectorOfCurrCluster = 0;
file->ByteOfCurrSector = 0;
}
while(startcluster != 0xffff); // last cluster has been deleted.
return(new_cluster);
}
 
/****************************************************************************************************************************************************/
/* Function: DirectoryEntryExist(int8_t *, uint8_t, uint8_t, File_t *) */
/* */
/* 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. */
/****************************************************************************************************************************************************/
uint8_t DirectoryEntryExist(int8_t *dirname, uint8_t attribfilter, uint8_t attribmask, File_t *file)
{
uint32_t dir_sector, max_dir_sector, curr_sector;
uint16_t dir_entry = 0;
 
//________________________________________________________________________________________________________________________________________
// Funtion: u16 GetFatClusterIndex(File *file);
//
// Description: This function returns the clusterindex of the cluster specified by file->cluster_pointer of the specified file.
//
//________________________________________________________________________________________________________________________________________
uint16_t end_of_directory_not_reached = 0;
uint8_t i = 0;
uint8_t direntry_exist = 0;
DirEntry_t * dir;
 
u16 GetFatClusterOffset(File *file)
{
u32 fat_sector_offset = 0;
// if incomming pointers are useless return immediatly
if((!Partition.IsValid) || (file == NULL) || (dirname == NULL)) return(direntry_exist);
 
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.
// 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
 
return((u16)fat_sector_offset);
}
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;
}
// 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; // 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.
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
{
Fat16_Deinit();
return(direntry_exist);
}
dir = (DirEntry_t *)file->Cache; // set pointer to directory
switch((uint8_t)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);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: u16 GetFatSectorIndex(File *file);
//
// Description: This function returns the sectorindex of the cluster specified by file->cluster_pointer of the specified file.
//
//________________________________________________________________________________________________________________________________________
// update current file data area position to start of first cluster
file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
file->SectorOfCurrCluster = 0;
file->ByteOfCurrSector = 0;
 
u16 GetFatSectorIndex(File *file)
{
u16 fat_pointer = 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
{
curr_sector = file->FirstSectorOfCurrCluster + dir_sector; // calculate sector number
file->SectorInCache = curr_sector; // upate the sector number of file cache.
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read the sector
{
Fat16_Deinit();
return(direntry_exist);
}
dir = (DirEntry_t *)file->Cache; // set pointer to directory
// search all directory entries within that sector
for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
{ // check for existing dir entry
switch((uint8_t)dir[dir_entry].Name[0])
{
case SLOT_EMPTY:
case SLOT_DELETED:
// ignore empty or deleted dir entries
break;
default:
// 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
// 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->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) && (!direntry_exist));
 
fat_pointer = GetFatClusterOffset(file);
fat_pointer = fat_pointer % 0x100; // Calculate the clusterposition in the fat
 
return(fat_pointer);
// if we are seaching in the data area and the file not found in this cluster so take next cluster.
if(!direntry_exist && ( Partition.FirstDataSector <= file->FirstSectorOfCurrCluster))
{
end_of_directory_not_reached = GetNextCluster(file); // updates File->FirstSectorOfCurrCluster
}
}while((end_of_directory_not_reached) && (!direntry_exist)); // repeat until a next cluster exist an no
return(direntry_exist);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: u16 CreateFileInDirectory(u8 *, File *)
//
// 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 CreateFileInDirectory(s8 *fname, File *file)
/****************************************************************************************************************************************/
/* Function: CreateDirectoryEntry(int8_t *, uint16_t, File_t *) */
/* */
/* Description: This function looks for the next free position in the directory and creates an entry. */
/* The type of an directory entry is specified by the file attribute. */
/* */
/* Returnvalue: Return 0 on error */
/****************************************************************************************************************************************/
uint8_t CreateDirectoryEntry(int8_t *dirname, uint8_t attrib, File_t *file)
{
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;
u32 cluster_temp = 0;
u16 cluster = 0;
s8 name[11] = " ";
uint32_t dir_sector, max_dir_sector, curr_sector;
uint16_t dir_entry = 0;
uint16_t subdircluster, dircluster = 0;
uint16_t end_of_directory_not_reached = 0;
uint8_t i = 0;
uint8_t retvalue = 0;
DirEntry_t* dir;
 
SeperateFileName(fname,name);
if((!Partition.IsValid) || (file == NULL) || (dirname == NULL)) return (retvalue);
// It is not checked here that the dir entry that should be created is already existent!
 
cluster_temp = (u32)FindNextFreeCluster(file); // the next free cluster on the disk.
// Dir entries can be created only in file-clusters that have
// the dir-flag set in its attribute or within the root directory
 
if(cluster_temp) // if a free cluster is available:
file->FirstSectorOfFirstCluster = 0;
// no current directory exist therefore assume creating in the root
if(file->DirectorySector == 0)
{
cluster = (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.
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;
}
// 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.
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
{
Fat16_Deinit();
return(retvalue);
}
dir = (DirEntry_t *)file->Cache; // set pointer to directory
switch((uint8_t)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);
}
 
// 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)(CWD + sector_offset),file->buffer); // Read the Rootdirectory.
DirectoryEntry = (struct DirEntry *)file->buffer;
while((rootentry<16) && (!retvalue))
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
{
if((DirectoryEntry[rootentry].attribute == 0) || (DirectoryEntry[rootentry].attribute == 0xE5)) // empty directory entry found
curr_sector = file->FirstSectorOfCurrCluster + dir_sector; // calculate sector number
file->SectorInCache = curr_sector; // upate the sector number of file cache.
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
{
for(i=0;i<11;i++) DirectoryEntry[rootentry].name[i] = name[i]; // Kopie the filename and the file extension to the directoryentry.
DirectoryEntry[rootentry].attribute = _FILE; // 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) (CWD + sector_offset);
file->directory_index = (u8) rootentry;
retvalue = 1;
SDC_PutSector((u32)(CWD + sector_offset),file->buffer);
Fat16_Deinit();
return(retvalue);
}
rootentry++;
cnt_enries_searched++;
}
if(!retvalue) // file not found in this sector so take next 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(((uint8_t)dir[dir_entry].Name[0] == SLOT_EMPTY) || ((uint8_t)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].DateTime = FileDateTime(&SystemTime); // set date/time
dir[dir_entry].Size = 0; // the new createted file has no content yet.
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache)) // write back to card
{
Fat16_Deinit();
return(retvalue);
}
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 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;
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;
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
{
Fat16_Deinit();
return(retvalue);
}
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].DateTime = 0;
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].DateTime = 0;
dir[1].Size = 0;
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))// read in the sector.
{
Fat16_Deinit();
return(retvalue);
}
}
retvalue = 1;
dir_entry = DIRENTRIES_PER_SECTOR; // stop for-loop
}
}
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))
{
rootentry = 0;
sector_offset++;
end_of_directory_not_reached = GetNextCluster(file); // updates File->FirstSectorOfCurrCluster
}
}
while((cnt_enries_searched< PossibleRootEntries) && (!retvalue));
 
}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.
return(retvalue); // return 1 if file has been created otherwise return 0.
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: u16 SeekFileInDirectory(s8 *fname, File *)
//
// Description: this function searches all possible entries withint the actual directory for the specified object.
//
// Returnvalue: This function returns 1 if the directoryentry specified was found.
//________________________________________________________________________________________________________________________________________
 
u8 SeekFileInDirectory(s8 *fname, File *file)
/********************************************************************************************************************************************/
/* Function: FileExist(const int8_t* filename, uint8_t attribfilter, uint8_t attribmask, File_t *file); */
/* */
/* Description: This function looks for the specified file including 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. */
/********************************************************************************************************************************************/
uint8_t FileExist(const int8_t* filename, const uint8_t attribfilter, const uint8_t attribmask, File_t *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;
s8 name[11] = " ";
int8_t* path = 0;
int8_t* subpath = 0;
uint8_t af, am, file_exist = 0;
int8_t dirname[12]; // 8+3 + temination character
 
SeperateFileName(fname,name);
// if incomming pointers are useless return immediatly
if ((filename == NULL) || (file == NULL) || (!Partition.IsValid)) return 0;
 
file->cluster_pointer = CWD; // start looking for the file in the actual directory.
 
// 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))
// trace along the filepath
path = (int8_t*)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
subpath = SeperateDirName(path, dirname);
if(subpath != NULL)
{
i=0;
if(DirectoryEntry[rootentry].name[0] != 0xe5) // ignore deleted items.
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
{
while((i<=10)&&(DirectoryEntry[rootentry].name[i] == name[i]))
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)
{
i++;
file_exist = 1; // last element of path chain was found with the given attribute filter
}
}
 
if((i==11) && (DirectoryEntry[rootentry].attribute & _FILE)) // 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.
else // error seperating the subpath
{
end_of_directory_not_reached = GetNextCluster(file);
return file_exist; // bad subdir format
}
path = subpath;
subpath = 0;
}
while((end_of_directory_not_reached) && (!retvalue));
return(retvalue);
return (file_exist);
}
 
 
 
//________________________________________________________________________________________________________________________________________
// 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(s8 *fname, s8 *name)
/********************************************************************************************************************************************/
/* Function: FileCreate(const s8* 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. */
/********************************************************************************************************************************************/
uint8_t FileCreate(const int8_t* filename, const uint8_t attrib, File_t *file)
{
u8 readpointer = 0;
u8 writepointer = 0;
u8 attribute = 1;
u8 i = 0;
int8_t *path = 0;
int8_t *subpath = 0;
uint8_t af, am, file_created = 0;
int8_t dirname[12];
 
// if incomming pointers are useless return immediatly
if ((filename == NULL) || (file == NULL) || (!Partition.IsValid)) return 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.
// trace along the filepath
path = (int8_t*)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
subpath = SeperateDirName(path, dirname);
if(subpath != NULL)
{
if(attribute) // is the filename "." or ".." ?
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
{
name[writepointer] = fname[readpointer];
readpointer++;
writepointer++;
af = ATTR_SUBDIRECTORY;
am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;
}
else
{
if(fname[(readpointer-1)] != '*')
{
for(i=writepointer;i<8;i++)
{
name[i] = ' ';
}
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);
}
readpointer++;
writepointer = 8;
else if (*subpath == 0) file_created = 1; // last element of path chain was created
}
}
else if(fname[readpointer] == '*') // wildcard found within the filename + extension.
else // error seperating the subpath
{
if(writepointer < 8) // in extension.
{
readpointer++;
writepointer = 8;
}
else // in filename.
{
writepointer = 11; // jump to the end of the string to terminate this function.
}
attribute = 0;
return file_created; // bad subdir format
}
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++;
attribute = 0;
}
path = subpath;
subpath = 0;
}
return (file_created);
}
 
//________________________________________________________________________________________________________________________________________
// Funtion: File * ReserveFilePointer_(void);
//
// Description: This function looks for a free filepointer and reserves it.
//
//
// Return: NULL = faild to reserve a filepointer
// otherwise filepointer
//________________________________________________________________________________________________________________________________________
 
File * ReserveFilePointer(void)
/********************************************************************************************************************************************/
/* Function: File_t * fopen_(int8_t* filename, int8_t mode); */
/* */
/* Description: This function looks for the specified file in the rootdirectory of the drive. If the file is found the number of the */
/* corrosponding filepointer is returned. Only modes 'r' (reading) and 'a' append are implemented yet. */
/* */
/* Returnvalue: The filepointer to the file or 0 if faild. */
/********************************************************************************************************************************************/
File_t * fopen_(const int8_t *filename, const int8_t mode)
{
File *file;
file = NULL;
u8 temp;
File_t *file = 0;
 
for(temp = 0;temp<__MAX_FILES_USED;temp++)
{
if(FilePointer[temp].state == _UNUSED) // free filepointer found?
if((!Partition.IsValid) || (filename == 0)) return(file);
 
// Look for an unused filepointer in the file pointer list?
file = LockFilePointer();
// if no unused file pointer was found return 0
if(file == NULL) return(file);
 
// 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).
file->ByteOfCurrSector = 0; // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
file->Mode = mode; // mode of fileoperation (read,write)
file->Size = 0; // the size of the opened file in bytes.
file->Position = 0; // pointer to a byte within the file 0 < fileposition < filesize
file->SectorInCache = 0; // the last sector read, wich is still in the sectorbuffer.
file->DirectorySector = 0; // the sectorposition where the directoryentry has been made.
file->DirectoryIndex = 0; // the index to the directoryentry within the specified sector.
file->Attribute = 0; // the attribute of the file opened.
 
// 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
{
file = &FilePointer[temp];
FilePointer[temp].state = _USED; // mark as used.
FilePointer[temp].mode = 0; // type of access (read/write) not defined yet.
FilePointer[temp].start_cluster = 0; // Sectorpointer to the first sector of the first datacluster of the file.
FilePointer[temp].cluster_pointer = 0; // Pointer to the cluster which is edited at the moment.
FilePointer[temp].sector_index = 0; // The sector which is edited at the moment (cluster_pointer + sector_index).
FilePointer[temp].byte_index = 0; // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
FilePointer[temp].filesize = 0; // the size of the opend file in bytes.
FilePointer[temp].fileposition = 0; // pointer to a character within the file 0 < fileposition < filesize
FilePointer[temp].sector_in_buffer = 0; // the last sector read, wich is still in the sectorbuffer.
FilePointer[temp].directory_sector = 0; // the sectorposition where the directoryentry has been made.
FilePointer[temp].directory_index = 0; // the index to the directoryentry within the specified sector.
FilePointer[temp].attribute = 0; // the attribute of the file opened.
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
fclose_(file);
file = NULL;
}
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
fclose_(file);
file = NULL;
}
else
{ // file is not marked as read only --> goto start of file
// free all clusters of that file
DeleteClusterChain(SectorToFat16Cluster(file->FirstSectorOfFirstCluster));
// mar an empy cluster as the last one and store the corresponding sector
file->FirstSectorOfFirstCluster = Fat16ClusterToSector(FindNextFreeCluster(file));
file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
file->SectorOfCurrCluster = 0;
file->ByteOfCurrSector = 0;
file->Size = 0;
file->Position = 0;
fseek_(file, 0, SEEK_SET);
}
break;
case 'r': // if mode is: read from file
// goto end of file
fseek_(file, 0, SEEK_SET);
break;
default: // other modes are not supported
fclose_(file);
file = NULL;
break;
}
return(file);
}
return(file);
}
 
 
//________________________________________________________________________________________________________________________________________
// Funtion: void FreeFilePointer_(File *);
//
// Description: This function free's the filepointer by marking it as unused.
//
//
// Return: none
//
//________________________________________________________________________________________________________________________________________
 
void FreeFilePointer(File *file)
{
u8 cnt = 0;
 
for(cnt=0;cnt<__MAX_FILES_USED;cnt++) // Is the filepointeradress vaild?
else // file does not exist
{
if(&FilePointer[cnt] == file) // filepointer found therefore it must be valid
switch(mode) // check mode
{
FilePointer[cnt].state = _UNUSED; // and can be marked as unused.
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
fclose_(file);
file = NULL;
}
break;
case 'r': // else opened for 'r'
default: // of unsupported mode
fclose_(file);
file = NULL;
break;
}
return(file);
}
// we should never come to this point
fclose_(file);
file = NULL;
return(file);
}
 
/****************************************************************************************************************************************************/
/* Function: fflush_(File *); */
/* */
/* Description: This function writes the data already in the buffer but not yet written to the file. */
/* */
/* Returnvalue: 0 on success EOF on error */
/****************************************************************************************************************************************************/
int16_t fflush_(File_t *file)
{
DirEntry_t *dir;
 
//________________________________________________________________________________________________________________________________________
// Funtion: void DelteDirectoryEntry(Find *)
//
// Description: This function deletes the directoryentry of the specified item.
//
//
// returnvalue: 1 if the directory could be created.
//________________________________________________________________________________________________________________________________________
if((file == NULL) || (!Partition.IsValid)) return (EOF);
 
void DeleteDirectoryEntry(Find *item)
{
u8 buffer[512];
switch(file->Mode)
{
case 'a':
case 'w':
if(file->ByteOfCurrSector > 0) // has data been added to the file?
{
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))// save the data still in the buffer
{
Fat16_Deinit();
return(EOF);
}
}
file->SectorInCache = file->DirectorySector;
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache)) // read the directory entry for this file.
{
Fat16_Deinit();
return(EOF);
}
 
dir = (DirEntry_t *)file->Cache;
dir[file->DirectoryIndex].Size = file->Size; // update file size
dir[file->DirectoryIndex].DateTime = FileDateTime(&SystemTime); // update date time
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache)) // write back to sd-card
{
Fat16_Deinit();
return(EOF);
}
break;
case 'r':
default:
return(EOF);
break;
 
SDC_GetSector((u32) item->cluster_pointer,buffer); // Read the Rootdirectory.
DirectoryEntry = (struct DirEntry *)buffer;
 
DirectoryEntry[(item->directory_index)-1].attribute = 0; // free the directoryentry.
DirectoryEntry[(item->directory_index)-1].name[0] = 0xE5; // free the directoryentry.
SDC_PutSector((u32) item->cluster_pointer,buffer); // Read the Rootdirectory.
}
return(0);
}
 
/****************************************************************************************************************************************/
/* Function: 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. */
/* */
/* Returnvalue: 0 on success EOF on error */
/****************************************************************************************************************************************/
int16_t fclose_(File_t *file)
{
int16_t returnvalue = EOF;
 
if(file == NULL) return(returnvalue);
returnvalue = fflush_(file);
UnlockFilePointer(file);
return(returnvalue);
}
 
 
//________________________________________________________________________________________________________________________________________
// Funtion: u8 CreateSubDirectory(u8 *)
//
// Description: This function creates an directory within the directory specified by CWD
//
//
// returnvalue: 1 if the directory could be created.
//________________________________________________________________________________________________________________________________________
 
u8 CreateSubDirectory(s8 *fname)
/********************************************************************************************************************************************/
/* Function: fgetc_(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. If 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. */
/********************************************************************************************************************************************/
int16_t fgetc_(File_t *file)
{
u16 index = 0; // index to an entry in the rootdirectory.
u16 cnt_entries_searched = 0; // count the number of rootentries which have been searched already.
u16 i = 0;
u16 sector_offset = 0; // index to the sector of the entry which is searched momentarily
u8 retvalue = 0;
u32 cluster_temp = 0;
u16 cluster = 0;
File file;
u8 name[11] = {" "};
int16_t c = EOF;
uint32_t curr_sector;
 
SeperateFileName(fname,name);
cluster_temp = (u32)FindNextFreeCluster(&file); // the next free cluster on the disk.
 
if(cluster_temp) // if a free cluster is available:
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) )
{
cluster = (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.
curr_sector = file->FirstSectorOfCurrCluster; // calculate the sector of the next character to be read.
curr_sector += file->SectorOfCurrCluster;
 
// -Initialise new cluster to zero--------------------------------------------------------
for(i=0;i<512;i++)
if(file->SectorInCache != curr_sector)
{
file.buffer[i] = 0; // initialise buffer to zero
file->SectorInCache = curr_sector;
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache,file->Cache))
{
Fat16_Deinit();
return(c);
}
}
for(sector_offset=0;sector_offset<SectorsPerCluster;sector_offset++) // initialise all sectors of new cluster with buffer.
c = (int16_t) file->Cache[file->ByteOfCurrSector];
file->Position++; // increment file position
file->ByteOfCurrSector++; // goto next byte in sector
if(file->ByteOfCurrSector >= BYTES_PER_SECTOR) // if end of sector
{
SDC_PutSector((u32)(file.start_cluster + sector_offset),file.buffer); // save the initialised sector to the card.
}
// -Create directoryentry "." -------------------------------------------------------------
DirectoryEntry = (struct DirEntry *)file.buffer;
DirectoryEntry[0].name[0] = '.';
DirectoryEntry[0].attribute = _DIRECTORY;
DirectoryEntry[0].startcluster = cluster;
// -Create directoryentry "." -------------------------------------------------------------
DirectoryEntry[1].name[0] = '.';
DirectoryEntry[1].name[1] = '.';
DirectoryEntry[1].attribute = _DIRECTORY;
if(CWD == RootDirectory)
{
DirectoryEntry[1].startcluster = 0;
}
else
{
cluster_temp = (CWD - FirstDataCluster);
cluster_temp /= SectorsPerCluster;
cluster_temp -= 2;
DirectoryEntry[1].startcluster = (u16) cluster_temp;
}
SDC_PutSector((u32) file.start_cluster,file.buffer); // save the initialised sector to the card.
// -create directoryentry within the cwd --------------------------------------------------
sector_offset = 0;
cnt_entries_searched = 0;
do
{ // search the next 16 rootentries in this sector of the roordirectory.
index=0;
SDC_GetSector((u32)(CWD + sector_offset),file.buffer); // Read the actual directory.
DirectoryEntry = (struct DirEntry *)file.buffer;
while((index<16) && (!retvalue))
file->ByteOfCurrSector = 0; // reset byte location
file->SectorOfCurrCluster++; // next sector
if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster) // if end of cluster is reached, the next datacluster has to be searched in the FAT.
{
if((DirectoryEntry[index].attribute == 0) || (DirectoryEntry[index].attribute == 0xE5)) // empty directory entry found
 
if(GetNextCluster(file)) // Sets the clusterpointer of the file to the next datacluster.
{
for(i=0;i<11;i++) DirectoryEntry[index].name[i] = name[i]; // Kopie the filename and the file extension to the directoryentry.
DirectoryEntry[index].attribute = _DIRECTORY; // Set the fileattribute to archive to reserve the directoryentry.
DirectoryEntry[index].startcluster = cluster; // copy the location of the first datacluster to the directoryentry.
DirectoryEntry[index].size = 0; // the new createted file has no content yet.
file.directory_sector = (u32) (CWD + sector_offset);
file.directory_index = (u8) index;
retvalue = 1;
SDC_PutSector((u32)(CWD + sector_offset),file.buffer);
file->SectorOfCurrCluster = 0; // start reading new cluster at first sector of the cluster.
}
index++;
cnt_entries_searched++;
else // the last cluster was allready reached
{
file->SectorOfCurrCluster--; // jump back to the last sector in the last cluster
file->ByteOfCurrSector = BYTES_PER_SECTOR; // set ByteOfCurrSector one byte over sector end
}
}
if(!retvalue) // file not found in this sector so take next sector.
{
index = 0;
sector_offset++;
}
}
while((cnt_entries_searched< PossibleRootEntries) && (!retvalue));
 
}
return(retvalue); // return 1 if file has been created otherwise return 0.
return(c);
}
 
 
//________________________________________________________________________________________________________________________________________
// Funtion: u16 SeekSubDirectory(s8 *fname)
//
// Description: looks for the specified directory within the CWD.
//
// Returnvalue: If the specified directory was found the startcluster is returned. otherwise 0.
//________________________________________________________________________________________________________________________________________
 
u16 SeekSubDirectory(s8 *fname)
/********************************************************************************************************************************************/
/* Function: fputc_( const s8 c, File *file); */
/* */
/* Description: This function writes a byte to the specified file and takes care of writing the necessary FAT- Entries. */
/* next sector of the cluster is read. If the last sector of the cluster read the next cluster will be searched in FAT. */
/* */
/* Returnvalue: The function returns the character written to the stream or EOF on error. */
/********************************************************************************************************************************************/
int16_t fputc_(const int8_t c, File_t *file)
{
u16 index = 0;
u16 end_of_directory_not_reached = 0; // the directory has been read completely without a result.
u8 i = 0;
u16 cluster_temp = 0;
s8 name[11] = " ";
File file;
uint32_t curr_sector = 0;
 
SeperateFileName(fname,name);
if((!Partition.IsValid) || (file == NULL)) return(EOF);
 
file.cluster_pointer = CWD; // start looking for the file in the actual directory.
file.start_cluster = CWD; // start looking for the file in the actual directory.
// If file position equals to file size, then the end of file has reached.
// In this chase it has to be checked that the ByteOfCurrSector is BYTES_PER_SECTOR
// and a new cluster should be appended.
if((file->Position >= file->Size) && (file->ByteOfCurrSector >= BYTES_PER_SECTOR))
{
if(!AppendCluster(file)) return(EOF);
}
 
// 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.
index=0;
SDC_GetSector((u32) file.cluster_pointer,file.buffer); // Read the Rootdirectory.
DirectoryEntry = (struct DirEntry *)file.buffer;
curr_sector = file->FirstSectorOfCurrCluster;
curr_sector += file->SectorOfCurrCluster;
if(file->SectorInCache != curr_sector)
{
file->SectorInCache = curr_sector;
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))
{
Fat16_Deinit();
return(EOF);
}
}
 
while((!cluster_temp)&&(index<16))
file->Cache[file->ByteOfCurrSector] = (uint8_t)c; // write databyte into the buffer. The byte will be written to the device at once
if(file->Size == file->Position) file->Size++; // a character has been written to the file so the size is incremented only when the character has been added at the end of the file.
file->Position++; // the actual positon within the file.
file->ByteOfCurrSector++; // goto next byte in sector
if(file->ByteOfCurrSector >= BYTES_PER_SECTOR) // if the end of this sector is reached yet
{ // save the sector to the sd-card
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
{
i=0;
if(DirectoryEntry[index].name[0] != 0xe5) // ignore deleted items.
{
while((i<=10)&&(DirectoryEntry[index].name[i] == name[i]))
Fat16_Deinit();
return(EOF);
}
file->ByteOfCurrSector = 0; // reset byte location
file->SectorOfCurrCluster++; // next sector
if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster)// if end of cluster is reached, the next datacluster has to be searched in the FAT.
{
if(!GetNextCluster(file)) // Sets the clusterpointer of the file to the next datacluster.
{ // if current cluster was the last cluster of the file
if(!AppendCluster(file)) // append a new and free cluster at the end of the file.
{
i++;
file->SectorOfCurrCluster--; // jump back to last sector of last cluster
file->ByteOfCurrSector = BYTES_PER_SECTOR; // set byte location to 1 byte over sector len
return(EOF);
}
}
 
if((i==11) && (DirectoryEntry[index].attribute & _DIRECTORY)) // entry found!! -> reading startcluster of entry from offset 26.
else // next cluster
{
cluster_temp = (u16)DirectoryEntry[index].startcluster;
file->SectorOfCurrCluster = 0; // start reading new cluster at first sector of the cluster.
}
index++;
}
if(!cluster_temp) // file not found in this sector so take next sector.
{
end_of_directory_not_reached = GetNextCluster(&file);
}
}
while((end_of_directory_not_reached) && (!cluster_temp));
return(cluster_temp);
return(0);
}
 
 
/****************************************************************************************************************************************/
/* Function: fread_(void *buffer, uint32_t size, uint32_t 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. */
/****************************************************************************************************************************************/
uint32_t fread_(void *buffer, uint32_t size, uint32_t count, File_t *file)
{
uint32_t object_cnt = 0; // count the number of objects read from the file.
uint32_t object_size = 0; // count the number of bytes read from the actual object.
uint8_t *pbuff = 0; // a pointer to the actual bufferposition.
uint8_t success = 1; // no error occured during read operation to the file.
int16_t c;
 
//________________________________________________________________________________________________________________________________________
// Funtion: u8 mkdir_(u8 *)
//
// Description: This function checks if the directory to be created already exists. If not the directory will be created.
//
//
// returnvalue: 1 if the directory could be created.
//________________________________________________________________________________________________________________________________________
if((!Partition.IsValid) || (file == NULL) || (buffer == NULL)) return(0);
 
u8 mkdir_(s8 *fname)
{
u8 retvalue = 0;
pbuff = (uint8_t *) buffer; // cast the void pointer to an u8 *
 
retvalue = SeekSubDirectory(fname); // check wether the specified directory already exists.
 
if(!retvalue)
while((object_cnt < count) && success)
{
CreateSubDirectory(fname); // if directory doesn't exist, create it.
retvalue = 1;
object_size = size;
while((size > 0) && success)
{
c = fgetc_(file);
if(c != EOF)
{
*pbuff = (uint8_t)c; // read a byte from the buffer to the opened file.
pbuff++;
size--;
}
else // error or end of file reached
{
success = 0;
}
}
if(success) object_cnt++;
}
else
{
retvalue = 0;
}
 
return(retvalue);
return(object_cnt); // return the number of objects succesfully read from the file
}
 
 
//________________________________________________________________________________________________________________________________________
// Funtion: u8 chdir_(u8 *)
//
// Description: This function changes the CWD to the directory specified.
//
//
// returnvalue: 1 if the directory could be changed.
//________________________________________________________________________________________________________________________________________
 
u8 chdir_(s8 *fname)
/****************************************************************************************************************************************/
/* Function: fwrite_(void *buffer, uint32_t size, uint32_t count, File *file); */
/* */
/* Description: This function writes count objects of the specified size */
/* from the buffer pointer to the actual position in the file. */
/* */
/* Returnvalue: The function returns the number of objects (not bytes) read from the file. */
/****************************************************************************************************************************************/
uint32_t fwrite_(void *buffer, uint32_t size, uint32_t count, File_t *file)
{
u8 retvalue = 0;
u8 name[11] = {" "};
uint32_t object_cnt = 0; // count the number of objects written to the file.
uint32_t object_size = 0; // count the number of bytes written from the actual object.
uint8_t *pbuff = 0; // a pointer to the actual bufferposition.
uint8_t success = 1; // no error occured during write operation to the file.
int16_t c;
 
u32 ultemp = 0;
if((!Partition.IsValid) || (file == NULL) || (buffer == NULL)) return(0);
 
SeperateFileName(fname,name);
pbuff = (uint8_t *) buffer; // cast the void pointer to an u8 *
 
ultemp = (u32)SeekSubDirectory(name);
if(ultemp >= 2)
while((object_cnt < count) && success)
{
ultemp -=2; // Clusterposition is ((position in FAT)-2). first two entries in FAT are reserved.
ultemp *= SectorsPerCluster; // Calculate relative sectorindex of first datacluster.
ultemp += FirstDataCluster;
CWD = ultemp;
retvalue = 1;
}
else
{
CWD = RootDirectory;
retvalue = 1;
}
 
return(retvalue);
}
 
 
//________________________________________________________________________________________________________________________________________
// Funtion: u8 FindItem(s8 *fname, Find *)
//
// Description: finds an item (file or directory) within common working directory (cwd). Wildcards '*' or '?' will be considered.
//
// Returnvalue: If an item was found this function returns '1' else '0'.
//________________________________________________________________________________________________________________________________________
 
u8 FindItem(Find *item)
{
u16 index = 0;
u16 end_of_directory_not_reached = 0; // the directory has been read completely without a result.
u8 i = 0;
u8 readpointer = 0;
u8 writepointer = 0;
u8 retvalue = 0;
File file;
 
 
file.cluster_pointer = item->cluster_pointer;
file.start_cluster = item->cluster_pointer;
index = item->directory_index;
// 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.
SDC_GetSector((u32) file.cluster_pointer,file.buffer); // Read the Rootdirectory.
DirectoryEntry = (struct DirEntry *)file.buffer;
 
while((!retvalue)&&(index<16))
object_size = size;
while((size > 0) && success)
{
i=0;
if(DirectoryEntry[index].name[0] != 0xe5) // ignore deleted items.
c = fputc_(*pbuff, file); // write a byte from the buffer to the opened file.
if(c != EOF)
{
while((i<=10)&&((DirectoryEntry[index].name[i] == item->searchstring[i]) || (item->searchstring[i]=='*') || item->searchstring[i]=='?'))
{
i++;
}
pbuff++;
size--;
}
 
if((i==11) && (DirectoryEntry[index].attribute & item->attribute))
else
{
for(readpointer=0;readpointer<=10;readpointer++)
{
if(DirectoryEntry[index].name[readpointer] != ' ')
{
item->name[writepointer] = DirectoryEntry[index].name[readpointer]; // copy the name of the item found to the find_structure.
writepointer++;
}
else if((readpointer==7) && (DirectoryEntry[index].attribute == _FILE)) // if the item found is a file
{
if(DirectoryEntry[index].name[readpointer] != ' ')
{
item->name[writepointer] = DirectoryEntry[index].name[readpointer]; // copy the name of the item found to the find_structure.
writepointer++;
}
item->name[writepointer] = '.'; // then seperate the name and the extension by a '.' at index 8.
writepointer++;
}
}
item->startcluster = (u16)DirectoryEntry[index].startcluster;
item->directory_index = ++index;
item->cluster_pointer = file.cluster_pointer;
retvalue = 1;
success = 0;
}
index++;
}
if(!retvalue) // file not found in this sector so take next sector.
{
end_of_directory_not_reached = GetNextCluster(&file);
}
index = 0;
if(success) object_cnt++;
}
while((end_of_directory_not_reached) && (!retvalue));
 
return(retvalue);
return(object_cnt); // return the number of objects succesfully written to the file
}
 
 
//________________________________________________________________________________________________________________________________________
// Funtion: u8 findfirst(s8 *fname, Find *)
//
// Description: finds the first item (file or directory) within common working directory (cwd). Wildcards '*' or '?' will be considered.
//
// Returnvalue: If an item was found this function returns '1' else '0'.
//________________________________________________________________________________________________________________________________________
 
u8 findfirst_(s8 *fname, Find *item, u8 attribute)
/****************************************************************************************************************************************/
/* Function: fputs_(const int8_t *string, File_t *File); */
/* */
/* Description: This function writes a string to the specified file. */
/* */
/* Returnvalue: The function returns a no negative value or EOF on error. */
/****************************************************************************************************************************************/
int16_t fputs_(const int8_t *string, File_t *file)
{
u8 retvalue = 0;
u8 i = 0;
uint8_t i=0;
int16_t c = 0;
 
for(i=0;i<=11;i++)
{
item->searchstring[i] = '*'; // initialise the searchstring with wildcards.
item->name[i] = 0;
}
if((!Partition.IsValid) || (file == NULL) || (string == NULL)) return(0);
 
SeperateFileName(fname,item->searchstring);
 
item->cluster_pointer = CWD; // findfirst_ starts at the beginning of the cwd.
item->directory_index = 0;
item->attribute = attribute;
 
retvalue = FindItem(item);
 
return(retvalue);
}
 
 
//________________________________________________________________________________________________________________________________________
// Funtion: u8 findnext(Find *)
//
// Description: finds the first item (file or directory) within common working directory (cwd). Wildcards '*' or '?' will be considered.
//
// Returnvalue: If an item was found this function returns '1' else '0'.
//________________________________________________________________________________________________________________________________________
 
 
u8 findnext_(Find *item)
{
u8 retvalue = 0;
u8 i = 0;
 
for(i=0;i<=11;i++)
while((string[i] != 0)&& (c != EOF))
{
item->name[i] = 0;
c = fputc_(string[i], file);
i++;
}
 
retvalue = FindItem(item);
 
return(retvalue);
return(c);
}
 
 
 
//________________________________________________________________________________________________________________________________________
// Funtion: u8 fdelete(s8 *fname)
//
// Description: Deletes the file specified by fname.
//
// Returnvalue:
//________________________________________________________________________________________________________________________________________
 
 
u8 fdelete_(s8 *fname)
/****************************************************************************************************************************************/
/* Function: fgets_(int8 *, int16_t , File_t *); */
/* */
/* Description: This function reads a string from the file to the specifies string. */
/* */
/* Returnvalue: A pointer to the string read from the file or 0 on error. */
/****************************************************************************************************************************************/
uint8_t * fgets_(int8_t *string, int16_t length, File_t *file)
{
u8 retvalue = 0;
Find item;
uint8_t *pbuff;
int16_t c = 0;
 
printf("\n\rDeleting file");
retvalue = findfirst_(fname,&item, _FILE); // look for the item to be deleted.
 
if(retvalue); // item found?
if((!Partition.IsValid) || (file == NULL) || (string == NULL) || (length = 0)) return (0);
pbuff = string;
while(length > 1) // read the count-1 characters from the file to the string.
{
printf("\n\r");
printf("%s", item.name);
c = fgetc_(file); // read a character from the opened file.
switch(c)
{
case 0x0A:
c = 0; // set string terminator
length = 1; // stop loop
break;
 
DeleteClusterChain(item.startcluster); // delete all fatentries of the item.
DeleteDirectoryEntry(&item); // free the directoryentry.
 
do
{
printf("\n\r");
printf("%s", item.name);
retvalue = findnext_(&item);
if(retvalue)
{
DeleteClusterChain(item.startcluster); // delete all fatentries of the item.
DeleteDirectoryEntry(&item); // free the directoryentry.
}
case EOF:
c = 0; // set string terminator
length = 1; // stop loop
break;
}
while(retvalue);
*pbuff = (uint8_t)c; // copy byte to string
length--;
pbuff++;
}
return(string);
}
 
printf("\n\rDone");
 
return(retvalue);
/****************************************************************************************************************************************/
/* Function: fexist_(const int8_t*); */
/* */
/* Description: This function checks if a file already exist. */
/* */
/* Returnvalue: 1 if the file exist else 0. */
/****************************************************************************************************************************************/
uint8_t fexist_(const int8_t* filename)
{
uint8_t exist = 0;
File_t *file = 0;
file = LockFilePointer();
exist = FileExist(filename, ATTR_NONE, ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL, file);
UnlockFilePointer(file);
return(exist);
}
 
 
 
//________________________________________________________________________________________________________________________________________
// Funtion: u8 rmdir(s8 *fname)
//
// Description: Deletes the directory specified by dname.
//
// Returnvalue:
//________________________________________________________________________________________________________________________________________
 
 
u8 rmdir_(s8 *dname)
/****************************************************************************************************************************************/
/* Function: feof_(File_t *File); */
/* */
/* Description: This function checks wether the end of the file has been reached. */
/* */
/* Returnvalue: 0 if the end of the file was not reached otherwise 1. */
/****************************************************************************************************************************************/
uint8_t feof_(File_t *file)
{
u8 retvalue = 0;
Find item;
 
printf("\n\rDeleting folder");
retvalue = findfirst_(dname,&item, _DIRECTORY); // look for the item to be deleted.
 
if(retvalue); // item found?
if(((file->Position)+1) < (file->Size))
{
printf("\n\r");
printf("%s", item.name);
 
DeleteClusterChain(item.startcluster); // delete all fatentries of the item.
DeleteDirectoryEntry(&item); // free the directoryentry.
 
do
{
printf("\n\r");
printf("%s", item.name);
retvalue = findnext_(&item);
if(retvalue)
{
DeleteClusterChain(item.startcluster); // delete all fatentries of the item.
DeleteDirectoryEntry(&item); // free the directoryentry.
}
}
while(retvalue);
return(0);
}
else
{
return(1);
}
}
 
printf("\n\rDone");
 
return(retvalue);
}
 
/FollowMe/fat16.h
1,267 → 1,69
#ifndef __fat16_h
#define __fat16_h
#ifndef _FAT16_H
#define _FAT16_H
 
 
 
 
 
//________________________________________________________________________________________________________________________________________
//
// Userspecific definitions
// Definitions
//
//________________________________________________________________________________________________________________________________________
 
#define __MAX_FILES_USED 1 // The number of files that can be opened simultaneously.
//#define __USE_TIME_DATE_ATTRIBUTE
#define FILE_MAX_OPEN 3 // The number of files that can accessed simultaneously.
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#define EOF (-1)
#define BYTES_PER_SECTOR 512
/*
________________________________________________________________________________________________________________________________________
 
 
 
 
 
 
 
 
//________________________________________________________________________________________________________________________________________
//
// Datatype definitions
//
//________________________________________________________________________________________________________________________________________
 
typedef unsigned char u8;
typedef signed char s8;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned long u32;
typedef signed long s32;
 
 
 
//________________________________________________________________________________________________________________________________________
//
// Structure of a filepointer
//
//________________________________________________________________________________________________________________________________________
 
#define _UNUSED 1 // Bits used in the attribute of an directory entry.
#define _USED 2
#define _ARCHIVE 2
#define _READ_ONLY 4
#define _SYSTEM 8
#define _DIRECTORY 16
#define _FILE 32
 
 
typedef struct afile
Structure of a filepointer
________________________________________________________________________________________________________________________________________
*/
typedef struct
{
u32 start_cluster; // Sectorpointer to the first sector of the first datacluster of the file.
u32 cluster_pointer; // Pointer to the cluster which is edited at the moment.
u8 sector_index; // The sector which is edited at the moment (cluster_pointer + sector_index).
u16 byte_index; // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
u8 mode; // mode of fileoperation (read,write)
u32 filesize; // the size of the opend file in bytes.
u32 fileposition; // pointer to a character within the file 0 < fileposition < filesize
u32 sector_in_buffer; // the last sector read, wich is still in the sectorbuffer.
u32 directory_root_sector; // pointer to the root of the
u32 directory_sector; // the sectorposition where the directoryentry has been made.
u8 directory_index; // the index to the directoryentry within the specified sector.
u8 attribute; // the attribute of the file opened.
u8 buffer[512]; // Buffer for read and write operation from or to the mmc.
u8 state; // state of the filepointer (used/unused/...)
} File;
uint32_t FirstSectorOfFirstCluster; // First sector of the first cluster of the file.
uint32_t FirstSectorOfCurrCluster; // First sector of the cluster which is edited at the moment.
uint8_t SectorOfCurrCluster; // The sector within the current cluster.
uint16_t ByteOfCurrSector; // The byte location within the current sector.
uint8_t Mode; // Mode of fileoperation (read,write)
uint32_t Size; // The size of the opend file in bytes.
uint32_t Position; // Pointer to a character within the file 0 < fileposition < filesize
uint32_t DirectorySector; // the sectorposition where the directoryentry has been made.
uint16_t DirectoryIndex; // The index to the directoryentry within the specified sector.
uint8_t Attribute; // The attribute of the file opened.
uint8_t Cache[BYTES_PER_SECTOR]; // Cache for read and write operation from or to the sd-card.
uint32_t SectorInCache; // The last sector read, which is still in the sector cache.
uint8_t State; // State of the filepointer (used/unused/...)
} File_t;
 
//________________________________________________________________________________________________________________________________________
//
// Structure of an item to find within the cwd
//
//________________________________________________________________________________________________________________________________________
 
typedef struct find
{
u8 name[12]; // filename + extension or directoryname of the item found within the cwd.
u8 searchstring[13];
u32 cluster_pointer; // Sectorpointer to the sector of the item searched within the cwd.
u16 startcluster; // pointer to the first datacluster of the item found in the cwd.
u32 filesize; // the size of the opend file in bytes.
u32 directory_sector; // the sector within the actual cluster where the directoryentry was found.
u8 directory_index; // the index to the directoryentry within the specified sector.
u8 attribute; // the attribute of the file opened.
} Find;
 
//________________________________________________________________________________________________________________________________________
//
// Directoryentries
//
//________________________________________________________________________________________________________________________________________
 
 
 
struct DirEntry
{
u8 name[8]; // 8 bytes name.
u8 extension[3]; // 3 bytes extension.
u8 attribute; // attribute of the directory entry (unused,archive,read-only,system,directory,volume)
u8 reserved[10]; // reserved bytes within the directory entry.
u16 time; // time and
u16 date; // date of last write acces to the file or directory.
u16 startcluster; // first cluster of the file or directory.
u32 size; // size of the file or directory in bytes.
} __attribute__((packed));
 
//________________________________________________________________________________________________________________________________________
//
// Structure of an entry within the fileallocationtable.
//
//________________________________________________________________________________________________________________________________________
 
struct FatEntry
{
u16 next_cluster; // the next cluster of the file.
} __attribute__((packed));
 
 
 
 
 
//________________________________________________________________________________________________________________________________________
//
// Partitions
//
//________________________________________________________________________________________________________________________________________
 
#define _EMPTY 0x00
#define _FAT12 0x01
#define _FAT16_ST_32_MB 0x04
#define _EXTENDED 0x05
#define _FAT16_LT_32_MB 0x06
#define _HPFS 0x07
#define _FAT32 0x0B
#define _FAT32_BIOS_Extension 0x0C
#define _FAT16_32_MB_BIOS_Extension 0x0E
#define _EXTENDED_BIOS_Extension 0x0F
#define _EISA 0x12
#define _DYNAMIC 0x42
#define _Linux_Swap 0x82
#define _Linux_Native 0x83
#define _Linux_LVM 0x8E
#define _FreeBSD 0xA5
#define _OpenBSD 0xA6
#define _NetBSD 0xA9
 
 
struct PartitionEntry
{
u8 PartitionState;
u8 BeginningHead;
u16 BeginningCylinder;
u8 Type;
u8 EndHead;
u16 EndCylinder;
u32 NoSectorsBeforePartition;
u32 NoSectorsPartition ;
} __attribute__((packed));
 
 
//________________________________________________________________________________________________________________________________________
//
// Structure of the VolumeBootRecord
//
//________________________________________________________________________________________________________________________________________
 
struct VBR_Entry
{
u8 dummy[11];
u16 bps;
u8 SectorsPerCluster;
u16 ReservedSectors;
u8 NoFATCopies;
u16 MaxRootEntries;
u16 dummy2;
u8 dummy3;
u16 SectorsPerFAT;
} __attribute__((packed));
 
 
 
//________________________________________________________________________________________________________________________________________
//
// Structure of the MasterBootRecord
//
//________________________________________________________________________________________________________________________________________
 
#define _MBR_SECTOR 0 // The MasterBootRecord is located in sector 0
 
struct MBR_Entry
{
u8 ExecutableCode[446];
struct PartitionEntry PartitionEntry1;
struct PartitionEntry PartitionEntry2;
struct PartitionEntry PartitionEntry3;
struct PartitionEntry PartitionEntry4;
u16 ExecutableMarker;
} __attribute__((packed));
 
 
 
 
//________________________________________________________________________________________________________________________________________
//
// API to the FAT16 filesystem
//
//________________________________________________________________________________________________________________________________________
 
extern u8 FAT16_Init(void);
extern File * fopen_(s8 *fname,s8 mode);
extern s16 fflush_(File *file);
extern void fclose_(File *file);
extern u32 fread_(void *buffer, u32 size, u32 count, File *file);
extern u32 fwrite_(void *buffer, u32 size, u32 count, File *file);
extern s16 fseek_(File *file, s32 offset, s16 origin);
extern s16 fgetchar_(File *file);
extern u8 fputchar_(File *file,s8 c);
extern u8 fputs_(File *file,s8 *string);
extern s8 * fgets_(s8 *s, s16 count, File *file);
extern s16 frename_(s8 *oldname, s8 *newname);
extern u8 fexist_(s8*fname);
extern u8 mkdir_(s8*fname);
extern u8 chdir_(s8 *fname);
extern u8 findfirst_(s8 *fname, Find *item, u8 attribute);
extern u8 findnext_(Find *item);
extern uint8_t Fat16_Init(void);
extern uint8_t Fat16_Deinit(void);
 
extern File_t * fopen_(const int8_t *filename, const int8_t mode);
extern int16_t fclose_(File_t *file);
extern uint8_t fexist_(const int8_t *filename);
extern int16_t fflush_(File_t *file);
extern int16_t fseek_(File_t *file, int32_t offset, int16_t origin);
extern int16_t fgetc_(File_t *file);
extern int16_t fputc_(int8_t c, File_t *file);
extern uint32_t fread_(void *buffer, uint32_t size, uint32_t count, File_t *file);
extern uint32_t fwrite_(void *buffer, uint32_t size, uint32_t count, File_t *file);
extern int16_t fputs_(const int8_t *string, File_t *file);
extern uint8_t * fgets_(int8_t *string, int16_t length, File_t *file);
extern uint8_t feof_(File_t *file);
 
 
//________________________________________________________________________________________________________________________________________
//
// Functions needed internaly for the fat16 implementation
//
//________________________________________________________________________________________________________________________________________
 
extern u8 SeekFileInDirectory(s8*fname, File *file);
extern u8 CreateFileInDirectory(s8*fname, File *file);
extern u16 FindNextFreeCluster(File *file);
extern void SeperateFileName(s8*fname, s8*name);
extern u8 ScanSubDirectories(s8*fname, File *file);
extern u16 GetNextCluster(File *file);
extern u8 AppendCluster(File *file);
extern u16 GetFatClusterOffset(File *file);
extern u16 GetFatSectorIndex(File *file);
extern File * ReserveFilePointer(void);
extern u16 SeekSubDirectory(s8 *fname);
extern u8 CreateSubDirectory_(s8 *fname);
extern u8 FindItem(Find *);
extern void FreeFilePointer(File *file);
#endif //_FAT16_H
 
//________________________________________________________________________________________________________________________________________
//
// Vaiables needed internaly for the fat16 implementation
//
//________________________________________________________________________________________________________________________________________
 
extern u8 SectorsPerCluster;
extern u32 CWD;
 
 
 
#endif
 
 
 
 
/FollowMe/main.c
1,54 → 1,3
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Copyright (c) 04.2007 Holger Buss
// + Nur für den privaten Gebrauch
// + 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 und 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 Medien veröffentlicht werden, muss unsere Webseite "http://www.mikrokopter.de"
// + eindeutig als Ursprung verlinkt und genannt 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 permittet
// + 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 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 <avr/boot.h>
 
#include <avr/io.h>
59,7 → 8,6
#include "uart0.h"
#include "uart1.h"
#include "fat16.h"
#include "sdc.h"
#include "led.h"
#include "menu.h"
#include "printf_P.h"
98,20 → 46,24
Button_Init();
// enable interrupts global
sei();
 
LEDRED_OFF;
#ifdef USE_FOLLOWME
LEDGRN_ON;
#endif
 
// try to initialize the FAT 16 filesystem on the SD-Card
Fat16_Init();
 
#ifdef USE_SDLOGGER
printf("\n\rHW: SD-Logger");
printf("\r\n\r\nHW: SD-Logger");
#endif
#ifdef USE_FOLLOWME
printf("\n\rHW: Follow-Me");
printf("\r\n\r\nHW: Follow-Me");
#endif
printf("\n\rFollow Me\n\rSoftware:V%d.%d%c ",VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH + 'a');
printf("\n\r==============================");
printf("\n\r");
printf("\r\nFollow Me\n\rSoftware:V%d.%d%c ",VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH + 'a');
printf("\r\n------------------------------");
printf("\r\n");
 
 
#ifdef USE_FOLLOWME
127,15 → 79,8
if(GetButton())
{
//BeepTime = 200;
printf("\n\rInit FAT16...");
if(SDC_Init())
{
printf("ok");
}
else
{
printf("failed");
}
Fat16_Init();
 
}
 
// restart ADConversion if ready
/FollowMe/sdc.c
7,7 → 7,7
#include "printf_P.h"
#include "crc16.h"
 
#define _SD_DEBUG
//#define _SD_DEBUG
 
#define CMD_GO_IDLE_STATE 0x00 /* CMD00: response R1 */
#define CMD_SEND_OP_COND 0x01 /* CMD01: response R1 */
140,9 → 140,9
SSC_Disable(); // disable chipselect.
SSC_PutChar(0xFF); // dummy to sync
SSC_Enable(); // enable chipselect.
_delay_loop_2(200);
//SDC_WaitForBusy(500); // wait 500ms until card is busy
 
SDC_WaitForBusy(500); // wait 500ms until card is busy
 
for (a = 0;a < 6; a++) // send the command sequence to the sdcard (6 bytes)
{
SSC_PutChar(cmd[a]);
152,7 → 152,7
do
{
r1 = SSC_GetChar(); // get byte from sd-card
if (timeout++ > 1000) break;
if (timeout++ > 500) break;
}while(r1 == 0xFF); // wait for the response byte from sd-card.
#ifdef _SD_DEBUG
printf("-->R1=%02X", r1);
243,15 → 243,15
uint8_t pn[6];
uint16_t temp1, temp2;
 
printf("\r\n Manufacturer ID: %i\r\n", pCID[0]);
printf("\r\n Manufacturer ID: %i\r\n", pCID[0]);
memcpy(pn, &pCID[1], 2);
pn[2] = '\0'; // terminate string
printf(" Application ID: %s\r\n",pn);
printf(" Application ID: %s\r\n",pn);
memcpy(pn, &pCID[3], 5);
pn[5] = '\0'; // terminate string
printf(" Product Name: %s\r\n",pn);
printf(" Product Rev.: %i.%i\r\n",pCID[8]>>4, pCID[8]&0xF);
printf(" Serial No.: ");
printf(" Product Name: %s\r\n",pn);
printf(" Product Rev.: %i.%i\r\n",pCID[8]>>4, pCID[8]&0xF);
printf(" Serial No.: ");
for(temp1 = 0; temp1<4; temp1++)
{
printf("%02X", pCID[9+temp1]);
259,7 → 259,7
printf("\r\n");
temp1 = pCID[14] & 0x0F; // month
temp2 = ((pCID[14]>>4)|(pCID[13]<<4)) + 2000; // year
printf(" Manufac. Date: %i/%i\r\n\r\n",temp1, temp2);
printf(" Manufac. Date: %i/%i\r\n\r\n",temp1, temp2);
}
 
//________________________________________________________________________________________________________________________________________
312,7 → 312,7
SSC_Init();
printf("ok");
 
_delay_loop_2(1050);
//_delay_loop_2(1050);
 
printf("\r\n SDC init...");
SDCardInfo.Valid = 0;
518,10 → 518,10
switch(SDCardInfo.Version)
{
case VER_1X:
printf(" SD-CARD V1.x");
printf("\r\n SD-CARD V1.x");
break;
case VER_20:
printf(" SD-CARD V2.0 or later");
printf("\r\n SD-CARD V2.0 or later");
default:
break;
}
/FollowMe/ssc.c
1,8 → 1,6
#include <avr/io.h>
#include "ssc.h"
 
 
 
//-------------------------------------- Hardware specific definitions --------------------------------------
#define PORTR_SPI PINB
#define PORTW_SPI PORTB //Port to which the sd-card is connected (SPI Port)
76,7 → 74,7
 
 
//________________________________________________________________________________________________________________________________________
// Funtion: SSC_Init(void);
// Function: SSC_Init(void);
//
// Description: This function initialises the synchronus serial channel to the sdcard.
//
115,7 → 113,9
 
void SSC_Deinit(void)
{
 
SSC_Disable();
SPCR = 0;
SPSR = 0;
}
 
//________________________________________________________________________________________________________________________________________