Windows平台使用文件模拟FatFs

Windows平台使用文件模拟FatFs

概述

因为最近在忙关于FatFs的项目,但是之前没有接触过FatFs,听说FatFs入门就是用文件模拟文件系统,所以分享一下自己的经历。

移植用到的FatFs版本是FF14,网址:http://elm-chan.org/fsw/ff/00index_e.html.

开发环境:VS2019

在移植FatFs时,我们只需要对其中几个文件进行修改,分别是:

  • ffconf.h: FatFs的配置
  • diskio.c: 实现读写等操作的文件,也是我们主要进行修改的文件

移植过程

ffconf.h

此项目主要是将FF_USE_MKFS设置成1,使程序能够使用f_mkfs()函数对FatFs进行格式化。

如果想要支持长文件名(默认只支持短文件名,文件名8为加后缀3位,具体长度不确定了,有点忘记了),需要将FF_USE_LFN设置为1,同时要在项目中包含ffunicode.c.

diskio.c

diskio.c是主要修改的文件,按照函数功能分类主要包含以下几个函数:

  • 存储设备控制
    • disk_status: 获取设备状态
    • disk_initialize: 初始化设备
    • disk_read: 读数据
    • disk_write: 写数据
    • disk_ioctl: 控制设备相关功能
  • 实时时钟
    • get_fattime: 获取当前时间

下面开始撸代码:

一些设置的全局变量

因为是文件模拟FatFs,所以文件是根本,需要设置一个文件的全局变量,以供下面那些函数进行使用。同时,需要用一个宏定义设置扇区大小。

#define SECTOR_SIZE 512
static HANDLE fp_fatfs = NULL;
disk_status函数

查询状态的函数,当文件句柄为NULL时返回没有初始化,其他时间都返回成功即可。

DSTATUS disk_status (
	BYTE pdrv		/* Physical drive nmuber to identify the drive */
)
{
	if (NULL == fp_fatfs)
		return STA_NOINIT;
	return RES_OK;
}
disk_initialize函数

初始化FatFs,在这个函数里面创建文件。

DSTATUS disk_initialize (
	BYTE pdrv				/* Physical drive nmuber to identify the drive */
)
{
	const char* FatFsFile = "E:\\Code\\VS_Project\\FatFsTest\\FF14Test1\\FF14Test1\\FatFs_Space";

	if (NULL == fp_fatfs)
	{
		fp_fatfs = CreateFile(FatFsFile,
			GENERIC_READ | GENERIC_WRITE,
			FILE_SHARE_READ | FILE_SHARE_WRITE,
			NULL,
			OPEN_ALWAYS,
			FILE_FLAG_NO_BUFFERING,
			NULL);
		if (fp_fatfs == INVALID_HANDLE_VALUE)
			return STA_NOINIT;
	}
	return RES_OK;
}
disk_read函数

读取数据的函数,需要将文件指针跳转到正确的位置,读取指定数量的数据。

DRESULT disk_read (
	BYTE pdrv,		/* Physical drive nmuber to identify the drive */
	BYTE *buff,		/* Data buffer to store read data */
	LBA_t sector,	/* Start sector in LBA */
	UINT count		/* Number of sectors to read */
)
{
	DRESULT res;
	DWORD rdBytes = 0;

	SetFilePointer(fp_fatfs, sector * SECTOR_SIZE, NULL, FILE_BEGIN);

	if (!ReadFile(fp_fatfs, buff, count * 512UL, &rdBytes, NULL))
	{
		return RES_ERROR;
	}


	return RES_OK;
}
disk_write函数

写入数据的函数,需要将文件指针跳转到正确的位置,写入指定数量的数据。

DRESULT disk_write (
	BYTE pdrv,			/* Physical drive nmuber to identify the drive */
	const BYTE *buff,	/* Data to be written */
	LBA_t sector,		/* Start sector in LBA */
	UINT count			/* Number of sectors to write */
)
{
	DRESULT res;
	DWORD rdBytes = 0;

	SetFilePointer(fp_fatfs, sector * SECTOR_SIZE, NULL, FILE_BEGIN);

	if (!WriteFile(fp_fatfs, buff, count * 512UL, &rdBytes, NULL))
	{
		return RES_ERROR;
	}


	return RES_OK;
}
disk_ioctl函数

设置一些FatFs的基本信息,这里有几个需要注意的地方,如果要设置文件系统大小,则要指定GET_SECTOR_COUNT的值,计算方法如下:扇区数量 = 总容量 / 扇区大小。

因此,如果设置2G的文件系统的话,GET_SECTOR_COUNT的值应该为:2 * 1024 * 1024 * 1024 / 512

DRESULT disk_ioctl (
	BYTE pdrv,		/* Physical drive nmuber (0..) */
	BYTE cmd,		/* Control code */
	void *buff		/* Buffer to send/receive control data */
)
{
	DRESULT res;

	res = RES_PARERR;
	switch (cmd) {
	case CTRL_SYNC:			/* Nothing to do */
		res = RES_OK;
		break;

	case GET_SECTOR_COUNT:	/* Get number of sectors(扇区) on the drive */
		*(DWORD*)buff = 4 * 1024 * 1024;
		res = RES_OK;
		break;

	case GET_SECTOR_SIZE:	/* Get size of sector for generic read/write */
		*(WORD*)buff = FF_MAX_SS;
		res = RES_OK;
		break;

	case GET_BLOCK_SIZE:	/* Get internal block size in unit of sector (以扇区为单位获取内部块大小)*/
		*(DWORD*)buff = 1;
		res = RES_OK;
		break;
	}

	return res;
}
get_fattime函数

这个函数是照扒别人的,如果使用这个函数,需要#include <time.h>

DWORD get_fattime(void)
{
	time_t timep;
	struct tm* p;
	time(&timep);
	p = localtime(&timep);
	return (((DWORD)(p->tm_year - 80) << 25) | ((DWORD)(1 + p->tm_mon) << 21) | ((DWORD)(p->tm_mday) << 16) |
		((DWORD)(p->tm_hour) << 11) | ((DWORD)(p->tm_min) << 5) | ((DWORD)(p->tm_sec) >> 1));
}

到这里,移植已经完成。下面写个文件进行测试。

测试文件

#include <iostream>
#include "ff.h"


using namespace std;

int FatFsTest()
{
    FATFS fatfs;
    FATFS* fs = &fatfs;
    FRESULT res;
    FIL fil;
    UINT bw = 0;

    BYTE work[FF_MAX_SS]; /* Work area (larger is better for processing time) */

    MKFS_PARM mkfs = {
        FM_FAT32,
        0,
        0,
        0,
        0
    };


    //cout << "----------------------------------------------------------------" << endl;

    //res = f_mount(fs, "0:", 0);

    //if (res != FR_OK)
    //{
    //    cout << "mount failed! res: " << res << endl;
    //    //return -1;
    //}

    //cout << "----------------------------------------------------------------" << endl;

    MKFS_PARM opt = { FM_FAT32 };
    //BYTE Buff[FF_MAX_SS];			/* Working buffer */

    res = f_mkfs("0:", 0, 1);
    res = f_mkfs("0:", &mkfs, work, sizeof work);
    res = f_mkfs("0:", 0, work, sizeof work);

    if (res != FR_OK)
    {
        cout << "f_mkfs failed! res: " << res << endl;
        return -1;
    }

    cout << "----------------------------------------------------------------" << endl;

    res = f_mount(fs, "0:", 1);

    if (res != FR_OK)
    {
        cout << "mount failed! res: " << res << endl;
        //return -1;
    }

    cout << "----------------------------------------------------------------" << endl;

    res = f_open(&fil, "0:\\test.txt", FA_CREATE_NEW | FA_WRITE);
    if (res != FR_OK)
    {
        cout << "open failed! res: " << res << endl;
        return -2;
    }

    const char* str_write = "Hello From FATFS";
    //const char* str_write2 = "str_write2";

    res = f_write(&fil, str_write, strlen(str_write), &bw);
    if (res != FR_OK)
    {
        cout << "write failed! res: " << res << endl;
        return -3;
    }
    cout << "Write Num: " << bw << endl;

    f_close(&fil);


    cout << "----------------------------------------------------------------" << endl;


    res = f_open(&fil, "0:\\test.txt", FA_READ);
    if (res != FR_OK)
    {
        cout << "open failed! res: " << res << endl;
        return -4;
    }

    char str_read[100] = { 0 };

    res = f_read(&fil, str_read, 100, &bw);
    if (res != FR_OK)
    {
        cout << "read failed! res: " << res << endl;
        return -5;
    }
    cout << "Read Num: " << bw << endl;

    cout << "str_read: " << str_read << endl;
    f_close(&fil);


    cout << "----------------------------------------------------------------" << endl;

    DWORD nclst = 0;
    f_getfree("0:", &nclst, &fs);
    cout << "f_getfree nclst == " << nclst << endl;

    cout << "----------------------------------------------------------------" << endl;

    return 0;
}


int main(int argc, char** argv)
{
    std::cout << "Hello World!\n";

    int Code = 0;

    Code = FatFsTest();
    //Code = test();

    cout << "Code: " << Code << endl;
}

结尾

程序到这已经结束,如果有不对的地方,还请大神多多指正。

完整程序已经上传到github,欢迎各位点星,地址:https://github.com/WangHan0711/File_FatFs

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值