FAT protocol (drive format)
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;
}
Written by: M. Mahdi K. Kanan – Full stack electronics and programming engineer and the founder of WiCardTech