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

📄 fat.c

📁 这项工程将让您把自己的MP3播放器平台
💻 C
📖 第 1 页 / 共 4 页
字号:
//++
//fat.c - MP3 Player Compact Flash Card functions
//
// Copyright (C) 2005 by Spare Time Gizmos.  All rights reserved.
//
// This file is part of the Spare Time Gizmos' MP3 Player firmware.
//
// This firmware 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.
//
//DESCRIPTION:
//   This module knows just enough about FAT file systems to a) mount the first
// partition on the CompactFlash card, b)list all the files in the root directory,
// and b) find and read the data in an individual file.  Other than that it's
// pretty limited.  It understands ONLY FAT16 file systems - neither FAT12 nor
// FAT32 are supported.  It also only knows how to read files; there's nothing to
// create files nor allocate free disk space for writing them!  This code does,
// however, have enough sanity checking to reject Compact Flash cards which don't
// meet our requirements.
//
//REFERENCES:
//	http://www.compuphase.com/mbr_fat.htm
//	http://support.microsoft.com/kb/q140418/
//	http://encyclopedia.thefreedictionary.com/FAT16
//	http://www.cse.scu.edu/~tschwarz/coen152_05/Lectures/FAT.html
//
//REVISION HISTORY:
// dd-mmm-yy    who     description
// 20-May-05	RLA	New file.
// 20-Jul-05	RLA	Change NextFATFile() and PreviousFATFile() so that they
//			 loop back when they reach the end/beginning of the root
//			 directory.  This way they just repeat the same sequence
//			 of files over and over again - just what we want an MP3
//			 player to do.
// 12-Oct-05	RLA	Change a lot of things that were parameters (e.g. volume
//			 label, FAT type, etc) into global static variables to
//			 make life easier for SDCC.
// 13-Oct-05	RLA	Semi-major changes to a) remove all statically allocated
//			 disk buffers - instead, buffers are pulled from the free
//			 pool as needed - and b) to allow the directory sector
//			 buffer to be freed while an MP3 is actually playing. This
//			 gives us an extra buffer for MP3 data, which makes it
//			 possible to run on an 89C664 MCU with only 2K RAM.
// 18-Oct-05	RLA	Add basic support for MBRs
// 19-Oct-05	RLA	Make the current FAT buffer statically allocated in XDATA.
//			 Since it's permanently allocated there's no real reason
//			 to use a disk buffer, and doing so wastes a BCB entry and
//			 lots of IDATA space that SDCC can't afford (it works great
//			 with C51, though!).
//			Move ID3 tag stuff to id3.c
//			A "return TRUE" was accidentally left out of StartDirScan()...
//			Add STACKSLOCS hack for SDCC (see slocs.h for more info)...
// 20-Oct-05	RLA	Don't crash if we find an actual LFN longer than MAX_LFN_LENGTH
//			Fix a little endian problem with GetFileLFN()
//--

// Include files...
#include <stdio.h>		// needed so DBGOUT(()) can find printf!
#include <string.h>		// strcpy(), etc...
#include "standard.h"		// standard types - BYTE, WORD, BOOL, etc
#include "cfcard.h"		// Compact Flash card I/O functions
#include "buffer.h"		// Buffer management functions
#include "fat.h"		// declarations for this module
#include "id3.h"		// ID3 v1.1 definitions


// Public members...
//   In the original C51 version, these items were usally automatic variables in another
// module (generally player.c) and passed as parameters to routines in this module.  SDCC,
// however, isn't all that swift at dealing with parameters and local variables, so they
// were converted to globals in the interest of simplifying the generated code.  Sadly, 
// the code quality suffers somewhat as a result, but I guess that's why Keil can charge
// the big bucks...
PUBLIC XDATA char g_szVolumeLabel[VOLUME_LABEL_LENGTH];	// GetVolumeData()
PUBLIC XDATA char g_szSystemType[SYSTEM_TYPE_LENGTH];	// InitializeFAT()
PUBLIC XDATA WORD g_wTotalMP3Files;			// GetVolumeData()
PUBLIC XDATA char g_szLongFileName[MAX_LFN_LENGTH];	// GetFileLFN()

// Volume data...
PRIVATE XDATA LONG  m_lVolFATOffset;	// offset (in sectors) of the first FAT
PRIVATE XDATA LONG  m_lVolRootOffset;	//  "  "   "    "  "   "   "  root directory
PRIVATE XDATA LONG  m_lVolDataOffset;	//  "  "   "    "  "   "   "  file data area
PRIVATE XDATA LONG  m_lVolFATSize;	// size of each FAT (in sectors)
PRIVATE XDATA LONG  m_lVolRootSize;	// size of the root directory (in sectors!)
PRIVATE XDATA BYTE  m_bVolClusterSize;	// sectors per cluster on this device
// Current directory sector status...
PRIVATE DATA  BYTE  m_bCurDirEntry;	// offset of the current directory entry
PRIVATE DATA  LONG  m_lCurDirSector;	// sector currently in directory buffer
//   The next member points to the buffer used to read directory sectors.  This can
// be, and often is, NULL, indicating that there is no buffer allocated.  Especially
// while we're playing, the directory buffer is released to free up more memory for
// MP3 file data.  Calling ReadDirSector() will allocate another buffer...
PRIVATE DATA  PIBCB m_pCurDirBCB;	// BCB of current directory sector
// Current FAT sector status...
PRIVATE IDATA LONG  m_lCurFATSector;	// LBN of the current sector (in m_wCurFAT)...
PRIVATE XDATA CLUSTER m_awCurFAT[CLUSTERS_PER_SECTOR];
// Current file status...
PRIVATE IDATA WORD  m_wCurFileCluster;	// current cluster we're reading
PRIVATE IDATA int   m_nRelFileSector;	// relative sector within the cluster
PRIVATE IDATA LONG  m_lCurFileSector;	// absolute sector (Cluster + RelSector)
PRIVATE IDATA LONG  m_lFileBytesLeft;	// bytes remaining before EOF
//   This is a temporary directory entry which NextMP3File() and PrevMP3File() use
// to cache the current file data while we're playing an MP3 file...
PRIVATE XDATA DIRECTORY_ENTRY m_CurDirEntCache;

//   This macro generates a pointer (of type PXDIRENT) to file #n in the current
// directory sector, m_pCurDirBCB.  The index n can safely range from 0 to
// DIRECTORY_ENTRIES_PER_SECTOR-1.  It's just a metter of caste ...
#define GetDirEntry(n)	( (PXDIRENT) (m_pCurDirBCB->pbBuffer + (n)*sizeof(DIRECTORY_ENTRY)) )
//   This macro is essentially the same, except that it always returns the
// current directory entry, as determined by m_bCurDirEntry...
#define GetCurDirEntry()  GetDirEntry(m_bCurDirEntry)


//++
//   This debugging routine will dump out the contents of a sector buffer in
// both hexadecimal and ASCII.  There's not much too it!
//--
#if 0
PRIVATE void DumpSector (PXBYTE pxBuffer)
{
  WORD wOffset, i;  char ch;
  for (wOffset = 0;  wOffset < IDE_SECTOR_SIZE;  wOffset += 16) {
    printf("%03X/ ", wOffset);
    for (i = 0;  i < 16;  ++i)
      printf(" %02bx", pxBuffer[wOffset+i]);
    printf("    ");
    for (i = 0;  i < 16;  ++i) {
     ch = pxBuffer[wOffset+i] & 0x7F;
     if ((ch < ' ') || (ch >= 0x7F)) ch = '.';
     printf("%c", ch);
    }
    printf("\n");
  }
}
#endif

//++
// Show one entry from the partition table in the MBR.  For debugging only!
//--
#ifdef SHOWPARTITION
PRIVATE void ShowPartition (BYTE bPart, MASTER_BOOT_RECORD XDATA *pxMBR)
{
  DBGOUT(("Partition #%bd - Flags = 0x%02bX, Type = 0x%02bX\n",
    bPart, pxMBR->aPartitions[bPart].bFlags, pxMBR->aPartitions[bPart].bType));
  DBGOUT(("\tStartCHS = 0x%02bX %02bX %02bX, EndCHS = 0x%02bX %02bX %02bX\n",
    pxMBR->aPartitions[bPart].abStartCHS[0], pxMBR->aPartitions[bPart].abStartCHS[1], 
    pxMBR->aPartitions[bPart].abStartCHS[2], pxMBR->aPartitions[bPart].abEndCHS[0],
    pxMBR->aPartitions[bPart].abEndCHS[1],  pxMBR->aPartitions[bPart].abEndCHS[2]));
  DBGOUT(("\tOffset (LBN) = %ld, Size (sectors) = %ld\n",
    LSWAP(pxMBR->aPartitions[bPart].lOffset), LSWAP(pxMBR->aPartitions[bPart].lSize)));
  DBGOUT(("Master boot record signature = 0x%04X\n", WSWAP(pxMBR->wSignature)));
}
#endif

//++
//   This debugging routine will print the contents of the boot sector.
// It's invaluable for figuring out what's wrong...
//--
#ifdef SHOWBOOTSECTOR
PRIVATE void ShowBootSector (BOOT_SECTOR XDATA *pxVBS)
{
  BPB XDATA *pxBPB = &(pxVBS->bpb);
  printf("Volume Boot Sector\n");
  printf("\tabJump = 0x%02bX %02bX %02bX \n", pxVBS->abJump[0], pxVBS->abJump[1], pxVBS->abJump[2]);
  printf("\tszOEMName[8] = \"%8s\"\n", pxVBS->szOEMName);
  printf("\twBootSignature = 0x%04X\n", WSWAP(pxVBS->wBootSignature));
  printf("BIOS Parameter Block\n");
  printf("\twBytesPerSector = %d\n", WSWAP(pxBPB->wBytesPerSector));
  printf("\tbSectorsPerCluster = %bd\n", pxBPB->bSectorsPerCluster);
  printf("\twReservedSectors = %d\n", WSWAP(pxBPB->wReservedSectors));
  printf("\tbNumberFATs = %bd\n", pxBPB->bNumberFATs);
  printf("\twRootEntries = %d\n", WSWAP(pxBPB->wRootEntries));
  printf("\twSmallSectors = %d\n", WSWAP(pxBPB->wSmallSectors));
  printf("\tbMediaDescriptor = 0x%02bX\n", pxBPB->bMediaDescriptor);
  printf("\twSectorsPerFAT = %d\n", WSWAP(pxBPB->wSectorsPerFAT));
  printf("\twSectorsPerTrack = %d\n", WSWAP(pxBPB->wSectorsPerTrack));
  printf("\twTotalHeads = %d\n", WSWAP(pxBPB->wTotalHeads));
  printf("\tlHiddenSectors = %ld\n", LSWAP(pxBPB->lHiddenSectors));
  printf("\tlLargeSectors = %ld\n", LSWAP(pxBPB->lLargeSectors));
  printf("\tbPhysicalDrive = %bd\n", pxBPB->bPhysicalDrive);
  printf("\tbCurrentHead = %bd\n", pxBPB->bCurrentHead);
  printf("\tbBootSignature = 0x%02bX\n", pxBPB->bBootSignature);
  printf("\tlVolumeID = 0x%08lX\n", LSWAP(pxBPB->lVolumeID));
  printf("\tszVolumeLabel[11] = \"%11.11s\"\n", &(pxBPB->szVolumeLabel));
  printf("\tszSystemID[8] = \"%8.8s\"\n", &(pxBPB->szSystemID));
}
#endif


//++
//   This routine will read sector zero from the flash card and attempt
// to determine if it contains a valid master boot record.  If an MBR
// is present, then this code uses the partition table in the MBR to
// find and return the first sector of the first partition on the drive.
// If no MBR is found, then it returns zero.
//
//   The value returned thus tells us where to go to look for the volume
// boot sector (VBS), which is the next step in reading the file system.
// Notice that it's no accident that zero is returned if no MBR is found,
// because in the case of flash cards that have been formatted without
// any MBR (i.e. they're formatted as if they were a big floppy disk) then
// sector zero is where we should look next for the VBS.
//
//   BTW, I know of no single, definitive, test to determine whether a volume
// has an MBR or not.  Unfortunately the 0xAA55 signature that's stored at the
// end of the MBR just happens to be the same signarture, and stored in the
// same place, that you'd find in a VBS.  Worse, most of the MBR is usually
// filled with zeros, and the partition table is the only part which holds any
// meaningful data.  That doesn't give us a lot to go on!
//--
PRIVATE LONG ReadMBR (void) STACKSLOCS
{
  PIBCB pBCB;  MASTER_BOOT_RECORD XDATA *pxMBR;  BYTE i;

  //   Allocate a buffer and read the master boot record.  Note that although
  // the VBS can move around, the MBR is ALWAYS in first sector on the disk!
  ALLOCATE_BUFFER(pBCB);
  if (pBCB == NULL) return 0L;
  //DBGOUT(("ReadMBR: reading master boot record from LBN 0\n"));
  if (!ReadSector(0L, pBCB->pbBuffer)) goto FAIL;
  pxMBR = (MASTER_BOOT_RECORD XDATA *) pBCB->pbBuffer;

  //  If the signature isn't valid, then this is neither a master boot record
  // nor a volume boot sector.  There isn't much we can do except give up!
  if (WSWAP(pxMBR->wSignature) != 0xAA55) goto FAIL;

  // Go thru all the partition table entries until we find one that's usable.
  for (i = 0;  i < MAX_PARTITIONS;  ++i) {
#ifdef SHOWPARTITION
    ShowPartition(i, pxMBR);
#endif
    //   Check the system type to see if this partition is a DOS FAT16 volume.
    // Unfortunately there are several types which are valid!
    if (   (pxMBR->aPartitions[i].bType != 0x04)   	// FAT16 for partitions <= 32Mb
        && (pxMBR->aPartitions[i].bType != 0x06)    	// FAT16 for partitions > 32Mb
        && (pxMBR->aPartitions[i].bType != 0x0E) ) 	// BIGDOS FAT16 partition
      continue;
    //   For the partition to be valid, the flags have to be either 0x00 (normal
    // partition) or 0x80 (a bootable partition).  The latter isn't likely, but

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -