前言
通过查看oneOS中对littlefs的移植工作,发现,littlefs源码本身,有用的就4个:
- lfs.c
- lfs.h
- lfs_util.c
- lfs_util.h
剩下的就是适配层:
- dfs_lfs.c
- lfs_config.h(和
lfs_util.h
差不多) - lfs_crc.c(和
lfs_util.c
差不多)
然后再对比其源码,发现,littlefs的源码完全没有更改,更改的只有是适配层,因此,接下来重点看看适配层到底改了什么!
适配层更改
先看lfs_crc.c
:
他和lfs_util.c
几乎一样,唯一区别在于:
如果没有定义宏LFS_CONFIG
,那么将使用lfs_util.c
中的lfs_crc
接口;
如果定义了宏LFS_CONFIG
,那么将使用lfs_crc.c
中的lfs_crc
接口。
oneOS在sconscript中是定义了该宏的:
CPPDEFINES = ['LFS_CONFIG=lfs_config.h']
另外该宏在lfs_util.h
中有被用到作为一个判断:
- 用户可以通过定义一个头文件来包含自己的配置来覆盖
lfs_util.h
,通过定义LFS_CONFIG
为一个头文件来包含(-DLFS_CONFIG=lfs_config.h
)。 - 如果使用了
LFS_CONFIG
,那么默认的lfs_util.h
将不会被输出,必须由配置文件提供。建议复制lfs_util.h
并根据需要修改。
#ifdef LFS_CONFIG
#define LFS_STRINGIZE(x) LFS_STRINGIZE2(x)
#define LFS_STRINGIZE2(x) #x
#include LFS_STRINGIZE(LFS_CONFIG)
#else
... ...
#endif
可见,是在lfs_util.h
文件中,直接include lfs_config.h
再看lfs_config.h
:
同样,他就是lfs_util.h
改过来的,并没有太大区别。主要看点在于:
- 如果没有定义
LFS_ASSERT&&LFS_NO_ASSERT
,util.h
用的是assert.h
里面的函数assert
,而config
用的是oneOS
自带的os_assert
。 - 如果没有定义
LFS_NO_MALLOC
,说明lfs
有malloc
,这时候util.h
用的是stdlib.h
里面的函数malloc
和free
,而config
用的是oneOS
自带的os_malloc
和os_free
。
适配dfs_lfs.c
最重要的适配层vfs_lfs.c,我把她单独拎出来,作为最高的敬意。
其实她的逻辑很清晰,最开始就是基本的配置,然后是littlefs需要用到的底层函数的适配,这两个都是对*struct* lfs_config
结构体成员的赋值,最后则是对接vfs层的接口适配。
基本配置
#ifndef RT_DEF_LFS_DRIVERS
#define RT_DEF_LFS_DRIVERS 1
#endif
#if (RT_DEF_LFS_DRIVERS < 1)
#error "#define RT_DEF_LFS_DRIVERS must > 0"
#endif
#ifndef LFS_READ_SIZE
#define LFS_READ_SIZE 256
#endif
#ifndef LFS_PROG_SIZE
#define LFS_PROG_SIZE 256
#endif
#ifndef LFS_BLOCK_SIZE
#define LFS_BLOCK_SIZE 4096
#endif
#ifndef LFS_CACHE_SIZE
#define LFS_CACHE_SIZE LFS_PROG_SIZE
#endif
#ifndef LFS_BLOCK_CYCLES
#define LFS_BLOCK_CYCLES (-1)
#endif
#ifndef LFS_LOOKAHEAD_MAX
#define LFS_LOOKAHEAD_MAX 128
#endif
lfs底层函数适配
static void _lfs_load_config(struct lfs_config* lfs_cfg, struct rt_mtd_nor_device* mtd_nor)
{
uint64_t mtd_size;
lfs_cfg->context = (void*)mtd_nor;
lfs_cfg->read_size = LFS_READ_SIZE;
lfs_cfg->prog_size = LFS_PROG_SIZE;
lfs_cfg->block_size = mtd_nor->block_size;
if (lfs_cfg->block_size < LFS_BLOCK_SIZE)
{
lfs_cfg->block_size = LFS_BLOCK_SIZE;
}
lfs_cfg->cache_size = LFS_CACHE_SIZE;
lfs_cfg->block_cycles = LFS_BLOCK_CYCLES;
mtd_size = mtd_nor->block_end - mtd_nor->block_start;
mtd_size *= mtd_nor->block_size;
lfs_cfg->block_count = mtd_size / lfs_cfg->block_size;
lfs_cfg->lookahead_size = 32 * ((lfs_cfg->block_count + 31) / 32);
if (lfs_cfg->lookahead_size > LFS_LOOKAHEAD_MAX)
{
lfs_cfg->lookahead_size = LFS_LOOKAHEAD_MAX;
}
#ifdef LFS_THREADSAFE
lfs_cfg->lock = _lfs_lock; //如果定义了线程安全,则使用mutex互斥锁
lfs_cfg->unlock = _lfs_unlock;
#endif
lfs_cfg->read = _lfs_flash_read; //littlefs用到的底层函数read
lfs_cfg->prog = _lfs_flash_prog; //littlefs用到的底层函数write
lfs_cfg->erase = _lfs_flash_erase;//littlefs用到的底层函数erase 直接返回OK
lfs_cfg->sync = _lfs_flash_sync; //littlefs用到的底层函数sync 直接返回OK
}
vfs对接层
主要是为了对接vfs层,让vfs的接口可以直接使用底层littfs函数。
static int _lfs_result_to_dfs(int result) //错误码转换
static int _vfs_lfs_mount(struct vfs_filesystem* vfs, unsigned long rwflag, const void* data) //挂载
static int _vfs_lfs_unmount(struct vfs_filesystem* vfs) //卸载
static int _vfs_lfs_open(struct vfs_file* file) //打开文件
... ...
static int _vfs_lfs_getdents(struct vfs_file* file, struct dirent* dirp, uint32_t count) //获得目录
适配总结
由此可见,适配lfs最重要的几步:
- 如果定义了LFS_CONFIG,要自己做好配置
- 基本的配置要做好,底层函数要适配,归结起来就是:
struct lfs_config
中的结构体成员要初始化好 - vfs对接层要做好,这是每一个底层文件系统到vfs层必须要做的
oneos-lfs对照
part_info->dev_info.dev = (void *)dev;
part_info->config.context = &part_info->dev_info;
part_info->config.read = g_lfs_dev_ops.read;
part_info->config.prog = g_lfs_dev_ops.prog;
part_info->config.erase = g_lfs_dev_ops.erase;
part_info->config.sync = g_lfs_dev_ops.sync;
#ifdef LFS_THREADSAFE
part_info->config.lock = g_lfs_dev_ops.lock;
part_info->config.unlock = g_lfs_dev_ops.unlock;
#endif
part_info->config.read_size = geometry.block_size;//最小读字节数,试了下不能乱改,sector
part_info->config.prog_size = geometry.block_size;//最小写字节数,试了下不能乱改,sector
part_info->config.block_size = geometry.block_size;//硬件块大小,试了下不能乱改,blocksize
part_info->config.block_count = geometry.capacity / geometry.block_size;//不用手动配
part_info->config.block_cycles = -1; //禁用块级磨损均衡
part_info->config.cache_size = geometry.block_size; //块缓存的大小,该值必须是读取和编程大小的倍数,并且是块大小的因数,就是要和block_size一样就好!!!
part_info->config.lookahead_size= LFS_LOOKAHEAD_SIZE; //块分配时的预测深度(分配块时每次步进多少个块),这个数值必须为8的整数倍,这个可以改!!!
part_info->config.read_buffer = OS_NULL; //lfs_init中会分配!
part_info->config.prog_buffer = OS_NULL; //lfs_init中会分配!
part_info->config.lookahead_buffer = OS_NULL; //lfs_init中会分配!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。