📄 fat.c
字号:
/* ****************************************************************************
* FAT16/32 file system driver (read & write support) for Atmel ATmega uC
* based on fat.h by Pascal Stang (only read support) which you can find at
* the website http://hubbard.engr.scu.edu/embedded/avr/avrlib/
*
* version: 0.1
* date: 2005-04-02
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* ***************************************************************************/
#define EXTRA_DEBUG 0
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <string.h>
#include <stdio.h>
#include "ata.h"
#if EXTRA_DEBUG
#include "rprintf.h"
#endif
#include "types.h" // by ao
#include "fat.h"
#include "fatconf.h"
// globals
unsigned char *SectorBuffer = (unsigned char *) SECTOR_BUFFER1_ADDR;
unsigned char *LongNameBuffer = (unsigned char *) LONGNAME_BUFFER_ADDR;
unsigned char *DirNameBuffer = (unsigned char *) DIRNAME_BUFFER_ADDR;
unsigned char FatCacheBuffer[ FAT_CACHE_SIZE ]; // by ao
struct partrecord PartInfo;
unsigned char Fat32Enabled;
unsigned long FirstDataSector;
unsigned int BytesPerSector;
unsigned int SectorsPerCluster;
unsigned long FirstFATSector;
unsigned long FirstFAT2Sector;
unsigned long FirstDirSector;
unsigned long FileSize;
unsigned long FatInCache = 0;
unsigned short FATSectors = 0;
unsigned short RootDirEntries = 0; // by ao
/*************************************************************************/
unsigned long fatClustToSect(unsigned long clust)
{
// mod. by ao
if( clust == 0 ) {
return FirstDataSector;
}
else {
return ((clust-2) * SectorsPerCluster) + (RootDirEntries * 32) / BytesPerSector + FirstDataSector;
}
}
unsigned int fatClusterSize(void)
{
// return the number of sectors in a disk cluster
return SectorsPerCluster;
}
unsigned char fatInit( unsigned char device)
{
//struct partrecord *pr;
struct bpb710 *bpb;
// read partition table
// TODO.... error checking
ataReadSectors(DRIVE0, 0, 1, SectorBuffer);
// map first partition record
// save partition information to global PartInfo
PartInfo = *((struct partrecord *) ((struct partsector *) SectorBuffer)->psPart);
// PartInfo = *pr;
// Read the Partition BootSector
// **first sector of partition in PartInfo.prStartLBA
ataReadSectors( DRIVE0, PartInfo.prStartLBA, 1, SectorBuffer );
bpb = (struct bpb710 *) ((struct bootsector710 *) SectorBuffer)->bsBPB;
// setup global disk constants
FirstDataSector = PartInfo.prStartLBA;
if(bpb->bpbFATsecs) {
// bpbFATsecs is non-zero and is therefore valid
FirstDataSector += bpb->bpbResSectors + bpb->bpbFATs * bpb->bpbFATsecs;
}
else {
// bpbFATsecs is zero, real value is in bpbBigFATsecs
FirstDataSector += bpb->bpbResSectors + bpb->bpbFATs * bpb->bpbBigFATsecs;
}
SectorsPerCluster = bpb->bpbSecPerClust;
BytesPerSector = bpb->bpbBytesPerSec;
FirstFATSector = bpb->bpbResSectors + PartInfo.prStartLBA;
FirstFAT2Sector = bpb->bpbResSectors + PartInfo.prStartLBA + bpb->bpbFATsecs; // bo ao
FATSectors = bpb->bpbFATsecs; // by ao
RootDirEntries = bpb->bpbRootDirEnts; // by ao
switch (PartInfo.prPartType) {
case PART_TYPE_DOSFAT16:
case PART_TYPE_FAT16:
case PART_TYPE_FAT16LBA:
// first directory cluster is 2 by default (clusters range 2->big)
//FirstDirSector = CLUST_FIRST; // rem by ao
FirstDirSector = MSDOSFSROOT; // by ao
// push data sector pointer to end of root directory area
//FirstDataSector += (bpb->bpbRootDirEnts)/DIRENTRIES_PER_SECTOR;
Fat32Enabled = FALSE;
break;
case PART_TYPE_FAT32LBA:
case PART_TYPE_FAT32:
// bpbRootClust field exists in FAT32 bpb710, but not in lesser bpb's
FirstDirSector = bpb->bpbRootClust;
// push data sector pointer to end of root directory area
// need this? FirstDataSector += (bpb->bpbRootDirEnts)/DIRENTRIES_PER_SECTOR;
Fat32Enabled = TRUE;
break;
default:
#if EXTRA_DEBUG
rprintfProgStrM("Found: No Partition!\r\n");
#endif
return -1;
break;
}
#if EXTRA_DEBUG
#ifdef DEBUG_FAT
switch (PartInfo.prPartType) {
case PART_TYPE_DOSFAT16:
rprintfProgStrM("Found: DOSFAT 16\r\n");
break;
case PART_TYPE_FAT16:
rprintfProgStrM("Found: FAT16\r\n");
break;
case PART_TYPE_FAT16LBA:
rprintfProgStrM("Found: FAT16 LBA\r\n");
break;
case PART_TYPE_FAT32LBA:
rprintfProgStrM("Found: FAT32 LBA\r\n");
break;
case PART_TYPE_FAT32:
rprintfProgStrM("Found: FAT32\r\n");
return -1;
break;
default:
rprintfProgStrM("Found: No Partition!\r\n");
return -1;
break;
}
rprintfProgStrM("First sector : "); rprintfu32(PartInfo.prStartLBA); rprintfCRLF();
rprintfProgStrM("Size : "); rprintfu32(PartInfo.prSize); rprintfCRLF();
rprintfProgStrM("bytes/sector : "); rprintfu16(bpb->bpbBytesPerSec); rprintfCRLF();
rprintfProgStrM("sectors/cluster : "); rprintfu08(bpb->bpbSecPerClust); rprintfCRLF();
rprintfProgStrM("reserved sectors: "); rprintfu16(bpb->bpbResSectors); rprintfCRLF();
rprintfProgStrM("FatSectors : "); rprintfu16(bpb->bpbFATsecs); rprintfCRLF();
rprintfProgStrM("BigFatSectors : "); rprintfu32(bpb->bpbBigFATsecs); rprintfCRLF();
rprintfProgStrM("Number of Fats : "); rprintfu08(bpb->bpbFATs); rprintfCRLF();
rprintfProgStrM("First Fat Sector: "); rprintfu32(FirstFATSector); rprintfCRLF();
rprintfProgStrM("First Data Sect : "); rprintfu32(FirstDataSector); rprintfCRLF();
rprintfProgStrM("First Dir Clust : "); rprintfu32(FirstDirSector); rprintfCRLF();
rprintfProgStrM("RootEntries : "); rprintfu16( bpb->bpbRootDirEnts ); rprintfCRLF();
#endif
#endif
return 0;
}
//////////////////////////////////////////////////////////////
unsigned int baseentry = 0;
unsigned int entrycount = 0;
unsigned char recurseLevel = 0; // by ao
unsigned long lastReadSectorNumber = 0; // by ao
unsigned short lastReadEntryNumber = 0; // by ao - entry number inside sector
unsigned long fatGetDirEntry(unsigned int entry, unsigned int count)
{
unsigned long sector;
struct direntry *de = 0; // avoid compiler warning by initializing
struct winentry *we;
unsigned int hasBuffer;
unsigned int b;
int i,index;
char *p;
// ---
//rprintfProgStrM("-> RLevel: ");
//rprintfu16( recurseLevel );
//rprintfProgStrM("\r\n");
// limit for recursion level
if( recurseLevel >= 5 ) return 0;
lastReadEntryNumber = 0;
if(count == 0) {
entrycount = 0;
//DirNameBuffer = 0;
*DirNameBuffer = 0;
}
// read dir data
sector = fatClustToSect(FirstDirSector);
hasBuffer = 0;
index = 16; // crank it up
do {
if(index == 16) { // time for next sector ?
//rprintfProgStrM("-> sector: ");
//rprintfu32( sector );
//rprintfProgStrM("\r\n");
lastReadSectorNumber = sector;
ataReadSectors( DRIVE0, sector++, 1, SectorBuffer);
de = (struct direntry *) SectorBuffer;
index = 0;
}
if(*de->deName != 0xE5) {
//if( *de->deName ) rprintfStr( de->deName );
//rprintfProgStrM("-> not deleted entry\r\n");
// if not a deleted entry
if(de->deAttributes == ATTR_LONG_FILENAME) {
//rprintfProgStrM("-> long name\r\n");
// we have a long name entry
we = (struct winentry *) de;
b = 13 *( (we->weCnt-1) & 0x0f); // index into string
p = &LongNameBuffer[b];
for (i=0;i<5;i++) *p++ = we->wePart1[i*2]; // copy first part
for (i=0;i<6;i++) *p++ = we->wePart2[i*2]; // second part
for (i=0;i<2;i++) *p++ = we->wePart3[i*2]; // and third part
if (we->weCnt & 0x40) *p = 0; // in case dirnamelength is multiple of 13
if ((we->weCnt & 0x0f) == 1) hasBuffer = 1; // mark that we have a long entry
#if EXTRA_DEBUG
rprintfStr( LongNameBuffer );
#endif
}
else {
// we have a short name entry
// check if this is the end of a multi-part long name entry
if(hasBuffer) {
// a long entry name has been collected
// is it a directory ?
if(de->deAttributes == ATTR_DIRECTORY) {
/*
unsigned long save = FirstDirSector;
unsigned int save2 = baseentry;
unsigned long rval;
strcpy(DirNameBuffer,LongNameBuffer);
strcat(DirNameBuffer,"/");
// rprintfStr(LongNameBuffer); rprintfProgStrM("/"); //EOL();
//rprintfProgStrM("FirstDirSector: "); rprintfu32( FirstDirSector ); rprintfCRLF();
// call recursively
FirstDirSector = ((unsigned long)de->deHighClust << 16) + de->deStartCluster;
//rprintfProgStrM("FirstDirSector: "); rprintfu32( FirstDirSector ); rprintfCRLF();
recurseLevel++;
rval = fatGetDirEntry(entry,1);
recurseLevel--;
FirstDirSector = save;
baseentry = save2;
if (rval) {
return rval;
}
else
{
// reload original sector
ataReadSectors( DRIVE0, sector-1, 1, SectorBuffer);
entrycount--; // decrement entry counter
*DirNameBuffer = 0;
}
*/
}
else { // normal file entry
//rprintfProgStrM("entrycount: ");
//rprintfu32( (u32) entrycount );
//rprintfProgStrM(", entry: ");
//rprintfu32( (u32) entry );
//rprintfProgStrM(", hasbuffer: ");
//rprintfu32( (u32) hasBuffer );
if(entrycount == entry)
break;
}
hasBuffer = 0; // clear buffer
entrycount++; // increment entry counter
}
// else ignore short_name_only entries
}
}
lastReadEntryNumber++; // by ao
de++;
index++;
} while (*de->deName || index == 16); // 0 in de->deName[0] if no more entries
if (hasBuffer == 0) // end of entries
return 0;
FileSize = de->deFileSize;
return (unsigned long) ((unsigned long)de->deHighClust << 16) + de->deStartCluster;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -