IO模拟SPI操作SD卡系列之五.实现Shell和Xmodem文件传输

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

.前言

前面我们移植了FATFS文件系统,此时就可以方便地读取TF卡上的文件了。为了和开发板进行交互,我们继续实现通过xmodem导入导出文件的功能。xmodem的实现和shell的实现参考公众号文章。

https://mp.weixin.qq.com/s/QSYKxND3DTyQZ0JtnSqkzQ XMODEM协议介绍与高效高可移植非阻塞版本实现

https://mp.weixin.qq.com/s/XLmbJn0SKoDT1aLdxHDrbg一个超级精简高可移植的shell命令行C实现

.Xmodem导入文件

shell_func.c

添加fatfs头文件

#include "ff.h"

中申明实现函数

static void rxfilefunc(uint8_t* param);

g_shell_cmd_list_ast中添加一行

{ (uint8_t*)"rxfile",       rxfilefunc,       (uint8_t*)"rxfile name len"},

实现函数rxfilefunc

void rxfilefunc(uint8_t* param){  char name[64];  uint32_t len;  int res = 0;  if(2 == sscanf((const char*)param, "%*s %s %ld", name, &len))  {    xprintf("rxfile %s %ld\r\n",name,len);    if(0 == rx_file_open(name))    {      xmodem_cfg_st cfg=      {          .buffer = rxtx_buf,          .crccheck = 1,          .getms = getms,          .io_read = io_read,          .io_read_flush = io_read_flush,          .io_write = io_write,          .start_timeout = 60,          .packet_timeout = 1000,          .ack_timeout = 1000,          .mem_write = rx_file_write,          .addr = 0,          .totallen = len,      };      xmodem_init_rx(&cfg);      while((res = xmodem_rx()) == 0);      rx_file_close(name);      xprintf("res:%d\r\n",res);    }    else    {      xprintf("open:%s err\r\n",name);    }  }}

需要实现相关的接口

static uint8_t rxtx_buf[1029];
static uint32_t getms(void){  return os_boot_time32();}
static uint32_t io_read(uint8_t* buffer, uint32_t len){  return fifo_cdc_rx_read(buffer, len);}
static void io_read_flush(void){  uint8_t tmp;  while(0 != fifo_cdc_rx_read(&tmp, 1));}
static uint32_t io_write(uint8_t* buffer, uint32_t len){  fifo_cdc_tx_write(buffer, len);  return len;}

文件相关接口

static FIL rx_fil;            /* File object */static int rx_file_open_flag = 0;
static int rx_file_open(char* name){  FRESULT res = f_open(&rx_fil, name, FA_CREATE_NEW | FA_WRITE);  if (FR_OK == 0)  {    rx_file_open_flag = 1;    return 0;  }  else  {    xprintf("open %s err %d\r\n",name,res);    return -1;  }}
static int rx_file_close(char* name){  if(rx_file_open_flag != 0)  {    rx_file_open_flag = 0;    FRESULT res = f_close(&rx_fil);    if(res != FR_OK)    {      xprintf("close err %d\r\n",res);     }    return 0;  }  else  {    return -1;  }}
static uint32_t  rx_file_write(uint32_t addr, uint8_t* buffer, uint32_t len){  if(rx_file_open_flag != 0)  {    UINT bw;    FRESULT res = f_write(&rx_fil, buffer, len, &bw);    if ((bw != len) || (res != FR_OK))    {      xprintf("write err %d %d\r\n",bw,res);    }    return bw;  }  else  {    return 0;  }}

需要初始化时已经挂在文件系统

   static FATFS fs;   /* Filesystem object */
    if(0 == (r = sd_itf_init()))    {        if(FR_OK != (res = f_mount (&fs, "0:", 1)))        {                       printf("mount err %d, mkfs\r\n",res);            res = f_mkfs("0:",0,work,sizeof(work));            if(res == 0)            {                printf("mkfs ok\r\n");                if(FR_OK == f_mount (&fs, "0:", 1))                {                    printf("mount ok\r\n");                }                else                {                    printf("mount err\r\n");                }            }            else            {                printf("mkfs err %d\r\n",res);            }        }          else        {            printf("mount ok\r\n");        }     }    else    {        printf("sd init err:%d\r\n",r);    }

测试输入help查看新添加的命令

输入

rxfile zhcy093.pdf 2573119回车

Crt中菜单栏

Transfer->Send Xmodem...

选择对应的文件,打开开始发送

开始传输

传输完成

用读卡器查看导入的文件

计算校验信息和原始文件一样

三. Xmodem导出文件

shell_func.c

中申明实现函数

static void sxfilefunc(uint8_t* param);

g_shell_cmd_list_ast中添加一行

{ (uint8_t*)"sxfile",       sxfilefunc,       (uint8_t*)"sxfile name len"}, 

实现函数sxfilefunc

void sxfilefunc(uint8_t* param){  char name[64];  uint32_t len;  int res = 0;  if(2 == sscanf((const char*)param, "%*s %s %ld", name, &len))  {    xprintf("sxfile %s %ld\r\n",name,len);    if(0 == tx_file_open(name))    {      xmodem_cfg_st cfg=      {        .buffer = rxtx_buf,        .plen = 1024,        .getms = getms,        .io_read = io_read,        .io_read_flush = io_read_flush,        .io_write = io_write,        .start_timeout = 60,        .packet_timeout = 1000,        .ack_timeout = 5000,        .mem_read = tx_file_read,        .addr = 0,        .totallen = len,      };      xmodem_init_tx(&cfg);      while((res = xmodem_tx()) == 0);      tx_file_close(name);      xprintf("res:%d\r\n",res);    }    else    {      xprintf("open:%s err\r\n",name);    }  }}

文件读接口实现

static FIL tx_fil;            /* File object */static int tx_file_open_flag = 0;
static int tx_file_open(char* name){  FRESULT res = f_open(&tx_fil, name,  FA_READ);  if (FR_OK == 0)  {    tx_file_open_flag = 1;    return 0;  }  else  {    xprintf("open %s err %d\r\n",name,res);    return -1;  }}
static int tx_file_close(char* name){  if(tx_file_open_flag != 0)  {    tx_file_open_flag = 0;    FRESULT res = f_close(&tx_fil);    if(res != FR_OK)    {      xprintf("close err %d\r\n",res);     }    return 0;  }  else  {    return -1;  }}
static uint32_t tx_file_read(uint32_t addr, uint8_t* buffer, uint32_t len){  UINT br;  FRESULT res = f_read(&tx_fil, buffer, len, &br);  if(res != 0)  {    xprintf("read err %d\r\n",res);   }  return br;}

测试输入help查看新添加的命令

输入

sxfile zhcy093.pdf 2573119 回车

Crt中菜单栏

Transfer->Receive Xmodem...

选择保存为文件zhcy093-1.pdf

传输中

传输完成

Xmodem协议最后不足包长需要填充0x1A,所以接收的文件中需要删除这部分,我们实现的xmodem会根据长度信息只保存指定长度没有这个问题。

删除这部分填充

检查校验信息,完全一致

四. 总结

得益于我们前面构造的shellxmodem的轮子,可以很快的就实现文件传输的功能,这也是之前文章分享中要不断积累自己的轮子的原因。平常功能模块注意设计好框架接口,按照面向对象思想设计,考虑可移植性,这样就可以快速的移植使用。











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