📄 znfat.c
字号:
#include "znfat.h"
#include "sd.h" //存储设备的扇区读写驱动,这里是SD卡
//#include "ch375.h" //存储设备的扇区读写驱动,这里是U盘
//#include "cf.h"
#include "string.h"
/*******************************************************
+-----------------------------------------+
|振南电子 原创程序模块 znFAT文件系统 5.18 |
+-----------------------------------------+
此源码版权属 振南 全权享有,如欲引用,敬请署名并告知
严禁随意用于商业目的,违者必究,后果自负
振南电子
->产品网站 http://www.znmcu.cn/
->产品网店 http://shop.znmcu.cn/
->产品咨询 QQ:987582714
MSN:yzn07@126.com
WW:yzn07
说明:znFAT经多方测试,确保其正确性与稳定性,请放心使用,
如有bug敬请告知,谢谢!!
********************************************************/
//全局变量定义
struct direntry temp_rec;
INT8 temp_dir_name[13];
UINT32 temp_dir_cluster;
UINT32 temp_last_cluster;
UINT8 xdata znFAT_Buffer[512]; //扇区数据读写缓冲区,由外部提供
/******************************************************************
- 功能描述:znFAT的存储设备初始化函数
- 隶属模块:znFAT文件系统模块
- 函数属性:外部(用于对存储设备进行初始化)
- 参数说明:无
- 返回说明:无
- 注:在调znFAT其它函数之前,必须先对存储设备进行成功的初始化。
******************************************************************/
void znFAT_Device_Init()
{
SD_Reset();
SD_Init();
}
/******************************************************************
- 功能描述:znFAT的存储设备底层驱动接口,读取存储设备的addr扇区的
512个字节的数据放入buf数据缓冲区中
- 隶属模块:znFAT文件系统模块
- 函数属性:内部(用于与存储设备的底层驱动对接)
- 参数说明:addr:扇区地址
buf:指向数据缓冲区的指针
- 返回说明:0表示读取扇区成功,否则失败
- 注:这里加入了天狼星精华板上的三种存储设备,即SD卡(有效)、U盘、
CF卡通过在程序中动态的切换不同的设备驱动,从而实现多设备(即同
时对多种存储设备进行操作,比如从SD卡拷贝文件到U盘等等),不同
驱动的切换,只需要在程序中改变Dev_No这个全局变量的值即可
******************************************************************/
UINT8 znFAT_ReadSector(UINT32 addr,UINT8 *buf)
{
switch(Dev_No) //由Dev_No来决定所使用的存储设备驱动
{
case SDCARD:
return SD_Read_Sector(addr,buf);
break;
case UDISK:
//return CH375_Read_Sector(addr,buf);
break;
case CFCARD:
//return CF_Read_Sector(addr,buf);
break;
case OTHER:
//return XXX_Read_Sector(addr,buf);
break;
}
}
/******************************************************************
- 功能描述:znFAT的存储设备底层驱动接口,将buf数据缓冲区中的512个
字节的数据写入到存储设备的addr扇区中
- 隶属模块:znFAT文件系统模块
- 函数属性:内部(用于与存储设备的底层驱动对接)
- 参数说明:addr:扇区地址
buf:指向数据缓冲区
- 返回说明:0表示读取扇区成功,否则失败
- 注:略
******************************************************************/
UINT8 znFAT_WriteSector(UINT32 addr,UINT8 *buf)
{
switch(Dev_No) //由Dev_No来决定所使用的存储设备驱动
{
case SDCARD:
return SD_Write_Sector(addr,buf);
break;
case UDISK:
//return CH375_Write_Sector(addr,buf);
break;
case CFCARD:
//return CF_WriteSector(addr,buf);
break;
case OTHER:
//return XXX_Write_Sector(addr,buf);
break;
}
}
/******************************************************************
- 功能描述:小端转大端,即LittleEndian车BigEndian
- 隶属模块:znFAT文件系统模块
- 函数属性:内部
- 参数说明:dat:指向要转为大端的字节序列
len:要转为大端的字节序列长度
- 返回说明:转为大端模式后,字节序列所表达的数据
- 注:比如:小端模式的 0x33 0x22 0x11 0x00 (低字节在前)
转为大端模式后为 0x00 0x11 0x22 0x33 (高字节在前)
所表达的数值为 0x00112233
(CISC的CPU通常是小端的,所以znFAT也设计为小端,而单片机
这种RISC的CPU,通常来说都是大端的,所以需要这个函数将字
节的存放次序进行调整,才能得到正确的数值)
******************************************************************/
UINT32 LE2BE(UINT8 *dat,UINT8 len)
{
UINT32 temp=0;
UINT32 fact=1;
UINT8 i=0;
for(i=0;i<len;i++)
{
temp+=dat[i]*fact; //将各字节乘以相应的权值后累加
fact*=256; //更新权值
}
return temp;
}
//-----------------------------------
/**************************************************************************
- 功能描述:清空某个簇的所有扇区,填充0
- 隶属模块:znFAT文件系统模块
- 函数属性:内部
- 参数说明:cluster:要清空的簇的簇号
- 返回说明:无
**************************************************************************/
#ifdef ZNFAT_EMPTY_CLUSTER
void znFAT_Empty_Cluster(UINT32 Cluster)
{
UINT32 iSec;
UINT16 i;
for(i=0;i<pArg->BytesPerSector;i++)
{
znFAT_Buffer[i]=0;
}
for(iSec=SOC(Cluster);iSec<SOC(Cluster)+pArg->SectorsPerClust;iSec++)
{
znFAT_WriteSector(iSec,znFAT_Buffer);
}
}
#endif
/***********************************************************************
- 功能描述:获取剩余容量
- 隶属模块:znFAT文件系统模块
- 函数属性:外部,使用户使用
- 参数说明:无
- 返回说明:剩余容量,单位字节
- 注:从FSInfo中读取空闲簇数,而从计算得到剩余的容量,单位字节
***********************************************************************/
#ifdef znFAT_GET_REMAIN_CAP
UINT32 znFAT_Get_Remain_Cap(void)
{
znFAT_ReadSector(1+pArg->BPB_Sector_No,znFAT_Buffer);
if(((struct FSInfo *)znFAT_Buffer)->Free_Cluster[0]==0xff
&& ((struct FSInfo *)znFAT_Buffer)->Free_Cluster[1]==0xff
&& ((struct FSInfo *)znFAT_Buffer)->Free_Cluster[2]==0xff
&& ((struct FSInfo *)znFAT_Buffer)->Free_Cluster[3]==0xff)
return pArg->Total_Size;
else
return LE2BE(((struct FSInfo *)znFAT_Buffer)->Free_Cluster,4)*pArg->SectorsPerClust*pArg->BytesPerSector;
}
#endif
//--------------------------------------------
/******************************************************************
- 功能描述:将小字字符转为大写
- 隶属模块:znFAT文件系统模块
- 函数属性:内部
- 参数说明:c:要转换为大写的字符
- 返回说明:要转换的字节的相应的大写字符
- 注:只对小写字符有效,如果不是a~z的小写字符,将直接返回
******************************************************************/
INT8 L2U(INT8 c)
{
if(c>='a' && c<='z') return c+'A'-'a';
else return c;
}
/***********************************************************************
- 功能描述:得到DBR所在的扇区号(如果没有MBR,则DBR就在0扇区)
- 隶属模块:znFAT文件系统模块
- 函数属性:内部
- 参数说明:无
- 返回说明:DBR的扇区地址
- 注:DBR中包含了很多有用的参数信息,因此正确定位DBR扇区的位置,是极为
重要的,后面将有专门的函数对DBR进行解析,正确解析DBR是实现znFAT的
基础
***********************************************************************/
UINT16 znFAT_Find_DBR(void)
{
UINT16 sec_dbr;
znFAT_ReadSector(0,znFAT_Buffer);
if(znFAT_Buffer[0]!=0xeb)
{
sec_dbr=LE2BE(((((struct PartSector *)(znFAT_Buffer))->Part[0]).StartLBA),4);
}
else
{
sec_dbr=0;
}
return sec_dbr;
}
/***********************************************************************
- 功能描述:获取分区的总容量
- 隶属模块:znFAT文件系统模块
- 函数属性:外部,使用户使用
- 参数说明:无
- 返回说明:分区容量值,单位为字节
- 注:这里得到的总容量是znFAT分区的容量,一定小于实际的物理容量
***********************************************************************/
#ifdef ZNFAT_GET_TOTAL_SIZE
UINT32 znFAT_Get_Total_Size(void)
{
return pArg->Total_Size;
}
#endif
/***********************************************************************
- 功能描述:读取FSInfo获取最近的一个可用空闲簇
- 隶属模块:znFAT文件系统模块
- 函数属性:内部
- 参数说明:无
- 返回说明:最近的一个可用空闲簇
- 注:znFAT中的FSInfo扇区(绝对1扇区)中记录了最近的一个可用空闲簇
***********************************************************************/
UINT32 Search_Last_Usable_Cluster(void)
{
znFAT_ReadSector(1+pArg->BPB_Sector_No,znFAT_Buffer);
return LE2BE(((struct FSInfo *)znFAT_Buffer)->Last_Cluster,4);
}
/***********************************************************************
- 功能描述:znFAT文件系统初始化
- 隶属模块:znFAT文件系统模块
- 函数属性:外部,使用户使用
- 参数说明:znFAT_Init_Arg类型的结构体指针,用于装载一些重要的参数信息,
以备后面使用
- 返回说明:无
- 注:在使用znFAT前,这个函数是必须先被调用的,将很多参数信息装入到
arg指向的结构体中,比如扇区大小、根目录的位置、FAT表大小等等。
这些参数绝大部分是来自于DBR的BPB中,因此此函数主要在作对DBR的参数解析
***********************************************************************/
void znFAT_Init(void)
{
struct znFAT_BPB *bpb;
bpb=(struct znFAT_BPB *)(znFAT_Buffer); //将数据缓冲区指针转为struct znFAT_BPB 型指针
pArg->DEV_No=Dev_No; //装入设备号
pArg->BPB_Sector_No =znFAT_Find_DBR(); //znFAT_FindBPB()可以返回BPB所在的扇区号
znFAT_ReadSector(pArg->BPB_Sector_No,znFAT_Buffer);
pArg->FATsectors =LE2BE((bpb->BPB_FATSz32) ,4);//装入FAT表占用的扇区数到FATsectors中
pArg->FirstDirClust =LE2BE((bpb->BPB_RootClus) ,4);//装入根目录簇号到FirstDirClust中
pArg->BytesPerSector =LE2BE((bpb->BPB_BytesPerSec),2);//装入每扇区字节数到BytesPerSector中
pArg->SectorsPerClust =LE2BE((bpb->BPB_SecPerClus) ,1);//装入每簇扇区数到SectorsPerClust 中
pArg->FirstFATSector =LE2BE((bpb->BPB_RsvdSecCnt) ,2)+pArg->BPB_Sector_No;//装入第一个FAT表扇区号到FirstFATSector 中
pArg->FirstDirSector =(pArg->FirstFATSector)+(bpb->BPB_NumFATs[0])*(pArg->FATsectors); //装入第一个目录扇区到FirstDirSector中
pArg->Total_Size =LE2BE((bpb->BPB_TotSec32),4)*pArg->BytesPerSector; //磁盘的总容量,单位是字节
temp_last_cluster=Search_Last_Usable_Cluster();
}
/***********************************************************************
- 功能描述:更新FSInfo中的可用空闲簇的数量
- 隶属模块:znFAT文件系统模块
- 函数属性:内部
- 参数说明:PlusOrMinus:可用空闲簇数加1或减1
- 返回说明:无
- 注:创建文件、追加数据、删除文件等操作都可能会使可用的空闲簇数变化
要及时更新
***********************************************************************/
#ifdef ZNFAT_UPDATE_FSINFO_FREE_CLU
void znFAT_Update_FSInfo_Free_Clu(UINT32 PlusOrMinus)
{
UINT32 Free_Clu=0;
znFAT_ReadSector(1+pArg->BPB_Sector_No,znFAT_Buffer);
Free_Clu=(znFAT_Get_Remain_Cap())/(pArg->SectorsPerClust*pArg->BytesPerSector);
if(PlusOrMinus) Free_Clu++;
else Free_Clu--;
((struct FSInfo *)znFAT_Buffer)->Free_Cluster[0]=Free_Clu&0x000000ff;//((UINT8 *)&Free_Clu)[0];
((struct FSInfo *)znFAT_Buffer)->Free_Cluster[1]=(Free_Clu&0x0000ff00)>>8;//((UINT8 *)&Free_Clu)[1];
((struct FSInfo *)znFAT_Buffer)->Free_Cluster[2]=(Free_Clu&0x00ff0000)>>16;//((UINT8 *)&Free_Clu)[2];
((struct FSInfo *)znFAT_Buffer)->Free_Cluster[3]=(Free_Clu&0xff000000)>>24;//((UINT8 *)&Free_Clu)[3];
znFAT_WriteSector(1+pArg->BPB_Sector_No,znFAT_Buffer);
}
#endif
/***********************************************************************
- 功能描述:更新FSInfo中的下一个可用空闲簇的簇号
- 隶属模块:znFAT文件系统模块
- 函数属性:内部
- 参数说明:Last_Clu:将要更新到FSInfo中的下一个可用空闲簇的簇号
- 返回说明:无
- 注:FSInfo中的下一个可用空闲簇号可以给文件系统一个参考,直接告诉文件系统
下一个可用的空闲簇在什么地方
***********************************************************************/
#ifdef ZNFAT_UPDATE_FSINFO_LAST_CLU
void znFAT_Update_FSInfo_Last_Clu(UINT32 Last_Clu)
{
znFAT_ReadSector(1+pArg->BPB_Sector_No,znFAT_Buffer);
((struct FSInfo *)znFAT_Buffer)->Last_Cluster[0]=Last_Clu&0x000000ff;//((UINT8 *)&Last_Clu)[0];
((struct FSInfo *)znFAT_Buffer)->Last_Cluster[1]=(Last_Clu&0x0000ff00)>>8;//((UINT8 *)&Last_Clu)[1];
((struct FSInfo *)znFAT_Buffer)->Last_Cluster[2]=(Last_Clu&0x00ff0000)>>16;//((UINT8 *)&Last_Clu)[2];
((struct FSInfo *)znFAT_Buffer)->Last_Cluster[3]=(Last_Clu&0xff000000)>>24;//((UINT8 *)&Last_Clu)[3];
znFAT_WriteSector(1+pArg->BPB_Sector_No,znFAT_Buffer);
}
#endif
/***********************************************************************
- 功能描述:获得下一个簇的簇号
- 隶属模块:znFAT文件系统模块
- 函数属性:内部
- 参数说明:LastCluster:基准簇号
- 返回说明:LastClutster的下一簇的簇号
- 注:获得下一簇的簇号,就是凭借FAT表中所记录的簇链关系来实现的
***********************************************************************/
#ifdef ZNFAT_GETNEXTCLUSTER
UINT32 znFAT_GetNextCluster(UINT32 LastCluster)
{
UINT32 temp;
struct znFAT_FAT *pFAT;
struct znFAT_FAT_Item *pFAT_Item;
temp=((LastCluster/128)+pArg->FirstFATSector);
znFAT_ReadSector(temp,znFAT_Buffer);
pFAT=(struct znFAT_FAT *)znFAT_Buffer;
pFAT_Item=&((pFAT->Items)[LastCluster%128]);
return LE2BE((UINT8 *)pFAT_Item,4);
}
#endif
/***********************************************************************
- 功能描述:比较目录名
- 隶属模块:znFAT文件系统模块
- 函数属性:内部
- 参数说明:a:指向目录名1的指针
b:指向目录名2的指针
- 返回说明:如果两个目录名相同就返回1,否则为0
***********************************************************************/
#ifdef COMPARE_DIR_NAME
UINT8 Compare_Dir_Name(CONST INT8 *a,CONST INT8 *b)
{
UINT8 i;
for(i=0;i<8;i++)
{
if(a[i]!=b[i]) return 0;
}
return 1;
}
#endif
/***********************************************************************
- 功能描述:文件名匹配(支持带*?通配符的文件名的匹配)
- 隶属模块:znFAT文件系统模块
- 函数属性:内部
- 参数说明:pat:源文件名,可以含*或?通配符 如 *.txt 或 A?.mp3等等
name:目标文件名
- 返回说明:如果两个文件名匹配就返回1,否则为0
- 注:关于通配文件名匹配,有这样的例子,比如 A*.txt 与 ABC.txt是匹配的
同时与 ABCDE.txt也是匹配的。此功能在文件枚举中将会用到,用来匹配
文件名符合一定条件的文件
***********************************************************************/
#ifdef FILENAMEMATCH
UINT8 FilenameMatch(INT8 *pat,INT8 *name)
{
UINT8 match,ndone;
INT8 *cpp,*cpn;
cpp=pat;
cpn=name;
match=1;
ndone=1;
while(ndone)
{
switch (*cpp)
{
case '*':
cpp++;
cpn=strchr(cpn,*cpp);
if(cpn==NULL)
{
cpn=name;
while(*cpn) cpn++;
}
break;
case '?':
cpp++;
cpn++;
break;
case 0:
if(*cpn!=0)
match=0;
ndone=0;
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -