Compare commits

..

47 Commits

Author SHA1 Message Date
朱天龙 (Armink) a67fffcb4a
Merge pull request #159 from shiyj/master
[fix] 当环形缓冲的开始地址大于结束地址时,index转成地址时要加上log_area_start_addr
2 years ago
shiyj f9adf31468 [fix] 当环形缓冲的开始地址大于结束地址时,index转成地址时要加上log_area_start_addr
由于整个存储的起始地址不一定是LOG_AREA_SIZE的倍数,不可通过取余获取偏移
2 years ago
朱天龙 (Armink) 7b2073086a
Merge pull request #157 from kaidegit/patch-1
修复被cpp调用时的一点小问题
2 years ago
Kai 9e525c7475
add extern c if cpp 2 years ago
朱天龙 (Armink) bee1918ebd
Merge pull request #155 from i-jaffer/develop
[fix] fix byte alignment logic judgment error bug.
3 years ago
jaffer cbb16391b1 Merge branch 'fix/align_judge_bug' into develop 3 years ago
jaffer ac971cb63d [feat]fix byte alignment logic judgment error bug.
Signed-off-by: jaffer <jaffer.work@foxmail.com>
3 years ago
朱天龙 (Armink) f732982f71
Merge pull request #149 from i-jaffer/feat/calcu_usage
[feat]增加log总大小计算接口
3 years ago
Jaffer 90bc6d5c06
Merge pull request #1 from i-jaffer/feat/calcu_usage
Merge from feat/calcu_usage to develop.
3 years ago
jaffer 06370af0a2 [feat]增加log总大小计算接口。
Signed-off-by: jaffer <jaffer.work@foxmail.com>
3 years ago
朱天龙 (Armink) aaa168123f
Merge pull request #148 from i-jaffer/master
[fix][log]修复log index2addr 计算溢出风险以及优化 ef_log_read 函数参数错误判断处理 #146 #147
3 years ago
jaffer a5f09478f7 [fix]修复log index2addr 溢出实际物理地址空间风险
Signed-off-by: jaffer <jaffer.work@foxmail.com>
3 years ago
jaffer af12a8e8a7 [fix]优化日志log读取函数接口参数错误判断处理
Signed-off-by: jaffer <jaffer.work@foxmail.com>
3 years ago
朱天龙 (Armink) 91eb583605
Merge pull request #139 from iysheng/master
1. Fix compile error with incompatible types and function argument mismatch in README
3 years ago
朱天龙 (Armink) 4e992a8917
Merge pull request #145 from wu1045718093/perf-first-write-speed
[优化]优化启动时读写速度
3 years ago
teng.wu c5b48a4736 [优化]优化启动时读写速度 3 years ago
iysheng c2879bbf75 1. Fix compile error with incompatible types
2. Fix function argument mismatch in README
4 years ago
朱天龙 (Armink) f886316b3f
Merge pull request #128 from mx1117/master
Update ef_env.c
4 years ago
mx1117 d80224448a Update ef_env.c
EF_WG_ALIGN_DOWN(size) 可能为0,需要额外判断以避免某些芯片flash写0长度数据出错。
4 years ago
armink ef3556f202 【更新】图片素材
Signed-off-by: armink <armink.ztl@gmail.com>
5 years ago
armink 173b09d718 【完善】说明文档
Signed-off-by: armink <armink.ztl@gmail.com>
6 years ago
朱天龙 (Armink) ad78365216
Merge pull request #98 from Mculover666/master
[修复]注释符不匹配
6 years ago
mculover666 e034e0879f [修复]注释符不匹配 6 years ago
armink d4ef8b6caf 【完善】初始化功能,避免重复初始化。
Signed-off-by: armink <armink.ztl@gmail.com>
6 years ago
armink 7cd2f0a979 【完善】env 获取功能,查找失败后,save_len 将被置 0 。
Signed-off-by: armink <armink.ztl@gmail.com>
6 years ago
armink d8405708b6 【修改】软件版本号
Signed-off-by: armink <armink.ztl@gmail.com>
6 years ago
armink 7483c7971f 【更新】软件版本号。
Signed-off-by: armink <armink.ztl@gmail.com>
6 years ago
朱天龙 (Armink) 2d31e24352
Merge pull request #88 from wudicgi/fix-bug
修正了 find_env_cb() 函数中的一处判断 key 是否相等错误的 bug
6 years ago
Wudi 12f8f0864c 去除了 find_env_cb() 中修正 bug 后遗留的无用代码,同时修改了 max_len 的变量名和类型 6 years ago
朱天龙 (Armink) bcae150bf9
Merge pull request #89 from wudicgi/fix-bug-2
修正了 del_env() 函数中的一处未判断 key 是否为 NULL 的 bug
6 years ago
Wudi 9a3daaa4c6 修正了 del_env() 函数中的一处未判断 key 是否为 NULL 的 bug
move_env() 中末尾处在调用 del_env() 时会使用 del_env(NULL, env, true),
此时 key 为 NULL, 需使用 old_env 中的 name 和 name_len
6 years ago
Wudi 3babfbc970 修正了 find_env_cb() 函数中的一处判断 key 是否相等错误的 bug
当 env->name 中 env->name_len 长度后含有垃圾数据时,由于调用的是字符串比较函数,且指定的 max_len 错误,
该 bug 会导致超出 env->name_len 长度但在 strlen(key) 长度内的垃圾数据也会参与比较,如果相等则认为找到了需要查找的 key.
实际需要避免这些垃圾数据影响实际 key 值的比较。
6 years ago
armink b91bd2c7f9 【增加】ef_get_env_obj 及 ef_read_env_value API,方便将 ENV 查找动作与读取动作分离。
Signed-off-by: armink <armink.ztl@gmail.com>
6 years ago
armink 10ff7de6ac 【更新】移植文件。
Signed-off-by: armink <armink.ztl@gmail.com>
6 years ago
armink aa491ca744 【完善】移植说明文档。
Signed-off-by: armink <armink.ztl@gmail.com>
6 years ago
朱天龙 (Armink) edc13635cb 【完善】配置文件描述
Signed-off-by: armink <armink.ztl@gmail.com>
6 years ago
armink 7076d58541 【修正】continue_ff_addr 访问 flash 可能越界的问题。
Signed-off-by: armink <armink.ztl@gmail.com>
6 years ago
朱天龙 (Armink) d19cd3c7e7
Merge pull request #73 from ylzbotian/hotfix/bug
【修正】如果环境变量key已存在,使用ef_get_env_blob("key", NULL, 0, &len)会出现assert错误。以及,第一次初始化时由于combined值随机导致get_next_sector_addr(sector)获取到的地址错误
6 years ago
ylz 779210861b 【修正】1.如果环境变量key已存在,使用ef_get_env_blob("key", NULL, 0, &len)会出现assert错误。
2.第一次初始化时由于combined值随机导致get_next_sector_addr(sector)获取到的地址错误
6 years ago
armink 058f773c1b 【修正】load_env 时可能存在重复上锁的问题。
Signed-off-by: armink <armink.ztl@gmail.com>
6 years ago
朱天龙 (Armink) bda011569d
Merge pull request #72 from xixijay1988/master
针对ENV添加大小端MCU的适配
6 years ago
xixi 3bec40409a 针对ENV添加大小端MCU的适配,修改配置方式 6 years ago
Dawn Xi 546418c418
Update easyflash/src/ef_env.c
修改大小端宏配置方式

Co-Authored-By: 朱天龙 (Armink) <armink.ztl@gmail.com>
6 years ago
xixi 3532410375 针对ENV添加大小端MCU的适配 6 years ago
xixi d3182370d7 针对ENV添加大小端MCU的适配 6 years ago
armink 16056b8a01 【更新】移植文档,移除 STM32L4 片内 Flash 的支持
Signed-off-by: armink <armink.ztl@gmail.com>
6 years ago
armink 46eca3f7b6 【更新】版本号。
Signed-off-by: armink <armink.ztl@gmail.com>
7 years ago

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2014-2019 Armink (armink.ztl@gmail.com)
Copyright (c) 2014-2020 Armink (armink.ztl@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

@ -1,9 +1,11 @@
# EasyFlash
[![GitHub release](https://img.shields.io/github/release/armink/EasyFlash.svg)](https://github.com/armink/EasyFlash/releases/latest) [![GitHub commits](https://img.shields.io/github/commits-since/armink/EasyFlash/3.3.0.svg)](https://github.com/armink/EasyFlash/compare/3.3.0...master) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/armink/EasyFlash/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/armink/EasyFlash.svg)](https://github.com/armink/EasyFlash/releases/latest) [![GitHub commits](https://img.shields.io/github/commits-since/armink/EasyFlash/4.1.0.svg)](https://github.com/armink/EasyFlash/compare/4.1.0...master) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/armink/EasyFlash/master/LICENSE)
## 1、介绍[English](#1-introduction)
> **提示** :从 EasyFlash V4.1 后,基于 EasyFlash 全新设计开发的 [FlashDB](https://github.com/armink/FlashDB) 开源项目正式上线新集成了时序数据库、多分区管理多数据库实例等功能也从一定程度上提升了整体性能欢迎关注https://github.com/armink/FlashDB 。同时,现有的 EasyFlash 也会继续维护。
[EasyFlash](https://github.com/armink/EasyFlash)是一款开源的轻量级嵌入式Flash存储器库方便开发者更加轻松的实现基于Flash存储器的常见应用开发。非常适合智能家居、可穿戴、工控、医疗、物联网等需要断电存储功能的产品资源占用极低支持各种 MCU 片上存储器。该库主要包括 **三大实用功能**
- **ENV** 快速保存产品参数,支持 **写平衡(磨损平衡)** 及 **掉电保护** 功能
@ -18,7 +20,13 @@ EasyFlash不仅能够实现对产品的 **设定参数** 或 **运行日志**
非常适合应用在小型的不带文件系统的产品中,方便开发人员快速定位、查找系统发生崩溃或死机的原因。同时配合[EasyLogger](https://github.com/armink/EasyLogger)(我开源的超轻量级、高性能C日志库它提供与EasyFlash的无缝接口)一起使用轻松实现C日志的Flash存储功能。
### 1.1、V4.0 NG 模式
### 1.1 两种 ENV 模式
目前 ENV 功能有两种主要模式,一种为 V4.0 带来的 **NG** 模式,还有一种为延续 V3.0 的 **legacy** 模式
#### 1.1.1、V4.0 引入的 NG 模式
> 对应源码文件为: `ef_env.c`
自 2019 年春节后EasyFlash 经过 4 年多的迭代,结合众多开发者的需求及建议,终于发布了 V4.0 版本,该版本中的 ENV 功能被命名为 **NG** (Next Generation) 模式,这是一个完全重构的新版本,具有以下新特性:
@ -27,12 +35,32 @@ EasyFlash不仅能够实现对产品的 **设定参数** 或 **运行日志**
- ENV 操作效率比以前的模式高,充分利用剩余空闲区域,擦除次数及操作时间显著降低;
- **原生支持** 磨损平衡、掉电保护功能 V4.0 之前需要占用额外的 Flash 扇区);
- ENV 支持 **增量升级** ,固件升级后 ENV 也支持升级;
- 支持大数据存储模式,**长度无限制**,数据可在多个 Flash 扇区上顺序存储。像脚本程序、音频等占用 Flash 超过 1 个扇区的资源也都可以存入 ENV即将在 V4.1 支持);
- 支持 **数据加密** ,提升存储的安全性,物联网时代的必备功能(即将在 V4.2 支持);
- 支持 **数据压缩** ,减低 Flash 占用(即将在 V4.3 支持);
- 支持大数据存储模式,**长度无限制**,数据可在多个 Flash 扇区上顺序存储。像脚本程序、音频等占用 Flash 超过 1 个扇区的资源也都可以存入 ENV即将在 V4.2 支持);
- 支持 **数据加密** ,提升存储的安全性,物联网时代的必备功能(即将在 V4.3 支持);
- 支持 **数据压缩** ,减低 Flash 占用(即将在 V4.4 支持);
V4.0 设计及内部原理V4.0 迁移指南等更多内容请继续阅读下面的 [文档章节](#3文档)
> **注意** :个别 Flash 存在无法逆序写入的问题,例如 STM32L4 片内 Flash所以无法使用 NG 模式,这种情况下建议使用 V3.0 的 legacy 模式
#### 1.1.2、延续 V3.0 的 legacy 模式
> 对应源码文件为: `ef_env_legacy.c``ef_env_legacy_wl.c`
**legacy** 模式也具有磨损平衡及掉电保护功能,相比于 V 4.0 NG 模式,使用 legacy 模式,需要有额外的 RAM 空间来临时缓存每个 ENV ,最终调用 save 接口,统一擦除扇区再存储到 Flash 上。
#### 1.1.3 ENV 模式对比
| | V4.0 NG 模式 | V3.0 legacy 模式 |
| -------------------- | ------------------------------------------ | ------------------------ |
| RAM 资源占用 | 低 | 高 |
| 支持 Flash 全面性 | 个别 Flash 受限:例如 STM32L4 片内 | 比较全面 |
| 是否需要 GC 垃圾回收 | 需要 GC ,这会导致触发 GC 时,写入速度变慢 | 不需要 |
| value 类型限制 | 无限制 | 对字符串类型支持的比较好 |
| 掉电保护 | 支持 | 支持 |
| 磨损平衡 | 支持 | 支持 |
| 增量升级 | 支持 | 支持 |
### 1.2、资源占用
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

@ -45,10 +45,11 @@
| ---------------------- | -------- | ------------ | ------------------------- |
| STM32F1 片内 Flash | 4bytes | 1K/2K | 均匀分布 |
| STM32F2/F4 片内 Flash | 1byte | 16K/64K/128K | 最大的有128K最小的有16K |
| STM32L4 片内 Flash | 8bytes | 4K | 均匀分布 |
| Nor FlashSPI-Flash | 1bit | 4K | 均匀分布 |
> **注意** 务必保证熟悉Flash规格后再继续下章节。
> **注意**
> - 1、务必保证熟悉Flash规格后再继续下章节
> - 2、V4.0 新模式暂时无法使用在 STM32L4 片内 Flash 上L4 只能使用 V3.0 版本或者 V4.0 的 EF_ENV_USING_LEGACY_MODE 模式
## 4、移植接口
@ -217,7 +218,7 @@ static const ef_env default_env_set[] = {
### 5.5 Flash 写入粒度
- 操作方法:修改`EF_WRITE_GRAN`宏对应值即可单位bit仅支持1/8/32/64
- 操作方法:修改`EF_WRITE_GRAN`宏对应值即可单位bit仅支持1/8/32
### 5.5 备份区

@ -30,75 +30,24 @@
#ifndef EASYFLASH_H_
#define EASYFLASH_H_
#include <ef_cfg.h>
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <ef_cfg.h>
#include <ef_def.h>
#ifdef __cplusplus
extern "C" {
#endif
/* EasyFlash debug print function. Must be implement by user. */
#ifdef PRINT_DEBUG
#define EF_DEBUG(...) ef_log_debug(__FILE__, __LINE__, __VA_ARGS__)
#else
#define EF_DEBUG(...)
#endif
/* EasyFlash routine print function. Must be implement by user. */
#define EF_INFO(...) ef_log_info(__VA_ARGS__)
/* EasyFlash assert for developer. */
#define EF_ASSERT(EXPR) \
if (!(EXPR)) \
{ \
EF_DEBUG("(%s) has assert failed at %s.\n", #EXPR, __FUNCTION__); \
while (1); \
}
/**
* ENV version number defined by user.
* Please change it when your firmware add a new ENV to default_env_set.
*/
#ifndef EF_ENV_VER_NUM
#define EF_ENV_VER_NUM 0
#endif
/* EasyFlash software version number */
#define EF_SW_VERSION "4.0.0"
#define EF_SW_VERSION_NUM 0x40000
typedef struct _ef_env {
char *key;
void *value;
size_t value_len;
} ef_env, *ef_env_t;
/* EasyFlash error code */
typedef enum {
EF_NO_ERR,
EF_ERASE_ERR,
EF_READ_ERR,
EF_WRITE_ERR,
EF_ENV_NAME_ERR,
EF_ENV_NAME_EXIST,
EF_ENV_FULL,
EF_ENV_INIT_FAILED,
} EfErrCode;
/* the flash sector current status */
typedef enum {
EF_SECTOR_EMPTY,
EF_SECTOR_USING,
EF_SECTOR_FULL,
} EfSecrorStatus;
/* easyflash.c */
EfErrCode easyflash_init(void);
#ifdef EF_USING_ENV
/* only supported on ef_env.c */
size_t ef_get_env_blob(const char *key, void *value_buf, size_t buf_len, size_t *saved_value_len);
bool ef_get_env_obj(const char *key, env_node_obj_t env);
size_t ef_read_env_value(env_node_obj_t env, uint8_t *value_buf, size_t buf_len);
EfErrCode ef_set_env_blob(const char *key, const void *value_buf, size_t buf_len);
/* ef_env.c, ef_env_legacy_wl.c and ef_env_legacy.c */
@ -136,6 +85,7 @@ EfErrCode ef_log_read(size_t index, uint32_t *log, size_t size);
EfErrCode ef_log_write(const uint32_t *log, size_t size);
EfErrCode ef_log_clean(void);
size_t ef_log_get_used_size(void);
size_t ef_log_get_total_size(void);
#endif
/* ef_utils.c */

@ -40,6 +40,10 @@
* Please change it when your firmware add a new ENV to default_env_set.
*/
#define EF_ENV_VER_NUM /* @note you must define it for a value, such as 0 */
/* MCU Endian Configuration, default is Little Endian Order. */
/* #define EF_BIG_ENDIAN */
#endif /* EF_USING_ENV */
/* using IAP function */
@ -52,9 +56,12 @@
#define EF_ERASE_MIN_SIZE /* @note you must define it for a value */
/* the flash write granularity, unit: bit
* only support 1(nor flash)/ 8(stm32f4)/ 32(stm32f1)/ 64(stm32l4) */
* only support 1(nor flash)/ 8(stm32f4)/ 32(stm32f1) */
#define EF_WRITE_GRAN /* @note you must define it for a value */
/* The size of read_env and continue_ff_addr function used*/
#define EF_READ_BUF_SIZE 32 /* @default 32, Larger numbers can improve first-time speed of alloc_env but require more stack space*/
/*
*
* This all Backup Area Flash storage index. All used flash area configure is under here.

@ -0,0 +1,124 @@
/*
* This file is part of the EasyFlash Library.
*
* Copyright (c) 2019-2020, Armink, <armink.ztl@gmail.com>
*
* 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: It is the definitions head file for this library.
* Created on: 2019-11-20
*/
#ifndef EF_DEF_H_
#define EF_DEF_H_
#ifdef __cplusplus
extern "C" {
#endif
/* EasyFlash software version number */
#define EF_SW_VERSION "4.1.99"
#define EF_SW_VERSION_NUM 0x40199
/*
* ENV version number defined by user.
* Please change it when your firmware add a new ENV to default_env_set.
*/
#ifndef EF_ENV_VER_NUM
#define EF_ENV_VER_NUM 0
#endif
/* the ENV max name length must less then it */
#ifndef EF_ENV_NAME_MAX
#define EF_ENV_NAME_MAX 32
#endif
/* EasyFlash debug print function. Must be implement by user. */
#ifdef PRINT_DEBUG
#define EF_DEBUG(...) ef_log_debug(__FILE__, __LINE__, __VA_ARGS__)
#else
#define EF_DEBUG(...)
#endif
/* EasyFlash routine print function. Must be implement by user. */
#define EF_INFO(...) ef_log_info(__VA_ARGS__)
/* EasyFlash assert for developer. */
#define EF_ASSERT(EXPR) \
if (!(EXPR)) \
{ \
EF_DEBUG("(%s) has assert failed at %s.\n", #EXPR, __FUNCTION__); \
while (1); \
}
typedef struct _ef_env {
char *key;
void *value;
size_t value_len;
} ef_env, *ef_env_t;
/* EasyFlash error code */
typedef enum {
EF_NO_ERR,
EF_ERASE_ERR,
EF_READ_ERR,
EF_WRITE_ERR,
EF_ENV_NAME_ERR,
EF_ENV_NAME_EXIST,
EF_ENV_FULL,
EF_ENV_INIT_FAILED,
} EfErrCode;
/* the flash sector current status */
typedef enum {
EF_SECTOR_EMPTY,
EF_SECTOR_USING,
EF_SECTOR_FULL,
} EfSecrorStatus;
enum env_status {
ENV_UNUSED,
ENV_PRE_WRITE,
ENV_WRITE,
ENV_PRE_DELETE,
ENV_DELETED,
ENV_ERR_HDR,
ENV_STATUS_NUM,
};
typedef enum env_status env_status_t;
struct env_node_obj {
env_status_t status; /**< ENV node status, @see node_status_t */
bool crc_is_ok; /**< ENV node CRC32 check is OK */
uint8_t name_len; /**< name length */
uint32_t magic; /**< magic word(`K`, `V`, `4`, `0`) */
uint32_t len; /**< ENV node total length (header + name + value), must align by EF_WRITE_GRAN */
uint32_t value_len; /**< value length */
char name[EF_ENV_NAME_MAX]; /**< name */
struct {
uint32_t start; /**< ENV node start address */
uint32_t value; /**< value start address */
} addr;
};
typedef struct env_node_obj *env_node_obj_t;
#ifdef __cplusplus
}
#endif
#endif /* EF_DEF_H_ */

@ -142,11 +142,11 @@ ef_set_struct("
/* 获取结构体类型环境变量 */
Student *student;
ef_get_struct("张三学生", student, stu_get_cb);
student = ef_get_struct("张三学生", stu_get_cb);
/* 打印获取到的结构体内容 */
printf("姓名:%s 籍贯:%s \n", student->name, student->hometown.name);
/* 释放获取结构体类型环境变量过程中开辟的动态内存 */
s2jHook.free_fn(student);
```
```

@ -82,7 +82,7 @@ long ef_get_long(const char *key) {
return atol(value);
} else {
EF_INFO("Couldn't find this ENV(%s)!\n", key);
return NULL;
return 0;
}
}
@ -96,7 +96,7 @@ double ef_get_double(const char *key) {
return atof(value);
} else {
EF_INFO("Couldn't find this ENV(%s)!\n", key);
return NULL;
return 0;
}
}

@ -33,6 +33,10 @@
#include <stdbool.h>
#include "struct2json\inc\s2j.h"
#ifdef __cplusplus
extern "C" {
#endif
/* EasyFlash types plugin's software version number */
#define EF_TYPES_SW_VERSION "0.11.03"
@ -73,4 +77,8 @@ EfErrCode ef_set_double_array(const char *key, double *value, size_t len);
EfErrCode ef_set_string_array(const char *key, char **value, size_t len);
EfErrCode ef_set_struct(const char *key, void *value, ef_types_set_cb set_cb);
#ifdef __cplusplus
}
#endif
#endif /* EF_TYPES_H_ */

@ -1,7 +1,7 @@
/*
* This file is part of the EasyFlash Library.
*
* Copyright (c) 2015, Armink, <armink.ztl@gmail.com>
* Copyright (c) 2015-2019, Armink, <armink.ztl@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -64,8 +64,6 @@ EfErrCode ef_port_init(ef_env const **default_env, size_t *default_env_size) {
EfErrCode ef_port_read(uint32_t addr, uint32_t *buf, size_t size) {
EfErrCode result = EF_NO_ERR;
EF_ASSERT(size % 4 == 0);
/* You can add your code under here. */
return result;
@ -104,8 +102,6 @@ EfErrCode ef_port_erase(uint32_t addr, size_t size) {
*/
EfErrCode ef_port_write(uint32_t addr, const uint32_t *buf, size_t size) {
EfErrCode result = EF_NO_ERR;
EF_ASSERT(size % 4 == 0);
/* You can add your code under here. */

@ -71,6 +71,11 @@ EfErrCode easyflash_init(void) {
size_t default_env_set_size = 0;
const ef_env *default_env_set;
EfErrCode result = EF_NO_ERR;
static bool init_ok = false;
if (init_ok) {
return EF_NO_ERR;
}
result = ef_port_init(&default_env_set, &default_env_set_size);
@ -93,6 +98,7 @@ EfErrCode easyflash_init(void) {
#endif
if (result == EF_NO_ERR) {
init_ok = true;
EF_INFO("EasyFlash V%s is initialize success.\n", EF_SW_VERSION);
} else {
EF_INFO("EasyFlash V%s is initialize fail.\n", EF_SW_VERSION);

@ -39,11 +39,6 @@
#error "the write gran can be only setting as 1, 8, 32 and 64"
#endif
/* the ENV max name length must less then it */
#ifndef EF_ENV_NAME_MAX
#define EF_ENV_NAME_MAX 32
#endif
/* magic word(`E`, `F`, `4`, `0`) */
#define SECTOR_MAGIC_WORD 0x30344645
/* magic word(`K`, `V`, `4`, `0`) */
@ -154,17 +149,6 @@ enum sector_dirty_status {
};
typedef enum sector_dirty_status sector_dirty_status_t;
enum env_status {
ENV_UNUSED,
ENV_PRE_WRITE,
ENV_WRITE,
ENV_PRE_DELETE,
ENV_DELETED,
ENV_ERR_HDR,
ENV_STATUS_NUM,
};
typedef enum env_status env_status_t;
struct sector_hdr_data {
struct {
uint8_t store[STORE_STATUS_TABLE_SIZE]; /**< sector store status @see sector_store_status_t */
@ -200,21 +184,6 @@ struct env_hdr_data {
};
typedef struct env_hdr_data *env_hdr_data_t;
struct env_meta_data {
env_status_t status; /**< ENV node status, @see node_status_t */
bool crc_is_ok; /**< ENV node CRC32 check is OK */
uint8_t name_len; /**< name length */
uint32_t magic; /**< magic word(`K`, `V`, `4`, `0`) */
uint32_t len; /**< ENV node total length (header + name + value), must align by EF_WRITE_GRAN */
uint32_t value_len; /**< value length */
char name[EF_ENV_NAME_MAX]; /**< name */
struct {
uint32_t start; /**< ENV node start address */
uint32_t value; /**< value start address */
} addr;
};
typedef struct env_meta_data *env_meta_data_t;
struct env_cache_node {
uint16_t name_crc; /**< ENV name's CRC32 low 16bit value */
uint16_t active; /**< ENV node access active degree */
@ -455,12 +424,17 @@ static bool get_env_from_cache(const char *name, size_t name_len, uint32_t *addr
*/
static uint32_t continue_ff_addr(uint32_t start, uint32_t end)
{
uint8_t buf[32], last_data = 0x00;
size_t i, addr = start;
uint8_t buf[EF_READ_BUF_SIZE], last_data = 0x00;
size_t i, addr = start, read_size;
for (; start < end; start += sizeof(buf)) {
ef_port_read(start, (uint32_t *) buf, sizeof(buf));
for (i = 0; i < sizeof(buf) && start + i < end; i++) {
if (start + sizeof(buf) < end) {
read_size = sizeof(buf);
} else {
read_size = end - start;
}
ef_port_read(start, (uint32_t *) buf, read_size);
for (i = 0; i < read_size; i++) {
if (last_data != 0xFF && buf[i] == 0xFF) {
addr = start + i;
}
@ -495,7 +469,11 @@ static uint32_t find_next_env_addr(uint32_t start, uint32_t end)
for (; start < end; start += (sizeof(buf) - sizeof(uint32_t))) {
ef_port_read(start, (uint32_t *) buf, sizeof(buf));
for (i = 0; i < sizeof(buf) - sizeof(uint32_t) && start + i < end; i++) {
#ifndef EF_BIG_ENDIAN /* Little Endian Order */
magic = buf[i] + (buf[i + 1] << 8) + (buf[i + 2] << 16) + (buf[i + 3] << 24);
#else /* Big Endian Order */
magic = buf[i + 3] + (buf[i + 2] << 8) + (buf[i + 1] << 16) + (buf[i] << 24);
#endif
if (magic == ENV_MAGIC_WORD && (start + i - ENV_MAGIC_OFFSET) >= start_bak) {
return start + i - ENV_MAGIC_OFFSET;
}
@ -505,7 +483,7 @@ static uint32_t find_next_env_addr(uint32_t start, uint32_t end)
return FAILED_ADDR;
}
static uint32_t get_next_env_addr(sector_meta_data_t sector, env_meta_data_t pre_env)
static uint32_t get_next_env_addr(sector_meta_data_t sector, env_node_obj_t pre_env)
{
uint32_t addr = FAILED_ADDR;
@ -529,7 +507,7 @@ static uint32_t get_next_env_addr(sector_meta_data_t sector, env_meta_data_t pre
addr = find_next_env_addr(addr, sector->addr + SECTOR_SIZE - SECTOR_HDR_DATA_SIZE);
if (addr > sector->addr + SECTOR_SIZE || pre_env->len == 0) {
//TODO 扇区连续模式
//TODO 扇区连续模式
return FAILED_ADDR;
}
} else {
@ -541,10 +519,10 @@ static uint32_t get_next_env_addr(sector_meta_data_t sector, env_meta_data_t pre
return addr;
}
static EfErrCode read_env(env_meta_data_t env)
static EfErrCode read_env(env_node_obj_t env)
{
struct env_hdr_data env_hdr;
uint8_t buf[32];
uint8_t buf[EF_READ_BUF_SIZE];
uint32_t calc_crc32 = 0, crc_data_len, env_name_addr;
EfErrCode result = EF_NO_ERR;
size_t len, size;
@ -564,7 +542,7 @@ static EfErrCode read_env(env_meta_data_t env)
env->crc_is_ok = false;
return EF_READ_ERR;
} else if (env->len > SECTOR_SIZE - SECTOR_HDR_DATA_SIZE && env->len < ENV_AREA_SIZE) {
//TODO 扇区连续模式,或者写入长度没有写入完整
//TODO 扇区连续模式,或者写入长度没有写入完整
EF_ASSERT(0);
}
@ -615,6 +593,7 @@ static EfErrCode read_sector_meta_data(uint32_t addr, sector_meta_data_t sector,
/* check magic word */
if (sector->magic != SECTOR_MAGIC_WORD) {
sector->check_ok = false;
sector->combined = SECTOR_NOT_COMBINED;
return EF_ENV_INIT_FAILED;
}
sector->check_ok = true;
@ -629,7 +608,7 @@ static EfErrCode read_sector_meta_data(uint32_t addr, sector_meta_data_t sector,
if (sector->status.store == SECTOR_STORE_EMPTY) {
sector->remain = SECTOR_SIZE - SECTOR_HDR_DATA_SIZE;
} else if (sector->status.store == SECTOR_STORE_USING) {
struct env_meta_data env_meta;
struct env_node_obj env_meta;
#ifdef EF_ENV_USING_CACHE
if (get_sector_from_cache(addr, &sector->empty_env)) {
@ -698,8 +677,8 @@ static uint32_t get_next_sector_addr(sector_meta_data_t pre_sec)
}
}
static void env_iterator(env_meta_data_t env, void *arg1, void *arg2,
bool (*callback)(env_meta_data_t env, void *arg1, void *arg2))
static void env_iterator(env_node_obj_t env, void *arg1, void *arg2,
bool (*callback)(env_node_obj_t env, void *arg1, void *arg2))
{
struct sector_meta_data sector;
uint32_t sec_addr;
@ -728,24 +707,24 @@ static void env_iterator(env_meta_data_t env, void *arg1, void *arg2,
}
}
static bool find_env_cb(env_meta_data_t env, void *arg1, void *arg2)
static bool find_env_cb(env_node_obj_t env, void *arg1, void *arg2)
{
const char *key = arg1;
bool *find_ok = arg2;
uint8_t max_len = strlen(key);
size_t key_len = strlen(key);
if (max_len < env->name_len) {
max_len = env->name_len;
if (key_len != env->name_len) {
return false;
}
/* check ENV */
if (env->crc_is_ok && env->status == ENV_WRITE && !strncmp(env->name, key, max_len)) {
if (env->crc_is_ok && env->status == ENV_WRITE && !strncmp(env->name, key, key_len)) {
*find_ok = true;
return true;
}
return false;
}
static bool find_env_no_cache(const char *key, env_meta_data_t env)
static bool find_env_no_cache(const char *key, env_node_obj_t env)
{
bool find_ok = false;
@ -754,7 +733,7 @@ static bool find_env_no_cache(const char *key, env_meta_data_t env)
return find_ok;
}
static bool find_env(const char *key, env_meta_data_t env)
static bool find_env(const char *key, env_node_obj_t env)
{
bool find_ok = false;
@ -793,7 +772,7 @@ static bool ef_is_str(uint8_t *value, size_t len)
static size_t get_env(const char *key, void *value_buf, size_t buf_len, size_t *value_len)
{
struct env_meta_data env;
struct env_node_obj env;
size_t read_len = 0;
if (find_env(key, &env)) {
@ -805,12 +784,44 @@ static size_t get_env(const char *key, void *value_buf, size_t buf_len, size_t *
} else {
read_len = buf_len;
}
ef_port_read(env.addr.value, (uint32_t *) value_buf, read_len);
if (value_buf){
ef_port_read(env.addr.value, (uint32_t *) value_buf, read_len);
}
} else if (value_len) {
*value_len = 0;
}
return read_len;
}
/**
* Get a ENV object by key name
*
* @param key ENV name
* @param env ENV object
*
* @return TRUE: find the ENV is OK, else return false
*/
bool ef_get_env_obj(const char *key, env_node_obj_t env)
{
bool find_ok = false;
if (!init_ok) {
EF_INFO("ENV isn't initialize OK.\n");
return 0;
}
/* lock the ENV cache */
ef_port_env_lock();
find_ok = find_env(key, env);
/* unlock the ENV cache */
ef_port_env_unlock();
return find_ok;
}
/**
* Get a blob ENV value by key name.
*
@ -870,6 +881,45 @@ char *ef_get_env(const char *key)
return NULL;
}
/**
* read the ENV value by ENV object
*
* @param env ENV object
* @param value_buf the buffer for store ENV value
* @param buf_len buffer length
*
* @return the actually read size on successful
*/
size_t ef_read_env_value(env_node_obj_t env, uint8_t *value_buf, size_t buf_len)
{
size_t read_len = 0;
EF_ASSERT(env);
EF_ASSERT(value_buf);
if (!init_ok) {
EF_INFO("ENV isn't initialize OK.\n");
return 0;
}
if (env->crc_is_ok) {
/* lock the ENV cache */
ef_port_env_lock();
if (buf_len > env->value_len) {
read_len = env->value_len;
} else {
read_len = buf_len;
}
ef_port_read(env->addr.value, (uint32_t *) value_buf, read_len);
/* unlock the ENV cache */
ef_port_env_unlock();
}
return read_len;
}
static EfErrCode write_env_hdr(uint32_t addr, env_hdr_data_t env_hdr) {
EfErrCode result = EF_NO_ERR;
/* write the status will by write granularity */
@ -1016,7 +1066,7 @@ static uint32_t alloc_env(sector_meta_data_t sector, size_t env_size)
return empty_env;
}
static EfErrCode del_env(const char *key, env_meta_data_t old_env, bool complete_del) {
static EfErrCode del_env(const char *key, env_node_obj_t old_env, bool complete_del) {
EfErrCode result = EF_NO_ERR;
uint32_t dirty_status_addr;
static bool last_is_complete_del = false;
@ -1029,7 +1079,7 @@ static EfErrCode del_env(const char *key, env_meta_data_t old_env, bool complete
/* need find ENV */
if (!old_env) {
struct env_meta_data env;
struct env_node_obj env;
/* find ENV */
if (find_env(key, &env)) {
old_env = &env;
@ -1047,8 +1097,14 @@ static EfErrCode del_env(const char *key, env_meta_data_t old_env, bool complete
if (!last_is_complete_del && result == EF_NO_ERR) {
#ifdef EF_ENV_USING_CACHE
/* only delete the ENV in flash and cache when only using del_env(key, env, true) in ef_del_env() */
update_env_cache(key, strlen(key), FAILED_ADDR);
/* delete the ENV in flash and cache */
if (key != NULL) {
/* when using del_env(key, NULL, true) or del_env(key, env, true) in ef_del_env() and set_env() */
update_env_cache(key, strlen(key), FAILED_ADDR);
} else if (old_env != NULL) {
/* when using del_env(NULL, env, true) in move_env() */
update_env_cache(old_env->name, old_env->name_len, FAILED_ADDR);
}
#endif /* EF_ENV_USING_CACHE */
}
@ -1068,7 +1124,7 @@ static EfErrCode del_env(const char *key, env_meta_data_t old_env, bool complete
/*
* move the ENV to new space
*/
static EfErrCode move_env(env_meta_data_t env)
static EfErrCode move_env(env_node_obj_t env)
{
EfErrCode result = EF_NO_ERR;
uint8_t status_table[ENV_STATUS_TABLE_SIZE];
@ -1082,7 +1138,7 @@ static EfErrCode move_env(env_meta_data_t env)
if ((env_addr = alloc_env(&sector, env->len)) != FAILED_ADDR) {
if (in_recovery_check) {
struct env_meta_data env_bak;
struct env_node_obj env_bak;
char name[EF_ENV_NAME_MAX + 1] = { 0 };
strncpy(name, env->name, env->name_len);
/* check the ENV in flash is already create success */
@ -1169,7 +1225,7 @@ static bool gc_check_cb(sector_meta_data_t sector, void *arg1, void *arg2)
static bool do_gc(sector_meta_data_t sector, void *arg1, void *arg2)
{
struct env_meta_data env;
struct env_node_obj env;
if (sector->check_ok && (sector->status.dirty == SECTOR_DIRTY_TRUE || sector->status.dirty == SECTOR_DIRTY_GC)) {
uint8_t status_table[DIRTY_STATUS_TABLE_SIZE];
@ -1230,9 +1286,13 @@ static EfErrCode align_write(uint32_t addr, const uint32_t *buf, size_t size)
#endif
memset(align_data, 0xFF, align_data_size);
result = ef_port_write(addr, buf, EF_WG_ALIGN_DOWN(size));
align_remain = EF_WG_ALIGN_DOWN(size);//use align_remain temporary to save aligned size.
if(align_remain > 0){//it may be 0 in this function.
result = ef_port_write(addr, buf, align_remain);
}
align_remain = size - EF_WG_ALIGN_DOWN(size);
align_remain = size - align_remain;
if (result == EF_NO_ERR && align_remain) {
memcpy(align_data, (uint8_t *)buf + EF_WG_ALIGN_DOWN(size), align_remain);
result = ef_port_write(addr + EF_WG_ALIGN_DOWN(size), (uint32_t *) align_data, align_data_size);
@ -1366,7 +1426,7 @@ EfErrCode ef_del_and_save_env(const char *key)
static EfErrCode set_env(const char *key, const void *value_buf, size_t buf_len)
{
EfErrCode result = EF_NO_ERR;
static struct env_meta_data env;
static struct env_node_obj env;
static struct sector_meta_data sector;
bool env_is_found = false;
@ -1517,7 +1577,7 @@ __exit:
return result;
}
static bool print_env_cb(env_meta_data_t env, void *arg1, void *arg2)
static bool print_env_cb(env_node_obj_t env, void *arg1, void *arg2)
{
bool value_is_str = true, print_value = false;
size_t *using_size = arg1;
@ -1570,7 +1630,7 @@ __reload:
*/
void ef_print_env(void)
{
struct env_meta_data env;
struct env_node_obj env;
size_t using_size = 0;
if (!init_ok) {
@ -1602,7 +1662,7 @@ static void env_auto_update(void)
if (get_env(VER_NUM_ENV_NAME, &saved_ver_num, sizeof(size_t), NULL) > 0) {
/* check version number */
if (saved_ver_num != setting_ver_num) {
struct env_meta_data env;
struct env_node_obj env;
size_t i, value_len;
struct sector_meta_data sector;
EF_DEBUG("Update the ENV from version %d to %d.\n", saved_ver_num, setting_ver_num);
@ -1655,7 +1715,7 @@ static bool check_and_recovery_gc_cb(sector_meta_data_t sector, void *arg1, void
return false;
}
static bool check_and_recovery_env_cb(env_meta_data_t env, void *arg1, void *arg2)
static bool check_and_recovery_env_cb(env_node_obj_t env, void *arg1, void *arg2)
{
/* recovery the prepare deleted ENV */
if (env->crc_is_ok && env->status == ENV_PRE_DELETE) {
@ -1670,7 +1730,7 @@ static bool check_and_recovery_env_cb(env_meta_data_t env, void *arg1, void *arg
} else if (env->status == ENV_PRE_WRITE) {
uint8_t status_table[ENV_STATUS_TABLE_SIZE];
/* the ENV has not write finish, change the status to error */
//TODO 绘制异常处理的状态装换图
//TODO 绘制异常处理的状态装换图
write_status(env->addr.start, status_table, ENV_STATUS_NUM, ENV_ERR_HDR);
return true;
}
@ -1686,13 +1746,10 @@ static bool check_and_recovery_env_cb(env_meta_data_t env, void *arg1, void *arg
EfErrCode ef_load_env(void)
{
EfErrCode result = EF_NO_ERR;
struct env_meta_data env;
struct env_node_obj env;
struct sector_meta_data sector;
size_t check_failed_count = 0;
/* lock the ENV cache */
ef_port_env_lock();
in_recovery_check = true;
/* check all sector header */
sector_iterator(&sector, SECTOR_STORE_UNUSED, &check_failed_count, NULL, check_sec_hdr_cb, false);
@ -1701,6 +1758,9 @@ EfErrCode ef_load_env(void)
EF_INFO("Warning: All sector header check failed. Set it to default.\n");
ef_env_set_default();
}
/* lock the ENV cache */
ef_port_env_lock();
/* check all sector header for recovery GC */
sector_iterator(&sector, SECTOR_STORE_UNUSED, NULL, NULL, check_and_recovery_gc_cb, false);

@ -410,6 +410,23 @@ size_t ef_log_get_used_size(void) {
return physical_size - header_total_num * LOG_SECTOR_HEADER_SIZE;
}
/**
* Get log flash total size.
*
* @return log flash total size. @note NOT contain sector headers
*/
size_t ef_log_get_total_size(void) {
size_t header_total_num = 0;
/* must be call this function after initialize OK */
if (!init_ok) {
return 0;
}
header_total_num = LOG_AREA_SIZE / EF_ERASE_MIN_SIZE;
return LOG_AREA_SIZE - header_total_num * LOG_SECTOR_HEADER_SIZE;
}
/**
* Sequential reading log data. It will ignore sector headers.
*
@ -457,14 +474,15 @@ static uint32_t log_index2addr(size_t index) {
size_t sector_num = index / (EF_ERASE_MIN_SIZE - LOG_SECTOR_HEADER_SIZE) + 1;
header_total_offset = sector_num * LOG_SECTOR_HEADER_SIZE;
uint32_t virtual_addr = log_start_addr + index + header_total_offset;
if (log_start_addr < log_end_addr) {
return log_start_addr + index + header_total_offset;
return virtual_addr;
} else {
if (log_start_addr + index + header_total_offset < log_area_start_addr + LOG_AREA_SIZE) {
return log_start_addr + index + header_total_offset;
return virtual_addr;
} else {
return log_start_addr + index + header_total_offset - LOG_AREA_SIZE;
// the address will restart from the first sector address.
return virtual_addr - (log_area_start_addr + LOG_AREA_SIZE) + log_area_start_addr;
}
}
}
@ -490,8 +508,14 @@ EfErrCode ef_log_read(size_t index, uint32_t *log, size_t size) {
return result;
}
EF_ASSERT(size % 4 == 0);
EF_ASSERT(index < cur_using_size);
if (size % 4 != 0) {
EF_DEBUG("Error: size must be word aligned.");
return EF_READ_ERR;
}
if (index >= cur_using_size) {
EF_DEBUG("Error: index out of ranges, current using size is %d", cur_using_size);
return EF_READ_ERR;
}
if (index + size > cur_using_size) {
EF_DEBUG("Warning: Log read size out of bound. Cut read size.\n");

Loading…
Cancel
Save