417 lines
13 KiB
C
417 lines
13 KiB
C
/**
|
|
******************************************************************************
|
|
* File Name : exfuns.c
|
|
* Description : This file provides code for the configuration
|
|
* of the External Functions instances.
|
|
******************************************************************************
|
|
* @attention
|
|
*
|
|
* <h2><center>© Copyright (c) 2019 STMicroelectronics.
|
|
* All rights reserved.</center></h2>
|
|
*
|
|
* This software component is licensed by ST under Ultimate Liberty license
|
|
* SLA0044, the "License"; You may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at:
|
|
* www.st.com/SLA0044
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include <string.h>
|
|
#include "malloc.h"
|
|
#include "exfuns.h"
|
|
#include "fattester.h"
|
|
#include "usart.h"
|
|
|
|
#define FILE_MAX_TYPE_NUM 7 //Most FILE_MAX_TYPE_NUM categories
|
|
#define FILE_MAX_SUBT_NUM 4 //Up to FILE_MAX_SUBT_NUM a small class
|
|
|
|
//File types list
|
|
char * const FILE_TYPE_TBL[FILE_MAX_TYPE_NUM][FILE_MAX_SUBT_NUM]=
|
|
{
|
|
{"BIN"}, //BIN file
|
|
{"LRC"}, //LRC files
|
|
{"NES"}, //NES file
|
|
{"TXT","C","H"}, //Text file
|
|
{"WAV","MP3","APE","FLAC"},//Supported music files
|
|
{"BMP","JPG","JPEG","GIF"},//Picture files
|
|
{"AVI"}, //Video file
|
|
};
|
|
///////////////////////////////Public files area, when using the malloc////////////////////////////////////////////
|
|
FATFS *fs[_VOLUMES]; //Logical disk.
|
|
FIL *file; //File 1
|
|
FIL *ftemp; //File 2.
|
|
UINT br,bw; //Read and write variables
|
|
FILINFO fileinfo; //File information
|
|
DIR dir; //Directory
|
|
|
|
u8 *fatbuf; //SD card data buffer
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//Exfuns for the memory
|
|
//Return values: 0-success
|
|
// 1 failure
|
|
u8 exfuns_init(void)
|
|
{
|
|
u8 i;
|
|
for (i = 0; i < _VOLUMES; i++)
|
|
{
|
|
fs[i] = (FATFS*)mymalloc(sizeof(FATFS)); //Applications for disk I workspace memory
|
|
if (!fs[i]) break;
|
|
}
|
|
file = (FIL*)mymalloc(sizeof(FIL)); //Applications for file memory
|
|
ftemp = (FIL*)mymalloc(sizeof(FIL)); //Ftemp application memory
|
|
fatbuf = (u8*) mymalloc(512); //Fatbuf for the memory
|
|
if (i == _VOLUMES && file && ftemp && fatbuf) return 0; //Success
|
|
else return 1; //Failed
|
|
}
|
|
|
|
//Lowercase letters to uppercase letters if numbers remained unchanged.
|
|
u8 char_upper(u8 c)
|
|
{
|
|
if (c < 'A') return c; //Numbers remain the same.
|
|
if (c >= 'a') return c - 0x20; //Uppercase.
|
|
else return c; //Capital, remains unchanged
|
|
}
|
|
//Report file type
|
|
//Fname: file name
|
|
//Return value: 0XFF, said it could not identify the type of file number.
|
|
// Other four member categories, low said four member categories.
|
|
u8 f_typetell(u8 *fname)
|
|
{
|
|
u8 tbuf[5];
|
|
u8 *attr = (u8*)'\0';//Extension name
|
|
u8 i=0,j;
|
|
while(i<250)
|
|
{
|
|
i++;
|
|
if(*fname=='\0')break;//Offset at the end of the.
|
|
fname++;
|
|
}
|
|
if(i==250)return 0XFF;//Error string.
|
|
for(i=0;i<5;i++)//Get extension
|
|
{
|
|
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]);//All uppercase
|
|
for(i=0;i<FILE_MAX_TYPE_NUM;i++) //Category comparison
|
|
{
|
|
for(j=0;j<FILE_MAX_SUBT_NUM;j++)//Subclass comparison
|
|
{
|
|
if(*FILE_TYPE_TBL[i][j]==0)break;//The members of this group have no comparable.
|
|
if(strcmp((const char *)FILE_TYPE_TBL[i][j],(const char *)tbuf)==0)//Found it
|
|
{
|
|
return (i<<4)|j;
|
|
}
|
|
}
|
|
}
|
|
return 0XFF;//Not found
|
|
}
|
|
|
|
//Get free disk capacity
|
|
//drv:Disk number("0:"/"1:")
|
|
//total:Total capacity (In KB)
|
|
//free:Remaining capacity (In KB)
|
|
//Return values: 0,., error code
|
|
u8 exf_getfree(u8 *drv,u32 *total,u32 *free)
|
|
{
|
|
FATFS *fs1;
|
|
u8 res;
|
|
u32 fre_clust=0, fre_sect=0, tot_sect=0;
|
|
//Get disk information and the number of free clusters
|
|
res =(u32)f_getfree((const TCHAR*)drv, (DWORD*)&fre_clust, &fs1);
|
|
if(res==0)
|
|
{
|
|
tot_sect=(fs1->n_fatent-2)*fs1->csize; //Total number of sectors
|
|
fre_sect=fre_clust*fs1->csize; //Get number of spare sectors
|
|
#if _MAX_SS!=512 //Sector size other than 512 bytes, then the conversion is 512 bytes
|
|
tot_sect*=fs1->ssize/512;
|
|
fre_sect*=fs1->ssize/512;
|
|
#endif
|
|
*total=tot_sect>>1; //Unit is KB
|
|
*free=fre_sect>>1; //Unit is KB
|
|
}
|
|
return res;
|
|
}
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//File replication
|
|
//Note the file size should not exceed 4GB.
|
|
//The pSrc file, copy to pdst.
|
|
//fcpymsg,A function pointer to implement copy information display
|
|
// pname:File/folder name
|
|
// pct:Percentage
|
|
// mode:
|
|
// [0]:Update file name
|
|
// [1]:Update percentage of PCT
|
|
// [2]:Update folder
|
|
// [3~7]:Reservation
|
|
//psrc,pdst:Source and target files
|
|
//totsize:Total size (when totsize 0 when says just to copy a single file)
|
|
//cpdsize:The size of replicated.
|
|
//fwmode:File in write mode
|
|
//0:Do not overwrite existing file
|
|
//1:Overwrite the original file
|
|
//Return values: 0 normal,
|
|
// Other, errors, 0XFF, force quit
|
|
u8 exf_copy(u8(*fcpymsg)(u8*pname,u8 pct,u8 mode),u8 *psrc,u8 *pdst,u32 totsize,u32 cpdsize,u8 fwmode)
|
|
{
|
|
u8 res;
|
|
u16 br=0;
|
|
u16 bw=0;
|
|
FIL *fsrc=0;
|
|
FIL *fdst=0;
|
|
u8 *fbuf=0;
|
|
u8 curpct=0;
|
|
fsrc=(FIL*)mymalloc(sizeof(FIL));//For the memory
|
|
fdst=(FIL*)mymalloc(sizeof(FIL));
|
|
fbuf=(u8 *)mymalloc(8192);
|
|
if(fsrc==NULL||fdst==NULL||fbuf==NULL)res=100;//Front left fatfs
|
|
else
|
|
{
|
|
if(fwmode==0)fwmode=FA_CREATE_NEW;//Do not overwrite
|
|
else fwmode=FA_CREATE_ALWAYS; //Overwrite the existing file
|
|
|
|
res=f_open(fsrc,(const TCHAR*)psrc,FA_READ|FA_OPEN_EXISTING); //Open a read-only file
|
|
if(res==0)res=f_open(fdst,(const TCHAR*)pdst,FA_WRITE|fwmode); //First open success, began to open the second
|
|
if(res==0)//Both open succeeded
|
|
{
|
|
if(totsize==0)//Only is a single file copy
|
|
{
|
|
totsize=fsrc->obj.objsize;
|
|
cpdsize=0;
|
|
curpct=0;
|
|
}else curpct=(cpdsize*100)/totsize; //Percentage of new
|
|
fcpymsg(psrc,curpct,0X02); //Update percentage
|
|
while(res==0)//Start copying
|
|
{
|
|
res=f_read(fsrc,fbuf,8192,(UINT*)&br); //The source read 512 bytes
|
|
if(res||br==0)break;
|
|
res=f_write(fdst,fbuf,(UINT)br,(UINT*)&bw); //Write destination file
|
|
cpdsize+=bw;
|
|
if(curpct!=(cpdsize*100)/totsize)//Do you need to update the percentage
|
|
{
|
|
curpct=(cpdsize*100)/totsize;
|
|
if(fcpymsg(psrc,curpct,0X02))//Update percentage
|
|
{
|
|
res=0XFF;//Force quit
|
|
break;
|
|
}
|
|
}
|
|
if(res||bw<br)break;
|
|
}
|
|
f_close(fsrc);
|
|
f_close(fdst);
|
|
}
|
|
}
|
|
myfree(fsrc);//Free up memory
|
|
myfree(fdst);
|
|
myfree(fbuf);
|
|
return res;
|
|
}
|
|
|
|
//Get the path's directory
|
|
//Return values: 0, path is a volume label.
|
|
// Other folder name address
|
|
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--; //Goes back to the last "\" or "/"
|
|
return ++dpfn;
|
|
}
|
|
//Get folder size
|
|
//Note the folder size not more than 4GB.
|
|
//Return values: 0, folder size is 0, or the error occurred during a read.
|
|
// Otherwise, the folder size.
|
|
u32 exf_fdsize(u8 *fdname)
|
|
{
|
|
#define MAX_PATHNAME_DEPTH 512+1 //Maximum depth of target file path + file name
|
|
u8 res=0;
|
|
DIR *fddir=0; //Directory
|
|
FILINFO *finfo=0; //File information
|
|
u8 *fn=0; //Long file names
|
|
u8 * pathname=0; //The destination folder path + file name
|
|
u16 pathlen=0; //Destination path length
|
|
u32 fdsize=0;
|
|
|
|
fddir=(DIR*)mymalloc(sizeof(DIR));//For the memory
|
|
finfo=(FILINFO*)mymalloc(sizeof(FILINFO));
|
|
if(fddir==NULL||finfo==NULL)res=100;
|
|
if(res==0)
|
|
{
|
|
finfo->fsize = _MAX_LFN * 2 + 1;
|
|
pathname = mymalloc(MAX_PATHNAME_DEPTH);
|
|
if(finfo->fname == NULL || pathname == NULL) res=101;
|
|
if(res==0)
|
|
{
|
|
pathname[0]=0;
|
|
strcat((char*)pathname,(const char*)fdname); //Copy path
|
|
res=f_opendir(fddir,(const TCHAR*)fdname); //Open source directory
|
|
if(res==0)//Open Directory successfully
|
|
{
|
|
while(res==0)//Start copying folders inside stuff
|
|
{
|
|
res=f_readdir(fddir,finfo); //Read a file directory
|
|
if(res!=FR_OK||finfo->fname[0]==0)break; //Errors/to the end of the exit
|
|
if(finfo->fname[0]=='.')continue; //Ignoring superior directory
|
|
if(finfo->fattrib&0X10)//Is the subdirectory (file attributes, 0X20, archive; 0X10, subdirectories;)
|
|
{
|
|
fn=(u8*)(finfo->fname);//Get file name
|
|
pathlen=strlen((const char*)pathname); //Get the current path length
|
|
strcat((char*)pathname,(const char*)"/"); //Add a slash
|
|
strcat((char*)pathname,(const char*)fn); //Source path and directory name
|
|
//printf("\r\nsub folder:%s\r\n",pathname); //Print a directory name
|
|
fdsize+=exf_fdsize(pathname); //Get directory size, recursive calls
|
|
pathname[pathlen]=0; //Join the terminator
|
|
}
|
|
else fdsize+=finfo->fsize; //Non-catalog direct plus the size of the file
|
|
|
|
}
|
|
}
|
|
myfree(pathname);
|
|
}
|
|
}
|
|
myfree(fddir);
|
|
myfree(finfo);
|
|
if(res)return 0;
|
|
else return fdsize;
|
|
}
|
|
//Folder replication
|
|
//Note the folder size not to exceed 4GB.
|
|
//The pSrc folder, copy to pdst folder.
|
|
//Pdst: must be shaped like "x:"/"X:XX"/"X:XX/XX" or something like that. but also the confirm folder one level up
|
|
//Fcpymsg, function pointer, used to implement a copy of information display
|
|
// pname:File/folder name
|
|
// pct:Percentage
|
|
// mode:
|
|
// [0]:Update file name
|
|
// [1]:Update percentage of PCT
|
|
// [2]:Update folder
|
|
// [3~7]:Reservation
|
|
//psrc,pdst:Source and destination folders
|
|
//totsize:Total size (when totsize 0 when says just to copy a single file)
|
|
//cpdsize:Total size of the copied.
|
|
//fwmode:File in write mode
|
|
//0:Do not overwrite existing file
|
|
//1:Overwrite the original file
|
|
//Return values: 0-success
|
|
// Other error code 0XFF, a forced exit
|
|
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 //Maximum depth of target file path + file name
|
|
u8 res=0;
|
|
DIR *srcdir=0; //The source directory
|
|
DIR *dstdir=0; //The destination directory
|
|
FILINFO *finfo=0; //File information
|
|
u8 *fn=0; //Long file names
|
|
|
|
u8 * dstpathname=0; //destination folder path + file name
|
|
u8 * srcpathname=0; //Source folder path + filename
|
|
|
|
u16 dstpathlen=0; //Destination path length
|
|
u16 srcpathlen=0; //Source path length
|
|
|
|
|
|
srcdir=(DIR*)mymalloc(sizeof(DIR));//For the memory
|
|
dstdir=(DIR*)mymalloc(sizeof(DIR));
|
|
finfo=(FILINFO*)mymalloc(sizeof(FILINFO));
|
|
|
|
if(srcdir==NULL||dstdir==NULL||finfo==NULL)res=100;
|
|
if(res==0)
|
|
{
|
|
finfo->fsize=_MAX_LFN*2+1;
|
|
dstpathname=mymalloc(MAX_PATHNAME_DEPTH);
|
|
srcpathname=mymalloc(MAX_PATHNAME_DEPTH);
|
|
if(finfo->fname==NULL||dstpathname==NULL||srcpathname==NULL)res=101;
|
|
if(res==0)
|
|
{
|
|
dstpathname[0]=0;
|
|
srcpathname[0]=0;
|
|
strcat((char*)srcpathname,(const char*)psrc); //A copy of the original source file path
|
|
strcat((char*)dstpathname,(const char*)pdst); //A copy of the original target file path
|
|
res=f_opendir(srcdir,(const TCHAR*)psrc); //Open source directory
|
|
if(res==0)//Open Directory successfully
|
|
{
|
|
strcat((char*)dstpathname,(const char*)"/");//Join slash
|
|
fn=exf_get_src_dname(psrc);
|
|
if(fn==0)//Label copy
|
|
{
|
|
dstpathlen=strlen((const char*)dstpathname);
|
|
dstpathname[dstpathlen]=psrc[0]; //Record label
|
|
dstpathname[dstpathlen+1]=0; //Terminator
|
|
}
|
|
else strcat((char*)dstpathname,(const char*)fn);//Add filename
|
|
fcpymsg(fn,0,0X04);//Update the folder name
|
|
res=f_mkdir((const TCHAR*)dstpathname);//If the folder already exists, is not created. create a new folder if it does not exist.
|
|
if(res==FR_EXIST)res=0;
|
|
while(res==0)//Start copying folders inside stuff
|
|
{
|
|
res=f_readdir(srcdir,finfo); //Read a file directory
|
|
if(res!=FR_OK||finfo->fname[0]==0)break; //Errors/to the end of the exit
|
|
if(finfo->fname[0]=='.')continue; //Ignoring superior directory
|
|
fn=(u8*)(finfo->fname); //Get file name
|
|
dstpathlen=strlen((const char*)dstpathname); //Get the length of the path to the current target
|
|
srcpathlen=strlen((const char*)srcpathname); //Get the source path length
|
|
|
|
strcat((char*)srcpathname,(const char*)"/");//Source path in slash
|
|
if(finfo->fattrib&0X10)//Is the subdirectory (file attributes, 0X20, archive; 0X10, subdirectories;)
|
|
{
|
|
strcat((char*)srcpathname,(const char*)fn); //Source path and directory name
|
|
res=exf_fdcopy(fcpymsg,srcpathname,dstpathname,totsize,cpdsize,fwmode); //Copy folder
|
|
}
|
|
else //Non-catalog
|
|
{
|
|
strcat((char*)dstpathname,(const char*)"/");//Target path in slash
|
|
strcat((char*)dstpathname,(const char*)fn); //Destination path and file name
|
|
strcat((char*)srcpathname,(const char*)fn); //Source path and file name
|
|
fcpymsg(fn,0,0X01);//Update file name
|
|
res=exf_copy(fcpymsg,srcpathname,dstpathname,*totsize,*cpdsize,fwmode);//Copy the files
|
|
*cpdsize+=finfo->fsize;//Add a file size
|
|
}
|
|
srcpathname[srcpathlen]=0;//Join the terminator
|
|
dstpathname[dstpathlen]=0;//Join the terminator
|
|
}
|
|
}
|
|
myfree(dstpathname);
|
|
myfree(srcpathname);
|
|
}
|
|
}
|
|
myfree(srcdir);
|
|
myfree(dstdir);
|
|
myfree(finfo);
|
|
return res;
|
|
}
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|