RT-Thread提供了一套简洁的虚拟文件系统支持,有了它以后,文件操作就如同Linux一样简单。
虚拟文件系统(VFS)是由Sun microsystems公司在定义网络文件系统(NFS)时创造的。它是一种用于网络环境的分布式文件系统,是允许和操作系统使用不同的文件系统实现的接口。
虚拟文件系统(VFS)是物理文件系统与服务之间的一个接口层,它对底层的每个文件系统的所有细节进行抽象,使得不同的文件系统在RT-Thread核心以及系统中运行的其他应用看来,都是相同的。严格说来,VFS并不是一种实际的文件系统。它只存在于内存中,不存在于任何外存空间。VFS在系统启动时建立,在系统关闭时消亡。
当前的RT-Thread实时操作系统支持:
- 面向SD卡、MMC卡、SPI Flash的FAT文件系统,底层实现采用ELM-Chan FatFs文件系统。
- 面向网络的NFS v3文件系统(0.4.x分支开始引入)
- 0.4.x分支也会引入NandFlash上的著名文件系统:YAFFS2
有了RT-Thread的虚拟文件系统,上层应用可以做到:
- 无视底层具体的文件系统实现;
- 无视实际的物理存储媒介;
- 访问文件、目录的操作接口统一,类似POSIX风格的函数接口。
如何个与实际的物理存储媒介无关化,
简单的说就是,只有在系统中实现了块设备,那么就能够整一套文件系统上去进行使用。
例如,把一个文件采用块设备的驱动接口实现,那么可以直接在这个文件上构造出另外一个文件系统。Linux上很有名的一个,文件系统里的文件系统,它这个就是把一个文件做为一个块设备来使用的。RT-Thread同样能够做到!
All in all,这些东西都是面向嵌入式系统的,小巧而五脏俱全,高效而简约。
一个块设备如何实现(针对LPC1768,我手头上的开发板):
开发板通过SPI0连接了SD卡,SD卡处于SPI工作模式下。
块设备需要5个接口函数,也就是5个UNIX下的著名接口:
open/close、read/write、control
然后,呵呵,还多加一个接口:init
init,用于做一些初始化动作
open/close用于打开和关闭一个设备,对于SD卡设备,并不是非常需要,可以直接返回即可。
read/write用于读出、写入数据,是针对SD卡的主要函数。
control,用于一些控制类的工作流程,例如获取卡的信息等。
可以说,control和read/write分属于两个不同的面:控制面和用户面。
是的,RT-Thread的块设备只需要实现这几个接口函数,当然少不了一个设备控制块,这个控制块用于通知系统,我的设备相关属性在哪里:
void rt_hw_sdcard_init()
{
/* 先对SD进行初始化,初始化成功后开始注册块设备 */
if (LPC17xx_SD_Init() && LPC17xx_SD_ReadCfg(&SDCfg))
{
bool status;
rt_uint8_t *sector;
/* 因为是涉及到文件系统,而文件系统中还有个讨厌的分区表,所以先需要得到正确的分区 */
sector = (rt_uint8_t*) rt_malloc (512);
if (sector == RT_NULL)
{
rt_kprintf("allocate partition sector buffer failed\n");
return;
}
/* 读取第0个扇区 */
status = LPC17xx_SD_ReadSector(0, sector, 512);
if (status == true)
{
/* 获得分区表 */
if (dfs_filesystem_get_partition(&part, sector, 0) != 0)
{
/* 如果没有分区表,那么这个SD卡是从0扇区开始的 */
part.offset = 0;
part.size = 0;
}
}
else
{
/* 如果没有分区表,那么这个SD卡是从0扇区开始的 */
part.offset = 0;
part.size = 0;
}
/* sector buffer是动态分配的,所以这里释放掉 */
rt_free(sector);
/* 对SD卡设备进行初始化 */
sdcard_device.type = RT_Device_Class_Block; /* 指定类型为块设备 */
/* 6个接口函数 */
sdcard_device.init = rt_sdcard_init;
sdcard_device.open = rt_sdcard_open;
sdcard_device.close = rt_sdcard_close;
sdcard_device.read = rt_sdcard_read;
sdcard_device.write = rt_sdcard_write;
sdcard_device.control = rt_sdcard_control;
sdcard_device.private = &SDCfg;
/* 对块设备进行注册,默认只注册一个分区 */
rt_device_register(&sdcard_device, "sd0",
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);
return;
}
/* 如果运行到这里,那么卡的初始化出错 */
rt_kprintf("sdcard init failed\n");
}
Note:
RT-Thread/LPC17xx的代码已经放在Google SVN上,当前已经包括内核、shell、文件系统、以太网的支持。
http://code.google.com/p/rt-thread/source/checkout
目前仅支持Keil MDK编译器,欢迎使用。以上的完整代码请见bsp/lpc176x/sd.c