一. 前言
我们现在已经实现了通过shell使用xmodem协议进行文件的导入导出,现在我们继续来实现文件操作的一些常见shell命令,比如查看文件,ls,移动我呢见mv等。
二. 实现ls
shell_func.c中申明实现函数
static void lsfilefunc(uint8_t* param);
g_shell_cmd_list_ast中添加一行
{ (uint8_t*)"ls", lsfilefunc, (uint8_t*)"ls path"},
实现函数如下
/* List contents of a directory */
static FRESULT list_dir (const char *path)
{
FRESULT res;
DIR dir;
FILINFO fno;
int nfile, ndir;
res = f_opendir(&dir, path); /* Open the directory */
if (res == FR_OK) {
nfile = ndir = 0;
for (;;) {
res = f_readdir(&dir, &fno); /* Read a directory item */
if (res != FR_OK || fno.fname[0] == 0) break; /* Error or end of dir */
if (fno.fattrib & AM_DIR) { /* Directory */
xprintf(" <DIR> %s\n", fno.fname);
ndir++;
} else { /* File */
xprintf("%10u %s\n", fno.fsize, fno.fname);
nfile++;
}
}
f_closedir(&dir);
printf("%d dirs, %d files.\n", ndir, nfile);
} else {
xprintf("Failed to open \"%s\". (%u)\n", path, res);
}
return res;
}
void lsfilefunc(uint8_t* param)
{
char path[128];
if(1 == sscanf((const char*)param, "%*s %s", path))
{
list_dir((const char *)path);
}
else
{
printf("param err");
}
}
Help查看命令
ls查看文件
三. 实现mv
使用rename实现
四. 实现cp
shell_func.c中申明实现函数
static void cpfilefunc(uint8_t* param);
g_shell_cmd_list_ast中添加一行
{ (uint8_t*)"cp", cpfilefunc, (uint8_t*)"cp srcpath dstpath"},
实现函数如下
void cpfilefunc(uint8_t* param)
{
char srcpath[128];
char dstpath[128];
uint8_t tmp[32];
FIL srcfil;
FIL dstfil;
UINT bw;
UINT br;
FRESULT res;
if(2 == sscanf((const char*)param, "%*s %s %s", srcpath, dstpath))
{
xprintf("cp %d to %s\r\n",srcpath,dstpath);
res = f_open(&srcfil, srcpath, FA_READ);
if(res == FR_OK)
{
res = f_open(&dstfil, dstpath, FA_CREATE_NEW | FA_WRITE);
if(res == FR_OK)
{
do
{
res = f_read(&srcfil, tmp, sizeof(tmp), &br);
if(res == 0)
{
res = f_write(&dstfil, tmp, br, &bw);
if ((bw != br) || (res != 0))
{
xprintf("write err %d %d\r\n",bw,res);
break;
}
}
else
{
xprintf("read err %d\r\n",res);
break;
}
}while(br > 0);
f_close(&dstfil);
f_close(&srcfil);
}
else
{
f_close(&srcfil);
xprintf("open %s err %d\r\n",dstpath,res);
}
}
else
{
xprintf("open %s err %d\r\n",srcpath,res);
}
}
else
{
xprintf("param err");
}
}
Help查看命令
ls查看文件,cp复制一份,ls再查看
五. 实现rm
shell_func.c中申明实现函数
static void rmfilefunc(uint8_t* param);
g_shell_cmd_list_ast中添加一行
{ (uint8_t*)"rm", rmfilefunc, (uint8_t*)"rm path"},
实现函数如下
void rmfilefunc(uint8_t* param)
{
FRESULT res;
char path[128];
if(1 == sscanf((const char*)param, "%*s %s", path))
{
if(FR_OK != (res = f_unlink((const char *)path)))
{
printf("unlink %s err %d\r\n",path,res);
}
}
else
{
printf("param err");
}
}
help查看命令
ls查看文件
rm删除文件
ls再查看是否删除
六. 实现rename
shell_func.c中申明实现函数
static void renamefilefunc(uint8_t* param);
g_shell_cmd_list_ast中添加一行
{ (uint8_t*)"rename", renamefilefunc, (uint8_t*)"rename path newpath"},
实现函数如下
void renamefilefunc(uint8_t* param)
{
FRESULT res;
char path[128];
char newpath[128];
if(2 == sscanf((const char*)param, "%*s %s %s", path, newpath))
{
if(FR_OK != (res = f_rename((const char *)path, (const char*)newpath)))
{
xprintf("rename %s to %s err %d\r\n",path,newpath,res);
}
}
else
{
xprintf("param err");
}
}
help查看命令
ls查看文件
rename修改名字
ls看名字是否修改
七. 实现mkdir
shell_func.c中申明实现函数
static void mkdirfunc(uint8_t* param);
g_shell_cmd_list_ast中添加一行
{ (uint8_t*)"mkdir", mkdirfunc, (uint8_t*)"mkdir path"},
实现函数如下
void mkdirfunc(uint8_t* param)
{
char path[128];
FRESULT res;
if(1 == sscanf((const char*)param, "%*s %s", path))
{
if(FR_OK != (res=f_mkdir((const char*)path)))
{
xprintf("mkdir %s err %d",path,res);
}
}
else
{
xprintf("param err");
}
}
help查看命令
mkdir创建命令,然后ls查看
八. 实现touch
shell_func.c中申明实现函数
static void touchfunc(uint8_t* param);
g_shell_cmd_list_ast中添加一行
{ (uint8_t*)"touch", touchfunc, (uint8_t*)"touch path size"},
实现函数如下
需要配置宏
#define FF_USE_EXPAND 1
void touchfunc(uint8_t* param)
{
FIL fil;
char path[128];
int size;
if(2 == sscanf((const char*)param, "%*s %s %d", path, &size))
{
FRESULT res = f_open(&fil, path, FA_CREATE_NEW | FA_WRITE);
if (FR_OK == res)
{
if(FR_OK != (res = f_expand(&fil,size,1)))
{
xprintf("expand %s size to %d err %d\r\n",path,size,res);
}
if(FR_OK != (res = f_close(&fil)))
{
xprintf("close %s err %d\r\n",path,res);
}
}
else
{
xprintf("open %s err %d\r\n",path,res);
}
}
else
{
xprintf("param err");
}
}
Help查看命令
touch创建一个文件
ls查看
九. 实现pwd
shell_func.c中申明实现函数
static void pwdfunc(uint8_t* param);
g_shell_cmd_list_ast中添加一行
{ (uint8_t*)"pwd", pwdfunc, (uint8_t*)"pwd"},
实现函数如下
以下宏要配置为2
#define FF_FS_RPATH 2
void pwdfunc(uint8_t* param)
{
FRESULT fr;
TCHAR str[128];
if(FR_OK != (fr = f_getcwd(str, 128))) /* Get current directory path */
{
xprintf("getcwd err %d\r\n",fr);
}
else
{
xprintf("%s\r\n",str);
}
}
help查看命令
pwd查看当前目录
十. 实现cd
shell_func.c中申明实现函数
static void cdfunc(uint8_t* param);
g_shell_cmd_list_ast中添加一行
{ (uint8_t*)"cd", cdfunc, (uint8_t*)"cd path"},
实现函数如下
以下宏要大于等于1 ,这里还要使用f_getcwd所以设置为2
#define FF_FS_RPATH 2
void cdfunc(uint8_t* param)
{
char path[128];
FRESULT res;
if(1 == sscanf((const char*)param, "%*s %s", path))
{
if(FR_OK != (res=f_chdir((const char*)path)))
{
xprintf("chdir to %s err %d",path,res);
}
}
else
{
xprintf("param err");
}
}
help查看命令
cd进入子目录,pwd再查看当前目录
十一. 实现hexdump
shell_func.c中申明实现函数
static void hexdumpfunc(uint8_t* param);
g_shell_cmd_list_ast中添加一行
{ (uint8_t*)"hexdump", hexdumpfunc, (uint8_t*)"hexdump path addr size"},
实现函数如下
void hexdumpfunc(uint8_t* param)
{
char path[128];
uint8_t tmp[16];
uint32_t addr;
uint32_t size;
FRESULT res;
FIL fil;
UINT br;
uint32_t offset = 0;
if(3 == sscanf((const char*)param, "%*s %s %lx %ld", path, &addr, &size))
{
xprintf("hexdump %s 0x%x %d\r\n",path,addr,size);
if(FR_OK == (res=f_open(&fil,(const char*)path, FA_READ)))
{
xprintf("\r\n");
do
{
br = 0;
if(FR_OK == (res = f_read(&fil,tmp,(size>16)?16:size,&br)))
{
xprintf("%08x ",offset);
offset+=br;
for(uint32_t i=0;i<br;i++)
{
xprintf("%02x",(uint32_t)tmp[i]);
}
xprintf(":");
for(uint32_t i=0;i<br;i++)
{
xprintf("%c",((tmp[i]>0x1F)&&(tmp[i]<0x7F))?(char)tmp[i]:'.');
}
xprintf("\r\n");
size -= br;
}
else
{
break;
}
}while(br > 0);
if(FR_OK != (res = f_close(&fil)))
{
xprintf("close %s err %d\r\n",path,res);
}
}
else
{
xprintf("open %s err %d",path,res);
}
}
else
{
xprintf("param err");
}
}
help查看命令
hexdump查看内容
十二. 实现hexwrite
shell_func.c中申明实现函数
static void hexwritefunc(uint8_t* param);
g_shell_cmd_list_ast中添加一行
{ (uint8_t*)"hexwrite", hexwritefunc, (uint8_t*)"hexwrite path addr[hex] hexstr"},
实现函数如下
static int ascii2uc(const char c, unsigned char *uc)
{
if ((c >= '0') && (c <= '9')) {
*uc = c - '0';
} else if ((c >= 'a') && (c <= 'f')) {
*uc = c - 'a' + 10;
} else if ((c >= 'A') && (c <= 'F')) {
*uc = c - 'A' + 10;
} else {
return -1;
}
return 0;
}
static uint32_t str2hex(const char* str, unsigned char *buff, uint32_t len)
{
uint32_t num = 0;
uint8_t hex = 0;
while(1)
{
uint8_t tmp1;
uint8_t tmp2;
if(ascii2uc(*str++, &tmp1) < 0)
{
break;
}
if(ascii2uc(*str++, &tmp2) < 0)
{
break;
}
hex = tmp1*16 + tmp2;
*buff++ = hex;
num++;
if(num >= len)
{
break;
}
}
return num;
}
void hexwritefunc(uint8_t* param)
{
char path[128];
uint8_t hexstr[32+1];
uint8_t tmp[16];
uint32_t hexnum = 0;
uint32_t addr;
FRESULT res;
FIL fil;
UINT bw;
if(3 == sscanf((const char*)param, "%*s %s %lx %s", path, &addr, hexstr))
{
xprintf("hexwrite %s 0x%x %s\r\n",path,addr,hexstr);
if(FR_OK == (res=f_open(&fil,(const char*)path, FA_WRITE)))
{
xprintf("\r\n");
hexnum = str2hex((const char*)hexstr,tmp,32);
if(hexnum > 0)
{
if(FR_OK == (res=(f_lseek(&fil,addr))))
{
if(FR_OK != (res = f_write(&fil,tmp,hexnum,&bw)))
{
xprintf("write err %d\r\n",res);
}
}
else
{
xprintf("seek %d err %d\r\n",addr,res);
}
}
if(FR_OK != (res = f_close(&fil)))
{
xprintf("close %s err %d\r\n",path,res);
}
}
else
{
xprintf("open %s err %d",path,res);
}
}
else
{
xprintf("param err");
}
}
Help查看命令
Hexwrite修改内容,再hexdump查看
十三. 实现md5sum
shell_func.c中申明实现函数
static void md5sumfunc(uint8_t* param);
g_shell_cmd_list_ast中添加一行
{ (uint8_t*)"md5sum", md5sumfunc, (uint8_t*)"md5sum path"},
实现函数如下
/* md5算法参考 https://www.rfc-editor.org/rfc/rfc1321 */
void md5sumfunc(uint8_t* param)
{
char path[128];
uint8_t tmp[32];
uint8_t out[16];
FIL fil;
UINT br;
FRESULT res;
MD5_CTX ctx;
MD5Init(&ctx);
if(1 == sscanf((const char*)param, "%*s %s",path))
{
res = f_open(&fil, path, FA_READ);
if(res == FR_OK)
{
do
{
res = f_read(&fil, tmp, sizeof(tmp), &br);
if(res == 0)
{
MD5Update(&ctx, tmp, br);
}
else
{
xprintf("read err %d\r\n",res);
break;
}
}while(br > 0);
MD5Final(out, &ctx);
for(int i=0; i<16;i++)
{
xprintf("%02x",out[i]);
}
xprintf("\r\n");
f_close(&fil);
}
else
{
xprintf("open %s err %d\r\n",path,res);
}
}
else
{
xprintf("param err");
}
}
help查看命令
md5sum计算,和电脑上计算一致
十四. 实现free
shell_func.c中申明实现函数
static void freefunc(uint8_t* param);
g_shell_cmd_list_ast中添加一行
{ (uint8_t*)"free", freefunc, (uint8_t*)"free path"},
实现函数如下
void freefunc(uint8_t* param)
{
char path[128];
FRESULT res;
if(1 == sscanf((const char*)param, "%*s %s", path))
{
FATFS *fs;
DWORD fre_clust, fre_sect, tot_sect;
/* Get volume information and free clusters of drive 1 */
res = f_getfree(path, &fre_clust, &fs);
if(res == FR_OK)
{
/* Get total sectors and free sectors */
tot_sect = (fs->n_fatent - 2) * fs->csize;
fre_sect = fre_clust * fs->csize;
/* Print the free space (assuming 512 bytes/sector) */
xprintf("%10lu KiB total drive space.\n%10lu KiB available.\n", tot_sect / 2, fre_sect / 2);
}
else
{
xprintf("getfree %s err %d\r\n",path,res);
}
}
else
{
xprintf("param err");
}
}
Help查看命令
Free查看空间大小,我这里是4GB的卡
十五.总结
以上实现了比较常用的文件操作shell命令,可以方便的进行文件操作了。