mirror of
https://github.com/esp8266/Arduino.git
synced 2025-06-17 22:23:10 +03:00
Initial Arduino IDE based on Processing.
This commit is contained in:
364
build/shared/lib/avrlib/fat.c
Executable file
364
build/shared/lib/avrlib/fat.c
Executable file
@ -0,0 +1,364 @@
|
||||
/*! \file fat.c \brief FAT16/32 file system driver. */
|
||||
//*****************************************************************************
|
||||
//
|
||||
// File Name : 'fat.c'
|
||||
// Title : FAT16/32 file system driver
|
||||
// Author : Pascal Stang
|
||||
// Date : 11/07/2000
|
||||
// Revised : 12/12/2000
|
||||
// Version : 0.3
|
||||
// Target MCU : ATmega103 (should work for Atmel AVR Series)
|
||||
// Editor Tabs : 4
|
||||
//
|
||||
// This code is based in part on work done by Jesper Hansen for his
|
||||
// YAMPP MP3 player project.
|
||||
//
|
||||
// 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 "ata.h"
|
||||
#include "rprintf.h"
|
||||
|
||||
#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;
|
||||
|
||||
struct partrecord PartInfo;
|
||||
unsigned char Fat32Enabled;
|
||||
unsigned long FirstDataSector;
|
||||
unsigned int BytesPerSector;
|
||||
unsigned int SectorsPerCluster;
|
||||
unsigned long FirstFATSector;
|
||||
unsigned long FirstDirSector;
|
||||
unsigned long FileSize;
|
||||
unsigned long FatInCache = 0;
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
unsigned long fatClustToSect(unsigned long clust)
|
||||
{
|
||||
return ((clust-2) * SectorsPerCluster) + 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;
|
||||
|
||||
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;
|
||||
// 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:
|
||||
rprintfProgStrM("Found: No Partition!\r\n");
|
||||
//return 1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
#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();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
unsigned int baseentry = 0;
|
||||
unsigned int entrycount = 0;
|
||||
|
||||
|
||||
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;
|
||||
|
||||
if(count == 0)
|
||||
{
|
||||
entrycount = 0;
|
||||
DirNameBuffer = 0;
|
||||
}
|
||||
|
||||
// read dir data
|
||||
sector = fatClustToSect(FirstDirSector);
|
||||
|
||||
hasBuffer = 0;
|
||||
|
||||
index = 16; // crank it up
|
||||
do
|
||||
{
|
||||
if(index == 16) // time for next sector ?
|
||||
{
|
||||
ataReadSectors( DRIVE0, sector++, 1, SectorBuffer);
|
||||
de = (struct direntry *) SectorBuffer;
|
||||
index = 0;
|
||||
}
|
||||
|
||||
if(*de->deName != 0xE5)
|
||||
{
|
||||
// if not a deleted entry
|
||||
if(de->deAttributes == ATTR_LONG_FILENAME)
|
||||
{
|
||||
// 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
|
||||
}
|
||||
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();
|
||||
|
||||
// call recursively
|
||||
FirstDirSector = ((unsigned long)de->deHighClust << 16) + de->deStartCluster;
|
||||
rval = fatGetDirEntry(entry,1);
|
||||
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
|
||||
if(entrycount == entry)
|
||||
break;
|
||||
hasBuffer = 0; // clear buffer
|
||||
entrycount++; // increment entry counter
|
||||
}
|
||||
// else ignore short_name_only entries
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
// return the size of the last directory entry
|
||||
unsigned long fatGetFilesize(void)
|
||||
{
|
||||
return FileSize;
|
||||
}
|
||||
|
||||
|
||||
// return the long name of the last directory entry
|
||||
char* fatGetFilename(void)
|
||||
{
|
||||
return LongNameBuffer;
|
||||
}
|
||||
|
||||
|
||||
// return the directory of the last directory entry
|
||||
char* fatGetDirname(void)
|
||||
{
|
||||
return DirNameBuffer;
|
||||
}
|
||||
|
||||
|
||||
// load a clusterfull of data
|
||||
void fatLoadCluster(unsigned long cluster, unsigned char *buffer)
|
||||
{
|
||||
register unsigned char i;
|
||||
// read cluster
|
||||
//while ( ataReadSectors( DRIVE0, clust2sect(cluster), SectorsPerCluster, buffer) != 0);
|
||||
for(i=0; i<SectorsPerCluster; i++)
|
||||
{
|
||||
// ataReadSectors( DRIVE0, clust2sect(cluster)+i, 1, buffer+(i<<9) );
|
||||
// temporary fix for wierd misaligned cluster problem
|
||||
// (only when using FAT16?)
|
||||
ataReadSectors( DRIVE0, fatClustToSect(cluster+8)+i, 1, buffer+(i<<9) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// find next cluster in the FAT chain
|
||||
unsigned long fatNextCluster(unsigned long cluster)
|
||||
{
|
||||
unsigned long nextCluster;
|
||||
unsigned long fatMask;
|
||||
unsigned long fatOffset;
|
||||
unsigned long sector;
|
||||
unsigned int offset;
|
||||
|
||||
// get fat offset in bytes
|
||||
if(Fat32Enabled)
|
||||
{
|
||||
// four FAT bytes (32 bits) for every cluster
|
||||
fatOffset = cluster << 2;
|
||||
// set the FAT bit mask
|
||||
fatMask = FAT32_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
// two FAT bytes (16 bits) for every cluster
|
||||
fatOffset = cluster << 1;
|
||||
// set the FAT bit mask
|
||||
fatMask = FAT16_MASK;
|
||||
}
|
||||
|
||||
// calculate the FAT sector that we're interested in
|
||||
sector = FirstFATSector + (fatOffset / BytesPerSector);
|
||||
// calculate offset of the our entry within that FAT sector
|
||||
offset = fatOffset % BytesPerSector;
|
||||
|
||||
// if we don't already have this FAT chunk loaded, go get it
|
||||
if (sector != FatInCache)
|
||||
{
|
||||
// read sector of FAT table
|
||||
while (ataReadSectors( DRIVE0, sector, 1, (unsigned char*)FAT_CACHE_ADDR) != 0);
|
||||
FatInCache = sector;
|
||||
}
|
||||
|
||||
// read the nextCluster value
|
||||
nextCluster = (*((unsigned long*) &((char*)FAT_CACHE_ADDR)[offset])) & fatMask;
|
||||
|
||||
// check to see if we're at the end of the chain
|
||||
if (nextCluster == (CLUST_EOFE & fatMask))
|
||||
nextCluster = 0;
|
||||
|
||||
#ifdef DEBUG_FAT
|
||||
rprintfProgStrM(">");
|
||||
rprintfu32(nextCluster);
|
||||
rprintfCRLF();
|
||||
#endif
|
||||
|
||||
return nextCluster;
|
||||
}
|
Reference in New Issue
Block a user