前言

FlashDB是一款超轻量级的嵌入式数据库,专注于提供嵌入式产品的数据存储方案。与传统的基于文件系统的数据库不同,FlashDB结合了 Flash 的特性,具有较强的性能及可靠性。并在保证极低的资源占用前提下,尽可能延长 Flash 使用寿命。

固件下载

github下载地址:https://github.com/armink/FlashDB

gitee下载地址:https://gitee.com/Armink/FlashDB

软件移植

1.闪存设备移植

(1)闪存设备表设置

目前只使用Norflash外部flash作为存储设备,所以只需要设置一个设备。设备表代码如下

/* flash device table */
#define FAL_FLASH_DEV_TABLE                                          \
{                                                                    \
    &nor_flash0,                                                     \
}

(2)闪存区块划分

目前闪存主要用于bsp数据、日志、文件系统存储,主要设置分区名称、关联的 Flash 设备名、偏移地址(相对 Flash 设备内部)、大小。

#define FAL_PART_TABLE                                                                 \
{                                                                                      \
    {FAL_PART_MAGIC_WROD,  FAL_PART_TSDB_BSP_NAME ,      "norflash0",   9*1024*1024, 1*1024*1024, 0}, \
    {FAL_PART_MAGIC_WROD,  FAL_PART_LOG_NAME,            "norflash0",  11*1024*1024, 8*1024*1024, 0}, \
    {FAL_PART_MAGIC_WROD,  FAL_PART_FATFS_NAME    ,     "norflash0",  32*1024*1024, 32*1024*1024, 0}, \
}

(3)闪存设备设置

norflash主要配置norflash的大小,名称,读写擦接口等。

struct fal_flash_dev nor_flash0 =
{
    .name       = FAL_USING_NOR_FLASH_DEV_NAME,
    .addr       = 0,
    .len        = 1 * 1024 * 1024,
    .blk_size   = 4096,
    .ops        = {init, read, write, erase},
    .write_gran = 1
};

其中函数接口主要是实现对norflash的初始化、读、写、擦

初始化函数

#define SFUD_FLASH_DEVICE_TABLE                                     \
{                                                                   \
[SFUD_W25_DEVICE_INDEX] = 
{.name 	 = "W25Q512JV", 				\
.spi.name = "SPI3",					\
.chip = {"W25Q512JV", SFUD_MF_ID_WINBOND, 0x40, 0x20, 64L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20},\
}
}

static int init(void)
{

	sfud_dev = sfud_get_device_table();


    if (NULL == sfud_dev)
    {
        return -1;
    }

    /* update the flash chip information */
    nor_flash0.blk_size = sfud_dev->chip.erase_gran;
    nor_flash0.len = sfud_dev->chip.capacity;
    lock_init();
    return 0;
}

读函数

static int read(long offset, uint8_t *buf, size_t size)
{
    assert(sfud_dev);
    assert(sfud_dev->init_ok);
    sfud_read(sfud_dev, nor_flash0.addr + offset, size, buf);

    return size;
}

写函数

static int write(long offset, const uint8_t *buf, size_t size)
{
    assert(sfud_dev);
    assert(sfud_dev->init_ok);
    if (sfud_write(sfud_dev, nor_flash0.addr + offset, size, buf) != SFUD_SUCCESS)
    {
        return -1;
    }

    return size;
}

擦除函数

static int erase(long offset, size_t size)
{
    assert(sfud_dev);
    assert(sfud_dev->init_ok);
    if (sfud_erase(sfud_dev, nor_flash0.addr + offset, size) != SFUD_SUCCESS)
    {
        return -1;
    }

    return size;
}

2.FlashDB配置

在fdb_cfg.h文件中可以设置相关配置,详见如下

FDB_USING_KVDB
// 使能 KVDB 功能

FDB_KV_AUTO_UPDATE
// 使能 KV 自动升级功能。该功能使能后, fdb_kvdb.ver_num 存储了当前数据库的版本,如果版本发生变化时,会自动触发升级动作,将更新新的默认 KV 集合至当前数据库中。

FDB_USING_TSDB
// 使能 TSDB 功能

FDB_USING_FAL_MODE
// 使能 FAL 模式,FAL 里的分区用于存储数据库。该模式下,FlashDB 直接操作 Flash,所以性能较好

// FDB_USING_FILE_LIBC_MODE 与 FDB_USING_FILE_POSIX_MODE 模式只能二选一。相比 FAL 模式,文件模式下数据库的存储位置、大小及数量没有限制。
FDB_USING_FILE_POSIX_MODE
// 使用 POSIX 的文件模式,需要系统提供 open/read/write/close 相关文件访问接口。
FDB_USING_FILE_LIBC_MODE
// 使用 C 标准库的文件模式,需要系统提供 fopen/fread/fwrite/fclose 相关文件访问接口。


FDB_WRITE_GRAN
// Flash 写粒度,单位为 bit。目前支持
// 1: nor flash
// 8: stm32f2/f4 片上 Flash
// 32: stm32f1 片上 Flash
// 如果数据库中使用了多种 Flash 规格,例如:既有 nor flash,也有 stm32f4 片上 Flash ,此时取最大值作为配置项,即:8 bit

FDB_BIG_ENDIAN
// MCU 大小端配置,默认不配置时,系统自动使用小端配置

FDB_PRINT(...)
// 打印函数宏定义配置,默认不配置时,使用 printf 作为打印日志是输出函数。用户也可以自定义新的打印函数宏定义,例如:

#define FDB_PRINT(...)              my_printf(__VA_ARGS__)
FDB_DEBUG_ENABLE
// 使能调试信息输出。关闭该配置时,系统将不会输出用于调试的日志。

3.FlashDB API接口

(1)首先初始化flashdb数据库

        fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_SET_LOCK, (void *)lock);
        fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_SET_UNLOCK, (void *)unlock);
        result = fdb_tsdb_init(&tsdb, "log", "fdb_tsdb1", get_time, 128, NULL);

(2)写入flashdb数据库

先将数据存放到自定义结构体中,制作blob包并将数据写入(追加写入)数据库中

    { /* APPEND new TSL (time series log) */
        struct env_status status;

        /* append new log to TSDB */
        status.temp = 36;
        status.humi = 85;
        fdb_tsl_append(tsdb, fdb_blob_make(&blob, &status, sizeof(status)));


        status.temp = 38;
        status.humi = 90;
        fdb_tsl_append(tsdb, fdb_blob_make(&blob, &status, sizeof(status)));

    }

(3)读取flashdb数据库

通过起始时间和结束时间将数据库中数据读到结构体中,同时可以读取这个时间段的TSL数据量

    { /* QUERY the TSDB by time */
        /* prepare query time (from 1970-01-01 00:00:00 to 2020-05-05 00:00:00) */
        struct tm tm_from = { .tm_year = 1970 - 1900, .tm_mon = 0, .tm_mday = 1, .tm_hour = 0, .tm_min = 0, .tm_sec = 0 };
        struct tm tm_to = { .tm_year = 2020 - 1900, .tm_mon = 4, .tm_mday = 5, .tm_hour = 0, .tm_min = 0, .tm_sec = 0 };
        time_t from_time = mktime(&tm_from), to_time = mktime(&tm_to);
        size_t count;
        /* query all TSL in TSDB by time */
        fdb_tsl_iter_by_time(tsdb, from_time, to_time, query_by_time_cb, tsdb);
        /* query all FDB_TSL_WRITE status TSL's count in TSDB by time */
        count = fdb_tsl_query_count(tsdb, from_time, to_time, FDB_TSL_WRITE);
        FDB_INFO("query count is: %zu\n", count);
    }

(4)清空flashdb数据库

{
    struct fdb_blob;
    gType_TSDBInfo_st *p_ts_info = NULL;
    fdb_tsl_clean(p_ts_info->p_tsdb);
}

4.参考文档

文档路径:

https://armink.gitee.io/flashdb/#/zh-cn/quick-started

更多推荐