FAT 协议 (驱动器格式)
 
本文概述了存储硬件协议。 FAT16 或 FAT 协议 最多可以 格式 化 2 GB 的存储器。
FAT 协议
在 FAT 协议 中,数据只是进行了分类,通过读取硬盘的开头就可以知道数据的地址。
使用 FAT 协议格式化的驱动器的起始位置是“跳转指令”。
跳转指令为0xeb3c90。
识别出这三个字节后,你几乎可以确定你已经进入了驱动器。 接下来的 8 个字节指定格式化驱动器的系统。
接下来的两个字节:16位,每个扇区的字节数。
下一个字节:8位,每簇的扇区数(sectors per cluster)。
接下来的两个字节:16 位,预取(保留)段
下一个字节:8位,文件分配表(fats)的数量
接下来的两个字节:16 位,内核(根)条目总数
下一个字节:16位,逻辑部分之和
下一个字节:8位,存储设备信息
接下来的两个字节:16 位,每个 fat 的逻辑段数
从地址0xb到0x1fe与偏差和操作系统有关,该数据量是可变的。
数据0x1fe=0x55和0x1ff=0xaa,称为数据旋转(移位)以进行同步。
每个簇的节数*每个节的字节数=格式化驱动器时输入的数字(分配单元大小),因此发现与驱动器外部的关系。
这里很清楚,任何数字数据的原始版本都不能以任何方式区分其副本。
你可以复制任何类型的数字数据,除非芯片不允许这样做,所以要复制这些受保护的数据,必须在先进的实验室中分割芯片并操纵其门,这几乎是不可能的。
* 字节 / byte
| | 该部门 / sector
( ) 簇 / cluster
( |**…*| |**…*| |**…*| )
大 多 数 格 式 中 的 扇 区 为 512 字 节。 下 面 的 程 序 从 存 储 卡 中 读 取 FAT16 或 FAT 格 式 文 件 的 基 本 信 息:
bool cTxos::bFileInit()
{
	if(!bSDMMCReceiveBlock(0x00000000))
	{
		strcpy(ucErrMsg,“File format 0“);
		return 0;
	}
	if(ucFileBlockData[0] != 0xeb
		|| ucFileBlockData[1] != 0x3c
		|| ucFileBlockData[2] != 0x90)//Jump instruction
	{
		strcpy(ucErrMsg,“File format J“);
		return 0;
	}
	usFileBPS = ucFileBlockData[11];
	usFileBPS |= ucFileBlockData[12] << 8;
	ucFileSPC = ucFileBlockData[13];
	usFileFRS = ucFileBlockData[14];
	usFileFRS |= ucFileBlockData[15] << 8;
	ucFileFAT = ucFileBlockData[16];
	usFileTRE = ucFileBlockData[17];
	usFileTRE |= ucFileBlockData[18] << 8;
	usFileSPF = ucFileBlockData[22];
	usFileSPF |= ucFileBlockData[23] << 8;
	if((ucFileSPC * usFileBPS) != 8192)//Block lengh
	{
		strcpy(ucErrMsg,“Block lengh is not 8192“);
		return 0;
	}
	ucFileMaxBlocksOfCals = (ucFileSPC * usFileBPS)/512;
	//root directory initialize
	if(!bOpenDir(0))
	{
		strcpy(ucErrMsg,“File format-Root dir“);
		return 0;
	}
	return 1;
}
bool cTxos::bOpenDir(unsigned short usCalusterNumber)
{
	unsigned int uiRamAddr;
	//root directory
	uiRamAddr = (usFileFRS+(usFileSPF * ucFileFAT))*usFileBPS;
	if(usCalusterNumber != 0)
		uiRamAddr += ((usCalusterNumber-2)*ucFileSPC*usFileBPS)+(usFileTRE*32);
	vDelayUS(10000);
	if(!bSDMMCReceiveBlock(uiRamAddr))
		return 0;
	for(usCalusterNumber=0; usCalusterNumber<512; usCalusterNumber++)
		ucFileDir[usCalusterNumber] = ucFileBlockData[usCalusterNumber];
	usFileEntryOffset = 0x0000; //First entry
	return 1;
}在 下 面 的 程 序 中,读 取 一 个 无 限 大 小 的 文 件; 每 次 填 满 256 个 存 储 单 元 后,都 会 重 新 从存 储 卡 的 开 头 读 取 数 据。
void cTxos::vReadDir()
{
	//File name 0x00
	ucFileName[0] = ucFileDir[usFileEntryOffset+0];//0x00:empty - 0xE5:deleted
	ucFileName[1] = ucFileDir[usFileEntryOffset+1];
	ucFileName[2] = ucFileDir[usFileEntryOffset+2];
	ucFileName[3] = ucFileDir[usFileEntryOffset+3];
	ucFileName[4] = ucFileDir[usFileEntryOffset+4];
	ucFileName[5] = ucFileDir[usFileEntryOffset+5];
	ucFileName[6] = ucFileDir[usFileEntryOffset+6];
	ucFileName[7] = ucFileDir[usFileEntryOffset+7];
	ucFileName[8] = '';
	//File type 0x08
	ucFileType[0] = ucFileDir[usFileEntryOffset+8];
	ucFileType[1] = ucFileDir[usFileEntryOffset+9];
	ucFileType[2] = ucFileDir[usFileEntryOffset+10];
	ucFileType[3] = '';
	//File first caluster 0x1A
	usFileOSR = ucFileDir[usFileEntryOffset+26];
	usFileOSR |= ucFileDir[usFileEntryOffset+27] << 8;
	usFileEntryOffset += 0x20; //Next entry
	//End of cache
	if(usFileEntryOffset == 0x200)
		usFileEntryOffset = 0x00; //First entry
}
bool cTxos::bOpenFile(unsigned short usCalusterNumber)
{
	unsigned short usX,
			usY,
			usFirstAddr = (usFileFRS*usFileBPS),
			usLastStart = usFirstAddr;
	vDelayUS(100);
	ucFileLastBlockOfCal = 0;
	ucFileLastCal = 0;
	usFileCalusters[0] = usCalusterNumber;
	usFileCalusters[255] = 0;
	usY = (usFileCalusters[0])*2;
	usFirstAddr = (usFileFRS*usFileBPS);
	usLastStart = usFirstAddr+(usY&0xfe00);
	if(!bSDMMCReceiveBlock(usLastStart))
		return 0;
	for(usX=0; usX<255;)
	{
		if(!((usFirstAddr+usY) >= usLastStart && (usFirstAddr+usY) < (usLastStart+512)))
		{ 
			usLastStart = usFirstAddr+(usY&0xfe00);
			if(!bSDMMCReceiveBlock(usLastStart))
				return 0;
		}
		usY = ucFileBlockData[(usY&0x01ff)]
			|(ucFileBlockData[(usY&0x01ff)+1]<<8);
		usX++;
		if(usY!=0xffff)
			usFileCalusters[usX] = usY;
		else
		{
			usFileCalusters[usX] = 0;
			break;
		}
		usY = (usFileCalusters[usX])*2;
	}
	return 1;
}
bool cTxos::bReadFile()
{ 
	vDelayUS(100);
	if(usFileCalusters[ucFileLastCal]==0)
		return 0;
	if(ucFileLastCal == 255)
		if(!bOpenFile(usFileCalusters[ucFileLastCal]))
			return 0;
	if(!bSDMMCReceiveBlock((( usFileFRS+(usFileSPF * ucFileFAT)+((usFileCalusters[ucFileLastCal]-2)*ucFileSPC) )*usFileBPS)+(usFileTRE*32)+(ucFileLastBlockOfCal*512)))
		return 0;
	if(ucFileLastBlockOfCal < ucFileMaxBlocksOfCals-1)
		ucFileLastBlockOfCal++;
	else
	{
		ucFileLastBlockOfCal = 0;
		ucFileLastCal++;
	}
	return 1;
}
void cTxos::vReadFileGoToAddr(unsigned int uiAddr)//512 bytes step - max 2MB offset from 0 in 8192 format
{
	ucFileLastCal = uiAddr/ucFileMaxBlocksOfCals;
	ucFileLastBlockOfCal = uiAddr%ucFileMaxBlocksOfCals;
}最 后 一 个 函 数 移 动 内 存 读 取 位 置 / 位 置,下 面 的 程 序 也 展 示 了 使 用 上 述 函 数 读 取 BMP-16bit-RGB-565 格 式 图 像 的 示 例:
bool cTxos::bDrawBMPFile(unsigned short usCalNumber)
{
	unsigned short usX;
	unsigned char ucY;
	if(!bOpenFile(usCalNumber))
		return 0;
	if(!bReadFile())
		return 0;
	if(ucFileBlockData[0]==0x42 && ucFileBlockData[1]==0x4d)
	{
		usCalNumber = ucFileBlockData[10]|(ucFileBlockData[11]<<8);
		for(ucY=240; ucY>0; )
		{
			ucY--;
			for(usX=0; usX<320;usX++)
			{
				if(usCalNumber == 512)
				{
					if(!bReadFile())
						return 0;
					usCalNumber = 0;
				}
				vPrintPixel(usX,ucY,ucFileBlockData[usCalNumber]|(ucFileBlockData[usCalNumber+1]<<8));
				usCalNumber+=2;
			}
		}
		return 1;
	}
	return 0;
}***“”电子、编程和 Arduino 项目,包括为工程师、学生和业余爱好者提供的源代码、原理图和 PCB 计划“”***

作者:M. Mahdi K. Kanan – 全栈电子和编程工程师、WiCardTech 创始人
