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

📄 cf_fat.c

📁 CF卡FAT for avr单片机 AVR atmega128 使用fat文件
💻 C
字号:
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include "CF_FAT.h"
#include "CF_IO.h"

uint8_t FS_Initialize(void)
{
	uint16_t w;
	uint32_t l;
	if(!(FS_BPB = (FS_TBPB *)malloc(sizeof(FS_TBPB))))
		return FS_ERR_NORAM;
	if(!(FS_FAT = (FS_TFAT *)malloc(sizeof(FS_TFAT))))
		return FS_ERR_NORAM;
	if(!(FS_RootDir = (FS_TFile *)malloc(sizeof(FS_TFile))))
		return FS_ERR_NORAM;
	if(!(FS_CurrentDir = (FS_TFile *)malloc(sizeof(FS_TFile))))
		return FS_ERR_NORAM;
	if(CF_Initialize())
		return FS_ERR_MEDIAERR;
	if(CF_LBAOpen(0))
		return FS_ERR_MEDIAERR;
	if(CF_LBAReadb() == 0xeb)		//If first byte is a instruction of JMP, it has no DPT.
		FS_BPB->StartLBA = 0;
	else
	{
		CF_LBASeek(0x1be);
		if(CF_LBAReadb() != 0x80)
		{
			CF_LBAClose();
			return FS_ERR_UNFORMAT;
		}
		CF_LBASeek(0x1c6);
		FS_BPB->StartLBA = CF_LBAReadl();
	}
	CF_LBAClose();
	CF_LBAOpen(FS_BPB->StartLBA);
	CF_LBASeek(0x00b);
	if(CF_LBAReadw() != 0x0200)
	{
		CF_LBAClose();
		return FS_ERR_UNKNOWNFAT;
	}
	FS_BPB->SectorsPerCluster = CF_LBAReadb();
	switch(FS_BPB->SectorsPerCluster)
	{
		case 1:
			FS_BPB->LShift = 0;
			break;
		case 2:
			FS_BPB->LShift = 1;
			break;
		case 4:
			FS_BPB->LShift = 2;
			break;
		case 8:
			FS_BPB->LShift = 3;
			break;
		case 16:
			FS_BPB->LShift = 4;
			break;
		case 32:
			FS_BPB->LShift = 5;
			break;
		case 64:
			FS_BPB->LShift = 6;
			break;
		case 128:
			FS_BPB->LShift = 7;
			break;
		default:
			CF_LBAClose();
			return FS_ERR_UNKNOWNFAT;
	}
	FS_BPB->Type = FS_TYPE_OTHER;
	FS_BPB->SectorsBeforeFAT = CF_LBAReadw();
	FS_BPB->FATs = CF_LBAReadb();
	FS_BPB->FAT16RootEntries = CF_LBAReadw();
	if(FS_BPB->FAT16RootEntries == 0)
		FS_BPB->Type = FS_TYPE_FAT32;
	w = CF_LBAReadw();
	if(w)
		FS_BPB->TotalSectors = w;
	CF_LBASeek(0x16);
	w = CF_LBAReadw();
	if(FS_BPB->Type != FS_TYPE_FAT32)
		FS_BPB->SectorsPerFAT = w;
	CF_LBASeek(0x20);
	l = CF_LBAReadl();
	if(l)
		FS_BPB->TotalSectors = l;
	if(FS_BPB->Type != FS_TYPE_FAT32)
	{
		if((FS_BPB->TotalSectors >> FS_BPB->LShift) < 4085)
			FS_BPB->Type = FS_TYPE_FAT12;
		else
			FS_BPB->Type = FS_TYPE_FAT16;
	}
	l = CF_LBAReadl();
	if(FS_BPB->Type == FS_TYPE_FAT32)
		FS_BPB->SectorsPerFAT = l;
	CF_LBASeek(0x2c);
	l = CF_LBAReadl();
	if(FS_BPB->Type == FS_TYPE_FAT32)
		FS_BPB->FAT32RootStartCluster = l;
	else
		FS_BPB->FAT32RootStartCluster = 0;
	FS_FAT->StartLBA = FS_BPB->StartLBA + FS_BPB->SectorsBeforeFAT;
	if(FS_BPB->Type == FS_TYPE_FAT32)
		FS_FAT->LShift = 2;
	else if(FS_BPB->Type == FS_TYPE_FAT16)
		FS_FAT->LShift = 1;
	else
		FS_FAT->LShift = 0;
	FS_CurrentDir->Attrib = FS_RootDir->Attrib = 0x10;
	FS_CurrentDir->StartCluster = FS_RootDir->StartCluster = FS_BPB->FAT32RootStartCluster;
	if(FS_BPB->Type == FS_TYPE_FAT32)
	{
		FS_FAT->DataStartLBA = FS_FAT->StartLBA + FS_BPB->FATs * FS_BPB->SectorsPerFAT;
		FS_CurrentDir->StartLBA = FS_RootDir->StartLBA = FS_FAT->DataStartLBA + ((FS_BPB->FAT32RootStartCluster - 2) << FS_BPB->LShift);
	}
	else
	{
		FS_CurrentDir->StartLBA = FS_RootDir->StartLBA = FS_FAT->StartLBA + FS_BPB->FATs * FS_BPB->SectorsPerFAT;
		FS_FAT->DataStartLBA = FS_RootDir->StartLBA + (FS_BPB->FAT16RootEntries >> 4);
	}
	FS_CurrentDir->Length = FS_RootDir->Length = 0;
	FS_CurrentDir->Offset = FS_RootDir->Offset = 0;
	CF_LBAClose();
	return FS_ERR_NOERR;
}

void FS_Destory(void)
{
	free(FS_BPB);
	free(FS_FAT);
	free(FS_RootDir);
	free(FS_CurrentDir);
}

uint32_t FS_GetNextCluster(uint32_t Cluster)
{
	uint8_t f1, f2;
	uint16_t cc;
	uint32_t c;
	if((FS_BPB->Type == FS_TYPE_FAT32) || (FS_BPB->Type == FS_TYPE_FAT16))	//FAT16 or FAT32
	{
		CF_LBAOpen(FS_FAT->StartLBA + (Cluster >> (9 - FS_FAT->LShift)));
		CF_LBASeek((Cluster & ((1 << (9 - FS_FAT->LShift)) - 1)) << FS_FAT->LShift);	// locate a FAT entry
		if(FS_BPB->Type == FS_TYPE_FAT32)		//FAT32
			c = CF_LBAReadl();
		else		//FAT16
			c = CF_LBAReadw();
	}
	else		//FAT12. It's more complicated. Because there are 1.5 bytes (12-bits) per FAT entry.
	{
		CF_LBAOpen(FS_FAT->StartLBA + ((Cluster + (Cluster << 1)) >> 10));	//multiply by 3, then divide by 1024
		cc = Cluster & 0b1111111111;
		if(cc < 342)
			CF_LBASeek(cc + (cc >> 1));	//multiply by 1.5 without using floating point
		else if(cc < 683)
			CF_LBASeek((cc - 342) + ((cc - 342) >> 1) + 1);
		else
			CF_LBASeek((cc - 682) + ((cc - 682) >> 1) - 1);
		if(((cc >> 1) << 1) == cc)
		{
			f1 = CF_LBAReadb();
			if(cc == 682)
				CF_LBAOpen(CF_CurrentLBA + 1);
			f2 = (CF_LBAReadb() & 0b00001111) << 4;
		}
		else
		{
			f1 = CF_LBAReadb() >> 4;
			if(cc == 341)
				CF_LBAOpen(CF_CurrentLBA + 1);
			f2 = CF_LBAReadb();
		}
		c = (((uint16_t)f2) << 4) + f1;
	}
	CF_LBAClose();
	return c;
}

uint8_t FS_SearchFile(char *FName, FS_TFile *R, uint8_t dir)
{
	uint8_t i = 0, j = 0, attr, s;
	uint16_t c, o;
	uint32_t LBA, Cluster;
	char Name[9], Ext[4];
	char dName[9], dExt[4];
	memset(Name, 0x20, 8);
	memset(Ext, 0x20, 3);
	while(FName[i])
		if(FName[i] == '.')
		{
			i ++;
			while(FName[i])
				Ext[j ++] = toupper(FName[i ++]);
		}
		else
		{
			Name[i] = toupper(FName[i]);
			i ++;
		}
	Name[8] = Ext[3] = 0;
	Cluster = FS_CurrentDir->StartCluster;
	LBA = FS_CurrentDir->StartLBA;
	while(1)
	{
		for(s = 0; s < FS_BPB->SectorsPerCluster; s ++, LBA ++)	//for each sector in a cluster
		{
			CF_LBAOpen(LBA);	//Open a sector of current directory
			for(o = 0; o < 512; o += 0x20)
			{
				CF_LBASeek(o);
				for(i = 0; i < 8; i ++)
					dName[i] = toupper(CF_LBAReadb());
				for(i = 0; i < 3; i ++)
					dExt[i] = toupper(CF_LBAReadb());
				attr = CF_LBAReadb();
				dName[8] = dExt[3] = 0;
				if(dName[0] == 0)
				{
					CF_LBAClose();
					return FS_ERR_NOTFOUND;
				}
				else if(dName[0] != 0xe5)
				{
					if((strcmp(Name, dName) == 0) && (strcmp(Ext, dExt) == 0) && ((attr & 0b00001000) == 0) && ((attr & 0b00010000) || (dir == 0)) )		//if bingo
					{
						R->Attrib = attr;
						CF_LBASeek(o + 0x14);
						c = CF_LBAReadw();
						CF_LBASeek(o + 0x1a);
						R->StartCluster = CF_LBAReadw();
						R->Length = CF_LBAReadl();
						if(FS_BPB->Type == FS_TYPE_FAT32)
							R->StartCluster += (uint32_t)c << 16;
						R->CurrentLBA = R->StartLBA = FS_FAT->DataStartLBA + ((R->StartCluster - 2) << FS_BPB->LShift);
						R->CurrentCluster = R->StartCluster;
						R->Offset = 0;
						CF_LBAClose();
						return FS_ERR_NOERR;
					}
				}
			}
		}
		if(Cluster != 0)	//Cluster==0 is for FAT16/FAT12, where the root directory is stored consecutively.
		{
			Cluster = FS_GetNextCluster(Cluster);
			if(	((FS_BPB->Type == FS_TYPE_FAT32) && (Cluster >= FS_FAT32_EOF)) ||
				((FS_BPB->Type == FS_TYPE_FAT16) && (Cluster >= FS_FAT16_EOF)) ||
				((FS_BPB->Type == FS_TYPE_FAT12) && (Cluster >= FS_FAT12_EOF)))	//if it is the last cluster
				return FS_ERR_NOTFOUND;
			LBA = FS_FAT->DataStartLBA + ((Cluster - 2) << FS_BPB->LShift);
		}
	}
}

uint8_t FS_ChangeDir(char *DirName)
{
	FS_TFile *D;
	if(strcmp(DirName, "\\") == 0)
	{
		FS_CurrentDir->Attrib = FS_RootDir->Attrib;
		FS_CurrentDir->StartCluster = FS_RootDir->StartCluster;
		FS_CurrentDir->StartLBA = FS_RootDir->StartLBA;
		FS_CurrentDir->Offset = FS_RootDir->Offset;
		FS_CurrentDir->Length = FS_RootDir->Length;
		return FS_ERR_NOERR;
	}
	D = (FS_TFile *)malloc(sizeof(FS_TFile));
	if(D == NULL)
		return FS_ERR_NORAM;
	if(FS_SearchFile(DirName, D, 1))
	{
		free(D);
		return FS_ERR_NOTFOUND;
	}
	else
	{
		FS_CurrentDir->Attrib = D->Attrib;
		FS_CurrentDir->StartCluster = D->StartCluster;
		FS_CurrentDir->StartLBA = D->StartLBA;
		FS_CurrentDir->Offset = D->Offset;
		FS_CurrentDir->Length = D->Length;
		free(D);
		return FS_ERR_NOERR;
	}
}

FS_TFile *FS_Open(char *FileName)
{
	FS_TFile *F;
	F = (FS_TFile *)malloc(sizeof(FS_TFile));
	if(F == NULL)
		return NULL;
	if(FS_SearchFile(FileName, F, 0))
	{
		free(F);
		return NULL;
	}
	else
		return F;
}

void FS_Close(FS_TFile *F)
{
	free(F);
}

uint8_t FS_Seek(FS_TFile *F, uint32_t off)
{
	uint32_t i;
	if(off >= F->Length)
		return FS_ERR_SEEKERR;
	else
	{
		if(off < F->Offset)
		{
			F->CurrentCluster = F->StartCluster;
			F->CurrentLBA = F->StartLBA;
			F->Offset = 0;
		}
		for(i = (F->Offset >> 9); i < (off >> 9); i ++)
		{
			F->CurrentLBA ++;
			if(((F->CurrentLBA - FS_FAT->DataStartLBA) & ((1 << FS_BPB->LShift) - 1)) == 0)
			{
				F->CurrentCluster = FS_GetNextCluster(F->CurrentCluster);
				F->CurrentLBA = FS_FAT->DataStartLBA + ((F->CurrentCluster - 2) << FS_BPB->LShift);
			}
		}
		F->Offset = off;
		return FS_ERR_NOERR;
	}
}

uint32_t FS_Read(FS_TFile *F, char *buf, uint32_t count)
{
	uint32_t i = 0;
	CF_LBAOpen(F->CurrentLBA);
	CF_LBASeek(F->Offset & 511);
	while(i < count)
	{
		*(buf ++) = CF_LBAReadb();
		i ++;
		if(FS_Seek(F, F->Offset + 1))
		{
			CF_LBAClose();
			return i;
		}
		if((F->Offset & 511) == 0)
			CF_LBAOpen(F->CurrentLBA);
	}
	CF_LBAClose();
	return i;
}

void FS_FastBlockRead(FS_TFile *F, char *buf, uint8_t sectors)
{
	F->Offset = ((F->Offset >> 9) << 9);
	while(sectors)
	{
		CF_LBAReadSector(F->CurrentLBA, 1, buf);
		buf += 512;
		FS_Seek(F, F->Offset + 512);
		sectors --;
	}
}

⌨️ 快捷键说明

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