📄 stdwrap.c
字号:
//file: stdwrap.c
//功能:stdio的接口包装,包括了以下常用函数:
// FILE* -> CXFILE*
// fopen -> cx_fopen,目前只支持rb, wb, wb+, rb+
// fread -> cx_fread
// fwrite -> cx_fwrite
// fseek -> cx_fseek
// ftell -> cx_ftell
// feof -> cx_feof
// fclose -> cx_fclose
// 上述函数的使用方法同C语言标准库的用法一致
// 使用时,要先调用StdioWrapperStartup()来初始化本封皮,而在使用完设备后要使用StdioWrapperCleanup()来做清理工作
// 注意:一定不要忘记在用完后调用StdioWrapperCleanup(),否则当BlkMdd启用cache,会有脏数据滞留在cache中未写回
// 这有可能导致优盘或SD卡上的数据崩溃!(我就曾因此弄丢了一块优盘上的数据)
// 本封皮会使用BlkMdd的功能进行读写,
// 与fat16.c交互时,花了很多时间在于弄清楚各指针参数的使用方法,最主要的就是指针所指的内存是由谁来负责分配及回收
// 因为其说明文档都没有说明,幸好对于指针的IN或是OUT还是谈到了
// 我对于读写速度做了测试。我的物理设备是用CH375驱动的朗科1GB优盘
// 读取速度约220KB/s。我嫌慢,就曾经写过一个ch375模块的测试函数,这个函数连续读取10000扇区的内容,约5MB,速度250KB/s
// 写入速度只有22KB/s左右。我也类似地做了测试,对1000个扇区调用CH375的扇区写函数做扇区写操作,大约38KB/s
// 后来我翻出一个很早的(4年前)的优盘,写速度只有9KB/s
// 我觉得ch375不应这么慢。我用的平台是AT91SAM7S128, 48MHz主频,I/O模拟的8位总线。可能是我模拟的不太好
// 后来我关掉了I/O统计功能,并且把一些小函数的调用在主调函数中就地展开,大约提高了24%左右的写入速度
// 使用这个文件系统,一定要打开BlkMdd的cache支持。有条件的最好配上2个cache,对于需要写入的场合尤其重要
// 另外,如果要对物理设备上的两个文件同时读写,比如像copy命令干的这种事,一定要配上3个cache,否则命中率只有60%左右
// 按照这种要求配置好cache,如果一次写入32个字节的话,cache命中率通常可高达96.5%
//注:这个文件系统有一个缺陷,就是对长文件名支持的不到位。如果长文件名/目录名是纯英文的,它和windows都能正常读取
// 如果长文件/目录名带中文,则依然能正常读取,但是在windows下会显示乱码
// 而且不能正确识别windows的中文长目录名
//#include <stdio.h>
#include <string.h>
#include "fsdefs.h"
#include "fat16.h"
#include "partition.h"
#include "partition_config.h"
#include "blkmdd.h"
#include "stdwrap.h"
BOOL BlkMdd_Flush(void);
static struct partition_struct* sg_pPart;
struct fat16_fs_struct* sg_fs;
struct fat16_dir_struct* sg_dd;
static DS_StdWrapCB sg_swcb;
static BOOL sg_isFsInited=FALSE;
BOOL StdioWrapperStartup(void)
{
IFAV i;
if ( sg_isFsInited) return TRUE;
if(!BlkMdd_Startup())
{
return FALSE;
}
sg_pPart = partition_open(BlkMdd_read,
BlkMdd_read_interval,
BlkMdd_write,
BlkMdd_write_interval,
0
);
if(!sg_pPart)
{
/* If the partition did not open, assume the storage device
* is a "superfloppy", i.e. has no MBR.
*/
sg_pPart = partition_open(BlkMdd_read,
BlkMdd_read_interval,
BlkMdd_write,
BlkMdd_write_interval,
(int8_t) -1
);
if(!sg_pPart)
{
return FALSE;
}
}
/* open file system */
sg_fs = fat16_open(sg_pPart);
if(!sg_fs)
{
BlkMdd_Cleanup();
return FALSE;
}
for (i=0;i<CFG_MaxFile;i++)
{
sg_swcb.fileAry[i].flags=0;
}
sg_isFsInited=TRUE;
return TRUE;
}
void StdWrap_FormatPath(char *psz)
{
if (psz[1]==':' && psz[2]=='\\')
{
psz+=2; //忽略前面的"x:"
}
//把所有的"\"整理为"/"
while (*psz)
{
if (*psz=='\\')
{
*psz='/';
}
if ( *psz>='a' && *psz<='z')
{
*psz-=0x20; //小写转大写
}
psz++;
}
}
//pFat16Ent: OUT。如果找到指定的文件,则被填充为在FAT16分配表中的入口内容,删除文件时需要此内容
//
BOOL StdWrap_FindFileInDir(struct fat16_fs_struct* fs, struct fat16_dir_struct* dd, const char* name, struct fat16_dir_entry_struct* OUT pFat16Ent)
{
while(fat16_read_dir(dd, pFat16Ent))
{
if(strcmp(pFat16Ent->long_name, name) == 0)
{
fat16_reset_dir(dd);
return TRUE;
}
}
return FALSE;
}
//返回值:文件名的第一个字符在整个路径字符串中的位置
U32 StdWrap_GetFileNameFromPath(char *pOriPath, char** IN ppPath)
{
I32 len;
len=(U32) strlen(pOriPath);
if (!len) return CON_MaxU32;
while(--len)
{
if (pOriPath[len]=='/')
{
break;
}
}
if (len==0)
{
if (pOriPath[0]=='/')
{
++len;
*ppPath= pOriPath+len;
}
}
else
{
++len;
*ppPath= pOriPath+len;
}
//如果len==0,则直接给出了文件名
return (U32) len;
}
CXFILE* StdWrap_AllocCXFILE(void)
{
IFAV i;
CXFILE *fp;
for ( i=0; i<CFG_MaxFile ; i++ )
{
if ( sg_swcb.fileAry[i].flags & FPFLAG_Inuse )
{
continue;
}
break;
}
if (i>=CFG_MaxFile)
{
return NULL;
}
fp= sg_swcb.fileAry+i;
fp->flags|= FPFLAG_Inuse;
fp->pdd=sg_dd;
fp->pfs=sg_fs;
return fp;
}
BOOL StdWrap_FreeCXFILE(CXFILE *fp)
{
if (fp)
{
fp->flags=0;
}
return TRUE;
}
//文件路径必须是绝对路径,根目录名字是"/"或者是"\", 但不应同时出现
//举例:
CXFILE* cx_fopen(const char *pszOriFilePath, const char *pszIODesc)
{
CXFILE *fp;
BOOL isToCreateFile=FALSE;
UFAV fileNameIdx;
struct fat16_dir_struct *pDir;
struct fat16_dir_entry_struct dirEnt, fileEnt;
char szFilePath[64], *pszFileName, *pszPathName;
char szRoot[]="/";
strcpy(szFilePath, pszOriFilePath);
StdWrap_FormatPath(szFilePath);
fileNameIdx= StdWrap_GetFileNameFromPath(szFilePath, &pszFileName);
//删除分开目录与文件之间的"/"
if (fileNameIdx==0)
{
//必须以"/"开头,因为只支持绝对路径
return NULL;
}
if (fileNameIdx>1)
{
szFilePath[fileNameIdx-1]=0;
pszPathName=szFilePath;
}
else
{
//在根目录下创建文件
pszPathName=szRoot;
}
//打开目录
if ( !fat16_get_dir_entry_of_path(sg_fs,pszPathName, &dirEnt) )
{
return NULL;
}
pDir=fat16_open_dir(sg_fs, &dirEnt);
if (NULL==pDir)
{
return NULL;
}
fp= StdWrap_AllocCXFILE();
if (NULL==fp)
{
fat16_close_dir(pDir);
return NULL;
}
fp->pdd=pDir;
fp->pfs=sg_fs;
if (pszIODesc[0]=='r' && pszIODesc[1]=='b' && pszIODesc[2]=='0')
{
fp->flags|= FPFLAG_Rd;
isToCreateFile=FALSE;
}
else if (pszIODesc[0]=='r' && pszIODesc[1]=='b' && pszIODesc[2]=='+')
{
fp->flags|= FPFLAG_Rd | FPFLAG_Wr;
isToCreateFile=FALSE;
}
else if (pszIODesc[0]=='w' && pszIODesc[1]=='b')
{
if (StdWrap_FindFileInDir(sg_fs,pDir,pszFileName, &fileEnt))
{
if (fileEnt.attributes & FAT16_ATTRIB_DIR)
{
goto cx_fopen_Cleanup; //该文件其实是个目录,不允许
}
if (!fat16_delete_file(sg_fs, &fileEnt))
{
goto cx_fopen_Cleanup;
}
}
fp->flags|= FPFLAG_Wr;
if (pszIODesc[2]=='+')
{
fp->flags|= FPFLAG_Rd;
}
isToCreateFile=TRUE;
}
if (pszIODesc[1]=='b' || pszIODesc[2]=='b')
{
fp->flags|= FPFLAG_Bin;
}
if (isToCreateFile)
{
if (!fat16_create_file(fp->pdd, pszFileName, &fileEnt))
{
goto cx_fopen_Cleanup;
}
fp->pfd=fat16_open_file(sg_fs,&fileEnt);
if (!fp->pfd)
{
goto cx_fopen_Cleanup;
}
}
else
{
if (!StdWrap_FindFileInDir(sg_fs,pDir,pszFileName,&fileEnt))
{
goto cx_fopen_Cleanup;
}
fp->pfd=fat16_open_file(sg_fs,&fileEnt);
if (!fp->pfd)
{
goto cx_fopen_Cleanup;
}
}
return fp;
cx_fopen_Cleanup:
fat16_close_dir(pDir);
StdWrap_FreeCXFILE(fp);
return NULL;
}
//返回值:0成功,-1失败
int cx_fclose(CXFILE* fp)
{
if (!fp) return -1;
if (!fp->pfd) return -1;
fat16_close_file(fp->pfd);
fat16_close_dir(fp->pdd);
fp->flags=0;
BlkMdd_Flush();
return 0;
}
int cx_fseek(CXFILE* fp, long newPos, int rel)
{
long offset;
if (!fp) return -1;
offset=newPos;
if (rel==SEEK_SET)
{
return fat16_seek_file(fp->pfd,&offset,FAT16_SEEK_SET);
}
else if (rel==SEEK_CUR)
{
return fat16_seek_file(fp->pfd,&offset,FAT16_SEEK_CUR);
}
else if (rel==SEEK_END)
{
return fat16_seek_file(fp->pfd,&offset,FAT16_SEEK_END);
}
return -1;
}
size_t cx_fread(void *pvBuf, size_t unitSize, size_t unitCnt, CXFILE *fp)
{
if (!fp) return (size_t) CON_MaxU32;
return (size_t) fat16_read_file(fp->pfd,pvBuf,(U16) (unitCnt*unitSize));
}
size_t cx_fwrite(const void *pvBuf, size_t unitSize, size_t unitCnt, CXFILE *fp)
{
if (!fp) return (size_t) CON_MaxU32;
return (size_t) fat16_write_file(fp->pfd,pvBuf,(U16) (unitCnt*unitSize));
}
long cx_ftell(CXFILE *fp)
{
if (!fp) return -1;
return fp->pfd->pos;
}
int cx_feof(CXFILE *fp)
{
if (!fp) return 0;
if ( fp->pfd->pos== fp->pfd->dir_entry.file_size)
{
return 1;
}
return 0;
}
extern U8* tab8x8Icons;
BOOL StdWrap_Test(char *pPath)
{
CXFILE *cfp, *cfp2;
U8 buf[32];
U32 fLen;
U32 unitLen;
fLen=128*1024;
unitLen=32;
cfp=cx_fopen(pPath,"rb");
if (!cfp) return FALSE;
cfp2=cx_fopen("/testout.txt","wb+");
if (!cfp2)
{
cx_fclose(cfp);
return FALSE;
}
cx_fseek(cfp,0, SEEK_END);
fLen=cx_ftell(cfp);
cx_fseek(cfp,0, SEEK_SET);
while (fLen)
{
if (fLen>unitLen)
{
cx_fread(buf,1,unitLen,cfp);
//cx_fwrite(buf,1,unitLen,cfp2);
fLen-=unitLen;
}
else
{
cx_fread(buf,1,fLen,cfp);
//cx_fwrite(buf,1,fLen,cfp2);
fLen=0;
}
}
cx_fclose(cfp);
cx_fclose(cfp2);
return TRUE;
}
BOOL StdWrap_TestWR(char *pPath)
{
CXFILE *cfp;
U8 *p= (U8 *) 0x00200000;
U32 fLen;
U32 unitLen;
fLen=256*1024;
unitLen=64;
cfp=cx_fopen(pPath,"wb");
while (fLen)
{
if (fLen>unitLen)
{
cx_fwrite(p,1,unitLen,cfp);
fLen-=unitLen;
p+=unitLen;
if (p>=(U8 *) 0x00203f00)
{
p=(U8 *) 0x00200000;
}
}
else
{
cx_fwrite(p,1,fLen,cfp);
fLen=0;
}
}
cx_fclose(cfp);
//CXFILE *cfp;
//FILE *fp;
//long fLen;
//char testBuf[128];
//sg_fs=fs;
//fp=fopen("testOri.jpg","rb");
//fseek(fp,0,SEEK_END);
//fLen=ftell(fp);
//fseek(fp,0,SEEK_SET);
//
//cfp=cx_fopen(pPath, "wb+");
//if (!cfp) return FALSE;
//while (fLen)
//{
// if (fLen>128)
// {
// fread(testBuf,1,128,fp);
// cx_fwrite(testBuf,1,128,cfp);
// fLen-=128;
// }
// else
// {
// fread(testBuf,1,fLen,fp);
// cx_fwrite(testBuf,1,fLen,cfp);
// fLen=0;
// }
//}
//cx_fclose(cfp);
//fclose(fp);
//fp=fopen("testDst.jpg","wb");
//cfp=cx_fopen(pPath, "rb+");
//cx_fseek(cfp,0,SEEK_END);
//fLen=cx_ftell(cfp);
//cx_fseek(cfp,0,SEEK_SET);
//while (fLen)
//{
// if (fLen>128)
// {
// cx_fread(testBuf,1,128,cfp);
// fwrite(testBuf,1,128,fp);
// fLen-=128;
// }
// else
// {
// cx_fread(testBuf,1,fLen,cfp);
// fwrite(testBuf,1,fLen,fp);
// fLen=0;
// }
//}
//fclose(fp);
//cx_fclose(cfp);
return TRUE;
}
BOOL StdioWrapperCleanup(void)
{
if (!sg_isFsInited) return TRUE;
/* close file system */
fat16_close(sg_fs);
/* close partition */
partition_close(sg_pPart);
BlkMdd_Cleanup();
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -