FAT protocol (drive format)

Electronics and Programming tutorials and projects

FAT protocol (drive format)

fat16 protocol FAT 协议

This article provides an overview of a storage hardware protocols. FAT16 or FAT protocol can format memories up to two gigabytes.

FAT protocol

In the FAT protocol, data is categorized only, and by reading the beginning of the hard disk, you can know the address of the data.

The starting location of a drive which is formatted with the FAT protocol, is a “jump instruction”.

The jump instruction is 0xeb3c90.

After identifying these three bytes, you can almost be sure that you have entered the drive. The next 8 bytes specify the system that formatted the drive.

Next two bytes: 16 bits, the number of bytes in each sector.

Next byte: 8 bits, the number of sectors per cluster (sectors per cluster).

Next two bytes: 16 bits, prefetched (reserved) segments

Next byte: 8 bits, the number of file allocation tables (fats)

Next two bytes: 16 bits, the total kernel (root) entries

Next byte: 16 bits, the sum of logical parts

Next byte: 8 bits, storage device information

Next two bytes: 16 bits, the logical number of segments per fat

From address 0xb to 0x1fe is related to bias and operating system, the volume of this data is variable.

Data 0x1fe=0x55 and 0x1ff=0xaa, which is called data rotation (shift) for synchronization.

Sections of each cluster * bytes of each section = the number you enter when formatting the drive (Allocation unit size), so a relationship with the outside of the drive was found.

It will be clear here that the original of any digital data cannot be distinguished from its copy in any way.

You can copy any type of digital data, unless the chip does not allow this, so to copy these kind of protected date, the chip must be split in advanced laboratories and its gates manipulated which is almost impossible.

* byte

| | the sector

( ) cluster

( |**…*| |**…*| |**…*| )

Sectors are 512 bytes in most of the formats. The following program reads the basic information of the FAT16 or FAT format file from the memory card:

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;
}

And with in the following program, a file with unlimited size is read; After each time the 256 memory cells will be filled, the data is read from the beginning of the memory card again.

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;
}

The last function moves the memory reading position/location, the following program also shows an example of using the above functions to read images in BMP-16bit-RGB-565 format:

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;
}

***””Electronics, Programming and Arduino projects, including the source codes, schematics and PCB plans for engineers, student and hobbyists””***

 

Leave a Reply

Your email address will not be published. Required fields are marked *

11 + 5 =