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

📄 fat.c

📁 用ATmega8 做的MP3播放器
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * Copyright (c) 2003-2004 K. John '2B|!2B' Crispin
 * Copyright (c) 2005      Stephan Dobretsberger
 *
 * 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, MA02111-1307USA
 *
 * Feedback, Bugs, ... mail stephan.dobretsberger@gmx.at
 *
 */


#include "types.h"
#include "mmc.h"
#include "vs1001.h"
#include "spi.h"
#include "fat.h"

#include "test.h"

u08 fat_buf[FAT_RD_BUF_SIZE+1];

// starts by scanning the BPB
// sector needs to be equal to the first sector of the first partition
// use fat_get_part_start to get this value
//
// the first fat32 sector is set up as follows -->
//  u08   jmpboot[3]    0xEB 0x?? 0x90    -- instructions to jump to the boot loader
//  u08   OEMName[8]      -- identifies system that formatted the card
//  u08   BPB[42]         -- BIOS Parameter Block -- see below
//  .
//  .
//  .
//  u08   0xAA            -- signature
//  u08   0x55            -- signature
//
// fat32 BPB -->
//  u08 bytes_per_sec[2]  -- the size of a sector. for MMC this is always 512
//  u08 sec_per_clus      -- the number of sectrs per cluster. for MMC normally 1
//  u08 rsvd_sec[2]       -- reserved sectors for additional boot code. fat32 normally has 32 sectors
//  u08 num_fats          -- number of fat-chains on the disk ? leave at 2 to be sure
//  u08 root_dir_ent[2]   -- 0 for fat32. used by fat16
//  u08 tot_sec_16[2]     -- 0 for fat32. used by fat16
//  u08 media_type        -- used by OS to determine removeable, fixed ... used by msdos 1.x
//  u08 sec_per_fat[2]    -- 0 for fat32. used by fat16
//  u08 sec_per_track[2]  -- something for geometry ?
//  u08 num_heads[2]      -- number of heads.
//  u08 hidden_secs[4]    -- something for HW int 0x13
//  u08 tot_sec_32[4]     -- the number of sectors on this partition
//  u08 sec_per_fat_32[4] -- sectors per fat
//  u08 ext_flags[2]      -- extended partition ?
//  u08 fs_ver[2]         -- ?? something for fs
//  u08 root_clus[4]      -- offset to the sector that contains the root directory
//  u08 fs_inf[2]         -- ?? something for fs
//  u08 bpb_bak[2]        -- backup of bpb in reserved area of media



// defines for the offsets of the values in the bpb that we are interested in

#define FAT_OEM_START          3
#define FAT_OEM_STOP          10

#define FAT_BYTES_PER_SECTOR  11
#define FAT_SEC_PER_CLUS      13
#define FAT_RSVD_SEC_CNT      14
#define FAT_NUM_FATS          16
#define FAT_ROOT_ENT_CNT      17
#define FAT_TOTSEC            32
#define FAT_SIZE              36
#define FAT_ROOT_CLUS         44

// file attribs
#define FAT_READ_ONLY       0x01
#define FAT_HIDDEN          0x02
#define FAT_SYS             0x04
#define FAT_VOL_ID          0x08
#define FAT_DIRECTORY       0x10
#define FAT_ARCHIVE         0x20
#define FAT_LONG_NAME       0x0F

static u16 bytes_per_sec  = 0;
static u08 sec_per_clus   = 0;
static u16 rsvd_sec_cnt   = 0;
static u08 num_fats       = 0;
static u16 tot_sech       = 0;
static u16 tot_secl       = 0;
static u16 root_clush     = 0;
static u16 root_clusl     = 0;
static u16 fat_sizeh      = 0;
static u16 fat_sizel      = 0;

// our offsets
static u16 first_part_sector  = 0;
static u16 first_fat_sector   = 0;
static u16 first_data_sectorl = 0;

// name of our volume
static u08 volume_id[8];

// the directiory that gets used if no other is specified
static DIR directory;

#ifdef LFN_SUPPORT
static u08 lfn_tmp[(LFN_MAX_BLOCK*13)+1];
#endif

/* is build in
void strcpy(u08 *to, u08 *from)
{ while(*from)
  { *to = *from;
    to++;
    from++;
  }
};
*/



/*------------------ FAT LAYER --------------*/

// reads the mbr
// check for fat32 identifier
// finds the start of the first partition
u08 FAT_read_mbr(void)
{ // the number of bytes read
  u16 length = 0;
  u08 tmp;

  // start reading the mbr
  MMC_get_sec_start(0x00,0x00);
  // get the data
  while(length < 512)
  { length++;
    // get next byte
    tmp = MMC_get_sec_next();

    // partition type
    if(length == 451 && tmp != 0x0b)
      while(1); // stop if no FAT32

    // get the start sector of the first partition
    if(length == 455) first_part_sector = tmp;
    if(length == 456) first_part_sector += ((u16)tmp) << 8;
  };
  // stop reading from the mmc
  MMC_get_sec_stop();
  // FAB
  return FAT_OK;
};

// scans the BPB in the first(0x00) sector of the first partition
void FAT_read_first_part_sector(void)
{ // the number of bytes read
  u16 length = 0;

  // start reading from the mmc
  MMC_get_sec_start(0x00, first_part_sector);
  while(length < 512)
  { // get the next byte
    u08 tmp = MMC_get_sec_next();
    // read fat data
    switch(length)
    { case FAT_BYTES_PER_SECTOR:
        // get upper byte;
        bytes_per_sec = MMC_get_sec_next();
        length++;
        // assemble word
        bytes_per_sec = (bytes_per_sec << 8) + tmp;
        break;
      case FAT_SEC_PER_CLUS:
        sec_per_clus = tmp;
        break;
      case FAT_RSVD_SEC_CNT:
        // get upper byte;
        rsvd_sec_cnt = MMC_get_sec_next();
        length++;
        // assemble word
        rsvd_sec_cnt = (rsvd_sec_cnt << 8) + tmp;
        break;
      case FAT_NUM_FATS:
        num_fats = tmp;
        break;
      case FAT_TOTSEC:
        // get second byte;
        tot_secl = MMC_get_sec_next();
        length++;
        // assemble word
        tot_secl = (tot_secl << 8) + tmp;

        // get byte 3 and 4
        tmp = MMC_get_sec_next();
        length++;
        // get second byte;
        tot_sech = MMC_get_sec_next();
        length++;
        // assemble word
        tot_sech = (tot_sech << 8) + tmp;
        break;
      case FAT_SIZE:
        // get second byte;
        fat_sizel = MMC_get_sec_next();
        length++;
        // assemble word
        fat_sizel = (fat_sizel << 8) + tmp;

        // get byte 3 and 4
        tmp = MMC_get_sec_next();
        length++;
        // get second byte;
        fat_sizeh = MMC_get_sec_next();
        length++;
        // assemble word
        fat_sizeh = (fat_sizeh << 8) + tmp;
        break;
      case FAT_ROOT_CLUS:
        // get second byte;
        root_clusl = MMC_get_sec_next();
        length++;
        // assemble word
        root_clusl = (root_clusl << 8) + tmp;

        // get byte 3 and 4
        tmp = MMC_get_sec_next();
        length++;
        // get second byte;
        root_clush = MMC_get_sec_next();
        length++;
        // assemble word
        root_clush = (root_clush << 8) + tmp;
        break;
    };
    length++;
  };
  MMC_get_sec_stop();
};

// calc cluster to sectors
// by multiplying them with sec_per_clus
void cluster_to_sector(u16 *hiword, u16 *loword)
{ switch(sec_per_clus)
  { case 2:
      *hiword = ((*hiword)<<1) + ((*loword)>>15);
      *loword = ((*loword)<<1);
      return;
    case 4:
      *hiword = ((*hiword)<<2) + ((*loword)>>14);
      *loword = ((*loword)<<2);
      return;
    case 8:
      *hiword = ((*hiword)<<3) + ((*loword)>>13);
      *loword = ((*loword)<<3);
      return;
    case 16:
      *hiword = ((*hiword)<<4) + ((*loword)>>12);
      *loword = ((*loword)<<4);
      return;
    case 32:
      *hiword = ((*hiword)<<5) + ((*loword)>>11);
      *loword = ((*loword)<<5);
      return;
    case 64:
      *hiword = ((*hiword)<<6) + ((*loword)>>10);
      *loword = ((*loword)<<6);
      return;
    case 128:
      *hiword = ((*hiword)<<7) + ((*loword)>>9);
      *loword = ((*loword)<<7);
      return;
  }
}

// this function gets the addr in the data region for the next cluster of a file
void FAT_get_next_clus_addr(u16* clusterh, u16* clusterl)
{ // determine the sector that we need to read and which dword defines our  next cluster address
  u16 myh = *clusterh;
  u16 myl = *clusterl;
  u16 myoffset = *clusterl;

  // turn clusters into byte address
  myoffset = myoffset & 0x7f;
  myl = (myl >> 7) + ((myh & 0x7f) << 9);
  myh = myh >> 7;

  myl += first_fat_sector;
  if(myl < first_fat_sector) myh++;

  // get the data
  MMC_get_part_sec_start(myh, myl, myoffset << 2 ,4);
  *clusterl = MMC_get_sec_next();
  *clusterl += (MMC_get_sec_next() << 8);
  *clusterh = MMC_get_sec_next();
  *clusterh += (MMC_get_sec_next() << 8);

  // fine
  MMC_get_sec_stop();
};




void fat_init(void);

//
// 1.) reads the MBR
//     gets start sector of first partition
// 2.) verifies start sector
// 3.) get BPB
// 4.) find fat start
// 5.) start reading fat


void FAT_startup(void)
{ u08 i;

  // 1.) read MBR
  if(FAT_read_mbr() != FAT_OK)
  { // some error occured
    return;
  }

  // 2.) read BPB
  FAT_read_first_part_sector();

  // 3.) find fat start
  first_fat_sector = first_part_sector + rsvd_sec_cnt;
  first_data_sectorl = first_fat_sector + (num_fats * fat_sizel) - root_clusl*sec_per_clus;


  for(i=0; i<8; i++)
  { volume_id[i] = 'X';
  };

#ifdef LFN_SUPPORT
  for(i=0; i < (LFN_MAX_BLOCK*12)+1; i++)
  { lfn_tmp[i]=0x00;
  };
#endif

  fat_init();
  return;
};



/*------------------ FAT LAYER --------------*/



// compares a 11 byte block from the fat table with a 8 byte name and 3 byte extension.
// '*' is supported as a wildcard
bool fat_cmp_names(u08 *from_fat, u08 *name, u08 *extension)
{ u08 count = 0;
  for(;count < 8; count++)
  { if(name[count] == '*')
    { count = 100;
    }
    else
    { if(name[count] != from_fat[count])
        return false;
    };
  };

  if(extension)
  { for(count=0; count < 3; count++)
    { if(extension[count] =='*')
      { count = 100;
      }
      else
      { if(extension[count] != from_fat[8+count])
          return false;
      };
    };
  };
  return true;
};

// setup all the data needed by file i/o. gets called by FAT_startup
void fat_init(void)
{ directory.dir_currenth = root_clush;
  directory.dir_currentl = root_clusl;
};

// takes a 32 byte long fat entry and opens the file contained within
void fat_load_file_ptr(u08 *fat_entry, FILE *stream)
{ u08 i;
  stream->file_first_clusterl = (((u16)fat_entry[27])<<8) + (u16)fat_entry[26];
  stream->file_first_clusterh = (((u16)fat_entry[21])<<8) + (u16)fat_entry[20];

  stream->file_current_clusterl = stream->file_first_clusterl;
  stream->file_current_clusterh = stream->file_first_clusterh;
  stream->file_current_sector   = 0;

  stream->file_full_sizel = stream->file_sizel = (((u16)fat_entry[29])<<8) + fat_entry[28];
  stream->file_full_sizeh = stream->file_sizeh = (((u16)fat_entry[31])<<8) + fat_entry[30];

  stream->file_offset = 0x00;
  for(i=0; i<11; i++)
  { stream->name[i] = fat_entry[i];
  };

#ifdef LFN_SUPPORT
  stream->lfn_name[0] = 0x00;
  strcpy(stream->lfn_name, lfn_tmp);
#endif

};

// takes a 32 byte long fat entry and opens the dir contained within
void fat_load_dir_ptr(u08 *fat_entry, DIR *stream)
{ // get the dirposition
  stream->dir_currentl = (((u16)fat_entry[27])<<8) + fat_entry[26];
  stream->dir_currenth = (((u16)fat_entry[21])<<8) + fat_entry[20];

};


⌨️ 快捷键说明

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