VSF 3rd -- 移植fatfs

[复制链接]
 楼主| vsfopen 发表于 2018-8-20 15:48 | 显示全部楼层 |阅读模式
本帖最后由 vsfopen 于 2018-8-20 15:59 编辑

fatfs的移植有2种方法:
1. 使用VSF种的mal块设备,通过独立堆栈的任务,直接调用fatfs的API来操作文件系统。
2. 把fatfs移植到VSF种的文件系统框架下,是的可以通过vsf的文件系统接口,通过fatfs来操作文件系统

第一种方式相对简单,指需要实现fatfs移植的几个口disk相关的操作接口即可:
  1. static struct vsf_fatfs_internal_t
  2. {
  3.         struct
  4.         {
  5.                 struct vsfmal_t *mal;
  6. #if FF_FS_REENTRANT
  7.                 struct vsfsm_crit_t crit;
  8. #endif
  9.         } disk[VSF_FATFS_CFG_MAXVOLUME];
  10.         uint32_t mskarr[(VSF_FATFS_CFG_MAXVOLUME + 31) >> 5];
  11. } vsf_fatfs;

  12. DSTATUS disk_status(BYTE pdrv)
  13. {
  14.         if (pdrv >= VSF_FATFS_CFG_MAXVOLUME) return STA_NOINIT;
  15.         return mskarr_get(vsf_fatfs.mskarr, pdrv) ? 0 : STA_NOINIT;
  16. }

  17. DSTATUS disk_initialize(BYTE pdrv)
  18. {
  19.         if (disk_status(pdrv))
  20.                 return STA_NOINIT;
  21.         else
  22.         {
  23.                 struct vsfmal_t *mal = vsf_fatfs.disk[pdrv].mal;
  24.                 struct vsfsm_pt_t pt =
  25.                 {
  26.                         .sm = &(vsfsm_thread_get_cur())->sm,
  27.                         .state = 0,
  28.                         .user_data = mal,
  29.                 };
  30.                 vsfsm_evt_t evt = VSFSM_EVT_NONE;
  31.                 vsf_err_t err;

  32.                 while (1)
  33.                 {
  34.                         err = vsfmal_init(&pt, evt);
  35.                         if (!err) break;
  36.                         else if (err < 0) return STA_NOINIT;
  37.                         else evt = vsfsm_thread_wait();
  38.                 }
  39.         }
  40.         return FR_OK;
  41. }

  42. DRESULT disk_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count)
  43. {
  44.         if (disk_status(pdrv))
  45.                 return RES_PARERR;
  46.         else
  47.         {
  48.                 struct vsfmal_t *mal = vsf_fatfs.disk[pdrv].mal;
  49.                 struct vsfsm_pt_t pt =
  50.                 {
  51.                         .sm = &(vsfsm_thread_get_cur())->sm,
  52.                         .state = 0,
  53.                         .user_data = mal,
  54.                 };
  55.                 vsfsm_evt_t evt = VSFSM_EVT_NONE;
  56.                 vsf_err_t err;

  57.                 sector *= mal->cap.block_size;
  58.                 count *= mal->cap.block_size;
  59.                 while (1)
  60.                 {
  61.                         err = vsfmal_read(&pt, evt, sector, buff, count);
  62.                         if (!err) break;
  63.                         else if (err < 0) return STA_NOINIT;
  64.                         else evt = vsfsm_thread_wait();
  65.                 }
  66.         }
  67.         return FR_OK;
  68. }

  1. int vsf_fatfs_add_disk(struct vsfmal_t *mal)
  2. {
  3.         uint8_t origlevel = vsfsm_sched_lock();
  4.         int idx = mskarr_ffz(vsf_fatfs.mskarr, VSF_FATFS_CFG_MAXVOLUME);
  5.         if (idx >= 0)
  6.         {
  7.                 mskarr_set(vsf_fatfs.mskarr, idx);
  8.                 vsf_fatfs.disk[idx].mal = mal;
  9.         }
  10.         vsfsm_sched_unlock(origlevel);
  11.         return idx;
  12. }

  13. void vsf_fatfs_remove_disk(struct vsfmal_t *mal)
  14. {
  15.         for (int i = 0; i < VSF_FATFS_CFG_MAXVOLUME; i++)
  16.         {
  17.                 if (mskarr_get(vsf_fatfs.mskarr, i) && (mal == vsf_fatfs.disk[i].mal))
  18.                 {
  19.                         mskarr_clr(vsf_fatfs.mskarr, i);
  20.                         break;
  21.                 }
  22.         }
  23. }
通过vsf_fatfs_add_disk把VSF种的块设备,注册到vsf_fatfs模块中,并且得到对应的index序号,就可以通过序号来访问块设备里的FAT文件系统了。

由于disk_initialize的接口是阻塞的,所以应用层必须是vsfsm_thread_t的独立堆栈任务,disk_initialize里,也只是调用了PT方式的块设备驱动接口。



第二种相对麻烦一些,因为fatfs这种文件系统的应用层API过于高层,并不适合vsf的底层文件系统驱动接口。不过,可以使用fatfs的FF_FS_RPATH来实现vsf底层文件系统接口需要的相对路径功能。

  1. void vsf_fatfs_run_mount(struct vsfsm_thread_t *thread)
  2. {
  3.         struct vsf_fatfs_t *fatfs = (struct vsf_fatfs_t *)thread->priv;
  4.         int idx = vsf_fatfs_add_disk(fatfs->mal);
  5.         char volume[3];

  6.         if (idx < 0)
  7.                 return;

  8.         volume[0] = '0' + idx;
  9.         volume[1] = ':';
  10.         volume[2] = '\0';
  11.         if (f_mount(&__fatfs, volume, 1) || f_opendir(&fatfs->root, volume))
  12.                 fatfs->root.obj.fs = NULL;
  13. }

  14. static vsf_err_t vsf_fatfs_mount(struct vsfsm_pt_t *pt, vsfsm_evt_t evt,
  15.                 struct vsfile_t *dir)
  16. {
  17.         struct vsf_fatfs_t *fatfs = (struct vsf_fatfs_t *)pt->user_data;

  18.         vsfsm_pt_begin(pt);
  19.         vsfsm_crit_init(&fatfs->crit, VSFSM_EVT_USER);
  20.         vsfsm_crit_enter(&fatfs->crit, pt->sm);

  21.         fatfs->thread.op.on_terminate = vsf_fatfs_on_finish;
  22.         fatfs->thread.stack_size = sizeof(fatfs->stack);
  23.         fatfs->thread.stack = fatfs->stack;

  24.         fatfs->pending_sm = pt->sm;
  25.         fatfs->thread.priv = fatfs;
  26.         fatfs->thread.op.on_run = vsf_fatfs_run_mount;
  27.         vsfsm_thread_start(&fatfs->thread);
  28.         vsfsm_pt_wfe(pt, VSFSM_EVT_USER);

  29.         vsfsm_crit_leave(&fatfs->crit);
  30.         vsfsm_pt_end(pt);
  31.         return !fatfs->root.obj.fs ? VSFERR_FAIL : VSFERR_NONE;
  32. }

  33. void vsf_fatfs_run_getchild(struct vsfsm_thread_t *thread)
  34. {
  35.         struct vsf_fatfs_t *fatfs = (struct vsf_fatfs_t *)thread->priv;
  36.         char *name = fatfs->getchild.name;
  37.         DIR *dir = fatfs->getchild.dir;
  38.         FILINFO fno;

  39.         fatfs->getchild.file = NULL;
  40.         while (1)
  41.         {
  42.                 if (f_readdir(dir, &fno) || !fno.fname[0])
  43.                         break;

  44.                 if (vsfile_match(name, fno.fname))
  45.                 {
  46.                         struct vsf_fatfs_file_t *file;
  47.                         uint32_t fname_len = strlen(fno.fname) + 1;
  48.                         uint32_t entry_len = fno.fattrib & AM_DIR ? sizeof(DIR) : sizeof(FIL);
  49.                         uint32_t size = sizeof(*file) + entry_len + fname_len;

  50.                         file = vsf_bufmgr_malloc(size);
  51.                         if (file != NULL)
  52.                         {
  53.                                 file->entry.ptr = &file[1];
  54.                                 file->file.name = (char *)file->entry.ptr + entry_len;

  55.                                 strcpy(file->file.name, fno.fname);
  56.                                 file->file.attr = fno.fattrib;
  57.                                 file->file.op = &vsf_fatfs_fsop;
  58.                                 file->file.size = fno.fsize;

  59.                                 __fatfs.cdir = dir->obj.sclust;
  60.                                 if (file->file.attr & VSFILE_ATTR_DIRECTORY)
  61.                                 {
  62.                                         DIR *dp = file->entry.d;
  63.                                         if (f_opendir(dp, file->file.name))
  64.                                                 return;
  65.                                 }
  66.                                 else
  67.                                 {
  68.                                         FIL *fp = file->entry.f;
  69.                                         if (f_open(fp, file->file.name, 1))
  70.                                                 return;
  71.                                 }

  72.                                 fatfs->getchild.file = file;
  73.                         }
  74.                         break;
  75.                 }
  76.         }
  77. }

  78. static vsf_err_t vsf_fatfs_getchild(struct vsfsm_pt_t *pt, vsfsm_evt_t evt,
  79.                 struct vsfile_t *dir, char *name, uint32_t idx, struct vsfile_t **file)
  80. {
  81.         struct vsf_fatfs_t *fatfs = (struct vsf_fatfs_t *)pt->user_data;

  82.         vsfsm_pt_begin(pt);
  83.         if (vsfsm_crit_enter(&fatfs->crit, pt->sm))
  84.                 vsfsm_pt_wfe(pt, VSFSM_EVT_USER);

  85.         fatfs->getchild.dir = ((struct vsf_fatfs_file_t *)dir)->entry.d;
  86.         if (!fatfs->getchild.dir)
  87.                 fatfs->getchild.dir = &fatfs->root;
  88.         fatfs->getchild.name = name;

  89.         fatfs->pending_sm = pt->sm;
  90.         fatfs->thread.priv = fatfs;
  91.         fatfs->thread.op.on_run = vsf_fatfs_run_getchild;
  92.         vsfsm_thread_start(&fatfs->thread);
  93.         vsfsm_pt_wfe(pt, VSFSM_EVT_USER);
  94.         *file = &fatfs->getchild.file->file;

  95.         vsfsm_crit_leave(&fatfs->crit);
  96.         vsfsm_pt_end(pt);
  97.         return VSFERR_NONE;
  98. }

  99. void vsf_fatfs_run_read(struct vsfsm_thread_t *thread)
  100. {
  101.         struct vsf_fatfs_t *fatfs = (struct vsf_fatfs_t *)thread->priv;
  102.         struct vsf_fatfs_file_t *file = fatfs->close.file;

  103.         fatfs->rw.rw_size = 0;
  104.         if (!f_lseek(file->entry.f, fatfs->rw.offset))
  105.                 f_read(file->entry.f, fatfs->rw.buff, fatfs->rw.size, &fatfs->rw.rw_size);
  106. }

  107. static vsf_err_t vsf_fatfs_read(struct vsfsm_pt_t *pt, vsfsm_evt_t evt,
  108.                 struct vsfile_t *file, uint64_t offset, uint32_t size, uint8_t *buff,
  109.                 uint32_t *rsize)
  110. {
  111.         struct vsf_fatfs_t *fatfs = (struct vsf_fatfs_t *)pt->user_data;

  112.         vsfsm_pt_begin(pt);
  113.         if (vsfsm_crit_enter(&fatfs->crit, pt->sm))
  114.                 vsfsm_pt_wfe(pt, VSFSM_EVT_USER);

  115.         fatfs->rw.file = (struct vsf_fatfs_file_t *)file;
  116.         fatfs->rw.buff = buff;
  117.         fatfs->rw.offset = offset;
  118.         fatfs->rw.size = size;

  119.         fatfs->pending_sm = pt->sm;
  120.         fatfs->thread.priv = fatfs;
  121.         fatfs->thread.op.on_run = vsf_fatfs_run_read;
  122.         vsfsm_thread_start(&fatfs->thread);
  123.         vsfsm_pt_wfe(pt, VSFSM_EVT_USER);
  124.         if (rsize != NULL)
  125.                 *rsize = fatfs->rw.rw_size;

  126.         vsfsm_crit_leave(&fatfs->crit);
  127.         vsfsm_pt_end(pt);
  128.         return VSFERR_NONE;
  129. }

vsf_fatfs_mount、vsf_fatfs_getchild、vsf_fatfs_read等等接口是VSF的文件系统驱动的接口,是PT形式的任务。由于fatfs需要使用vsfsm_thread_t形式的任务,所以在这些接口里,只是简单的设置了参数,并且启动对应的vsfsm_thread_t任务,并等待执行完成,返回结果。

其中,mount和读写等接口相对简单,直接调用fatfs对应的API即可。不过,vsf的文件系统有一个getchild接口,用于得到指定目录下,指定的文件或者子目录。这个接口就需要相对的路径,fatfs正好可以通过FF_FS_RPATH来使能相对路径,但是f_chdir接口仍旧需要绝对路径,所以i这里就只是简单的通过设置fatfs.cdir来设置当前的目录,然后就后面的路径就是基于这个当前目录的相对路径。

注意:一些中间参数和变量(包括vsfsm_thread_t)会放在fatfs的结构中,所以,调用这些接口的时候,需要保证其他任务不对调用,以避免资源使用的冲突,这里使用了一个vsfsm_crit_t来避免这个问题。所以,所有这些PT的文件系统接口,会先做保护,然后再使用共享资源。
ayong147 发表于 2020-2-22 19:58 | 显示全部楼层
先看看怎么样!

90

主题

325

帖子

8

粉丝
快速回复 在线客服 返回列表 返回顶部