355 lines
10 KiB
C
355 lines
10 KiB
C
#include "string.h"
|
||
#include "exfuns.h"
|
||
#include "malloc.h"
|
||
#include "usart.h"
|
||
//////////////////////////////////////////////////////////////////////////////////
|
||
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
|
||
//ALIENTEK STM32开发板
|
||
//FATFS 扩展代码
|
||
//正点原子@ALIENTEK
|
||
//技术论坛:www.openedv.com
|
||
//创建日期:2016/1/7
|
||
//版本:V1.1
|
||
//版权所有,盗版必究。
|
||
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
|
||
//All rights reserved
|
||
//********************************************************************************
|
||
//升级说明
|
||
//V1.1
|
||
//修正exf_copy函数,文件进度显示错误的bug
|
||
//////////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
#define FILE_MAX_TYPE_NUM 7 //最多FILE_MAX_TYPE_NUM个大类
|
||
#define FILE_MAX_SUBT_NUM 4 //最多FILE_MAX_SUBT_NUM个小类
|
||
|
||
//文件类型列表
|
||
u8*const FILE_TYPE_TBL[FILE_MAX_TYPE_NUM][FILE_MAX_SUBT_NUM]=
|
||
{
|
||
{"BIN"}, //BIN文件
|
||
{"LRC"}, //LRC文件
|
||
{"NES","SMS"}, //NES/SMS文件
|
||
{"TXT","C","H"}, //文本文件
|
||
{"WAV","MP3","APE","FLAC"},//支持的音乐文件
|
||
{"BMP","JPG","JPEG","GIF"},//图片文件
|
||
{"AVI"}, //视频文件
|
||
};
|
||
///////////////////////////////公共文件区,使用malloc的时候////////////////////////////////////////////
|
||
FATFS *fs[_VOLUMES];//逻辑磁盘工作区.
|
||
FIL *file; //文件1
|
||
FIL *ftemp; //文件2.
|
||
UINT br,bw; //读写变量
|
||
FILINFO fileinfo; //文件信息
|
||
DIR dir; //目录
|
||
|
||
u8 *fatbuf; //SD卡数据缓存区
|
||
///////////////////////////////////////////////////////////////////////////////////////
|
||
//为exfuns申请内存
|
||
//返回值:0,成功
|
||
//1,失败
|
||
u8 exfuns_init(void)
|
||
{
|
||
u8 i;
|
||
for(i=0;i<_VOLUMES;i++)
|
||
{
|
||
fs[i]=(FATFS*)mymalloc(SRAMEX,sizeof(FATFS)); //为磁盘i工作区申请内存
|
||
if(!fs[i])break;
|
||
}
|
||
file=(FIL*)mymalloc(SRAMEX,sizeof(FIL)); //为file申请内存
|
||
ftemp=(FIL*)mymalloc(SRAMEX,sizeof(FIL)); //为ftemp申请内存
|
||
fatbuf=(u8*)mymalloc(SRAMEX,512); //为fatbuf申请内存
|
||
if(i==_VOLUMES&&file&&ftemp&&fatbuf)return 0; //申请有一个失败,即失败.
|
||
else return 1;
|
||
}
|
||
|
||
//将小写字母转为大写字母,如果是数字,则保持不变.
|
||
u8 char_upper(u8 c)
|
||
{
|
||
if(c<'A')return c;//数字,保持不变.
|
||
if(c>='a')return c-0x20;//变为大写.
|
||
else return c;//大写,保持不变
|
||
}
|
||
//报告文件的类型
|
||
//fname:文件名
|
||
//返回值:0XFF,表示无法识别的文件类型编号.
|
||
// 其他,高四位表示所属大类,低四位表示所属小类.
|
||
u8 f_typetell(u8 *fname)
|
||
{
|
||
u8 tbuf[5];
|
||
u8 *attr='\0';//后缀名
|
||
u8 i=0,j;
|
||
while(i<250)
|
||
{
|
||
i++;
|
||
if(*fname=='\0')break;//偏移到了最后了.
|
||
fname++;
|
||
}
|
||
if(i==250)return 0XFF;//错误的字符串.
|
||
for(i=0;i<5;i++)//得到后缀名
|
||
{
|
||
fname--;
|
||
if(*fname=='.')
|
||
{
|
||
fname++;
|
||
attr=fname;
|
||
break;
|
||
}
|
||
}
|
||
strcpy((char *)tbuf,(const char*)attr);//copy
|
||
for(i=0;i<4;i++)tbuf[i]=char_upper(tbuf[i]);//全部变为大写
|
||
for(i=0;i<FILE_MAX_TYPE_NUM;i++) //大类对比
|
||
{
|
||
for(j=0;j<FILE_MAX_SUBT_NUM;j++)//子类对比
|
||
{
|
||
if(*FILE_TYPE_TBL[i][j]==0)break;//此组已经没有可对比的成员了.
|
||
if(strcmp((const char *)FILE_TYPE_TBL[i][j],(const char *)tbuf)==0)//找到了
|
||
{
|
||
return (i<<4)|j;
|
||
}
|
||
}
|
||
}
|
||
return 0XFF;//没找到
|
||
}
|
||
|
||
//得到磁盘剩余容量
|
||
//drv:磁盘编号("0:"/"1:")
|
||
//total:总容量 (单位KB)
|
||
//free:剩余容量 (单位KB)
|
||
//返回值:0,正常.其他,错误代码
|
||
u8 exf_getfree(u8 *drv,u32 *total,u32 *free)
|
||
{
|
||
FATFS *fs1;
|
||
u8 res;
|
||
u32 fre_clust=0, fre_sect=0, tot_sect=0;
|
||
//得到磁盘信息及空闲簇数量
|
||
res =(u32)f_getfree((const TCHAR*)drv, (DWORD*)&fre_clust, &fs1);
|
||
if(res==0)
|
||
{
|
||
tot_sect=(fs1->n_fatent-2)*fs1->csize; //得到总扇区数
|
||
fre_sect=fre_clust*fs1->csize; //得到空闲扇区数
|
||
#if _MAX_SS!=512 //扇区大小不是512字节,则转换为512字节
|
||
tot_sect*=fs1->ssize/512;
|
||
fre_sect*=fs1->ssize/512;
|
||
#endif
|
||
*total=tot_sect>>1; //单位为KB
|
||
*free=fre_sect>>1; //单位为KB
|
||
}
|
||
return res;
|
||
}
|
||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
//文件复制
|
||
//注意文件大小不要超过4GB.
|
||
//将psrc文件,copy到pdst.
|
||
//fcpymsg,函数指针,用于实现拷贝时的信息显示
|
||
// pname:文件/文件夹名
|
||
// pct:百分比
|
||
// mode:
|
||
// [0]:更新文件名
|
||
// [1]:更新百分比pct
|
||
// [2]:更新文件夹
|
||
// [3~7]:保留
|
||
//psrc,pdst:源文件和目标文件
|
||
//totsize:总大小(当totsize为0的时候,表示仅仅为单个文件拷贝)
|
||
//cpdsize:已复制了的大小.
|
||
//fwmode:文件写入模式
|
||
//0:不覆盖原有的文件
|
||
//1:覆盖原有的文件
|
||
//返回值:0,正常
|
||
// 其他,错误,0XFF,强制退出
|
||
u8 exf_copy(u8(*fcpymsg)(u8*pname,u8 pct,u8 mode),u8 *psrc,u8 *pdst,u32 totsize,u32 cpdsize,u8 fwmode)
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
//得到路径下的文件夹
|
||
//返回值:0,路径就是个卷标号.
|
||
// 其他,文件夹名字首地址
|
||
u8* exf_get_src_dname(u8* dpfn)
|
||
{
|
||
u16 temp=0;
|
||
while(*dpfn!=0)
|
||
{
|
||
dpfn++;
|
||
temp++;
|
||
}
|
||
if(temp<4)return 0;
|
||
while((*dpfn!=0x5c)&&(*dpfn!=0x2f))dpfn--; //追述到倒数第一个"\"或者"/"处
|
||
return ++dpfn;
|
||
}
|
||
//得到文件夹大小
|
||
//注意文件夹大小不要超过4GB.
|
||
//返回值:0,文件夹大小为0,或者读取过程中发生了错误.
|
||
// 其他,文件夹大小.
|
||
u32 exf_fdsize(u8 *fdname)
|
||
{
|
||
#define MAX_PATHNAME_DEPTH 512+1 //最大目标文件路径+文件名深度
|
||
u8 res=0;
|
||
DIR *fddir=0; //目录
|
||
FILINFO *finfo=0; //文件信息
|
||
u8 * pathname=0; //目标文件夹路径+文件名
|
||
u16 pathlen=0; //目标路径长度
|
||
u32 fdsize=0;
|
||
|
||
fddir=(DIR*)mymalloc(SRAMEX,sizeof(DIR));//申请内存
|
||
finfo=(FILINFO*)mymalloc(SRAMEX,sizeof(FILINFO));
|
||
if(fddir==NULL||finfo==NULL)res=100;
|
||
if(res==0)
|
||
{
|
||
pathname=mymalloc(SRAMEX,MAX_PATHNAME_DEPTH);
|
||
if(pathname==NULL)res=101;
|
||
if(res==0)
|
||
{
|
||
pathname[0]=0;
|
||
strcat((char*)pathname,(const char*)fdname); //复制路径
|
||
res=f_opendir(fddir,(const TCHAR*)fdname); //打开源目录
|
||
if(res==0)//打开目录成功
|
||
{
|
||
while(res==0)//开始复制文件夹里面的东东
|
||
{
|
||
res=f_readdir(fddir,finfo); //读取目录下的一个文件
|
||
if(res!=FR_OK||finfo->fname[0]==0)break; //错误了/到末尾了,退出
|
||
if(finfo->fname[0]=='.')continue; //忽略上级目录
|
||
if(finfo->fattrib&0X10)//是子目录(文件属性,0X20,归档文件;0X10,子目录;)
|
||
{
|
||
pathlen=strlen((const char*)pathname); //得到当前路径的长度
|
||
strcat((char*)pathname,(const char*)"/"); //加斜杠
|
||
strcat((char*)pathname,(const char*)finfo->fname); //源路径加上子目录名字
|
||
//printf("\r\nsub folder:%s\r\n",pathname); //打印子目录名
|
||
fdsize+=exf_fdsize(pathname); //得到子目录大小,递归调用
|
||
pathname[pathlen]=0; //加入结束符
|
||
}else fdsize+=finfo->fsize; //非目录,直接加上文件的大小
|
||
|
||
}
|
||
}
|
||
myfree(SRAMEX,pathname);
|
||
}
|
||
}
|
||
myfree(SRAMEX,fddir);
|
||
myfree(SRAMEX,finfo);
|
||
if(res)return 0;
|
||
else return fdsize;
|
||
}
|
||
//文件夹复制
|
||
//注意文件夹大小不要超过4GB.
|
||
//将psrc文件夹,copy到pdst文件夹.
|
||
//pdst:必须形如"X:"/"X:XX"/"X:XX/XX"之类的.而且要实现确认上一级文件夹存在
|
||
//fcpymsg,函数指针,用于实现拷贝时的信息显示
|
||
// pname:文件/文件夹名
|
||
// pct:百分比
|
||
// mode:
|
||
// [0]:更新文件名
|
||
// [1]:更新百分比pct
|
||
// [2]:更新文件夹
|
||
// [3~7]:保留
|
||
//psrc,pdst:源文件夹和目标文件夹
|
||
//totsize:总大小(当totsize为0的时候,表示仅仅为单个文件拷贝)
|
||
//cpdsize:已复制了的大小.
|
||
//fwmode:文件写入模式
|
||
//0:不覆盖原有的文件
|
||
//1:覆盖原有的文件
|
||
//返回值:0,成功
|
||
// 其他,错误代码;0XFF,强制退出
|
||
u8 exf_fdcopy(u8(*fcpymsg)(u8*pname,u8 pct,u8 mode),u8 *psrc,u8 *pdst,u32 *totsize,u32 *cpdsize,u8 fwmode)
|
||
{
|
||
#define MAX_PATHNAME_DEPTH 512+1 //最大目标文件路径+文件名深度
|
||
u8 res=0;
|
||
DIR *srcdir=0; //源目录
|
||
DIR *dstdir=0; //源目录
|
||
FILINFO *finfo=0; //文件信息
|
||
u8 *fn=0; //长文件名
|
||
|
||
u8 * dstpathname=0; //目标文件夹路径+文件名
|
||
u8 * srcpathname=0; //源文件夹路径+文件名
|
||
|
||
u16 dstpathlen=0; //目标路径长度
|
||
u16 srcpathlen=0; //源路径长度
|
||
|
||
|
||
srcdir=(DIR*)mymalloc(SRAMEX,sizeof(DIR));//申请内存
|
||
dstdir=(DIR*)mymalloc(SRAMEX,sizeof(DIR));
|
||
finfo=(FILINFO*)mymalloc(SRAMEX,sizeof(FILINFO));
|
||
|
||
if(srcdir==NULL||dstdir==NULL||finfo==NULL)res=100;
|
||
if(res==0)
|
||
{
|
||
dstpathname=mymalloc(SRAMEX,MAX_PATHNAME_DEPTH);
|
||
srcpathname=mymalloc(SRAMEX,MAX_PATHNAME_DEPTH);
|
||
if(dstpathname==NULL||srcpathname==NULL)res=101;
|
||
if(res==0)
|
||
{
|
||
dstpathname[0]=0;
|
||
srcpathname[0]=0;
|
||
strcat((char*)srcpathname,(const char*)psrc); //复制原始源文件路径
|
||
strcat((char*)dstpathname,(const char*)pdst); //复制原始目标文件路径
|
||
res=f_opendir(srcdir,(const TCHAR*)psrc); //打开源目录
|
||
if(res==0)//打开目录成功
|
||
{
|
||
strcat((char*)dstpathname,(const char*)"/");//加入斜杠
|
||
fn=exf_get_src_dname(psrc);
|
||
if(fn==0)//卷标拷贝
|
||
{
|
||
dstpathlen=strlen((const char*)dstpathname);
|
||
dstpathname[dstpathlen]=psrc[0]; //记录卷标
|
||
dstpathname[dstpathlen+1]=0; //结束符
|
||
}else strcat((char*)dstpathname,(const char*)fn);//加文件名
|
||
fcpymsg(fn,0,0X04);//更新文件夹名
|
||
res=f_mkdir((const TCHAR*)dstpathname);//如果文件夹已经存在,就不创建.如果不存在就创建新的文件夹.
|
||
if(res==FR_EXIST)res=0;
|
||
while(res==0)//开始复制文件夹里面的东东
|
||
{
|
||
res=f_readdir(srcdir,finfo); //读取目录下的一个文件
|
||
if(res!=FR_OK||finfo->fname[0]==0)break; //错误了/到末尾了,退出
|
||
if(finfo->fname[0]=='.')continue; //忽略上级目录
|
||
fn=(u8*)finfo->fname; //得到文件名
|
||
dstpathlen=strlen((const char*)dstpathname); //得到当前目标路径的长度
|
||
srcpathlen=strlen((const char*)srcpathname); //得到源路径长度
|
||
|
||
strcat((char*)srcpathname,(const char*)"/");//源路径加斜杠
|
||
if(finfo->fattrib&0X10)//是子目录(文件属性,0X20,归档文件;0X10,子目录;)
|
||
{
|
||
strcat((char*)srcpathname,(const char*)fn); //源路径加上子目录名字
|
||
res=exf_fdcopy(fcpymsg,srcpathname,dstpathname,totsize,cpdsize,fwmode); //拷贝文件夹
|
||
}else //非目录
|
||
{
|
||
strcat((char*)dstpathname,(const char*)"/");//目标路径加斜杠
|
||
strcat((char*)dstpathname,(const char*)fn); //目标路径加文件名
|
||
strcat((char*)srcpathname,(const char*)fn); //源路径加文件名
|
||
fcpymsg(fn,0,0X01);//更新文件名
|
||
res=exf_copy(fcpymsg,srcpathname,dstpathname,*totsize,*cpdsize,fwmode);//复制文件
|
||
*cpdsize+=finfo->fsize;//增加一个文件大小
|
||
}
|
||
srcpathname[srcpathlen]=0;//加入结束符
|
||
dstpathname[dstpathlen]=0;//加入结束符
|
||
}
|
||
}
|
||
myfree(SRAMEX,dstpathname);
|
||
myfree(SRAMEX,srcpathname);
|
||
}
|
||
}
|
||
myfree(SRAMEX,srcdir);
|
||
myfree(SRAMEX,dstdir);
|
||
myfree(SRAMEX,finfo);
|
||
return res;
|
||
}
|
||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|