From 834747375bfa52d4134eeb9b6dd71a787abf779b Mon Sep 17 00:00:00 2001 From: armink Date: Sat, 2 Feb 2019 22:51:51 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E5=A2=9E=E5=8A=A0=E3=80=91=E4=B8=8B?= =?UTF-8?q?=E4=B8=80=E4=BB=A3=20EasyFlash=204.0=20=E9=83=A8=E5=88=86?= =?UTF-8?q?=E6=A1=86=E6=9E=B6=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: armink --- easyflash/src/ef_env_ng.c | 393 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 393 insertions(+) create mode 100644 easyflash/src/ef_env_ng.c diff --git a/easyflash/src/ef_env_ng.c b/easyflash/src/ef_env_ng.c new file mode 100644 index 0000000..3e9bc07 --- /dev/null +++ b/easyflash/src/ef_env_ng.c @@ -0,0 +1,393 @@ +/* + * This file is part of the EasyFlash Library. + * + * Copyright (c) 2019, Armink, + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * 'Software'), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Function: Environment variables operating interface. This is the Next Generation version. + * Created on: 2019-02-02 + */ + +#include + +#if defined(EF_USING_ENV) + +/* the flash write granularity, unit: bit */ +//#define EF_WRITE_GRAN 1 +#define EF_WRITE_GRAN 8 + + + +#if EF_WRITE_GRAN != 1 && EF_WRITE_GRAN != 8 && EF_WRITE_GRAN != 32 && EF_WRITE_GRAN != 64 +#error "the write gran can be only setting as 1, 8, 32 and 64" +#endif + +/* the ENV max name length must less then it */ +#define EF_ENV_NAME_MAX 256 +/* magic word(`E`, `F`, `4`, `0`) */ +#define SECTOR_MAGIC_WORD 0x45463430 + +/* the using status sector table length */ +#ifndef USING_SECTOR_TABLE_LEN +#define USING_SECTOR_TABLE_LEN 4 +#endif + +/* Return the most contiguous size aligned at specified width. RT_ALIGN(13, 4) + * would return 16. + */ +#define EF_ALIGN(size, align) (((size) + (align) - 1) & ~((align) - 1)) + +#define STATUS_MASK ((1UL << EF_WRITE_GRAN) - 1) + +#define STATUS_TABLE_SIZE(status_number) (EF_ALIGN(status_number * EF_WRITE_GRAN, 8) / 8) + +#define STORE_STATUS_TABLE_SIZE STATUS_TABLE_SIZE(SECTOR_STORE_STATUS_NUM) +#define DIRTY_STATUS_TABLE_SIZE STATUS_TABLE_SIZE(SECTOR_DIRTY_STATUS_NUM) +#define ENV_STATUS_TABLE_SIZE STATUS_TABLE_SIZE(ENV_STATUS_NUM) + +enum sector_store_status { + SECTOR_STORE_EMPTY, + SECTOR_STORE_USING, + SECTOR_STORE_FULL, + SECTOR_STORE_STATUS_NUM, +}; +typedef enum sector_store_status sector_store_status_t; + +enum sector_dirty_status { + SECTOR_DIRTY_FALSE, + SECTOR_DIRTY_TRUE, + SECTOR_DIRTY_STATUS_NUM, +}; +typedef enum sector_dirty_status sector_dirty_status_t; + +enum env_status { + ENV_PRE_WRITE, + ENV_WRITE, + ENV_DELETED, + ENV_GC, + ENV_STATUS_NUM, +}; +typedef enum env_status env_status_t; + +struct sector_hdr_data { + uint32_t magic; /**< magic word(`E`, `F`, `4`, `0`) */ + uint32_t combined; /**< the combined next sector number, 0xFFFFFFFF: not combined */ + uint32_t reserved; + struct { + uint8_t store[STORE_STATUS_TABLE_SIZE]; /**< sector store status @see sector_store_status_t */ + uint8_t dirty[DIRTY_STATUS_TABLE_SIZE]; /**< sector dirty status @see sector_dirty_status_t */ + } status_table; +}; + +struct sector_meta_data { + struct { + sector_store_status_t store; /**< sector store status @see sector_store_status_t */ + sector_dirty_status_t dirty; /**< sector dirty status @see sector_dirty_status_t */ + } status; + uint32_t addr; /**< sector start address */ + uint32_t magic; /**< magic word(`E`, `F`, `4`, `0`) */ + uint32_t combined; /**< the combined next sector number, 0xFFFFFFFF: not combined */ + size_t remain; /**< remain size */ + uint32_t first_env; /**< the first ENV node address on this sector */ + uint32_t empty_env; /**< the next empty ENV node start address */ +}; +typedef struct sector_meta_data *sector_meta_data_t; + +struct env_hdr_data { + uint32_t len; /**< ENV node total length (header + name + value), must align by EF_WRITE_GRAN */ + uint8_t status_table[ENV_STATUS_TABLE_SIZE]; /**< ENV node status, @see node_status_t */ + uint32_t crc32; /**< ENV node crc32(name_len + data_len + name + value) */ + uint8_t name_len; /**< name length */ + uint32_t value_len; /**< value length */ +}; + +struct env_meta_data { + bool crc_is_ok; /**< ENV node CRC32 check is OK */ + uint8_t name_len; /**< name length */ + env_status_t status; /**< ENV node status, @see node_status_t */ + uint32_t value_len; /**< value length */ + struct { + uint32_t start; /**< ENV node start adress */ + uint32_t name; /**< name start address */ + uint32_t value; /**< value start address */ + } addr; +}; +typedef struct env_meta_data *env_meta_data_t; + +static const uint64_t status_mask = ((1UL << EF_WRITE_GRAN) - 1); +/* ENV start address in flash */ +static uint32_t env_start_addr = 0; +/* default ENV set, must be initialized by user */ +static ef_env const *default_env_set; +/* default ENV set size, must be initialized by user */ +static size_t default_env_set_size = 0; +/* initialize OK flag */ +static bool init_ok = false; +/* the using status sector table */ +static struct sector_meta_data using_sec_table[USING_SECTOR_TABLE_LEN]; + +static size_t set_status(uint8_t status_table[], size_t status_num, size_t status_index) +{ + size_t byte_index = ~0UL; + /* + * | write garn | status0 | status1 | status2 | + * --------------------------------------------------------------------------------- + * | 1bit | 0xFF | 0x7F | 0x3F | + * | 8bit | 0xFFFF | 0x00FF | 0x0000 | + * | 32bit | 0xFFFFFFFF FFFFFFFF | 0x00FFFFFF FFFFFFFF | 0x00FFFFFF 00FFFFFF | + */ + memset(status_table, 0xFF, STATUS_TABLE_SIZE(status_num)); + if (status_index > 0) { +#if (EF_WRITE_GRAN == 1) + byte_index = (status_index - 1) / 8; + status_table[byte_index] &= ~(0x80 >> ((status_index - 1) % 8)); +#else + byte_index = (status_index - 1) * (EF_WRITE_GRAN / 8); + status_table[byte_index] = 0x00; +#endif /* EF_WRITE_GRAN == 1 */ + } + + return byte_index; +} + +static size_t get_status(uint8_t status_table[], size_t status_num) +{ + size_t i = 0, status_num_bak = --status_num; + + while (status_num --) { + /* get the first 0 position from end address to start address */ +#if (EF_WRITE_GRAN == 1) + if ((status_table[status_num / 8] & (0x80 >> (status_num % 8))) == 0x00) { + break; + } +#else /* (EF_WRITE_GRAN == 8) || (EF_WRITE_GRAN == 32) || (EF_WRITE_GRAN == 64) */ + if (status_table[status_num * EF_WRITE_GRAN / 8] == 0x00) { + break; + } +#endif /* EF_WRITE_GRAN == 1 */ + i++; + } + + return status_num_bak - i; +} + +static env_meta_data_t get_next_env(sector_meta_data_t sector, env_meta_data_t pre_env) +{ + //TODO 计算下一个节点的地址,注意考虑越界 + //TODO 读取节点的各个元数据 + //TODO 检查 CRC32 是否正确 + + return pre_env; +} + +static EfErrCode read_sector_meta_data(uint32_t addr, sector_meta_data_t sector) +{ + EfErrCode result = EF_NO_ERR; + + //TODO 检查入参 + //TODO 通过 flash 读取数据 + //TODO 检查各个数据有效性,出错则退出 + //TODO 计算剩余空间 + + return result; +} + +static EfErrCode find_env(const char *key, env_meta_data_t env) +{ + EfErrCode result = EF_NO_ERR; + + //TODO 遍历所有正在使用及已满扇区 + + return result; +} + +/** + * Get an ENV value by key name. + * + * @param key ENV name + * + * @return value + */ +char *ef_get_env(const char *key) +{ + //TODO 查找 env + //TODO 找到后检查其是否为字符串,否则弹出警告 + + + //TODO 如何返回值!!!!!!!! + + return NULL; +} + +static EfErrCode create_env_blob(const char *key, void *value, size_t len) +{ + //TODO 计算 ENV 节点占用 Flash 大小,结合 flash 写粒度 + //TODO 检查节点长度是否过大,过大则断言,后期支持大数据存储模式 + //TODO 检查所有扇区的剩余空间,是否有合适的扇区,优先 using_sec_table + //TODO 计算 CRC,拷贝数据,写入等 + //TODO 更新 using_sec_table +} + +/** + * Set an ENV.If it value is NULL, delete it. + * If not find it in ENV table, then create it. + * + * @param key ENV name + * @param value ENV value + * + * @return result + */ +EfErrCode ef_set_env(const char *key, const char *value) +{ + EfErrCode result = EF_NO_ERR; + + //TODO 从第一个扇区开始查找所有正在使用及已满扇区,确认该环境变量是否存在 + //TODO 如果存在则备份原始节点元数据,标记该节点为正在删除 + //TODO 新增节点 + //TODO 如果之前存在节点,则标记以前的节点为已删除 + //TODO GC + + + return result; +} + +/** + * Delete an ENV. + * + * @param key ENV name + * + * @return result + */ +EfErrCode ef_del_env(const char *key) +{ + EfErrCode result = EF_NO_ERR; + + return result; +} + +/** + * Save ENV to flash. + */ +EfErrCode ef_save_env(void) +{ + /* do nothing not cur mode */ + return EF_NO_ERR; +} + +/** + * ENV set default. + * + * @return result + */ +EfErrCode ef_env_set_default(void) +{ + EfErrCode result = EF_NO_ERR; + + return result; +} + +/** + * Print ENV. + */ +void ef_print_env(void) +{ + +} + +#ifdef EF_ENV_AUTO_UPDATE +/** + * Auto update ENV to latest default when current EF_ENV_VER is changed. + * + * @return result + */ +static EfErrCode env_auto_update(void) +{ + size_t i; + + /* lock the ENV cache */ + ef_port_env_lock(); + + //TODO 检查环境变量版本号 + //TODO 自动升级环境变量 + //TODO 更新环境变量版本号 + + /* unlock the ENV cache */ + ef_port_env_unlock(); + + return EF_NO_ERR; +} +#endif /* EF_ENV_AUTO_UPDATE */ + +/** + * Check and load the flash ENV meta data. + * + * @return result + */ +EfErrCode ef_load_env(void) +{ + //TODO 检查各个扇区状态,magic 不对则退出 返回 EF_ENV_INIT_FAILED + //TODO 如果异常则执行全盘格式化,还原默认环境变量 + //TODO 检查是否存在未完成的环境变量操作,存在则执行掉电恢复 + //TODO 检查是否存在未完成的垃圾回收工作,存在则继续整理 + //TODO 装载环境变量元数据,using_sec_table + + return EF_NO_ERR; +} + +/** + * Flash ENV initialize. + * + * @param default_env default ENV set for user + * @param default_env_size default ENV set size + * + * @return result + */ +EfErrCode ef_env_init(ef_env const *default_env, size_t default_env_size) { + EfErrCode result = EF_NO_ERR; + + EF_ASSERT(ENV_AREA_SIZE); + EF_ASSERT(EF_ERASE_MIN_SIZE); + /* must be aligned with erase_min_size */ + EF_ASSERT(ENV_AREA_SIZE % EF_ERASE_MIN_SIZE == 0); + EF_ASSERT(default_env); + + env_start_addr = EF_START_ADDR; + default_env_set = default_env; + default_env_set_size = default_env_size; + + EF_DEBUG("ENV start address is 0x%08X, size is %d bytes.\n", EF_START_ADDR, ENV_AREA_SIZE); + + result = ef_load_env(); + +#ifdef EF_ENV_AUTO_UPDATE + if (result == EF_NO_ERR) { + env_auto_update(); + } +#endif + + if (result == EF_NO_ERR) { + init_ok = true; + } + + return result; +} + +#endif /* defined(EF_USING_ENV) */