📄 fat16avr.c
字号:
//############################################################################
//
// File Name : 'fat.c'
// Title : FAT16 file system driver
// Author : Zoltan Gradwohl
// Date : 28/07/2005
// Revised : 28/07/2005
// Version : 1.0
// Target MCU : ATmega128 (2K Byte Internal SRAM required)
// Editor Tabs : 4
//
//
// NOTE: This code is currently below version 1.0, and therefore is considered
// to be lacking in some functionality or documentation, or may not be fully
// tested. Nonetheless, you can expect most functions to work.
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
//############################################################################
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <string.h>
#include "mmc.h"
#include "rprintf.h"
#include "fat.h"
#include "fatconf.h"
#include "debug.h"
// globals
volatile uint16_t RootDirectoryRegionStart;
volatile uint32_t DataRegionStart;
volatile uint16_t FATRegionSize;
volatile uint16_t RootDirectoryRegionSize;
volatile uint32_t DataRegionSize;
volatile uint8_t SectorsPerCluster;
volatile uint16_t BytePerSector;
volatile uint16_t FATRegionStart;
volatile uint16_t NumberOfFATs;
volatile uint8_t SectorsPerFAT;
volatile uint16_t VolumeStart = 0;
volatile uint16_t ReservedSectors;
uint16_t glbl_FAT_Entry = 0; // FAT entry
uint32_t glbl_FileSize = 0; // filesize
uint32_t glbl_DataSector = 0; // Sector where data starts
uint32_t glbl_Sector = 0; // Sector which contains file size inforation
uint8_t glbl_SubSector = 0; // Which of the 16 32byte long SubSectors contains the file size
uint8_t glbl_Attributes = 0; // Attribute Dir, archive, hidden, system, volume ...
uint16_t FATSectorAddress_old = 0; // Zum überprüfen ob der FAT Sector schon geladen wurde
#define NAMEBUFFERSIZE 32
char NameBuffer[NAMEBUFFERSIZE];
char NameBufferShort[8];
char NameBufferExt[3];
char Name2FindBuffer[NAMEBUFFERSIZE];
union FAT16_Buffer F16;
#define F16_BUFFER_ONE (uint8_t*)(&F16.FATBuffer)
uint16_t FAT_Buf2[256];
#define F16_BUFFER_TWO (uint8_t*)(&FAT_Buf2)
#define RootEntiesCount F16.BootSec.bsRootEntCnt
#define TotalNumberOfSectors F16.BootSec.bsTotSec32
//############################################################################
unsigned char fatInit(void)
//############################################################################
{
// mmc read first sector
mmcRead( 0 , F16_BUFFER_ONE );
//If partitions are available
if( F16.BootSec.bsjmpBoot == 0 )
{
// Number of Sectors Between the MBR and the First Sector in the Partition (32bit)
VolumeStart = (uint16_t)F16.MBS.mbPartitionEntries[0].prStartLBA;
// mmc read Fat16 boot sector
mmcRead( VolumeStart , F16_BUFFER_ONE );
}
//
ReservedSectors = F16.BootSec.bsRsvdSecCnt; // 6
BytePerSector = F16.BootSec.bsBytesPerSec; // 512
SectorsPerCluster = F16.BootSec.bsSecPerClus; // 4
NumberOfFATs = F16.BootSec.bsNumFATs; // 2
SectorsPerFAT = F16.BootSec.bsNrSeProFAT; // 245
// Calculation Algorithms
FATRegionStart = VolumeStart + ReservedSectors; // 6
RootDirectoryRegionStart = FATRegionStart + (NumberOfFATs * SectorsPerFAT); // 496
RootDirectoryRegionSize = (RootEntiesCount*32)/ BytePerSector; // 32
DataRegionStart = RootDirectoryRegionStart + RootDirectoryRegionSize; // 528
FATRegionSize = NumberOfFATs * SectorsPerFAT; // 490
DataRegionSize = TotalNumberOfSectors - (ReservedSectors + FATRegionSize + RootDirectoryRegionSize);
#ifdef DEBUG_FAT
rprintfCRLF();
rprintfProgStrM("OEM Name : "); rprintfStrLen(F16.BootSec.bsOEMName, 0, 8 ); rprintfCRLF();
rprintfProgStrM("Bytes Per Sector: "); rprintfNum(10,6, FALSE,' ',F16.BootSec.bsBytesPerSec); rprintfCRLF();
rprintfProgStrM("Sector Per Clust: "); rprintfNum(10,6, FALSE,' ',F16.BootSec.bsSecPerClus); rprintfCRLF();
rprintfProgStrM("Reserved SecCnt : "); rprintfNum(10,6, FALSE,' ',F16.BootSec.bsRsvdSecCnt); rprintfCRLF();
rprintfProgStrM("Number Of FAT : "); rprintfNum(10,6, FALSE,' ',F16.BootSec.bsNumFATs); rprintfCRLF();
rprintfProgStrM("Root Dir Entries: "); rprintfNum(10,6, FALSE,' ',F16.BootSec.bsRootEntCnt); rprintfCRLF();
rprintfProgStrM("Total Sector 16 : "); rprintfNum(10,6, FALSE,' ',F16.BootSec.bsTotSec16); rprintfCRLF();
rprintfProgStrM("Media : ");
switch (F16.BootSec.bsMedia)
{
// TODO expand further cases
case 0xf8:
rprintfProgStrM("Found: Hard disk. DOS version 2.0 \r\n");
break;
default:
rprintfProgStrM("Found: No Partition!\r\n");
break;
}
rprintfProgStrM("Total Sector 32 : "); rprintfNum(10,6, FALSE,' ',F16.BootSec.bsTotSec32); rprintfCRLF();
rprintfProgStrM("Sector Per FAT : "); rprintfNum(10,6, FALSE,' ',F16.BootSec.bsNrSeProFAT); rprintfCRLF();
rprintfProgStrM("Volume Label : "); rprintfStrLen(F16.BootSec.bsVolLbl, 0, 11 ); rprintfCRLF();
rprintfProgStrM("Filesystem Type : "); rprintfStrLen(F16.BootSec.bsFileSysType, 0, 8); rprintfCRLF();
rprintfCRLF();
rprintfProgStrM("RootDirectoryRegionStart: "); rprintfNum(10,6, FALSE,' ',RootDirectoryRegionStart); rprintfCRLF();
rprintfProgStrM("DataRegionStart : "); rprintfNum(10,6, FALSE,' ',DataRegionStart); rprintfCRLF();
rprintfProgStrM("FATRegionSize : "); rprintfNum(10,6, FALSE,' ',FATRegionSize); rprintfCRLF();
rprintfProgStrM("RootDirectoryRegionSize : "); rprintfNum(10,6, FALSE,' ',RootDirectoryRegionSize); rprintfCRLF();
rprintfProgStrM("DataRegionSize : "); rprintfNum(10,6, FALSE,' ',DataRegionSize); rprintfCRLF();
rprintfCRLF();
#endif
return 0;
}
//####################################################################################
void FAT16_Search ( char *FilePathName, // In: File name to find
int8_t SelectMode ) // In: Select operation: overwrite or contiue data
//####################################################################################
{
#ifdef DEBUG_FAT
uint32_t notused = 0;
#endif
int8_t ret = TRUE;
// Reset varaibles and buffers
FATSectorAddress_old = 0;
glbl_FAT_Entry = 0; // FAT entry
glbl_FileSize = 0; // filesize
glbl_DataSector = 0; // Current data sector
glbl_Sector = 0; // Sector which contains file size inforation
glbl_SubSector = 0; // Which of the 16 32byte long SubSectors contains the file size
glbl_Attributes = 0; // Attribute Dir, archive, hidden, system, volume ...
memset( F16_BUFFER_ONE, 0x00 , 512 ); // Clear buffer
memset( F16_BUFFER_TWO, 0x00 , 512 ); // Clear buffer
memset( NameBuffer, 0x00 , NAMEBUFFERSIZE ); // Clear buffer
memset( NameBufferShort, 0x00 , 8 ); // Clear buffer
memset( NameBufferExt, 0x00 , 3 ); // Clear buffer
memset( Name2FindBuffer, 0x00 , NAMEBUFFERSIZE ); // Clear buffer
#ifdef DEBUG_FAT
rprintfProgStrM("Searching for >"); rprintfStrLen(FilePathName, 0, 64 );
if( SelectMode == OVERWRITE) rprintfProgStrM(" (OVERWRITE)");
if( SelectMode == CONTINUE) rprintfProgStrM(" (CONTINUE)");
rprintfCRLF();
#endif
ret = fatSearch_File( FilePathName, // In: File name to find
&glbl_FAT_Entry, // In/Ret: FAT entry where data starts
&glbl_FileSize, // Return: Return filesize
&glbl_Sector, // Return: Sector which contains file size inforation
&glbl_SubSector, // Return: Return which of the 16 32byte long SubSectors contains the file size
&glbl_DataSector, // Return: Return sector where data starts
&glbl_Attributes, // Return: Return Attribute Dir, archive, hidden, system, volume ...
F16_BUFFER_ONE ); // In: Buffer to use
// empty name buffer for next use
memset( FilePathName, 0x00 , 64 );
if( (ret == TRUE) && (glbl_Attributes == ATTR_ARCHIVE) )
{
if( SelectMode == OVERWRITE )
{
// delete fat entries of current file from "glbl_FAT_Entry" on until end of file and init File
fat_Delete( &glbl_FAT_Entry, // In/Ret: FAT entry where data starts
&glbl_FileSize, // Return: Return filesize
&glbl_Sector, // In: Sector which contains file size inforation
&glbl_SubSector, // In: Return which of the 16 32byte long SubSectors contains the file size
&glbl_DataSector, // Return: Sector where data starts
F16_BUFFER_TWO ); // In: Select buffer to use
}
// if filesize and fat entry is zero (means that file hasn't been used until now)
// search fat address, where data can start
fat_Init_File ( &glbl_FAT_Entry, // In/Ret: FAT entry where data starts
&glbl_FileSize, // In: Filesize
&glbl_Sector, // In: Sector which contains file size inforation
&glbl_SubSector, // In: Return which of the 16 32byte long SubSectors contains the file size
&glbl_DataSector, // Return: Sector where data starts
F16_BUFFER_ONE); // In: Select buffer to use
#ifdef DEBUG_FAT
rprintfCRLF();
rprintfProgStrM("Data starts at FAT address : "); rprintfNum( 10,6, FALSE,' ', glbl_FAT_Entry ); rprintfCRLF();
rprintfProgStrM("Sector containing file info : "); rprintfNum( 10,6, FALSE,' ', glbl_Sector ); rprintfCRLF();
rprintfProgStrM("Data starts in sector : "); rprintfNum( 10,6, FALSE,' ', glbl_DataSector ); rprintfCRLF();
rprintfProgStrM("FileSize [uint8_t] : "); rprintfNum( 10,6, FALSE,' ', glbl_FileSize ); rprintfCRLF();
fatRead_File( &glbl_FAT_Entry, // In: Start clusters of file
¬used, // In:
&glbl_FileSize, // In:
F16_BUFFER_ONE ); // In: Select buffer to use
#endif
if( SelectMode == CONTINUE ){
#ifdef DEBUG_FAT
rprintfProgStrM("\r\n----- Searching end of file -----\r\n");
#endif
// load last sector in current file into F16_BUFFER_ONE
fatWrite_Continue( &glbl_FAT_Entry, // In/Ret: FAT entry where data starts
&glbl_DataSector, // Return: Current data sector address
&glbl_FileSize, // Return: Return filesize
F16_BUFFER_ONE ); // In: Select buffer to use
#ifdef DEBUG_FAT
rprintfCRLF();
rprintfProgStrM("Data ends in FAT address: "); rprintfNum( 10,6, FALSE,' ', glbl_FAT_Entry ); rprintfCRLF();
rprintfProgStrM("Data ends in sector : "); rprintfNum( 10,6, FALSE,' ', glbl_DataSector ); rprintfCRLF();
rprintfProgStrM("FileSize : "); rprintfNum( 10,6, FALSE,' ', glbl_FileSize ); rprintfCRLF();
rprintfProgStrM("Loading last sector of file ->"); rprintfCRLF();
debugPrintHexTable(0x200, F16_BUFFER_ONE);
#endif
}
}
else{
#ifdef DEBUG_FAT
rprintfProgStrM("\r\n----- File not found -----\r\n");
#endif
}
}
//############################################################################
void fatWrite_Continue ( uint16_t *FATEntry, // In/Ret: FAT entry where data starts
uint32_t *SectorAddress, // Return: Current data sector address
uint32_t *FileSize, // Return: Return filesize
uint8_t *Buffer) // In: Select buffer to use
//############################################################################
{
uint16_t FAT_Entry_Temp = 0;
uint16_t offset = 0;
// find at which sector in current cluster the data ends
offset = *FileSize / BytePerSector;
offset %= SectorsPerCluster;
// search end of file to continue to save data there
while(*FATEntry != 0xFFFF)
{
FAT_Entry_Temp = *FATEntry;
fatLoad( FATEntry, SectorAddress, F16_BUFFER_TWO ); // F16_BUFFER_TWO
}
*FATEntry = FAT_Entry_Temp;
*SectorAddress += offset;
// Sector_Address_Temp contains only the address of the first sector in a cluster
// 'offset' contains an offset. So the exact sector address in a cluster can be determined
// read last sector of curent file, which contains data
mmcRead( *SectorAddress , Buffer );
}
//############################################################################
void fat_Delete ( uint16_t *FATEntry, // In/Ret: FAT entry where data starts
uint32_t *FileSize, // Return: Return filesize
uint32_t *Sector, // In: Sector which contains file size inforation
uint8_t *SubSector, // In: Return which of the 16 32byte long SubSectors contains the file size
uint32_t *DataSector, // Return: Sector where data starts
uint8_t *Buffer) // In: Select buffer to use
//############################################################################
{
uint16_t FATSectorAddress;
uint16_t Temp;
if(*FileSize != 0)
{
#ifdef DEBUG_FAT
// deleting file content by deleting FAT addresses
rprintfProgStrM("\r\n----- Deleting file content -----\r\n");
#endif
// Calculate which FAT-sector has to be read depending on FAT-entry
FATSectorAddress = ((*FATEntry*2) / BytePerSector) + FATRegionStart; // ((8*2)/512) + 6 = 6
mmcRead( FATSectorAddress , Buffer );
FATSectorAddress_old = FATSectorAddress;
do{
Temp = FAT_Buf2[*FATEntry]; // load next FAT-address from current FAT-address
FAT_Buf2[*FATEntry] = 0; // clear contents in current FAT-address
*FATEntry = Temp; // prepare next FAT-address
// Calculate which FAT-sector has to be read depending on FAT-entry
FATSectorAddress = ((*FATEntry*2) / BytePerSector) + FATRegionStart; // ((8*2)/512) + 6 = 6
// If new FAT-entry is in new FAT-sector then save old FAT-sector at first and then load new FAT-sector
if (FATSectorAddress != FATSectorAddress_old)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -