打印

VSF 3rd -- 移植fatfs

[复制链接]
818|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
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相关的操作接口即可:
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的文件系统接口,会先做保护,然后再使用共享资源。

使用特权

评论回复

相关帖子

沙发
ayong147| | 2020-2-22 19:58 | 只看该作者
先看看怎么样!

使用特权

评论回复
发新帖
您需要登录后才可以回帖 登录 | 注册

本版积分规则

89

主题

324

帖子

8

粉丝