📄 kw_fat32.c
字号:
/**************************************************************************************
Copyright (C), 1988-1999, Xi'an Keyway Control & Measurement Technology Co., Ltd
FileName: kw_nand.c
Description :nandflash 接口模块。
Version :1.0
Function List :
History: // 历史修改记录
<author> <time> <version > <desc>
LigangWang 07/08/08 1.0 build this moudle
*************************************************************************************/
#include "globals.h"
DWORD xdata FM_ptr_fats; // FAT区首地址
DWORD xdata FM_ptr_data; // 数据区首地址
DWORD xdata FM_ptr_root; // 目录区首地址
DWORD xdata FM_dirs_fat; // FAT中目录数
WORD xdata FM_sectors_fat; // 每个FAT区扇区数
BYTE xdata FM_num_fats; // FAT区数量
DWORD xdata FM_unuse_clus; // 未使用簇数量
BYTE xdata FM_sectors_clus; // 每簇扇区数
DWORD xdata FM_CurrentDirLBA; // 当前打开文件的目录LBA地址
DWORD xdata FM_CurrentFileLength; // 当前打开文件长度
Dir_tag xdata * FM_pCurrentDir; // 当前文件名所在目录表页中偏移
BYTE xdata FM_DataBuff1[MAX_RS232_BUFF]; // 数据缓冲区1 用于接收RS232数据
BYTE xdata FM_DataBuff2[MAX_RS232_BUFF]; // 数据缓冲区2 用于接收RS232数据
WORD xdata FM_DPointer1; // 数据缓冲区1 索引
WORD xdata FM_DPointer2; // 数据缓冲区2 索引
BYTE xdata FM_CurrentBuff; // 数据缓冲指示,用于标识当前缓冲区
BYTE xdata FM_FileName[12]; // 文件名,标识最后一个文件名
BYTE xdata FM_FileName_F[12]; // 文件名,标识第一个文件名
/*************************************************************************************
Function: FM_fat_install
Description: 安装FAT文件系统
Called By:
Input: N/A
Output: N/A
Return: 1:成功 0:失败
Others: 系统初始化时调用,仅调用一次,用于初始化FAT文件系统
读取系统参数、创建并打开数据文件
*************************************************************************************/
bit FM_fat_install (void)
{
NM_ReadPage(MBR_ADDRESS); //读取MBR信息
FM_ptr_fats = 0x01;
if ((EP6FIFOBUF[0] == 0xEB) && (EP6FIFOBUF[2] == 0x90)) //检查跳转标志
{
if ((EP6FIFOBUF[21] & 0xF0) == 0xF0) //检查媒体类型
{
if ((EP6FIFOBUF[510] == 0x55) && (EP6FIFOBUF[511] == 0xAA)) //检查结束标志
{
FM_ptr_fats = 0x00000000; //OK,FAT信息正确
}
else
{
return 0; //FAT信息错误
}
}
}
if (FM_ptr_fats) //FAT信息错误,返回
{
return 0;
}
//检查FAT16文件系统
FM_sectors_clus = EP6FIFOBUF[13]; //offset = 13: 每簇扇区数;
((BYTE*)&FM_ptr_fats)[3] = EP6FIFOBUF[14]; //offset = 14: LSB of reserved sector.;
((BYTE*)&FM_ptr_fats)[2] = EP6FIFOBUF[15]; //offset = 15: MSB of reserved sector.;
((BYTE*)&FM_ptr_fats)[1] = 0;
((BYTE*)&FM_ptr_fats)[0] = 0;
((BYTE*)&FM_sectors_fat)[1] = EP6FIFOBUF[22];
((BYTE*)&FM_sectors_fat)[0] = EP6FIFOBUF[23];
//获取根目录: root = reserved sectors + num of FATs * sectors per FAT
FM_num_fats = EP6FIFOBUF[16]; //offset 16: FAT区数量
FM_ptr_root = FM_ptr_fats + FM_num_fats * FM_sectors_fat;
((BYTE*)&FM_dirs_fat)[3] = EP6FIFOBUF[17]; //获取每FAT区目录数量
((BYTE*)&FM_dirs_fat)[2] = EP6FIFOBUF[18];
((BYTE*)&FM_dirs_fat)[1] = 0;
((BYTE*)&FM_dirs_fat)[0] = 0;
//获取数据区: data = FM_ptr_root +(32 * dir in FAT)/Byte per sector;
FM_ptr_data = FM_ptr_root + (32 * FM_dirs_fat) / 512;
FM_DPointer1 = FM_DPointer2 = 0;
FM_CurrentBuff = 0;
//FAT安装成功
FM_DeleteFileInRoot("KWSYSTEM.LOG");
if(CM_ReadConfigToParam() == 0) //读取配置参数
{
CM_SetConfigParameterDefault(); //如果配置参数错误则使用默认参数
}
if(CM_ConfigParameter.RTC_Valid == 1) //如果配置参数中RTC时间有效
{
RM_SetRTCTime(); //则设置RTC时间
}
FM_CreateNewFileName(); //创建新文件名称,保存于FM_FileName
FM_OpenFileInRoot(FM_FileName); //打开新文件
return 0;
}
/*************************************************************************************
Function: FM_GetFreeClu
Description: 用于从文件分配表中获取一个空簇
Called By:
Input: N/A
Output: N/A
Return: 空簇地址,0则表示没有空簇
Others: 找到空簇后,将该簇设置为0xFFFF,标识占用
*************************************************************************************/
WORD FM_GetFreeClu()
{
DWORD xdata i,j;
WORD xdata * pTmp;
WORD xdata FreeClu = 0;
for(i = 0; i < FM_sectors_fat; i++) //读取所有文件分配区
{
NM_ReadPage(FM_ptr_fats + i); //读取一个扇区
pTmp = (WORD * )(&EP6FIFOBUF[0]); //从扇区开始地址查找
for(j=0;j<512/2;j++) //扇区512字节,簇地址为Word型
{
if(*pTmp == 0x0000) //找到空簇,设置占有标志,并回写
{
*pTmp = 0xffff;
NM_WritePages(FM_ptr_fats + i);
return FreeClu;
}
FreeClu += 1; //簇地址递增
pTmp++; //下一簇号
}
}
return 0;
}
/*************************************************************************************
Function: FM_OpenFileInRoot
Description: 打开根目录一个文件,若文件不存在则创建
Called By:
Input: sFileName @ char *: 文件名
Output: N/A
Return: 文件目录指针,NULL则创建(打开)失败
Others:
*************************************************************************************/
Dir_tag * FM_OpenFileInRoot(char * sFileName)
{
WORD xdata i,j,StartClu;
DWORD xdata tmpLBA = 0;
Dir_tag xdata * pDir = 0;
FM_pCurrentDir = 0;
for(i=0; i<((32 * FM_dirs_fat) / 512); i++)
{
NM_ReadPage(FM_ptr_root + i); //读取目录表
pDir = ((Dir_tag * ) (& EP6FIFOBUF[0])); //指向第一个目录
for(j=0;j<16;j++) //每扇区有16个目录
{
if(pDir->FileName[0] == 0x00 //跳过空项及以删除项
|| pDir->FileName[0] == 0xe5)
{
if(FM_pCurrentDir == 0) //如果当前文件为空则记录该项的偏移及LBA
{ //后面创建文件要用到。
FM_pCurrentDir = pDir;
tmpLBA = FM_ptr_root + i;
}
pDir ++;
continue;
}
if(pDir->attribute & 0x18) //如果时目录则跳过
{
pDir ++;
continue;
}
//比较文件名是否相同,这个代码要修改
if( sFileName[0] == pDir->FileName[0] && sFileName[1] == pDir->FileName[1]
&& sFileName[2] == pDir->FileName[2] && sFileName[3] == pDir->FileName[3]
&& sFileName[4] == pDir->FileName[4] && sFileName[5] == pDir->FileName[5]
&& sFileName[6] == pDir->FileName[6] && sFileName[7] == pDir->FileName[7]
&& pDir->ExtName[0] == sFileName[9] && pDir->ExtName[1] == sFileName[10]
&& pDir->ExtName[2] == sFileName[11])
{
FM_CurrentDirLBA = FM_ptr_root + i;
FM_pCurrentDir = pDir;
return pDir; //文件找到,返回目录项
}
pDir ++;
}
}
//当文件无法找到,即文件不存在,则创建
if(tmpLBA != 0) //LBA地址不为0说明前面找到了一个空目录项
{
StartClu = FM_GetFreeClu(); //分配一个空簇
while(StartClu == 0 || StartClu > 0xf900)
{
FM_DeleteFirstFile(); //若无法分配空簇则删除文件
StartClu = FM_GetFreeClu();
}
FM_CurrentDirLBA = tmpLBA; //保存扇区 LBA地址
NM_ReadPage(FM_CurrentDirLBA); //打开目录项所在LBA扇区
for(i=0;i<8;i++) //复制文件名
FM_pCurrentDir->FileName[i] = sFileName[i];
FM_pCurrentDir->ExtName[0] = sFileName[9]; //扩展名
FM_pCurrentDir->ExtName[1] = sFileName[10];
FM_pCurrentDir->ExtName[2] = sFileName[11];
FM_pCurrentDir->StartClus[0] = StartClu & 0xff; //设置起始簇地址
FM_pCurrentDir->StartClus[1] = (StartClu >>8 )& 0xff;
FM_pCurrentDir->FileLength[0] = 0; //设置新文件长度为0
FM_pCurrentDir->FileLength[1] = 0;
FM_pCurrentDir->FileLength[2] = 0;
FM_pCurrentDir->FileLength[3] = 0;
FM_pCurrentDir->attribute = 0; //设置文件属性
RM_ReadRTCTime(); //获取RTC时间
i = RM_GetTimeForFAT();
FM_pCurrentDir->time[0] = i&0xff; //设置文件时间
FM_pCurrentDir->time[1] = (i>>8)&0xff;
i = RM_GetDateForFAT();
FM_pCurrentDir->date[0] = i&0xff; //设置文件日期
FM_pCurrentDir->date[1] = (i>>8)&0xff;
NM_WritePages(FM_CurrentDirLBA); //写文件到目录项中
return FM_pCurrentDir;
}
return 0;
}
/*************************************************************************************
Function: FM_GetNextClus
Description: 获取指定簇的下一簇
Called By:
Input: c @ WORD: 当前簇
Output: N/A
Return: 下簇地址
Others:
*************************************************************************************/
WORD FM_GetNextClus(WORD c)
{
WORD xdata * pTmp;
NM_ReadPage(FM_ptr_fats+((c>>8)&0xff)); //计算当前簇LBA地址并读取
pTmp = (WORD *)EP6FIFOBUF; //获取簇号
return (pTmp[c&0xff]>>8 & 0xff) | (pTmp[c&0xff]<<8 & 0xff00); //自己排列
}
/*************************************************************************************
Function: FM_GetFormatedSize
Description: 计算剩余容量,簇数量
Called By:
Input: N/A
Output: N/A
Return: void
Others: 该函数不使用
*************************************************************************************/
/*
void FM_GetFormatedSize()
{
DWORD xdata i,j;
WORD xdata * pTmp;
FM_unuse_clus = 0;
for(i = 0; i < FM_sectors_fat; i++)
{
NM_ReadPage(FM_ptr_fats + i);
pTmp = (WORD * )(&EP6FIFOBUF[0]);
for(j=0;j<512/2;j++)
{
if(*pTmp == 0x0000)
FM_unuse_clus++;
pTmp++;
}
}
}
*/
/*************************************************************************************
Function: FM_DeleteCluLink
Description: 删除簇链,用于删除文件
Called By:
Input: nStart@Word:簇链起始号
Output: N/A
Return: void
Others: 无意义
*************************************************************************************/
bit FM_DeleteCluLink(WORD nStart)
{
WORD xdata nTmp;
WORD xdata * pBuffStart = (WORD *)EP6FIFOBUF;
NM_ReadPage(FM_ptr_fats+((nStart>>8)&0xff)); //获取首簇LBA,并读取
while(nStart != 0xffff) //直到簇链结束
{
if(pBuffStart[nStart & 0xff] == 0xffff) //若下簇为簇链尾
{
pBuffStart[nStart & 0xff] = 0x0000; //置空
NM_WritePages(FM_ptr_fats+((nStart>>8)&0xff)); //回写
return 1;
}
else
{
//如果当前簇和下一簇都在同一扇区,则直接置空当前簇
if(((nStart >> 8)&0xff) == (pBuffStart[nStart&0xff] & 0xff))
{
nTmp = (pBuffStart[nStart&0xff]>>8 & 0xff) | (pBuffStart[nStart&0xff]<<8 & 0xff00);
pBuffStart[nStart&0xff] = 0x0000;
nStart = nTmp;
}
//否则,置空当前簇,并读取下簇LBA扇区
else
{
nTmp = (pBuffStart[nStart&0xff]>>8 & 0xff) | (pBuffStart[nStart&0xff]<<8 & 0xff00);
pBuffStart[nStart&0xff] = 0x0000;
NM_WritePages(FM_ptr_fats+((nStart>>8)&0xff));
nStart = nTmp;
NM_ReadPage(FM_ptr_fats+((nStart>>8)&0xff));
}
}
}
}
/*************************************************************************************
Function: FM_DeleteFileInRoot
Description: 删除根目录文件
Called By:
Input: sFileName@BYTE*:文件名
Output: N/A
Return: 1:成功,0:失败
Others: 无意义
*************************************************************************************/
bit FM_DeleteFileInRoot(BYTE * sFileName)
{
DWORD xdata i,j;
Dir_tag xdata * pDir;
//首先找到文件,具体可参考打开文件代码
for(i=0; i<((32 * FM_dirs_fat) / 512); i++)
{
NM_ReadPage(FM_ptr_root + i);
pDir = ((Dir_tag * ) (& EP6FIFOBUF[0]));
for(j=0;j<16;j++)
{
if(pDir->FileName[0] == 0x00 || pDir->FileName[0] == 0xe5) //FileName[0]
{
pDir ++;
continue;
}
if(pDir->attribute & 0x18)
{
pDir ++;
continue;
}
if( sFileName[0] == pDir->FileName[0] && sFileName[1] == pDir->FileName[1]
&& sFileName[2] == pDir->FileName[2] && sFileName[3] == pDir->FileName[3]
&& sFileName[4] == pDir->FileName[4] && sFileName[5] == pDir->FileName[5]
&& sFileName[6] == pDir->FileName[6] && sFileName[7] == pDir->FileName[7]
&& sFileName[9] == pDir->ExtName[0] && sFileName[10] == pDir->ExtName[1]
&& sFileName[11] == pDir->ExtName[2] )
{
//文件被找到
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -