IO模拟SPI操作SD卡系列之六:实现shell文件操作命令集

文摘   2024-08-16 08:00   湖南  

一. 前言

我们现在已经实现了通过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命令,可以方便的进行文件操作了。


嵌入式Lee
嵌入式软硬件技术:RTOS,GUI,FS,协议栈,ARM,总线,嵌入式C,开发环境 and blablaba....多年经验分享,非硬货不发,带你扒开每一个技术背后的根本原理。
 最新文章