⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fat.c

📁 AVR ATMega library for using MMC /SD cart.
💻 C
📖 第 1 页 / 共 2 页
字号:
/* ****************************************************************************
 *  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 + -