first submission

This commit is contained in:
qiyongshuang
2023-02-01 14:19:13 +08:00
parent d534aad004
commit b79c6ac80d
3711 changed files with 745432 additions and 2 deletions
@@ -0,0 +1,195 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : UDisk_Func_CreatDir.c
* Author : WCH
* Version : V1.0.0
* Date : 2022/11/22
* Description : USB full-speed port host operation functions.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
/*******************************************************************************/
/* Header File */
#include "Udisk_Operation.h"
/*******************************************************************************
* Function Name : CreateDirectory
* Description : 新建目录并打开,如果目录已经存在则直接打开,目录名在mCmdParam.Create.mPathName中,与文件名规则相同
* Input :
* Output : None
* Return : ERR_SUCCESS = 打开目录成功或者创建目录成功,
ERR_FOUND_NAME = 已经存在同名文件,
ERR_MISS_DIR = 路径名无效或者上级目录不存在
*******************************************************************************/
uint8_t CreateDirectory( void )
{
uint8_t i, j;
uint32_t UpDirCluster;
uint8_t * DirXramBuf;
uint8_t *DirConstData;
j = 0xFF;
for ( i = 0; i != sizeof( mCmdParam.Create.mPathName ); i ++ ) //检查目录路径
{
if ( mCmdParam.Create.mPathName[ i ] == 0 )
{
break;
}
if ( mCmdParam.Create.mPathName[ i ] == PATH_SEPAR_CHAR1 || mCmdParam.Create.mPathName[ i ] == PATH_SEPAR_CHAR2 )
{
j = i; //记录上级目录
}
}
i = ERR_SUCCESS;
if ( j == 0 || (j == 2 && mCmdParam.Create.mPathName[1] == ':') )
{
UpDirCluster = 0; //在根目录下创建子目录
}
else
{
if ( j != 0xFF ) //对于绝对路径应该获取上级目录的起始簇号
{
mCmdParam.Create.mPathName[ j ] = 0;
i = CHRV3FileOpen( ); //打开上级目录
if ( i == ERR_SUCCESS )
{
i = ERR_MISS_DIR; //是文件而非目录
}
else if ( i == ERR_OPEN_DIR )
{
i = ERR_SUCCESS; //成功打开上级目录
}
mCmdParam.Create.mPathName[ j ] = PATH_SEPAR_CHAR1; //恢复目录分隔符
}
UpDirCluster = CHRV3vStartCluster; //保存上级目录的起始簇号
}
if ( i == ERR_SUCCESS ) //成功获取上级目录的起始簇号
{
i = CHRV3FileOpen( ); //打开本级子目录
if ( i == ERR_SUCCESS )
{
i = ERR_FOUND_NAME; //是文件而非目录
}
else if ( i == ERR_OPEN_DIR )
{
i = ERR_SUCCESS; //目录已经存在
}
else if ( i == ERR_MISS_FILE ) //目录不存在,可以新建
{
i = CHRV3FileCreate( ); //以创建文件的方法创建目录
if ( i == ERR_SUCCESS )
{
if ( pDISK_FAT_BUF == pDISK_BASE_BUF )
{
memset(pDISK_FAT_BUF,0,CHRV3vSectorSize); //如果FILE_DATA_BUF与DISK_BASE_BUF合用则必须清除磁盘缓冲区
}
DirXramBuf = pDISK_FAT_BUF; //文件数据缓冲区
DirConstData = ". \x10\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x21\x30\x0\x0\x0\x0\x0\x0.. \x10\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x21\x30\x0\x0\x0\x0\x0\x0";
for ( i = 0x40; i != 0; i -- ) //目录的保留单元,分别指向自身和上级目录
{
*DirXramBuf = *DirConstData;
DirXramBuf ++;
DirConstData ++;
}
*(pDISK_FAT_BUF+0x1A) = ( (uint8_t *)&CHRV3vStartCluster )[3];//自身的起始簇号
*(pDISK_FAT_BUF+0x1B) = ( (uint8_t *)&CHRV3vStartCluster )[2];
*(pDISK_FAT_BUF+0x14) = ( (uint8_t *)&CHRV3vStartCluster )[1];
*(pDISK_FAT_BUF+0x15) = ( (uint8_t *)&CHRV3vStartCluster )[0];
*(pDISK_FAT_BUF+0x20+0x1A) = ( (uint8_t *)&UpDirCluster )[3];//上级目录的起始簇号
*(pDISK_FAT_BUF+0x20+0x1B) = ( (uint8_t *)&UpDirCluster )[2];
*(pDISK_FAT_BUF+0x20+0x14) = ( (uint8_t *)&UpDirCluster )[1];
*(pDISK_FAT_BUF+0x20+0x15) = ( (uint8_t *)&UpDirCluster )[0];
// for ( count = 0x40; count != CHRV3vSectorSizeH*256; count ++ ) { /* 清空目录区剩余部分 */
// *DirXramBuf = 0;
// DirXramBuf ++;
// }
mCmdParam.Write.mSectorCount = 1;
mCmdParam.Write.mDataBuffer = pDISK_FAT_BUF; //指向文件数据缓冲区的起始地址
i = CHRV3FileWrite( ); //向文件写入数据
if ( i == ERR_SUCCESS )
{
DirXramBuf = pDISK_FAT_BUF;
for ( i = 0x40; i != 0; i -- ) //清空目录区
{
*DirXramBuf = 0;
DirXramBuf ++;
}
for ( j = 1; j != CHRV3vSecPerClus; j ++ )
{
if ( pDISK_FAT_BUF == pDISK_BASE_BUF )
{
memset(pDISK_FAT_BUF,0,CHRV3vSectorSize); //如果FILE_DATA_BUF与DISK_BASE_BUF合用则必须清除磁盘缓冲区
}
mCmdParam.Write.mSectorCount = 1;
mCmdParam.Write.mDataBuffer = pDISK_FAT_BUF; //指向文件数据缓冲区的起始地址
i = CHRV3FileWrite( ); //清空目录的剩余扇区
if ( i != ERR_SUCCESS )
{
break;
}
}
if ( j == CHRV3vSecPerClus ) //成功清空目录
{
mCmdParam.Modify.mFileSize = 0; //目录的长度总是0
mCmdParam.Modify.mFileDate = 0xFFFF;
mCmdParam.Modify.mFileTime = 0xFFFF;
mCmdParam.Modify.mFileAttr = 0x10; //置目录属性
i = CHRV3FileModify( ); //将文件信息修改为目录
}
}
}
}
}
return( i );
}
/*********************************************************************
* @fn UDisk_USBH_CreatDirectory
*
* @brief Demo Function For UDisk Create Directory (EXAM9)
*
* @return none
*/
void UDisk_USBH_CreatDirectory( void )
{
uint8_t i;
uint8_t ret;
ret = UDisk_USBH_DiskReady( );
if( ( ret == DISK_READY )&&( UDisk_Opeation_Flag == 1 ) )
{
UDisk_Opeation_Flag = 0;
printf("CHRV3DiskStatus:%02x\r\n",CHRV3DiskStatus);
printf( "Create Level 1 Directory /YEAR2004 \r\n" );
strcpy( mCmdParam.Create.mPathName, "/YEAR2004" ); //目录名,该目录建在根目录下
ret = CreateDirectory( ); //新建或者打开目录
mStopIfError( ret );
/* 目录新建或者打开成功,下面在这个子目录中新建一个演示文件 */
printf( "Create New File /YEAR2004/DEMO2004.TXT \r\n" );
strcpy( mCmdParam.Create.mPathName, "/YEAR2004/DEMO2004.TXT" );//文件名
ret = CHRV3FileCreate( ); //新建文件并打开,如果文件已经存在则先删除后再新建
mStopIfError( ret );
printf( "Write some data to file DEMO2004.TXT \r\n" );
i = sprintf( Com_Buffer, "演示文件\xd\xa" );
mCmdParam.ByteWrite.mByteCount = i; //指定本次写入的字节数,单次读写的长度不能超过MAX_BYTE_IO
mCmdParam.ByteWrite.mByteBuffer = Com_Buffer; //指向缓冲区
ret = CHRV3ByteWrite( ); //以字节为单位向文件写入数据,单次读写的长度不能超过MAX_BYTE_IO
mStopIfError( ret );
printf( "Close file DEMO2004.TXT \r\n" );
mCmdParam.Close.mUpdateLen = 1; //自动计算文件长度,以字节为单位写文件,建议让程序库关闭文件以便自动更新文件长度
ret = CHRV3FileClose( );
mStopIfError( ret );
/* 下面新建二级子目录,方法与前面的一级子目录完全相同 */
printf( "Create Level 2 Directory /YEAR2004/MONTH05 \r\n" );
strcpy( mCmdParam.Create.mPathName, "/YEAR2004/MONTH05" ); //目录名,该目录建在YEAR2004子目录下,YEAR2004目录必须事先存在
ret = CreateDirectory( ); //新建或者打开目录
mStopIfError( ret );
printf( "Close\r\n" );
mCmdParam.Close.mUpdateLen = 0; //对于目录不需要自动更新文件长度
ret = CHRV3FileClose( ); //关闭目录,目录不需要关闭,关闭只是为了防止下面误操作
mStopIfError( ret );
}
}
@@ -0,0 +1,596 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : Udisk_Func_longname.c
* Author : WCH
* Version : V1.0.0
* Date : 2022/11/22
* Description : USB full-speed port host operation functions.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
/*******************************************************************************/
/* Header File */
#include "Udisk_Operation.h"
/*******************************************************************************/
/* Variable Definition */
uint8_t LongNameBuf[ LONG_NAME_BUF_LEN ];
/*
长文件名示例(UNICODE编码的大小端 必须与UNICODE_ENDIAN定义相同)
以下是LongName里编码内容:
建立长文件名,输入两个参数: 1.采用(unicode 大端),字符串末尾用两个0表示结束;2.ANSI编码短文件名.TXT
*/
uint8_t LongName[ ] =
#if UNICODE_ENDIAN == 1
{
0x5E, 0xFA, 0x7A, 0xCB, 0x95, 0x7F, 0x65, 0x87, 0x4E, 0xF6, 0x54, 0x0D, 0xFF, 0x0C, 0x8F, 0x93,
0x51, 0x65, 0x4E, 0x24, 0x4E, 0x2A, 0x53, 0xC2, 0x65, 0x70, 0xFF, 0x1A, 0x00, 0x20, 0x00, 0x31,
0x00, 0x2E, 0x91, 0xC7, 0x75, 0x28, 0x00, 0x28, 0x00, 0x75, 0x00, 0x6E, 0x00, 0x69, 0x00, 0x63,
0x00, 0x6F, 0x00, 0x64, 0x00, 0x65, 0x00, 0x20, 0x59, 0x27, 0x7A, 0xEF, 0x00, 0x29, 0xFF, 0x0C,
0x5B, 0x57, 0x7B, 0x26, 0x4E, 0x32, 0x67, 0x2B, 0x5C, 0x3E, 0x75, 0x28, 0x4E, 0x24, 0x4E, 0x2A,
0x00, 0x30, 0x88, 0x68, 0x79, 0x3A, 0x7E, 0xD3, 0x67, 0x5F, 0x00, 0x3B, 0x00, 0x32, 0x00, 0x2E,
0x00, 0x41, 0x00, 0x4E, 0x00, 0x53, 0x00, 0x49, 0x7F, 0x16, 0x78, 0x01, 0x77, 0xED, 0x65, 0x87,
0x4E, 0xF6, 0x54, 0x0D, 0x00, 0x2E, 0x00, 0x54, 0x00, 0x58, 0x00, 0x54
};
#else
{
0xFA, 0x5E, 0xCB, 0x7A, 0x7F, 0x95, 0x87, 0x65, 0xF6, 0x4E, 0x0D, 0x54, 0x0C, 0xFF, 0x93, 0x8F,
0x65, 0x51, 0x24, 0x4E, 0x2A, 0x4E, 0xC2, 0x53, 0x70, 0x65, 0x1A, 0xFF, 0x20, 0x00, 0x31, 0x00,
0x2E, 0x00, 0xC7, 0x91, 0x28, 0x75, 0x28, 0x00, 0x75, 0x00, 0x6E, 0x00, 0x69, 0x00, 0x63, 0x00,
0x6F, 0x00, 0x64, 0x00, 0x65, 0x00, 0x20, 0x00, 0x27, 0x59, 0xEF, 0x7A, 0x29, 0x00, 0x0C, 0xFF,
0x57, 0x5B, 0x26, 0x7B, 0x32, 0x4E, 0x2B, 0x67, 0x3E, 0x5C, 0x28, 0x75, 0x24, 0x4E, 0x2A, 0x4E,
0x30, 0x00, 0x68, 0x88, 0x3A, 0x79, 0xD3, 0x7E, 0x5F, 0x67, 0x3B, 0x00, 0x32, 0x00, 0x2E, 0x00,
0x41, 0x00, 0x4E, 0x00, 0x53, 0x00, 0x49, 0x00, 0x16, 0x7F, 0x01, 0x78, 0xED, 0x77, 0x87, 0x65,
0xF6, 0x4E, 0x0D, 0x54, 0x2E, 0x00, 0x54, 0x00, 0x58, 0x00, 0x54, 0x00
};
#endif
/*********************************************************************
* @fn UDisk_USBH_Longname
*
* @brief Demo Function For UDisk long-name Operation(EXAM 13)
*
* @return none
*/
void UDisk_USBH_Longname( void )
{
uint8_t ret, i, len;
uint16_t j;
ret = UDisk_USBH_DiskReady( );
if( ( ret == DISK_READY )&&( UDisk_Opeation_Flag == 1 ) )
{
UDisk_Opeation_Flag = 0;
/*==================== 以下演示创建及读取长文件名 ============================*/
// 复制长文件名(UNICODE 大端)到LongNameBuf里
len = LongName_Len;
memcpy( LongNameBuf, LongName, len );
// 末尾用两个0表示结束
LongNameBuf[len] = 0x00;
LongNameBuf[len + 1] = 0x00;
// 该长文件名的ANSI编码短文件名(8+3格式)
strcpy( mCmdParam.Create.mPathName, "\\长文件名.TXT" );
i = CHRV3CreateLongName( );
if( i == ERR_SUCCESS )
{
DUG_PRINTF( "Created Long Name OK!\r\n" );
}
else
{
/* Error code defined in "udisk_operaion.h" */
DUG_PRINTF( "Error Code: %02X\r\n", (uint16_t)i );
}
DUG_PRINTF( "Get long Name#\r\n" );
strcpy( mCmdParam.Open.mPathName, "\\长文件名.TXT" );
// 以上需要输入文件名的完整路径
i = CHRV3GetLongName( );
if( i == ERR_SUCCESS )
{
// 长文件名收集完成,以UNICODE编码方式(按UNICODE_ENDIAN定义)
// 存放在LongNameBuf缓冲里,长文件名最后用两个0结束.
// 以下显示缓冲区里所有数据
DUG_PRINTF( "LongNameBuf: " );
for( j=0; j!=LONG_NAME_BUF_LEN; j++ )
{
DUG_PRINTF( "%02X ", (uint16_t)LongNameBuf[j] );
}
DUG_PRINTF( "\r\n" );
}
else
{
/* Error code defined in "udisk_operaion.h" */
DUG_PRINTF( "Error Code: %02X\r\n", (uint16_t)i );
}
}
}
/*********************************************************************
* @fn CheckNameSum
*
* @brief 检查长文件名的短文件名检验和
*
* @return 计算后的校验和
*/
uint8_t CheckNameSum( uint8_t *p )
{
uint8_t FcbNameLen;
uint8_t Sum;
Sum = 0;
for (FcbNameLen=0; FcbNameLen!=11; FcbNameLen++)
Sum = ((Sum & 1) ? 0x80 : 0) + (Sum >> 1) + *p++;
return Sum;
}
/*********************************************************************
* @fn AnalyzeLongName
*
* @brief 整理长文件名 返回有几个的26长度
*
* @return 返回有多少个26的长度
*/
uint8_t AnalyzeLongName( void )
{
uint8_t i, j;
uint16_t index;
i = FALSE;
for( index=0; index!=LONG_NAME_BUF_LEN; index = index + 2 )
{
if( ( LongNameBuf[index] == 0 ) && ( LongNameBuf[index+1] == 0 ) )
{
i = TRUE;
break;
}
}
if( ( i == FALSE ) || ( index == 0) )
return 0; // 返回0表示错误的长文件名
i = index % 26;
if( i != 0 )
{
index += 2;
if( index % 26 != 0 ) // 加0刚好结束
{
for( j=i+2; j!=26; j++ )// 把剩余数据填为0XFF
LongNameBuf[index++] = 0xff;
}
}
return (index / 26);
}
/*********************************************************************
* @fn CHRV3CreateLongName
*
* @brief 创建长文件名,需要输入短文件名的完整路径
*
* @return 操作状态
*/
uint8_t CHRV3CreateLongName( void )
{
// 分析 保留文件路径 创建一个空文件 得到FDT偏移和其所在扇区 删除文件
// 向后偏移扇区 可能失败 如FAT12/16处在根目录处 填充完毕后再次创建文件
uint8_t i;
uint8_t len; // 存放路径的长度
uint16_t index; // 长文件偏移索引
uint16_t indexBak; // 长文件偏移索引备份
uint32_t Secoffset; // 扇区偏移
uint8_t Fbit; // 第一次进入写扇区
uint8_t Mult; // 长文件名长度26的倍数
uint8_t MultBak; // 长文件名长度26的倍数备份
uint16_t Backoffset; // 保存文件偏移备份
uint16_t BackoffsetBak; // 保存偏移备份的备份
uint32_t BackFdtSector; // 保寸偏移上一个扇区
uint8_t sum; // 保存长文件名的校验和
uint8_t BackPathBuf[MAX_PATH_LEN]; // 保存文件路径
Mult = AnalyzeLongName( ); // 保存长文件名是26的倍数
if( Mult == 0 )
return ERR_LONG_NAME;
MultBak = Mult;
i = CHRV3FileOpen(); // 短文件名存在则返回错误
if( i == ERR_SUCCESS )
return ERR_NAME_EXIST;
i = CHRV3FileCreate( );
if( i == ERR_SUCCESS )
{
Backoffset = CHRV3vFdtOffset;
BackoffsetBak = Backoffset;
BackFdtSector = CHRV3vFdtLba;
sum = CheckNameSum( &DISK_BASE_BUF[Backoffset ] );
for( i=0; i!=MAX_PATH_LEN; i++ ) // 对文件路径进行备份
BackPathBuf[i] = mCmdParam.Open.mPathName[i];
CHRV3FileErase( ); // 删除此文件
Secoffset = 0; // 从0开始偏移
index = Mult*26; // 得到长文件名的长度
indexBak = index;
Fbit = FALSE; // 默认没有进入
// 打开上级 进行数据填充数据
P_RETRY:
for(len=0; len!=MAX_PATH_LEN; len++)
{
if(mCmdParam.Open.mPathName[len] == 0)
break; // 得到字符串长度
}
for(i=len-1; i!=0xff; i--) // 得到上级目录位置
{
if((mCmdParam.Open.mPathName[i] == '\\') || (mCmdParam.Open.mPathName[i] == '/'))
break;
}
mCmdParam.Open.mPathName[i] = 0x00;
if( i==0 ) // 打开一级目录注意:处在根目录开始的特殊情况
{
mCmdParam.Open.mPathName[0] = '/';
mCmdParam.Open.mPathName[1] = 0;
}
i = CHRV3FileOpen(); // 打开上级目录
if( i == ERR_OPEN_DIR )
{
while( 1 ) // 循环填写 直到完成
{
mCmdParam.Locate.mSectorOffset = Secoffset;
i = CHRV3FileLocate( );
if( i == ERR_SUCCESS )
{
if( Fbit ) // 第二次进入次写扇区
{
if( mCmdParam.Locate.mSectorOffset != 0x0FFFFFFFF )
{
BackFdtSector = mCmdParam.Locate.mSectorOffset;
Backoffset = 0;
}
else
{
for( i=0; i!=MAX_PATH_LEN; i++ )// 还原文件路径
mCmdParam.Open.mPathName[i] = BackPathBuf[i];
i = CHRV3FileCreate( ); // 进行空间扩展
if( i != ERR_SUCCESS )
return i;
CHRV3FileErase( );
goto P_RETRY; // 重新打开上级目录
}
}
if( BackFdtSector == mCmdParam.Locate.mSectorOffset )
{
mCmdParam.Read.mSectorCount = 1; // 读一个扇区到磁盘缓冲区
mCmdParam.Read.mDataBuffer = &DISK_BASE_BUF[0];
i = CHRV3FileRead( );
CHRV3DirtyBuffer( ); // 清除磁盘缓冲区
if( i!= ERR_SUCCESS )
return i;
i = ( CHRV3vSectorSize - Backoffset ) / 32;
if( Mult > i )
Mult = Mult - i; // 剩余的倍数
else
{
i = Mult;
Mult = 0;
}
for( len=i; len!=0; len-- )
{
indexBak -= 26;
index = indexBak;
for( i=0; i!=5; i++) // 长文件名的1-5个字符
{ // 在磁盘上UNICODE用小端方式存放
#if UNICODE_ENDIAN == 1
DISK_BASE_BUF[Backoffset + i*2 + 2 ] =
LongNameBuf[index++];
DISK_BASE_BUF[Backoffset + i*2 + 1 ] =
LongNameBuf[index++];
#else
DISK_BASE_BUF[Backoffset + i*2 + 1 ] =
LongNameBuf[index++];
DISK_BASE_BUF[Backoffset + i*2 + 2 ] =
LongNameBuf[index++];
#endif
}
for( i =0; i!=6; i++) // 长文件名的6-11个字符
{
#if UNICODE_ENDIAN == 1
DISK_BASE_BUF[Backoffset + 14 + i*2 + 1 ] =
LongNameBuf[index++];
DISK_BASE_BUF[Backoffset + 14 + i*2 ] =
LongNameBuf[index++];
#else
DISK_BASE_BUF[Backoffset + 14 + i*2 ] =
LongNameBuf[index++];
DISK_BASE_BUF[Backoffset + 14 + i*2 + 1 ] =
LongNameBuf[index++];
#endif
}
for( i=0; i!=2; i++) // 长文件名的12-13个字符
{
#if UNICODE_ENDIAN == 1
DISK_BASE_BUF[Backoffset + 28 + i*2 + 1 ] =
LongNameBuf[index++];
DISK_BASE_BUF[Backoffset + 28 + i*2 ] =
LongNameBuf[index++];
#else
DISK_BASE_BUF[Backoffset + 28 + i*2 ] =
LongNameBuf[index++];
DISK_BASE_BUF[Backoffset + 28 + i*2 + 1 ] =
LongNameBuf[index++];
#endif
}
DISK_BASE_BUF[Backoffset + 0x0b] = 0x0f;
DISK_BASE_BUF[Backoffset + 0x0c] = 0x00;
DISK_BASE_BUF[Backoffset + 0x0d] = sum;
DISK_BASE_BUF[Backoffset + 0x1a] = 0x00;
DISK_BASE_BUF[Backoffset + 0x1b] = 0x00;
DISK_BASE_BUF[Backoffset] = MultBak--;
Backoffset += 32;
}
if( !Fbit )
{
Fbit = TRUE;
DISK_BASE_BUF[ BackoffsetBak ] |= 0x40;
}
CHRV3vLbaCurrent = BackFdtSector;
i = CHRV3WriteSector( 1, DISK_BASE_BUF );
if( i!= ERR_SUCCESS )
return i;
if( Mult==0 )
{ // 还原文件路径
CHRV3FileClose( );
for( i=0; i!=MAX_PATH_LEN; i++ )
mCmdParam.Open.mPathName[i] = BackPathBuf[i];
i = CHRV3FileCreate( );
return i;
}
}
}
else
return i;
Secoffset++;
}
}
}
return i;
}
/*********************************************************************
* @fn GetUpSectorData
*
* @brief 由当前扇区得到上一个扇区的数据,放在磁盘缓冲区
*
* @return 操作状态
*/
uint8_t GetUpSectorData( uint32_t *NowSector )
{
uint8_t i;
uint8_t len; // 存放路径的长度
uint32_t index; // 目录扇区偏移扇区数
index = 0;
for(len=0; len!=MAX_PATH_LEN; len++)
{
if(mCmdParam.Open.mPathName[len] == 0) // 得到字符串长度
break;
}
for(i=len-1; i!=0xff; i--) // 得到上级目录位置
{
if((mCmdParam.Open.mPathName[i] == '\\') || (mCmdParam.Open.mPathName[i] == '/'))
break;
}
mCmdParam.Open.mPathName[i] = 0x00;
if( i==0 ) // 打开一级目录注意:处在根目录开始的特殊情况
{
mCmdParam.Open.mPathName[0] = '/';
mCmdParam.Open.mPathName[1] = 0;
i = CHRV3FileOpen();
if ( i == ERR_OPEN_DIR )
goto P_NEXT0;
}
else
{
i = CHRV3FileOpen();
if ( i == ERR_OPEN_DIR )
{
while( 1 )
{
P_NEXT0:
mCmdParam.Locate.mSectorOffset = index;
i = CHRV3FileLocate( );
if( i == ERR_SUCCESS )
{
if( *NowSector == mCmdParam.Locate.mSectorOffset )
{
if( index==0 ) // 处于根目录扇区的开始
return ERR_NO_NAME;
mCmdParam.Locate.mSectorOffset = --index;
i = CHRV3FileLocate( ); // 读上一个扇区的数据
if( i == ERR_SUCCESS )
{ // 以下保存当前所在扇区数
*NowSector = mCmdParam.Locate.mSectorOffset;
mCmdParam.Read.mSectorCount = 1; // 读一个扇区到磁盘缓冲区
mCmdParam.Read.mDataBuffer = &DISK_BASE_BUF[0];
i = CHRV3FileRead( );
CHRV3DirtyBuffer( ); // 清除磁盘缓冲区
return i;
}
else
return i;
}
}
else
return i;
index++;
}
}
}
return i;
}
/*********************************************************************
* @fn CHRV3GetLongName
*
* @brief 由完整短文件名路径(可以是文件或文件夹)得到相应的长文件名
*
* @return 操作状态
*/
uint8_t CHRV3GetLongName( void )
{
// 需要变量扇区大小
// 第一步:打开文件是否找到文件,分析文件是否存在,并得到FDT在此扇区的偏移和所在扇区
// 第二步:分析上面的信息看是否有长文件名存在,是否处于目录的第一个扇区的开始
// 第三步:实现向后偏移一个扇区?读取长文件名(扇区512字节的U盘)
uint8_t i;
uint16_t index; // 在长文件名缓冲区内的索引
uint32_t BackFdtSector; // 保寸偏移上一个扇区
uint8_t sum; // 保存长文件名的校验和
//uint16_t Backoffset; // 保存文件偏移备份
uint16_t offset; // 扇区内文件偏移32倍数
uint8_t FirstBit; // 长文件名跨越两个扇区标志位
uint8_t BackPathBuf[MAX_PATH_LEN]; // 保存文件路径
i = CHRV3FileOpen( );
if( ( i == ERR_SUCCESS ) || ( i == ERR_OPEN_DIR ) )
{
for( i=0; i!=MAX_PATH_LEN; i++ )
BackPathBuf[i] = mCmdParam.Open.mPathName[i];
// 以上完成对路径的备份
sum = CheckNameSum( &DISK_BASE_BUF[CHRV3vFdtOffset] );
index = 0;
FirstBit = FALSE;
// Backoffset = CHRV3vFdtOffset;
BackFdtSector = CHRV3vFdtLba;
if( CHRV3vFdtOffset == 0 )
{
// 先判断是否处于一个扇区开始 是否处于根目录开始 ,否则向后偏移
if( FirstBit == FALSE )
FirstBit = TRUE;
i = GetUpSectorData( &BackFdtSector );
if( i == ERR_SUCCESS )
{
CHRV3vFdtOffset = CHRV3vSectorSize;
goto P_NEXT1;
}
}
else
{
// 读取偏移后的数据,直到结束。如果不够则向后偏移
P_NEXT1:
offset = CHRV3vFdtOffset;
while( 1 )
{
if( offset != 0 )
{
offset = offset - 32;
if( ( DISK_BASE_BUF[offset + 11] == ATTR_LONG_NAME )
&& ( DISK_BASE_BUF[offset + 13] == sum ) )
{
if( (index + 26) > LONG_NAME_BUF_LEN )
return ERR_BUF_OVER;
for( i=0; i!=5; i++) // 长文件名的1-5个字符
{ // 在磁盘上UNICODE用小端方式存放
#if UNICODE_ENDIAN == 1
LongNameBuf[index++] =
DISK_BASE_BUF[offset + i*2 + 2];
LongNameBuf[index++] =
DISK_BASE_BUF[offset + i*2 + 1];
#else
LongNameBuf[index++] =
DISK_BASE_BUF[offset + i*2 + 1];
LongNameBuf[index++] =
DISK_BASE_BUF[offset + i*2 + 2];
#endif
}
for( i =0; i!=6; i++) // 长文件名的6-11个字符
{
#if UNICODE_ENDIAN == 1
LongNameBuf[index++] =
DISK_BASE_BUF[offset + 14 + i*2 + 1];
LongNameBuf[index++] =
DISK_BASE_BUF[offset + + 14 + i*2 ];
#else
LongNameBuf[index++] =
DISK_BASE_BUF[offset + + 14 + i*2 ];
LongNameBuf[index++] =
DISK_BASE_BUF[offset + 14 + i*2 + 1];
#endif
}
for( i=0; i!=2; i++) // 长文件名的12-13个字符
{
#if UNICODE_ENDIAN == 1
LongNameBuf[index++] =
DISK_BASE_BUF[offset + 28 + i*2 + 1];
LongNameBuf[index++] =
DISK_BASE_BUF[offset + 28 + i*2 ];
#else
LongNameBuf[index++] =
DISK_BASE_BUF[offset + 28 + i*2 ];
LongNameBuf[index++] =
DISK_BASE_BUF[offset + 28 + i*2 + 1];
#endif
}
if( DISK_BASE_BUF[offset] & 0X40 )
{
if( ! (((LongNameBuf[index -1] ==0x00)
&& (LongNameBuf[index -2] ==0x00))
|| ((LongNameBuf[index -1] ==0xFF)
&& (LongNameBuf[index -2 ] ==0xFF))))
{ // 处理刚好为26字节长倍数的文件名
if(index + 52 >LONG_NAME_BUF_LEN )
return ERR_BUF_OVER;
LongNameBuf[ index ] = 0x00;
LongNameBuf[ index + 1] = 0x00;
}
return ERR_SUCCESS; // 成功完成长文件名收集完成
}
}
else
return ERR_NO_NAME; // 错误的长文件名,程序返回
}
else
{
if( FirstBit == FALSE )
FirstBit = TRUE;
else // 否则第二次进入
{
for( i=0; i!=MAX_PATH_LEN; i++ )// 还原路径
mCmdParam.Open.mPathName[i] = BackPathBuf[i];
}
i = GetUpSectorData( &BackFdtSector );
if( i == ERR_SUCCESS )
{
CHRV3vFdtOffset = CHRV3vSectorSize;
goto P_NEXT1;
}
else
return i;
// 向后偏移扇区
}
}
}
}
return i; // 返回错误
}
@@ -0,0 +1,317 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : UDisk_HW.c
* Author : WCH
* Version : V1.0.0
* Date : 2022/09/01
* Description : USB full-speed port host operation functions.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
/*******************************************************************************/
/* Header File */
#include "Udisk_Operation.h"
/*******************************************************************************/
/* Variable Definition */
__attribute__((aligned(4))) uint8_t Com_Buffer[ DEF_COM_BUF_LEN ]; // even address , used for host enumcation and udisk operation
__attribute__((aligned(4))) uint8_t DevDesc_Buf[ 18 ]; // Device Descriptor Buffer
struct _ROOT_HUB_DEVICE RootHubDev[ DEF_TOTAL_ROOT_HUB ];
struct __HOST_CTL HostCtl[ DEF_TOTAL_ROOT_HUB * DEF_ONE_USB_SUP_DEV_TOTAL ];
volatile uint8_t UDisk_Opeation_Flag = 0;
/*********************************************************************
* @fn mStopIfError
*
* @brief Checking the operation status, displaying the error code and stopping if there is an error
* input : iError - Error code input
*
* @return none
*/
void mStopIfError( uint8_t iError )
{
if ( iError == ERR_SUCCESS )
{
/* operation success, return */
return;
}
/* Display the errors */
DUG_PRINTF( "Error:%02x\r\n", iError );
/* After encountering an error, you should analyze the error code and CHRV3DiskStatus status, for example,
* call CHRV3DiskReady to check whether the current USB disk is connected or not,
* if the disk is disconnected then wait for the disk to be plugged in again and operate again,
* Suggested steps to follow after an error:
* 1, call CHRV3DiskReady once, if successful, then continue the operation, such as Open, Read/Write, etc.
* 2?If CHRV3DiskReady is not successful, then the operation will be forced to start from the beginning.
*/
while(1)
{ }
}
/*********************************************************************
* @fn Udisk_USBH_Initialization
*
* @brief USB Host Udisk process Initialization, include usb-host initialization
* usb libs initialization, udisk-related values Initialization
and the others
*
* @para none
*
* @return none
*/
void Udisk_USBH_Initialization( void )
{
/* USB Host Initialization */
printf( "USB Host & UDisk Lib Initialization. \r\n" );
/* Initialize USBFS host */
DUG_PRINTF( "USBFS Host Init\r\n" );
USBFS_RCC_Init( );
USBFS_Host_Init( ENABLE );
memset( &RootHubDev[ DEF_USB_PORT_FS ].bStatus, 0, sizeof( struct _ROOT_HUB_DEVICE ) );
memset( &HostCtl[ DEF_USB_PORT_FS ].InterfaceNum, 0, sizeof( struct __HOST_CTL ) );
/* USB Libs Initialization */
printf( "UDisk library Initialization. \r\n" );
CHRV3LibInit( );
}
/*********************************************************************
* @fn Udisk_USBH_EnumRootDevice
*
* @brief Generally enumerate a device connected to host port.
*
* @para index: USB host port
*
* @return Enumeration result
*/
uint8_t Udisk_USBH_EnumRootDevice( uint8_t usb_port )
{
uint8_t s;
uint8_t enum_cnt;
uint8_t cfg_val;
uint16_t i;
uint16_t len;
DUG_PRINTF( "Enum:\r\n" );
enum_cnt = 0;
ENUM_START:
/* Delay and wait for the device to stabilize */
Delay_Ms( 100 );
enum_cnt++;
Delay_Ms( 8 << enum_cnt );
/* Reset the USB device and wait for the USB device to reconnect */
USBFSH_ResetRootHubPort( 0 );
for( i = 0, s = 0; i < DEF_RE_ATTACH_TIMEOUT; i++ )
{
if( USBFSH_EnableRootHubPort( &RootHubDev[ usb_port ].bSpeed ) == ERR_SUCCESS )
{
i = 0;
s++;
if( s > 6 )
{
break;
}
}
Delay_Ms( 1 );
}
if( i )
{
/* Determine whether the maximum number of retries has been reached, and retry if not reached */
if( enum_cnt <= 5 )
{
goto ENUM_START;
}
return ERR_USB_DISCON;
}
/* Select USB speed */
USBFSH_SetSelfSpeed( RootHubDev[ usb_port].bSpeed );
/* Get USB device device descriptor */
DUG_PRINTF("Get DevDesc: ");
s = USBFSH_GetDeviceDescr( &RootHubDev[ usb_port ].bEp0MaxPks, DevDesc_Buf );
if( s == ERR_SUCCESS )
{
/* Print USB device device descriptor */
#if DEF_DEBUG_PRINTF
for( i = 0; i < 18; i++ )
{
DUG_PRINTF( "%02x ", DevDesc_Buf[ i ] );
}
DUG_PRINTF("\n");
#endif
}
else
{
/* Determine whether the maximum number of retries has been reached, and retry if not reached */
DUG_PRINTF( "Err(%02x)\n", s );
if( enum_cnt <= 5 )
{
goto ENUM_START;
}
return DEF_DEV_DESCR_GETFAIL;
}
/* Set the USB device address */
DUG_PRINTF("Set DevAddr: ");
RootHubDev[ usb_port ].bAddress = (uint8_t)( DEF_USB_PORT_FS + USB_DEVICE_ADDR );
s = USBFSH_SetUsbAddress( RootHubDev[ usb_port ].bEp0MaxPks, RootHubDev[ usb_port ].bAddress );
if( s == ERR_SUCCESS )
{
DUG_PRINTF( "OK\n" );
}
else
{
/* Determine whether the maximum number of retries has been reached, and retry if not reached */
DUG_PRINTF( "Err(%02x)\n", s );
if( enum_cnt <= 5 )
{
goto ENUM_START;
}
return DEF_DEV_ADDR_SETFAIL;
}
Delay_Ms( 5 );
/* Get the USB device configuration descriptor */
DUG_PRINTF("Get CfgDesc: ");
s = USBFSH_GetConfigDescr( RootHubDev[ usb_port ].bEp0MaxPks, Com_Buffer, DEF_COM_BUF_LEN, &len );
if( s == ERR_SUCCESS )
{
cfg_val = ( (PUSB_CFG_DESCR)Com_Buffer )->bConfigurationValue;
/* Print USB device configuration descriptor */
#if DEF_DEBUG_PRINTF
for( i = 0; i < len; i++ )
{
DUG_PRINTF( "%02x ", Com_Buffer[ i ] );
}
DUG_PRINTF("\n");
#endif
}
else
{
/* Determine whether the maximum number of retries has been reached, and retry if not reached */
DUG_PRINTF( "Err(%02x)\n", s );
if( enum_cnt <= 5 )
{
goto ENUM_START;
}
return DEF_CFG_DESCR_GETFAIL;
}
/* Set USB device configuration value */
DUG_PRINTF("Set Cfg: ");
s = USBFSH_SetUsbConfig( RootHubDev[ usb_port ].bEp0MaxPks, cfg_val );
if( s == ERR_SUCCESS )
{
DUG_PRINTF( "OK\n" );
}
else
{
/* Determine whether the maximum number of retries has been reached, and retry if not reached */
DUG_PRINTF( "Err(%02x)\n", s );
if( enum_cnt <= 5 )
{
goto ENUM_START;
}
return ERR_USB_UNSUPPORT;
}
return ERR_SUCCESS;
}
/*********************************************************************
* @fn UDisk_USBH_PreDeal
*
* @brief usb host preemption operations,
* including detecting device insertion and enumerating device information
*
* @return none
*/
uint8_t UDisk_USBH_PreDeal( void )
{
uint8_t usb_port;
uint8_t index;
uint8_t ret;
usb_port = DEF_USB_PORT_FS;
ret = USBFSH_CheckRootHubPortStatus( RootHubDev[ usb_port ].bStatus );
if( ret == ROOT_DEV_CONNECTED )
{
DUG_PRINTF("USB Dev In.\n");
USBFSH_CheckRootHubPortStatus( RootHubDev[ usb_port ].bStatus );
RootHubDev[ usb_port ].bStatus = ROOT_DEV_CONNECTED; // Set connection status_
RootHubDev[ usb_port ].DeviceIndex = usb_port * DEF_ONE_USB_SUP_DEV_TOTAL;
/* Enumerate root device */
ret = Udisk_USBH_EnumRootDevice( usb_port );
if( ret == ERR_SUCCESS )
{
DUG_PRINTF( "USB Port %02x Device Enumeration Succeed\r\n", usb_port );
RootHubDev[ usb_port ].bStatus = ROOT_DEV_SUCCESS;
return ERR_SUCCESS;
}
else
{
DUG_PRINTF( "USB Port %02x Device Enumeration ERR %02x.\r\n", usb_port, ret );
RootHubDev[ usb_port ].bStatus = ROOT_DEV_FAILED;
return ERR_USB_UNAVAILABLE;
}
}
else if( ret == ROOT_DEV_DISCONNECT )
{
DUG_PRINTF("USB Port %02x Device Out.\r\n", usb_port );
/* Clear parameters */
index = RootHubDev[ usb_port ].DeviceIndex;
memset( &RootHubDev[ usb_port ].bStatus, 0, sizeof( struct _ROOT_HUB_DEVICE ) );
memset( &HostCtl[ index ].InterfaceNum, 0, sizeof( struct __HOST_CTL ) );
UDisk_Opeation_Flag = 1;
CHRV3DiskStatus = DISK_UNKNOWN;
return ERR_USB_DISCON;
}
return ERR_USB_UNKNOWN;
}
/*********************************************************************
* @fn UDisk_USBH_DiskReady
*
* @brief Check if UDisk is Ready and update status in 'CHRV3DiskStatus'
*
* @return none
*/
uint8_t UDisk_USBH_DiskReady( void )
{
uint8_t ret, i;
/* Detect USB Device & Enumeration processing */
ret = UDisk_USBH_PreDeal( );
if( ret == ERR_SUCCESS )
{
/* Wait for uDisk Ready */
CHRV3DiskStatus = DISK_USB_ADDR;
for ( i = 0; i != 10; i ++ )
{
DUG_PRINTF( "Wait Disk Ready...\r\n" );
ret = CHRV3DiskReady( );
if ( ret == ERR_SUCCESS )
{
/* Disk Ready */
DUG_PRINTF( "Disk Ready Code:%02x.\r\n", ret );
DUG_PRINTF( "CHRV3DiskStatus:%02x\n", CHRV3DiskStatus);
UDisk_Opeation_Flag = 1;
return DISK_READY;
}
else
{
DUG_PRINTF("Not Ready Code :%02x.\r\n", ret);
DUG_PRINTF("CHRV3DiskStatus:%02x.\n", CHRV3DiskStatus);
}
Delay_Ms( 50 );
}
}
return CHRV3DiskStatus;
}
@@ -0,0 +1,78 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : UDisk_Operation.h
* Author : WCH
* Version : V1.0.0
* Date : 2022/11/20
* Description : This file contains all the functions prototypes for the Udisk
host operation.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef USER_UDISK_OPERATION_H_
#define USER_UDISK_OPERATION_H_
#include "debug.h"
#include "string.h"
#include "CHRV3UFI.h"
#include "ch32v20x_usbfs_host.h"
#include "usb_host_config.h"
/*******************************************************************************/
/* Public Extern Variables */
extern volatile uint8_t UDisk_Opeation_Flag;
extern struct _ROOT_HUB_DEVICE RootHubDev[ DEF_TOTAL_ROOT_HUB ];
extern struct __HOST_CTL HostCtl[ DEF_TOTAL_ROOT_HUB * DEF_ONE_USB_SUP_DEV_TOTAL ];
extern volatile uint8_t UDisk_Opeation_Flag;
extern uint8_t *pCodeStr;
extern __attribute__((aligned(4))) uint8_t Com_Buffer[ DEF_COM_BUF_LEN ]; // even address , used for host enumcation and udisk operation
extern __attribute__((aligned(4))) uint8_t DevDesc_Buf[ 18 ]; // Device Descriptor Buffer
/*******************************************************************************/
/* 长文件名相关的宏定义极其全局变量 */
// 长文件名缓冲区从(0到20)*26
#define LONG_NAME_BUF_LEN (20*26)
#define UNICODE_ENDIAN 0 // 1为UNICDOE大端编码 0为小端
// 长文件名存放缓冲区(Unicode编码)
extern uint8_t LongNameBuf[ ];
// 长文件名(Unicode编码)
extern uint8_t LongName[ ];
#define LongName_Len 124
#define TRUE 1
#define FALSE 0
// 函数返回
#define ERR_NO_NAME 0X44 // 此短文件名没有长文件名或错误的长文件
#define ERR_BUF_OVER 0X45 // 长文件缓冲区溢出
#define ERR_LONG_NAME 0X46 // 错误的长文件名
#define ERR_NAME_EXIST 0X47 // 此短文件名存在
/*******************************************************************************/
/* Extern UDisk Operation Functions */
extern void mStopIfError( uint8_t iError );
extern void Udisk_USBH_Initialization( void );
extern uint8_t Udisk_USBH_EnumRootDevice( uint8_t usb_port );
extern uint8_t UDisk_USBH_PreDeal( void );
extern uint8_t UDisk_USBH_DiskReady( void );
/* Extern Long-name Operation Functions */
extern void UDisk_USBH_Longname( void );
extern uint8_t CHRV3GetLongName( void );
extern uint8_t GetUpSectorData( uint32_t *NowSector );
extern uint8_t CHRV3CreateLongName( void );
extern uint8_t AnalyzeLongName( void );
extern uint8_t CheckNameSum( uint8_t *p );
/* Extern Creating Directory Functions */
extern void UDisk_USBH_CreatDirectory( void );
extern uint8_t CreateDirectory( void );
/* Extern Byte/Sector Open/Read/Modify/Delete and File-Enumeration Functions */
extern void UDisk_USBH_ByteOperation( void );
extern void UDisk_USBH_SectorOperation( void );
extern void UDisk_USBH_EnumFiles( void );
#endif /* USER_UDISK_OPERATION_H_ */
@@ -0,0 +1,345 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : Udisk_Func_BasicOp.c
* Author : WCH
* Version : V1.0.0
* Date : 2022/11/22
* Description : USB full-speed port host operation functions.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
/*******************************************************************************/
/* Header File */
#include "Udisk_Operation.h"
uint8_t *pCodeStr;
/*******************************************************************************/
/* Variable Definition */
__attribute__((aligned(4))) uint8_t MY_DATA_BUF[ DISK_BASE_BUF_LEN ]; /* MY_DATA_BUF指向外部RAM的磁盘数据缓冲区,缓冲区长度为至少一个扇区的长度,用于用户数据缓存 */
uint8_t *pCodeStr;
/*********************************************************************
* @fn UDisk_USBH_ByteOperation
*
* @brief Demo Function For UDisk File Byte-operation
* including Create\Modify\Read\Erase (EXAM1)
*
* @return none
*/
void UDisk_USBH_ByteOperation( void )
{
uint8_t ret;
uint8_t i,t;
uint16_t TotalCount = 0;
ret = UDisk_USBH_DiskReady( );
if( (ret == DISK_READY)&&( UDisk_Opeation_Flag == 1 ) )
{
UDisk_Opeation_Flag = 0;
printf("CHRV3DiskStatus:%02x\r\n",CHRV3DiskStatus);
/* 读文件 */
strcpy( (char *)mCmdParam.Open.mPathName, "/C51/NEWFILE.C" ); //设置将要操作的文件路径和文件名/C51/NEWFILE.C
ret = CHRV3FileOpen( ); //打开文件
if ( ret == ERR_MISS_DIR || ret == ERR_MISS_FILE ) //没有找到文件
{
//创建文件演示
printf( "Find No File And Create\r\n" );
strcpy( (char *)mCmdParam.Create.mPathName, "/C51/NEWFILE.C" ); //新文件名,在根目录下,中文文件名
ret = CHRV3FileCreate( ); //新建文件并打开,如果文件已经存在则先删除后再新建
mStopIfError( ret );
printf( "ByteWrite\r\n" );
//实际应该判断写数据长度和定义缓冲区长度是否相符,如果大于缓冲区长度则需要多次写入
i = sprintf( (char *)Com_Buffer,"Note: \xd\xa这个程序是以字节为单位进行U盘文件读写,简单演示功能。\xd\xa");
for(t=0; t<10; t++)
{
mCmdParam.ByteWrite.mByteCount = i; //指定本次写入的字节数
mCmdParam.ByteWrite.mByteBuffer = Com_Buffer; //指向缓冲区
ret = CHRV3ByteWrite( ); //以字节为单位向文件写入数据
mStopIfError( ret );
printf("成功写入 %02X次\r\n",(uint16_t)t);
}
//演示修改文件属性
printf( "Modify\r\n" );
mCmdParam.Modify.mFileAttr = 0xff; //输入参数: 新的文件属性,为0FFH则不修改
mCmdParam.Modify.mFileTime = 0xffff; //输入参数: 新的文件时间,为0FFFFH则不修改,使用新建文件产生的默认时间
mCmdParam.Modify.mFileDate = MAKE_FILE_DATE( 2015, 5, 18 ); //输入参数: 新的文件日期: 2015.05.18
mCmdParam.Modify.mFileSize = 0xffffffff; // 输入参数: 新的文件长度,以字节为单位写文件应该由程序库关闭文件时自动更新长度,所以此处不修改
i = CHRV3FileModify( ); //修改当前文件的信息,修改日期
mStopIfError( i );
printf( "Close\r\n" );
mCmdParam.Close.mUpdateLen = 1; //自动计算文件长度,以字节为单位写文件,建议让程序库关闭文件以便自动更新文件长度
i = CHRV3FileClose( );
mStopIfError( i );
/* 删除某文件 */
// printf( "Erase\n" );
// strcpy( (char *)mCmdParam.Create.mPathName, "/OLD" ); //将被删除的文件名,在根目录下
// i = CHRV3FileErase( ); //删除文件并关闭
// if ( i != ERR_SUCCESS ) printf( "Error: %02X\n", (uint16_t)i ); //显示错误
}
else
{
/* 一、写入文件 */
printf( "ByteWrite\r\n" ); //如果希望将新数据添加到原文件的尾部,可以移动文件指针
mCmdParam.ByteLocate.mByteOffset = 0xffffffff; //移到文件的尾部
CHRV3ByteLocate( ); //实际应该判断写数据长度和定义缓冲区长度是否相符,如果大于缓冲区长度则需要多次写入
i = sprintf( (char *)Com_Buffer,"Note: \xd\xa这个程序是以字节为单位进行U盘文件读写,简单演示功能。\xd\xa"); //演示文字
for(t=0; t<10; t++)
{
mCmdParam.ByteWrite.mByteCount = i; //指定本次写入的字节数
mCmdParam.ByteWrite.mByteBuffer = Com_Buffer; // 指向缓冲区
ret = CHRV3ByteWrite( ); // 以字节为单位向文件写入数据
mStopIfError( ret );
printf("成功写入 %02X次\r\n",(uint16_t)t);
}
/* 二、读取文件前N字节 */
TotalCount = 60; //设置准备读取总长度100字节
strcpy( (char *)mCmdParam.Open.mPathName, "/C51/NEWFILE.C" ); //设置将要操作的文件路径和文件名/C51/NEWFILE.C
CHRV3FileOpen( ); //打开文件
printf( "读出的前%d个字符是:\r\n",TotalCount );
while ( TotalCount )
{
//如果文件比较大,一次读不完,可以再调用CH103ByteRead继续读取,文件指针自动向后移动
if ( TotalCount > (MAX_PATH_LEN-1) )
{
t = MAX_PATH_LEN-1; // 剩余数据较多,限制单次读写的长度不能超过 sizeof( mCmdParam.Other.mBuffer )
}
else
{
t = TotalCount; //最后剩余的字节数
}
mCmdParam.ByteRead.mByteCount = t; //请求读出几十字节数据
mCmdParam.ByteRead.mByteBuffer= &Com_Buffer[0];
ret = CHRV3ByteRead( ); //以字节为单位读取数据块,单次读写的长度不能超过MAX_BYTE_IO,第二次调用时接着刚才的向后读
TotalCount -= mCmdParam.ByteRead.mByteCount; //计数,减去当前实际已经读出的字符数
for ( i=0; i!=mCmdParam.ByteRead.mByteCount; i++ )
{
printf( "%c", mCmdParam.ByteRead.mByteBuffer[i] ); //显示读出的字符
}
printf( "\r\n" );
if ( mCmdParam.ByteRead.mByteCount < t ) //实际读出的字符数少于要求读出的字符数,说明已经到文件的结尾
{
printf( "\r\n" );
printf( "文件已经结束\r\n" );
break;
}
}
i = CHRV3FileClose( ); //关闭文件
mStopIfError( i );
}
}
}
/*********************************************************************
* @fn UDisk_USBH_SectorOperation
*
* @brief Demo Function For UDisk File Sector-operation
* including Create\Modify\Read\Erase (EXAM6)
*
* @return none
*/
void UDisk_USBH_SectorOperation( void )
{
uint8_t ret, SecCount, s;
uint8_t i;
uint16_t tmp;
uint8_t tmpbuf[64];
ret = UDisk_USBH_DiskReady( );
if( ( ret == DISK_READY )&&( UDisk_Opeation_Flag == 1 ) )
{
UDisk_Opeation_Flag = 0;
/* 查询磁盘物理容量 */
printf( "DiskSize\r\n" );
i = CHRV3DiskQuery( );
mStopIfError( i );
printf( "TotalSize = %u MB \n", (unsigned int)( mCmdParam.Query.mTotalSector * CHRV3vSectorSizeB / 2 ) ); //显示为以MB为单位的容量
/* 读取原文件 */
printf( "Open\r\n" );
strcpy( mCmdParam.Open.mPathName, "/NEWFILE.TXT" );//文件名,该文件在C51子目录下
s = CHRV3FileOpen( ); //打开文件
if ( s == ERR_MISS_DIR || s == ERR_MISS_FILE )//没有找到文件
{
printf( "没有找到文件\r\n" );
}
else //找到文件或者出错
{
printf( "Query\r\n" );
i = CHRV3FileQuery( ); //查询当前文件的信息
mStopIfError( i );
printf( "Read\r\n" );
CHRV3vFileSize = CHRV3vFileSize+(sizeof( MY_DATA_BUF )-1); //原文件的长度
SecCount = CHRV3vFileSize/ sizeof( MY_DATA_BUF ) ;//计算文件的扇区数,因为读写是以扇区为单位的,先加CHRV3vSectorSize-1是为了读出文件尾部不足1个扇区的部分
printf( "Size=%ld, Sec=%d\r\n", CHRV3vFileSize, (uint16_t)SecCount );
while(SecCount--)
{
mCmdParam.Read.mSectorCount = sizeof( MY_DATA_BUF )/512; //读取全部数据,如果超过2个扇区则只读取2个扇区
mCmdParam.Read.mDataBuffer = &MY_DATA_BUF[0];//指向文件数据缓冲区的起始地址
i = CHRV3FileRead( ); //从文件读取数据
mStopIfError( i );
if(SecCount == 0) break;
/*
for(tmp=0; tmp<sizeof( MY_DATA_BUF ); tmp++)
{
printf("%02X ",(uint16_t)MY_DATA_BUF[tmp]);
}
printf("\n");
*/
}
tmp = (CHRV3vFileSize-(sizeof( MY_DATA_BUF )-1))%sizeof( MY_DATA_BUF );
if((tmp == 0)&&(CHRV3vFileSize != 0)) tmp = sizeof( MY_DATA_BUF );
CHRV3vFileSize = CHRV3vFileSize-(sizeof( MY_DATA_BUF )-1); //恢复原文件的长度
/*
for(i=0; i<tmp; i++)
{
printf("%02X ",(uint16_t)MY_DATA_BUF[i]);
}
printf("\n");
*/
/*
如果文件比较大,一次读不完,可以再调用CHRV3FileRead继续读取,文件指针自动向后移动
while ( 1 )
{
c = 4; 每次读取4个扇区,缓冲区定义的越大,一次读取的扇区数越多
mCmdParam.Read.mSectorCount = c; 指定读取的扇区数
mCmdParam.Read.mDataBuffer = &MY_DATA_BUF[0]; 指向文件数据缓冲区的起始地址
CHRV3FileRead(); 读完后文件指针自动后移 处理数据
if ( mCmdParam.Read.mSectorCount < c ) break; 实际读出的扇区数较小则说明文件已经结束
}
如果希望从指定位置开始读写,可以移动文件指针
mCmdParam.Locate.mSectorOffset = 3; 跳过文件的前3个扇区开始读写
i = CHRV3FileLocate( );
mCmdParam.Read.mSectorCount = 10;
mCmdParam.Read.mDataBuffer = &MY_DATA_BUF[0]; 指向文件数据缓冲区的起始地址
CHRV3FileRead(); 直接读取从文件的第(CHRV3vSectorSizeH*256*3)个字节开始的数据,前3个扇区被跳过
如果希望将新数据添加到原文件的尾部,可以移动文件指针
i = CHRV3FileOpen( );
mCmdParam.Locate.mSectorOffset = 0xffffffff; 移到文件的尾部,以扇区为单位,如果原文件是3字节,则从CHRV3vSectorSizeH个字节处开始添加
i = CHRV3FileLocate( );
mCmdParam.Write.mSectorCount = 10;
mCmdParam.Write.mDataBuffer = &MY_DATA_BUF[0];
CHRV3FileWrite(); 在原文件的后面添加数据
使用CHRV3FileRead可以自行定义数据缓冲区的起始地址
mCmdParam.Read.mSectorCount = 2;
mCmdParam.Read.mDataBuffer = 0x50; 将读出的数据放到50H开始的缓冲区中,需要指定缓冲区的起始地址
CHRV3FileRead(); 从文件中读取2个扇区到指定缓冲区
使用CHRV3FileWrite可以自行定义数据缓冲区的起始地址
mCmdParam.Wiite.mSectorCount = 2;
mCmdParam.Write.mDataBuffer = 0x50; 将50H开始的缓冲区中的数据写入
CHRV3FileWrite(); 将指定缓冲区中的数据写入2个扇区到文件中
*/
printf( "Close\r\n" );
i = CHRV3FileClose( ); //关闭文件
mStopIfError( i );
}
printf( "Create\r\n" );
strcpy( mCmdParam.Create.mPathName, "/NEWFILE.TXT" );//新文件名,在根目录下,中文文件名
s = CHRV3FileCreate( ); //新建文件并打开,如果文件已经存在则先删除后再新建 */
mStopIfError( s );
printf( "Write\r\n" );
strcpy( tmpbuf, "0000ABCDEFGHIJKLMNOPQRSTUVWXYZ\xd\xa" );//准备写文件数据
for(i=0; i<(DISK_BASE_BUF_LEN/sizeof(tmpbuf)); i++)
{
tmp=i*sizeof(tmpbuf);
strcpy(&MY_DATA_BUF[tmp],tmpbuf);
}
for(tmp=0; tmp<sizeof(MY_DATA_BUF); tmp++)
{
printf("%02X",(uint16_t)MY_DATA_BUF[tmp]);
}
printf("\r\n");
for(s=0; s<10; s++)
{
mCmdParam.Write.mSectorCount = 1; //写入所有扇区的数据
mCmdParam.Write.mDataBuffer = &MY_DATA_BUF[0]; //指向文件数据缓冲区的起始地址
i = CHRV3FileWrite( ); //向文件写入数据
mStopIfError( i );
printf("成功写入 %02X次\r\n",(uint16_t)s);
}
/* printf( "Modify\n" );
mCmdParam.Modify.mFileAttr = 0xff; 输入参数: 新的文件属性,为0FFH则不修改
mCmdParam.Modify.mFileTime = 0xffff; 输入参数: 新的文件时间,为0FFFFH则不修改,使用新建文件产生的默认时间
mCmdParam.Modify.mFileDate = MAKE_FILE_DATE( 2015, 5, 18 ); 输入参数: 新的文件日期: 2015.05.18
mCmdParam.Modify.mFileSize = 0xffffffff; 输入参数: 新的文件长度,以字节为单位写文件应该由程序库关闭文件时自动更新长度,所以此处不修改
i = CHRV3FileModify( ); 修改当前文件的信息,修改日期
mStopIfError( i );
*/
printf( "Close\r\n" );
mCmdParam.Close.mUpdateLen = 1; //自动计算文件长度,以字节为单位写文件,建议让程序库关闭文件以便自动更新文件长度
i = CHRV3FileClose( );
mStopIfError( i );
/* 删除某文件 */
/*printf( "Erase\n" );
strcpy( mCmdParam.Create.mPathName, "/OLD.TXT" ); 将被删除的文件名,在根目录下
i = CHRV3FileErase( ); 删除文件并关闭
if ( i != ERR_SUCCESS ) printf( "Error File not exist: %02X\n", (uint16_t)i ); 显示错误
*/
printf( "U盘演示完成\r\n" );
}
}
/*********************************************************************
* @fn UDisk_USBH_EnumFiles
*
* @brief Demo Function For Enumerating files in UDisk(EXAM11)
*
* @return none
*/
void UDisk_USBH_EnumFiles( void )
{
uint8_t i, s, ret;
uint16_t j;
ret = UDisk_USBH_DiskReady( );
if( ( ret == DISK_READY )&&( UDisk_Opeation_Flag == 1 ) )
{
UDisk_Opeation_Flag = 0;
/* 读取原文件 */
printf( "Open\r\n" );
strcpy( mCmdParam.Open.mPathName, "/C51/CHRV3HFT.C" );//文件名,该文件在C51子目录下
s = CHRV3FileOpen( ); //打开文件
/* 列出文件 */
if ( s == ERR_MISS_DIR )
{
printf("不存在该文件则列出所有文件\r\n"); //C51子目录不存在则列出根目录下的所有文件
pCodeStr = "/*";
}
else
{
pCodeStr = "/C51/*"; //CHRV3HFT.C文件不存在则列出\C51子目录下的以CHRV3开头的文件
}
printf( "List file %s\r\n", pCodeStr );
for ( j = 0; j < 10000; j ++ ) //最多搜索前10000个文件,实际上没有限制
{
strcpy( (char *)mCmdParam.Open.mPathName, pCodeStr );//搜索文件名,*为通配符,适用于所有文件或者子目录
i = strlen( mCmdParam.Open.mPathName );
mCmdParam.Open.mPathName[ i ] = 0xFF; //根据字符串长度将结束符替换为搜索的序号,从0到254,如果是0xFF即255则说明搜索序号在CHRV3vFileSize变量中
CHRV3vFileSize = j; //指定搜索/枚举的序号
i = CHRV3FileOpen( ); //打开文件,如果文件名中含有通配符*,则为搜索文件而不打开
/* CHRV3FileEnum 与 CHRV3FileOpen 的唯一区别是当后者返回ERR_FOUND_NAME时那么对应于前者返回ERR_SUCCESS */
if ( i == ERR_MISS_FILE )
{
break; //再也搜索不到匹配的文件,已经没有匹配的文件名
}
if ( i == ERR_FOUND_NAME )
{
/* 搜索到与通配符相匹配的文件名,文件名及其完整路径在命令缓冲区中 */
printf( " match file %04d#: %s\r\n", (unsigned int)j, mCmdParam.Open.mPathName );//显示序号和搜索到的匹配文件名或者子目录名
continue; //继续搜索下一个匹配的文件名,下次搜索时序号会加1
}
else
{
/* 出错 */
mStopIfError( i );
break;
}
}
printf( "Close\r\n" );
CHRV3FileClose( ); //关闭文件
printf( "U盘演示完成\r\n" );
}
}