- static struct vsf_fatfs_internal_t
- {
- struct
- {
- struct vsfmal_t *mal;
- #if FF_FS_REENTRANT
- struct vsfsm_crit_t crit;
- #endif
- } disk[VSF_FATFS_CFG_MAXVOLUME];
- uint32_t mskarr[(VSF_FATFS_CFG_MAXVOLUME + 31) >> 5];
- } vsf_fatfs;
- DSTATUS disk_status(BYTE pdrv)
- {
- if (pdrv >= VSF_FATFS_CFG_MAXVOLUME) return STA_NOINIT;
- return mskarr_get(vsf_fatfs.mskarr, pdrv) ? 0 : STA_NOINIT;
- }
- DSTATUS disk_initialize(BYTE pdrv)
- {
- if (disk_status(pdrv))
- return STA_NOINIT;
- else
- {
- struct vsfmal_t *mal = vsf_fatfs.disk[pdrv].mal;
- struct vsfsm_pt_t pt =
- {
- .sm = &(vsfsm_thread_get_cur())->sm,
- .state = 0,
- .user_data = mal,
- };
- vsfsm_evt_t evt = VSFSM_EVT_NONE;
- vsf_err_t err;
- while (1)
- {
- err = vsfmal_init(&pt, evt);
- if (!err) break;
- else if (err < 0) return STA_NOINIT;
- else evt = vsfsm_thread_wait();
- }
- }
- return FR_OK;
- }
- DRESULT disk_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count)
- {
- if (disk_status(pdrv))
- return RES_PARERR;
- else
- {
- struct vsfmal_t *mal = vsf_fatfs.disk[pdrv].mal;
- struct vsfsm_pt_t pt =
- {
- .sm = &(vsfsm_thread_get_cur())->sm,
- .state = 0,
- .user_data = mal,
- };
- vsfsm_evt_t evt = VSFSM_EVT_NONE;
- vsf_err_t err;
- sector *= mal->cap.block_size;
- count *= mal->cap.block_size;
- while (1)
- {
- err = vsfmal_read(&pt, evt, sector, buff, count);
- if (!err) break;
- else if (err < 0) return STA_NOINIT;
- else evt = vsfsm_thread_wait();
- }
- }
- return FR_OK;
- }
- int vsf_fatfs_add_disk(struct vsfmal_t *mal)
- {
- uint8_t origlevel = vsfsm_sched_lock();
- int idx = mskarr_ffz(vsf_fatfs.mskarr, VSF_FATFS_CFG_MAXVOLUME);
- if (idx >= 0)
- {
- mskarr_set(vsf_fatfs.mskarr, idx);
- vsf_fatfs.disk[idx].mal = mal;
- }
- vsfsm_sched_unlock(origlevel);
- return idx;
- }
- void vsf_fatfs_remove_disk(struct vsfmal_t *mal)
- {
- for (int i = 0; i < VSF_FATFS_CFG_MAXVOLUME; i++)
- {
- if (mskarr_get(vsf_fatfs.mskarr, i) && (mal == vsf_fatfs.disk[i].mal))
- {
- mskarr_clr(vsf_fatfs.mskarr, i);
- break;
- }
- }
- }
通过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底层文件系统接口需要的相对路径功能。
- void vsf_fatfs_run_mount(struct vsfsm_thread_t *thread)
- {
- struct vsf_fatfs_t *fatfs = (struct vsf_fatfs_t *)thread->priv;
- int idx = vsf_fatfs_add_disk(fatfs->mal);
- char volume[3];
- if (idx < 0)
- return;
- volume[0] = '0' + idx;
- volume[1] = ':';
- volume[2] = '\0';
- if (f_mount(&__fatfs, volume, 1) || f_opendir(&fatfs->root, volume))
- fatfs->root.obj.fs = NULL;
- }
- static vsf_err_t vsf_fatfs_mount(struct vsfsm_pt_t *pt, vsfsm_evt_t evt,
- struct vsfile_t *dir)
- {
- struct vsf_fatfs_t *fatfs = (struct vsf_fatfs_t *)pt->user_data;
- vsfsm_pt_begin(pt);
- vsfsm_crit_init(&fatfs->crit, VSFSM_EVT_USER);
- vsfsm_crit_enter(&fatfs->crit, pt->sm);
- fatfs->thread.op.on_terminate = vsf_fatfs_on_finish;
- fatfs->thread.stack_size = sizeof(fatfs->stack);
- fatfs->thread.stack = fatfs->stack;
- fatfs->pending_sm = pt->sm;
- fatfs->thread.priv = fatfs;
- fatfs->thread.op.on_run = vsf_fatfs_run_mount;
- vsfsm_thread_start(&fatfs->thread);
- vsfsm_pt_wfe(pt, VSFSM_EVT_USER);
- vsfsm_crit_leave(&fatfs->crit);
- vsfsm_pt_end(pt);
- return !fatfs->root.obj.fs ? VSFERR_FAIL : VSFERR_NONE;
- }
- void vsf_fatfs_run_getchild(struct vsfsm_thread_t *thread)
- {
- struct vsf_fatfs_t *fatfs = (struct vsf_fatfs_t *)thread->priv;
- char *name = fatfs->getchild.name;
- DIR *dir = fatfs->getchild.dir;
- FILINFO fno;
- fatfs->getchild.file = NULL;
- while (1)
- {
- if (f_readdir(dir, &fno) || !fno.fname[0])
- break;
- if (vsfile_match(name, fno.fname))
- {
- struct vsf_fatfs_file_t *file;
- uint32_t fname_len = strlen(fno.fname) + 1;
- uint32_t entry_len = fno.fattrib & AM_DIR ? sizeof(DIR) : sizeof(FIL);
- uint32_t size = sizeof(*file) + entry_len + fname_len;
- file = vsf_bufmgr_malloc(size);
- if (file != NULL)
- {
- file->entry.ptr = &file[1];
- file->file.name = (char *)file->entry.ptr + entry_len;
- strcpy(file->file.name, fno.fname);
- file->file.attr = fno.fattrib;
- file->file.op = &vsf_fatfs_fsop;
- file->file.size = fno.fsize;
- __fatfs.cdir = dir->obj.sclust;
- if (file->file.attr & VSFILE_ATTR_DIRECTORY)
- {
- DIR *dp = file->entry.d;
- if (f_opendir(dp, file->file.name))
- return;
- }
- else
- {
- FIL *fp = file->entry.f;
- if (f_open(fp, file->file.name, 1))
- return;
- }
- fatfs->getchild.file = file;
- }
- break;
- }
- }
- }
- static vsf_err_t vsf_fatfs_getchild(struct vsfsm_pt_t *pt, vsfsm_evt_t evt,
- struct vsfile_t *dir, char *name, uint32_t idx, struct vsfile_t **file)
- {
- struct vsf_fatfs_t *fatfs = (struct vsf_fatfs_t *)pt->user_data;
- vsfsm_pt_begin(pt);
- if (vsfsm_crit_enter(&fatfs->crit, pt->sm))
- vsfsm_pt_wfe(pt, VSFSM_EVT_USER);
- fatfs->getchild.dir = ((struct vsf_fatfs_file_t *)dir)->entry.d;
- if (!fatfs->getchild.dir)
- fatfs->getchild.dir = &fatfs->root;
- fatfs->getchild.name = name;
- fatfs->pending_sm = pt->sm;
- fatfs->thread.priv = fatfs;
- fatfs->thread.op.on_run = vsf_fatfs_run_getchild;
- vsfsm_thread_start(&fatfs->thread);
- vsfsm_pt_wfe(pt, VSFSM_EVT_USER);
- *file = &fatfs->getchild.file->file;
- vsfsm_crit_leave(&fatfs->crit);
- vsfsm_pt_end(pt);
- return VSFERR_NONE;
- }
- void vsf_fatfs_run_read(struct vsfsm_thread_t *thread)
- {
- struct vsf_fatfs_t *fatfs = (struct vsf_fatfs_t *)thread->priv;
- struct vsf_fatfs_file_t *file = fatfs->close.file;
- fatfs->rw.rw_size = 0;
- if (!f_lseek(file->entry.f, fatfs->rw.offset))
- f_read(file->entry.f, fatfs->rw.buff, fatfs->rw.size, &fatfs->rw.rw_size);
- }
- static vsf_err_t vsf_fatfs_read(struct vsfsm_pt_t *pt, vsfsm_evt_t evt,
- struct vsfile_t *file, uint64_t offset, uint32_t size, uint8_t *buff,
- uint32_t *rsize)
- {
- struct vsf_fatfs_t *fatfs = (struct vsf_fatfs_t *)pt->user_data;
- vsfsm_pt_begin(pt);
- if (vsfsm_crit_enter(&fatfs->crit, pt->sm))
- vsfsm_pt_wfe(pt, VSFSM_EVT_USER);
- fatfs->rw.file = (struct vsf_fatfs_file_t *)file;
- fatfs->rw.buff = buff;
- fatfs->rw.offset = offset;
- fatfs->rw.size = size;
- fatfs->pending_sm = pt->sm;
- fatfs->thread.priv = fatfs;
- fatfs->thread.op.on_run = vsf_fatfs_run_read;
- vsfsm_thread_start(&fatfs->thread);
- vsfsm_pt_wfe(pt, VSFSM_EVT_USER);
- if (rsize != NULL)
- *rsize = fatfs->rw.rw_size;
- vsfsm_crit_leave(&fatfs->crit);
- vsfsm_pt_end(pt);
- return VSFERR_NONE;
- }
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的文件系统接口,会先做保护,然后再使用共享资源。