c语言sscanf函数的用法是什么
385
2022-11-23
RT-Thread DFS 组件的主要功能特点
1.1 文件系统引入
在早期的嵌入式系统中,需要存储的数据比较少,数据类型也比较单一,往往使用直接在存储设备中的指定地址写入数据的方法来存储数据。然而随着嵌入式设备功能的发展,需要存储的数据越来越多,也越来越复杂,这时仍使用旧方法来存储并管理数据就变得非常繁琐困难。因此我们需要新的数据管理方式来简化存储数据的组织形式,这就是文件系统的由来。
1.2 虚拟文件系统引入
2 DFS 简介
DFS( Device File System)是一种抽象的文件机制,RT-Thread中对文件系统的相关操作实际上都是通过操作DFS实现,也就是说DFS是对各种文件系统的抽象。DFS使的其他部分无须关心不同文件系统之间的差异,使得RT-Thread可以支持多种类型的文件系统。
3 DFS 框架
RT-Thread DFS 组件的主要功能特点有:
DFS 的层次架构如下图所示,主要分为 POSIX 接口层、虚拟文件系统层和设备抽象层。
POSIX 接口层:
虚拟文件系统层:
用户可以将具体的文件系统注册到 DFS 中,如 FatFS、RomFS、DevFS 等。
设备抽象层:设备抽象层将物理设备如 SD Card、SPI Flash、Nand Flash,抽象成符合文件系统能够访问的设备,例如 FAT 文件系统要求存储设备必须是块设备类型。
不同文件系统类型是独立于存储设备驱动而实现的,因此把底层存储设备的驱动接口和文件系统对接起来之后,才可以正确地使用文件系统功能。
4 DFS 数据结构
文件系统操作表:
文件系统表:
1struct dfs_filesystem filesystem_table[DFS_FILESYSTEMS_MAX];
文件描述符:
5 虚拟文件系统使用步骤
初始化 DFS 组件。
注册具体类型的文件系统。
挂载文件系统
当文件系统不再使用,可以将它卸载。
5.1 初始化 DFS 组件
dfs_init() 函数会初始化 DFS 所需的相关资源,创建一些关键的数据结构, 有了这些数据结构,DFS 便能在系统中找到特定的文件系统,并获得对特定存储设备内文件的操作方法。
dfs_init()加入了自动初始化机制,在系统上电后会自动运行dfs_init()。
1INIT_PREV_EXPORT(dfs_init);
实例化DFS 组件相关的数据结构
1struct dfs_filesystem filesystem_table[DFS_FILESYSTEMS_MAX]
1static struct dfs_fdtable _fdtab
创建当前目录表
1char working_directory[DFS_PATH_MAX] = {“/”}
初始化 DFS:
清除文件系统操作表
清除文件系统表
清除文件描述符表
初始化互斥量
设置当前工作目录为“/”
5.2 注册具体类型的文件系统
在 DFS 组件初始化之后,还需要初始化使用的具体类型的文件系统,也就是将具体类型的文件系统注册到 DFS 中。注册文件系统的接口如下所示:
1int dfs_register(const struct dfs_filesystem_ops *ops);
检查这个文件系统是否已经存在于文件系统操作表的目录中
在文件系统操作表中找出一个空的文件类型条目
将这个文件系统的数据结构地址赋值给空的文件系统操作表目录
5.3 挂载文件系统
在挂载文件系统之前,如果是用作存储设备,还需要先存储设备注册为块设备,然后格式化成对应的文件系统后,才能挂载。
在 RT-Thread 中,挂载是指将一个存储设备挂接到一个已存在的路径上。我们要访问存储设备中的文件,必须将文件所在的分区挂载到一个已存在的路径上,然后通过这个路径来访问存储设备。挂载文件系统的接口如下所示:
1int dfs_mount(const char *device_name,
2 const char *path,
3 const char *filesystemtype,
4 unsigned long rwflag,
5 const void *data);
在文件系统操作表中找出特定的文件系统
为特殊文件系统建立完整路径
检查路径是否存在
检查文件系统是否挂载在文件系统表中
检查文件系统表是否有空余,如果有,把空余地址指向给此文件系统
注册文件系统
调用此文件系统的挂载接口
5.4 卸载文件系统
当某个文件系统不需要再使用了,那么可以将它卸载掉。卸载文件系统的接口如下所示:
1int dfs_unmount(const char *specialfile);
检查路径是否存在
在文件系统表中找到此文件系统
清除文件系统表的这个条目内容
调用此文件系统的卸载接口
6 文件系统实例演示
6.1 devfs文件系统
6.1.1 简介
devfs是设备文件系统,设备文件系统是用来把一切设备都抽象为像文件那样操作(如可读,可写)。devfs默认挂载在“/dev”路径下。但是会发现在根目录下使用shell 的ls命令不能看到“/dev”目录, 但是cd “/dev” 能进入dev 目录 ,并且进入dev目录后也能显示dev下的设备。因为根目录“/“下并没有创建任何文件夹,所以在根目录下ls命令自然看不到“/dev”目录。由于挂载文件系统需要挂载在一个已存在的路径上,devfs属于特殊文件系统,DFS为devfs设备文件系统注册时设置了专门的“/dev”路径以供设备文件系统挂载。
2 if ((strcmp(fullpath, ”/“) != 0) && (strcmp(fullpath, ”/dev“) != 0))
3 {
4 struct dfs_fd fd;
5
6 if (dfs_file_open(&fd, fullpath, O_RDONLY | O_DIRECTORY) 《 0)
7 {
8 rt_free(fullpath);
9 rt_set_errno(-ENOTDIR);
10
11 return -1;
12 }
13 dfs_file_close(&fd);
14 }
6.1.2 注册devfs文件系统
如果开启了DFS,devfs设备文件系统会在dfs_init()里自动初始化和挂载。
1#ifdef RT_USING_DFS_DEVFS
2 {
3 extern int devfs_init(void);
4
5 /* if enable devfs, initialize and mount it as soon as possible */
6 devfs_init();
7
8 dfs_mount(NULL, ”/dev“, ”devfs“, 0, 0);
9 }
10#endif
设置devfs文件系统的数据结构:_device_fs
1static const struct dfs_filesystem_ops _device_fs =
2{
3 ”devfs“,
4 DFS_FS_FLAG_DEFAULT,
5 &_device_fops,
6
7 dfs_device_fs_mount,
8 RT_NULL,
9 RT_NULL,
10 RT_NULL,
11
12 RT_NULL,
13 dfs_device_fs_stat,
14 RT_NULL,
15};
将devfs文件系统的数据结构挂载到文件系统操作表里
1int devfs_init(void)
2{
3 /* register rom file system */
4 dfs_register(&_device_fs);
5
6 return 0;
7}
检查devfs文件系统是否已经存在于文件系统操作表的目录中
在文件系统操作表中找出一个空的文件类型条目
将devfs文件系统的数据结构_device_fs地址赋值给空的文件系统操作表目录
文件系统操作表filesystem_operation_table的第一个目录:
6.1.2 挂载devfs文件系统
1dfs_mount(NULL, ”/dev“, ”devfs“, 0, 0)
在文件系统操作表中找出devfs文件系统
跳过检查”/dev“路径是否存在
检查devfs文件系统是否已经挂载在文件系统表中
检查文件系统表是否有空余,如果有,把空余地址赋值给devfs文件系统
注册文件系统
调用devfs文件系统的挂载接口
文件系统表filesystem_table的第一个目录:
在根目录下使用shell 的cd命令切换到/dev目录,然后使用ls命令:
6.2 RomFS文件系统
6.2.1 简介
RomFS是在嵌入式设备上常用的一种文件系统,具备体积小,可靠性高,读取速度快等优点,常用来作为系统初始文件系统。但也具有其局限性,RomFS是一种只读文件系统。
6.2.2 注册devfs文件系统
把RomFS当作初始文件系统rootfs挂载在根目录,在RomFS里创建几个目录,用于其他文件系统的挂载点。
更改… omfs.c文件,添加mnt文件夹和user文件夹。
2#include 《dfs_romfs.h》
3
4static const struct romfs_dirent _romfs_root[] = {
5 {ROMFS_DIRENT_DIR, ”mnt“, RT_NULL, 0},
6 {ROMFS_DIRENT_DIR, ”user“, RT_NULL, 0}
7};
8
9const struct romfs_dirent romfs_root = {
10 ROMFS_DIRENT_DIR, ”/“, (rt_uint8_t *)_romfs_root, sizeof(_romfs_root)/sizeof(_romfs_root[0])
11};
设置romfs文件系统的数据结构:_romfs
1static const struct dfs_filesystem_ops _romfs =
2{
3 ”rom“,
4 DFS_FS_FLAG_DEFAULT,
5 &_rom_fops,
6
7 dfs_romfs_mount,
8 dfs_romfs_unmount,
9 NULL,
10 NULL,
11
12 NULL,
13 dfs_romfs_stat,
14 NULL,
15};
将romfs文件系统的数据结构挂载到文件系统操作表里
1int dfs_romfs_init(void)
2{
3 /* register rom file system */
4 dfs_register(&_romfs);
5 return 0;
6}
7INIT_COMPONENT_EXPORT(dfs_romfs_init);//自动初始化
检查romfs文件系统是否已经存在于文件系统操作表的目录中
在文件系统操作表中找出一个空的文件类型条目
将romfs文件系统的数据结构_romfs地址赋值给空的文件系统操作表目录
文件系统操作表filesystem_operation_table的第二个目录:
6.2.3 挂载romfs文件系统
1int mnt_init(void)
2{
3 if(dfs_mount (RT_NULL,”/“,”rom“,0,&(romfs_root)) == 0)
4 {
5 rt_kprintf(”ROM file system initializated;
“);
6 }
7 else
8 {
“);
10 }
11 return 0;
12}
13INIT_ENV_EXPORT(mnt_init);
在文件系统操作表中找出romfs文件系统
检查”/“路径是否存在
检查romfs文件系统是否已经挂载在文件系统表中
检查文件系统表是否有空余,如果有,把空余地址指向romfs文件系统
注册文件系统
调用romfs文件系统的挂载接口
文件系统表filesystem_table的第二个目录:
6.2.4 测试RomFS文件系统
在根目录下使用shell 的ls命令:
6.3.1 简介
RamFS是内存文件系统,它不能格式化,可以同时创建多个,在创建时可以指定其最大能使用的内存大小。其优点是读写速度很快,但存在掉电丢失的风险。如果一个进程的性能瓶颈是硬盘的读写,那么可以考虑在RamFS上进行大文件的读写操作。
RT-Thread的RamFS设计之初未考虑支持文件夹,所以不能使用mkdir。
6.3.2 注册RamFS文件系统
设置ramfs文件系统的数据结构:_ramfs
1static const struct dfs_filesystem_ops _ramfs =
2{
3 ”ram“,
4 DFS_FS_FLAG_DEFAULT,
5 &_ram_fops,
6
7 dfs_ramfs_mount,
8 dfs_ramfs_unmount,
9 NULL, /* mkfs */
10 dfs_ramfs_statfs,
11
12 dfs_ramfs_unlink,
13 dfs_ramfs_stat,
14 dfs_ramfs_rename,
15};
将ramfs文件系统的数据结构挂载到文件系统操作表里
1int dfs_ramfs_init(void)
2{
3 /* register ram file system */
4 dfs_register(&_ramfs);
5
6 return 0;
7}
8INIT_COMPONENT_EXPORT(dfs_ramfs_init);
检查ramfs文件系统是否已经存在于文件系统操作表的目录中
在文件系统操作表中找出一个空的文件类型条目
将ramfs文件系统的数据结构_ramfs地址赋值给空的文件系统操作表目录
文件系统操作表filesystem_operation_table的第三个目录:
6.3.3 挂载RamFS文件系统
1int mnt_ram_elminit(void)
2{
3 if(dfs_mount (RT_NULL,”/mnt“,”ram“,0,dfs_ramfs_create(rampool, 1024)) == 0)
4 {
5 rt_kprintf(”ram file system initializated;
“);
6 }
7 else
8 {
9 rt_kprintf(”ram file system initializate failed;
“);
10 }
11 return 0;
12}
13INIT_ENV_EXPORT(mnt_ram_elminit);
在文件系统操作表中找出ramfs文件系统
检查”/mnt“路径是否存在
检查ramfs文件系统是否已经挂载在文件系统表中
检查文件系统表是否有空余,如果有,把空余地址指向ramfs文件系统
注册文件系统
调用ramfs文件系统的挂载接口
文件系统表filesystem_table的第三个目录:
6.3.4 测试RamFS文件系统
在根目录下使用shell 的cd命令切换到/mnt目录,然后使用ls命令:
6.4 elm-FAT文件系统
6.4.1 简介
FatFs 是一个通用的文件系统(FAT/exFAT)模块,用于在小型嵌入式系统中实现FAT文件系统。
6.4.2 使用流程
初始化 DFS 组件。
初始化具体类型的文件系统。
格式化块设备。
挂载块设备到 DFS 目录中。
当文件系统不再使用,可以将它卸载
6.4.3 注册elm-FAT文件系统
设置fatfs文件系统的数据结构:dfs_elm
1static const struct dfs_filesystem_ops dfs_elm =
2{
3 ”elm“,
4 DFS_FS_FLAG_DEFAULT,
5 &dfs_elm_fops,
6
7 dfs_elm_mount,
8 dfs_elm_unmount,
9 dfs_elm_mkfs,
10 dfs_elm_statfs,
11
12 dfs_elm_unlink,
13 dfs_elm_stat,
14 dfs_elm_rename,
15};
将fatfs文件系统的数据结构挂载到文件系统操作表里
1int elm_init(void)
2{
3 /* register fatfs file system */
4 dfs_register(&dfs_elm);
5
6 return 0;
7}
8INIT_COMPONENT_EXPORT(elm_init);
检查fatfs文件系统是否已经存在于文件系统操作表的目录中
在文件系统操作表中找出一个空的文件类型条目
将fatfs文件系统的数据结构dfs_elm 地址赋值给空的文件系统操作表目录
elm-FAT文件系统注册过程如下图所示:
6.4.4 挂载elm-FAT文件系统
1void sd_mount(void *parameter)
2{
3 while (1)
4 {
5 rt_thread_mdelay(500);
6 if(rt_device_find(”sd0“) != RT_NULL)
7 {
8 if (dfs_mount(”sd0“, ”/fatfs“, ”elm“, 0, 0) == RT_EOK)
9 {
10 LOG_I(”sd card mount to ‘/fatfs’“);
11 break;
12 }
13 else
14 {
15 LOG_W(”sd card mount to ‘/fatfs’ failed!“);
16 }
17 }
18 }
19}
20
22{
23 rt_thread_t tid;
24
25 tid = rt_thread_create(”sd_mount“, sd_mount, RT_NULL,
26 1024, RT_THREAD_PRIORITY_MAX - 2, 20);
27 if (tid != RT_NULL)
28 {
29 rt_thread_startup(tid);
30 }
31 else
32 {
33 LOG_E(”create sd_mount thread err!“);
34 }
35 return RT_EOK;
36}
在文件系统操作表中找出elm文件系统
检查”/fatfs“路径是否存在
检查elm文件系统是否已经挂载在文件系统表中
检查文件系统表是否有空余,如果有,把空余地址指向elm文件系统
注册文件系统
调用elm文件系统的挂载接口
6.4.5 测试elm-FAT文件系统
在根目录下使用shell 的cd命令切换到/fatfs目录,然后使用ls命令:
6.5 littlefs文件系统
6.5.1 简介
自带擦写均衡
支持掉电保护
占用的 RAM/ROM 少
littlefs 自带的擦写均衡和掉电保护使开发者可以放心的将文件系统挂载到 nor flash 上。层级关系
littlefs 在 RT-Thread 上运行的层级关系图如下所示:
6.5.2 使用流程
初始化 DFS 组件。
使能 littlefs 软件包。
使能 MTD 设备。
使能 fal,用来创建 MTD 设备。
创建 MTD 设备
挂载MTD设备到 DFS 目录中。
6.5.3 注册littlefs文件系统
设置littlefs文件系统的数据结构:_dfs_lfs_ops
1static const struct dfs_filesystem_ops _dfs_lfs_ops = {
2 ”lfs“,
3 DFS_FS_FLAG_DEFAULT,
4 &_dfs_lfs_fops,
5
6 _dfs_lfs_mount,
7 _dfs_lfs_unmount,
8
9 _dfs_lfs_mkfs,
10 _dfs_lfs_statfs,
11 _dfs_lfs_unlink,
12 _dfs_lfs_stat,
13 _dfs_lfs_rename,
14};
将littlefs文件系统的数据结构挂载到文件系统操作表里
1int dfs_lfs_init(void)
2{
3 /* init file system lock */
5 /* register ram file system */
6 return dfs_register(&_dfs_lfs_ops);
7}
8INIT_COMPONENT_EXPORT(dfs_lfs_init);
检查littlefs文件系统是否已经存在于文件系统操作表的目录中
在文件系统操作表中找出一个空的文件类型条目
将littlefs文件系统的数据结构_dfs_lfs_ops 地址赋值给空的文件系统操作表目录
6.5.4 挂载littlefs文件系统
1 。..
2 struct rt_device *mtd_dev = RT_NULL;
3
4 。..
5 /* 初始化 fal */
6 fal_init();
7 /* 生成 mtd 设备 */
8 mtd_dev = fal_mtd_nor_device_create(FS_PARTITION_NAME);
9 if (!mtd_dev)
10 {
12 }
13 else
14 {
15 /* 挂载 littlefs */
16 if (dfs_mount(FS_PARTITION_NAME, ”/littlefs“, ”lfs“, 0, 0) == 0)
17 {
18 LOG_I(”Filesystem initialized!“);
19 }
20 else
21 {
22 /* 格式化文件系统 */
23 dfs_mkfs(”lfs“, FS_PARTITION_NAME);
24 /* 挂载 littlefs */
25 if (dfs_mount(”filesystem“, ”/littlefs“, ”lfs“, 0, 0) == 0)
26 {
27 LOG_I(”Filesystem initialized!“);
28 }
29 else
30 {
31 LOG_E(”Failed to initialize filesystem!“);
32 }
33 }
34 }
35 。..
在文件系统操作表中找出lfs文件系统
检查”/littlefs“路径是否存在
检查littlefs文件系统是否已经挂载在文件系统表中
检查文件系统表是否有空余,如果有,把空余地址指向littlefs文件系统
注册文件系统
调用littlefs文件系统的挂载接口
6.5.5 测试littlefs文件系统
在根目录下使用shell 的cd命令切换到/littlefs目录,然后使用ls命令:
注意:spi_flash.h中缺少一个头文件,需要自行添加
6.6 文件系统综合例程
DevFS、RomFS、RamFS、FatFS文件系统配置:
littlefs文件系统配置;
主程序:
1#include 《rtthread.h》
2#include 《rtdevice.h》
3#include 《board.h》
4#include 《fal.h》
5
6#include 《dfs_fs.h》
7#include 《dfs_romfs.h》
8#include 《dfs_ramfs.h》
9#include 《dfs_posix.h》
10
11#define DBG_TAG ”main“
12#define DBG_LVL DBG_LOG
13#include 《rtdbg.h》
14
15/* defined the LED0 pin: PH10 */
16#define LED0_PIN GET_PIN(H, 10)
17
18int main(void)
19{
20 int count = 1;
21 rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
22
23 while (count++)
24 {
25 rt_pin_write(LED0_PIN, PIN_HIGH);
26 rt_thread_mdelay(1000);
27 rt_pin_write(LED0_PIN, PIN_LOW);
28 rt_thread_mdelay(1000);
29 }
30
31 return RT_EOK;
32}
33rt_uint8_t rampool[128];
34
35void sd_mount(void *parameter)
36{
37 while (1)
38 {
39 rt_thread_mdelay(500);
40 if(rt_device_find(”sd0“) != RT_NULL)
41 {
42 if (dfs_mount(”sd0“, ”/fatfs“, ”elm“, 0, 0) == RT_EOK)
43 {
44 LOG_I(”sd card mount to ’/fatfs‘“);
45 break;
46 }
47 else
48 {
49 LOG_W(”sd card mount to ’/fatfs‘ failed!“);
50 }
51 }
52 }
53}
54
55int fs_init(void)
56{
57 /* partition initialized */
58 fal_init();
59
60 if(dfs_mount (RT_NULL,”/“,”rom“,0,&(romfs_root)) == 0)
61 {
62 LOG_I(”ROM file system initializated;
“);
63 }
64 else
65 {
66 LOG_I(”ROM file system initializate failed;
“);
67 }
68
69 if(dfs_mount (RT_NULL,”/ram“,”ram“,0,dfs_ramfs_create(rampool, sizeof(rampool))) == 0)
70 {
71 LOG_I(”ram file system initializated;
“);
72 }
73 else
74 {
75 LOG_I(”ram file system initializate failed;
“);
76 }
77
78 /* Create a block device on the file system partition of spi flash */
79 struct rt_device *flash_dev = fal_mtd_nor_device_create(”filesystem“);
80
81 if (flash_dev == RT_NULL)
82 {
83 LOG_I(”Can’t create a mtd device on ‘%s’ partition.“, ”filesystem“);
84 }
85 else
86 {
87 LOG_I(”Create a mtd device on the %s partition of flash successful.“, ”filesystem“);
88 }
89 /* mount the file system from ”filesystem“ partition of spi flash. */
90 if (dfs_mount(flash_dev-》parent.name, ”/littlefs“, ”lfs“, 0, 0) == 0)
91 {
92 LOG_I(”littlefs initialized!“);
93 }
94 else
95 {
96 dfs_mkfs(”lfs“, flash_dev-》parent.name);
97 if (dfs_mount(flash_dev-》parent.name, ”/“, ”lfs“, 0, 0) == 0)
98 {
99 LOG_I(”littlefs initialized!“);
100 }
101 }
102
103 rt_thread_t tid;
104
105 tid = rt_thread_create(”sd_mount“, sd_mount, RT_NULL,
106 1024, RT_THREAD_PRIORITY_MAX - 2, 20);
107 if (tid != RT_NULL)
108 {
109 rt_thread_startup(tid);
110 }
111 else
112 {
113 LOG_E(”create sd_mount thread err!“);
114 }
115 return 0;
116}
117INIT_COMPONENT_EXPORT(fs_init);
测试:
责任编辑:pj
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~