diff --git a/easyflash/inc/easyflash.h b/easyflash/inc/easyflash.h index 0ae00f8..5285525 100644 --- a/easyflash/inc/easyflash.h +++ b/easyflash/inc/easyflash.h @@ -46,9 +46,11 @@ extern "C" { /* #define EF_USING_LOG */ /* the user setting size of ENV, must be word alignment */ #define EF_USER_SETTING_ENV_SIZE (2 * 1024) /* default 2K */ -/* using wear leveling mode or normal mode */ +/* using wear leveling mode or normal mode for ENV */ /* #define EF_ENV_USING_WL_MODE */ #define EF_ENV_USING_NORMAL_MODE +/* using power fail safeguard mode for ENV */ +/* #define EF_ENV_USING_PFS_MODE */ /* EasyFlash debug print function. Must be implement by user. */ #define EF_DEBUG(...) ef_log_debug(__FILE__, __LINE__, __VA_ARGS__) @@ -62,7 +64,7 @@ if (!(EXPR)) \ while (1); \ } /* EasyFlash software version number */ -#define EF_SW_VERSION "1.07.06" +#define EF_SW_VERSION "1.07.10" typedef struct _eflash_env{ char *key; @@ -90,7 +92,7 @@ typedef enum { EfErrCode easyflash_init(void); #ifdef EF_USING_ENV -/* env.c env_wl.c */ +/* ef_env.c ef_env_wl.c */ void ef_load_env(void); void ef_print_env(void); char *ef_get_env(const char *key); @@ -102,7 +104,7 @@ size_t ef_get_env_write_bytes(void); #endif #ifdef EF_USING_IAP -/* iap.c */ +/* ef_iap.c */ EfErrCode ef_erase_bak_app(size_t app_size); EfErrCode ef_erase_user_app(uint32_t user_app_addr, size_t user_app_size); EfErrCode ef_erase_bl(uint32_t bl_addr, size_t bl_size); @@ -113,19 +115,19 @@ EfErrCode ef_copy_bl_from_bak(uint32_t bl_addr, size_t bl_size); #endif #ifdef EF_USING_LOG -/* log.c */ +/* ef_log.c */ 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); #endif -/* utils.c */ +/* ef_utils.c */ uint32_t ef_calc_crc32(uint32_t crc, const void *buf, size_t size); FlashSecrorStatus ef_get_sector_status(uint32_t addr, size_t sec_size); uint32_t ef_find_sec_using_end_addr(uint32_t addr, size_t sec_size); -/* port.c */ +/* ef_port.c */ EfErrCode ef_port_read(uint32_t addr, uint32_t *buf, size_t size); EfErrCode ef_port_erase(uint32_t addr, size_t size); EfErrCode ef_port_write(uint32_t addr, const uint32_t *buf, size_t size); diff --git a/easyflash/port/ef_port.c b/easyflash/port/ef_port.c index 476ad3b..7999194 100644 --- a/easyflash/port/ef_port.c +++ b/easyflash/port/ef_port.c @@ -32,15 +32,10 @@ #define ENV_START_ADDR /* @note you must define it for a value */ /* the minimum size of flash erasure */ #define ERASE_MIN_SIZE /* @note you must define it for a value */ -#ifdef EF_ENV_USING_WL_MODE -/* ENV section total bytes size in wear leveling mode. */ +/* ENV section total bytes size. */ #define ENV_SECTION_SIZE /* @note you must define it for a value */ -#else -/* ENV section total bytes size in normal mode. It's equal with FLASH_USER_SETTING_ENV_SIZE */ -#define ENV_SECTION_SIZE (EF_USER_SETTING_ENV_SIZE) -#endif /* saved log section size */ -#define LOG_AREA_SIZE /* @note you must define it for a value */ +#define LOG_AREA_SIZE /* @note you must define it for a value */ /* print debug information of flash */ #define PRINT_DEBUG diff --git a/easyflash/src/easyflash.c b/easyflash/src/easyflash.c index 875a909..b26b043 100644 --- a/easyflash/src/easyflash.c +++ b/easyflash/src/easyflash.c @@ -83,26 +83,13 @@ EfErrCode easyflash_init(void) { #ifdef EF_USING_IAP if (result == EF_NO_ERR) { - if (ef_get_env_total_size() < erase_min_size) { - result = ef_iap_init(env_start_addr + erase_min_size + log_size); - } else if (ef_get_env_total_size() % erase_min_size == 0) { - result = ef_iap_init(env_start_addr + ef_get_env_total_size() + log_size); - } else { - result = ef_iap_init((ef_get_env_total_size() / erase_min_size + 1) * erase_min_size + log_size); - } + result = ef_iap_init(env_start_addr + env_total_size + log_size); } #endif #ifdef EF_USING_LOG if (result == EF_NO_ERR) { - if (ef_get_env_total_size() < erase_min_size) { - result = ef_log_init(env_start_addr + erase_min_size, log_size, erase_min_size); - } else if (ef_get_env_total_size() % erase_min_size == 0) { - result = ef_log_init(env_start_addr + ef_get_env_total_size(), log_size, erase_min_size); - } else { - result = ef_log_init((ef_get_env_total_size() / erase_min_size + 1) * erase_min_size, - log_size, erase_min_size); - } + result = ef_log_init(env_start_addr + env_total_size, log_size, erase_min_size); } #endif diff --git a/easyflash/src/ef_env.c b/easyflash/src/ef_env.c index 9ea389d..26830f0 100644 --- a/easyflash/src/ef_env.c +++ b/easyflash/src/ef_env.c @@ -43,12 +43,19 @@ * All ENV must be 4 bytes alignment. The remaining part must fill '\0'. * * @note Word = 4 Bytes in this file + * @note It will has two ENV areas(Area0, Area1) when used power fail safeguard mode. */ /* flash ENV parameters index and size in system section */ enum { /* data section ENV end address index in system section */ ENV_PARAM_INDEX_END_ADDR = 0, + +#ifdef EF_ENV_USING_PFS_MODE + /* saved count for ENV area */ + ENV_PARAM_INDEX_SAVED_COUNT, +#endif + /* data section CRC32 code index in system section */ ENV_PARAM_INDEX_DATA_CRC, /* flash ENV parameters word size */ @@ -61,11 +68,20 @@ enum { static ef_env const *default_env_set = NULL; /* default ENV set size, must be initialized by user */ static size_t default_env_set_size = NULL; +/* flash ENV all section total size */ +static size_t env_total_size = NULL; /* ENV RAM cache */ static uint32_t env_cache[EF_USER_SETTING_ENV_SIZE / 4] = { 0 }; /* ENV start address in flash */ static uint32_t env_start_addr = NULL; +#ifdef EF_ENV_USING_PFS_MODE +/* current load ENV area address */ +static uint32_t cur_load_area_addr = NULL; +/* next save ENV area address */ +static uint32_t next_save_area_addr = NULL; +#endif + static uint32_t get_env_system_addr(void); static uint32_t get_env_data_addr(void); static uint32_t get_env_end_addr(void); @@ -97,18 +113,35 @@ EfErrCode ef_env_init(uint32_t start_addr, size_t total_size, size_t erase_min_s EF_ASSERT(start_addr); EF_ASSERT(total_size); - /* user_size must equal with total_size in normal mode */ - EF_ASSERT(EF_USER_SETTING_ENV_SIZE == total_size); EF_ASSERT(default_env); EF_ASSERT(default_env_size < total_size); /* must be word alignment for ENV */ EF_ASSERT(total_size % 4 == 0); +#ifndef EF_ENV_USING_PFS_MODE + /* total_size must be aligned with erase_min_size */ + if (EF_USER_SETTING_ENV_SIZE % erase_min_size == 0) { + EF_ASSERT(EF_USER_SETTING_ENV_SIZE == total_size); + } else { + EF_ASSERT((EF_USER_SETTING_ENV_SIZE/erase_min_size + 1)*erase_min_size == total_size); + } +#else + /* total_size must be aligned with erase_min_size */ + if (EF_USER_SETTING_ENV_SIZE % erase_min_size == 0) { + /* it has double area when used power fail safeguard mode */ + EF_ASSERT(2*EF_USER_SETTING_ENV_SIZE == total_size); + } else { + /* it has double area when used power fail safeguard mode */ + EF_ASSERT(2*(EF_USER_SETTING_ENV_SIZE/erase_min_size + 1)*erase_min_size == total_size); + } +#endif + env_start_addr = start_addr; + env_total_size = total_size; 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", start_addr, total_size); + EF_DEBUG("ENV start address is 0x%08X, size is %d bytes.\n", start_addr, total_size); ef_load_env(); @@ -133,6 +166,11 @@ EfErrCode ef_env_set_default(void){ /* set environment end address is at data section start address */ set_env_end_addr(get_env_data_addr()); +#ifdef EF_ENV_USING_PFS_MODE + /* set saved count to default 0 */ + env_cache[ENV_PARAM_INDEX_SAVED_COUNT] = 0; +#endif + /* create default ENV */ for (i = 0; i < default_env_set_size; i++) { create_env(default_env_set[i].key, default_env_set[i].value); @@ -152,8 +190,13 @@ EfErrCode ef_env_set_default(void){ * @return system section start address */ static uint32_t get_env_system_addr(void) { +#ifndef EF_ENV_USING_PFS_MODE EF_ASSERT(env_start_addr); return env_start_addr; +#else + EF_ASSERT(cur_load_area_addr); + return cur_load_area_addr; +#endif } /** @@ -162,8 +205,7 @@ static uint32_t get_env_system_addr(void) { * @return data section start address */ static uint32_t get_env_data_addr(void) { - EF_ASSERT(env_start_addr); - return env_start_addr + ENV_PARAM_BYTE_SIZE; + return get_env_system_addr() + ENV_PARAM_BYTE_SIZE; } /** @@ -202,7 +244,7 @@ static size_t get_env_data_size(void) { * @return size */ size_t ef_get_env_total_size(void) { - return EF_USER_SETTING_ENV_SIZE; + return env_total_size; } /** @@ -211,7 +253,12 @@ size_t ef_get_env_total_size(void) { * @return write bytes */ size_t ef_get_env_write_bytes(void) { +#ifndef EF_ENV_USING_PFS_MODE return get_env_end_addr() - env_start_addr; +#else + /* It has two ENV areas(Area0, Area1) on used power fail safeguard mode */ + return 2 * (get_env_end_addr() - get_env_system_addr()); +#endif } /** @@ -233,11 +280,13 @@ static EfErrCode write_env(const char *key, const char *value) { env_str_len = (env_str_len / 4 + 1) * 4; } /* check capacity of ENV */ - if (env_str_len + get_env_data_size() >= ef_get_env_total_size()) { + if (env_str_len + get_env_data_size() >= EF_USER_SETTING_ENV_SIZE) { return EF_ENV_FULL; } + /* calculate current ENV ram cache end address */ - env_cache_bak += ef_get_env_write_bytes(); + env_cache_bak += get_env_end_addr() - get_env_system_addr(); + /* copy key name */ memcpy(env_cache_bak, key, ker_len); env_cache_bak += ker_len; @@ -278,7 +327,7 @@ static uint32_t *find_env(const char *key) { /* from data section start to data section end */ env_start = (char *) ((char *) env_cache + ENV_PARAM_BYTE_SIZE); - env_end = (char *) ((char *) env_cache + ef_get_env_write_bytes()); + env_end = (char *) ((char *) env_cache + (get_env_end_addr() - get_env_system_addr())); /* ENV is null */ if (env_start == env_end) { @@ -468,21 +517,29 @@ void ef_print_env(void) { } } } - ef_print("\nENV size: %ld/%ld bytes, mode: normal.\n", + +#ifndef EF_ENV_USING_PFS_MODE + ef_print("\nENV size: %ld/%ld bytes.\n", ef_get_env_write_bytes(), ef_get_env_total_size()); +#else + ef_print("\nENV size: %ld/%ld bytes, saved count: %ld, mode: power fail safeguard.\n", + ef_get_env_write_bytes(), ef_get_env_total_size(), env_cache[ENV_PARAM_INDEX_SAVED_COUNT]); + +#endif } /** * Load flash ENV to ram. */ +#ifndef EF_ENV_USING_PFS_MODE void ef_load_env(void) { uint32_t *env_cache_bak, env_end_addr; /* read ENV end address from flash */ ef_port_read(get_env_system_addr() + ENV_PARAM_INDEX_END_ADDR * 4, &env_end_addr, 4); /* if ENV is not initialize or flash has dirty data, set default for it */ - if ((env_end_addr == 0xFFFFFFFF) - || (env_end_addr > env_start_addr + ef_get_env_total_size())) { + if ((env_end_addr == 0xFFFFFFFF) || (env_end_addr < env_start_addr) + || (env_end_addr > env_start_addr + EF_USER_SETTING_ENV_SIZE)) { ef_env_set_default(); } else { /* set ENV end address */ @@ -501,17 +558,110 @@ void ef_load_env(void) { } } } +#else +void ef_load_env(void) { + uint32_t area0_start_address = env_start_addr, area1_start_address = env_start_addr + + env_total_size / 2; + uint32_t area0_end_addr, area1_end_addr, area0_crc, area1_crc, area0_saved_count, area1_saved_count; + bool area0_is_valid = true, area1_is_valid = true; + /* read ENV area end address from flash */ + ef_port_read(area0_start_address + ENV_PARAM_INDEX_END_ADDR * 4, &area0_end_addr, 4); + ef_port_read(area1_start_address + ENV_PARAM_INDEX_END_ADDR * 4, &area1_end_addr, 4); + if ((area0_end_addr == 0xFFFFFFFF) || (area0_end_addr < area0_start_address) + || (area0_end_addr > area0_start_address + EF_USER_SETTING_ENV_SIZE)) { + area0_is_valid = false; + } + if ((area1_end_addr == 0xFFFFFFFF) || (area1_end_addr < area1_start_address) + || (area1_end_addr > area1_start_address + EF_USER_SETTING_ENV_SIZE)) { + area1_is_valid = false; + } + /* check area0 CRC when it is valid */ + if (area0_is_valid) { + /* read ENV area0 crc32 code from flash */ + ef_port_read(area0_start_address + ENV_PARAM_INDEX_DATA_CRC * 4, &area0_crc, 4); + /* read ENV from ENV area0 */ + ef_port_read(area0_start_address, env_cache, area0_end_addr - area0_start_address); + /* current load ENV area address is area0 start address */ + cur_load_area_addr = area0_start_address; + if (!env_crc_is_ok()) { + area0_is_valid = false; + } + } + /* check area1 CRC when it is valid */ + if (area1_is_valid) { + /* read ENV area1 crc32 code from flash */ + ef_port_read(area1_start_address + ENV_PARAM_INDEX_DATA_CRC * 4, &area1_crc, 4); + /* read ENV from ENV area1 */ + ef_port_read(area1_start_address, env_cache, area1_end_addr - area1_start_address); + /* current load ENV area address is area1 start address */ + cur_load_area_addr = area1_start_address; + if (!env_crc_is_ok()) { + area1_is_valid = false; + } + } + /* all ENV area CRC is OK then compare saved count */ + if (area0_is_valid && area1_is_valid) { + /* read ENV area saved count from flash */ + ef_port_read(area0_start_address + ENV_PARAM_INDEX_SAVED_COUNT * 4, + &area0_saved_count, 4); + ef_port_read(area1_start_address + ENV_PARAM_INDEX_SAVED_COUNT * 4, + &area1_saved_count, 4); + /* the bigger saved count area is valid */ + if ((area0_saved_count > area1_saved_count)||((area0_saved_count == 0)&&(area1_saved_count == 0xFFFFFFFF))) { + area1_is_valid = false; + } else { + area0_is_valid = false; + } + } + if (area0_is_valid) { + /* current load ENV area address is area0 start address */ + cur_load_area_addr = area0_start_address; + /* next save ENV area address is area1 start address */ + next_save_area_addr = area1_start_address; + /* read all ENV from area0 */ + ef_port_read(area0_start_address, env_cache, area0_end_addr - area0_start_address); + } else if (area1_is_valid) { + /* next save ENV area address is area0 start address */ + next_save_area_addr = area0_start_address; + } else { + /* current load ENV area address is area1 start address */ + cur_load_area_addr = area1_start_address; + /* next save ENV area address is area0 start address */ + next_save_area_addr = area0_start_address; + /* set the ENV to default */ + ef_env_set_default(); + } +} +#endif /** * Save ENV to flash. */ EfErrCode ef_save_env(void) { EfErrCode result = EF_NO_ERR; + uint32_t write_addr, write_size; +#ifndef EF_ENV_USING_PFS_MODE + write_addr = get_env_system_addr(); + write_size = get_env_end_addr() - get_env_system_addr(); + /* calculate and cache CRC32 code */ + env_cache[ENV_PARAM_INDEX_DATA_CRC] = calc_env_crc(); +#else + write_addr = next_save_area_addr; + write_size = get_env_end_addr() - get_env_system_addr(); + /* replace next_save_area_addr with cur_load_area_addr */ + next_save_area_addr = cur_load_area_addr; + cur_load_area_addr = write_addr; + /* change the ENV end address to next save area address */ + set_env_end_addr(write_addr + write_size); + /* ENV area saved count +1 */ + env_cache[ENV_PARAM_INDEX_SAVED_COUNT]++; /* calculate and cache CRC32 code */ env_cache[ENV_PARAM_INDEX_DATA_CRC] = calc_env_crc(); +#endif + /* erase ENV */ - result = ef_port_erase(get_env_system_addr(), ef_get_env_write_bytes()); + result = ef_port_erase(write_addr, write_size); switch (result) { case EF_NO_ERR: { EF_INFO("Erased ENV OK.\n"); @@ -525,7 +675,7 @@ EfErrCode ef_save_env(void) { } /* write ENV to flash */ - result = ef_port_write(get_env_system_addr(), env_cache, ef_get_env_write_bytes()); + result = ef_port_write(write_addr, env_cache, write_size); switch (result) { case EF_NO_ERR: { EF_INFO("Saved ENV OK.\n"); @@ -548,11 +698,18 @@ EfErrCode ef_save_env(void) { static uint32_t calc_env_crc(void) { uint32_t crc32 = 0; - /* Calculate the ENV end address and all ENV data CRC32. - * The 4 is ENV end address bytes size. */ + /* Calculate the ENV end address CRC32. The 4 is ENV end address bytes size. */ crc32 = ef_calc_crc32(crc32, &env_cache[ENV_PARAM_INDEX_END_ADDR], 4); + +#ifdef EF_ENV_USING_PFS_MODE + /* Calculate the ENV area saved count CRC32. */ + crc32 = ef_calc_crc32(crc32, &env_cache[ENV_PARAM_INDEX_SAVED_COUNT], 4); +#endif + + /* Calculate the all ENV data CRC32. */ crc32 = ef_calc_crc32(crc32, &env_cache[ENV_PARAM_WORD_SIZE], get_env_data_size()); - EF_DEBUG("Calculate Env CRC32 number is 0x%08X.\n", crc32); + + EF_DEBUG("Calculate ENV CRC32 number is 0x%08X.\n", crc32); return crc32; } @@ -564,7 +721,7 @@ static uint32_t calc_env_crc(void) { */ static bool env_crc_is_ok(void) { if (calc_env_crc() == env_cache[ENV_PARAM_INDEX_DATA_CRC]) { - EF_DEBUG("Verify Env CRC32 result is OK.\n"); + EF_DEBUG("Verify ENV CRC32 result is OK.\n"); return true; } else { return false; diff --git a/easyflash/src/ef_env_wl.c b/easyflash/src/ef_env_wl.c index 9b097be..3f33d16 100644 --- a/easyflash/src/ef_env_wl.c +++ b/easyflash/src/ef_env_wl.c @@ -42,7 +42,7 @@ * 2. Data section * The data section storage ENV's parameters and detail. * When an exception has occurred on flash erase or write. The current using data section - * address will move to next available position. This position depends on FLASH_MIN_ERASE_SIZE. + * address will move to next available position. This position depends on flash_erase_min_size. * 2.1 ENV parameters part * It storage ENV's parameters. * 2.2 ENV detail part @@ -50,12 +50,19 @@ * All ENV must be 4 bytes alignment. The remaining part must fill '\0'. * * @note Word = 4 Bytes in this file + * @note It will has two ENV areas(Area0, Area1) in data section when used power fail safeguard mode. */ /* flash ENV parameters part index and size */ enum { /* data section ENV detail part end address index */ ENV_PARAM_PART_INDEX_END_ADDR = 0, + +#ifdef EF_ENV_USING_PFS_MODE + /* saved count for ENV area */ + ENV_PARAM_PART_INDEX_SAVED_COUNT, +#endif + /* data section CRC32 code index */ ENV_PARAM_PART_INDEX_DATA_CRC, /* ENV parameters part word size */ @@ -68,8 +75,10 @@ enum { static ef_env const *default_env_set = NULL; /* default ENV set size, must be initialized by user */ static size_t default_env_set_size = NULL; -/* flash ENV all section total size */ +/* flash ENV all section(system section and data section) total size */ static size_t env_total_size = NULL; +/* flash ENV data section size */ +static size_t env_data_section_size = NULL; /* the minimum size of flash erasure */ static size_t flash_erase_min_size = NULL; /* ENV RAM cache */ @@ -79,6 +88,11 @@ static uint32_t env_start_addr = NULL; /* current using data section address */ static uint32_t cur_using_data_addr = NULL; +#ifdef EF_ENV_USING_PFS_MODE +/* next save ENV area address */ +static uint32_t next_save_area_addr = NULL; +#endif + static uint32_t get_env_start_addr(void); static uint32_t get_cur_using_data_addr(void); static uint32_t get_env_detail_addr(void); @@ -116,10 +130,21 @@ EfErrCode ef_env_init(uint32_t start_addr, size_t total_size, size_t erase_min_s EF_ASSERT(default_env); EF_ASSERT(default_env_size < EF_USER_SETTING_ENV_SIZE); /* must be word alignment for ENV */ - EF_ASSERT(EF_USER_SETTING_ENV_SIZE % 4 == 0); EF_ASSERT(total_size % 4 == 0); - /* the ENV total size should be an integral multiple of erase minimum size. */ - EF_ASSERT(total_size % erase_min_size == 0); + EF_ASSERT(EF_USER_SETTING_ENV_SIZE % 4 == 0); + /* system section size is erase_min_size, so last part is data section */ + env_data_section_size = total_size - erase_min_size; + /* the ENV data section size should be an integral multiple of erase minimum size. */ + EF_ASSERT(env_data_section_size % erase_min_size == 0); + +#ifndef EF_ENV_USING_PFS_MODE + EF_ASSERT(env_data_section_size >= EF_USER_SETTING_ENV_SIZE); +#else + /* it has double area when used power fail safeguard mode */ + EF_ASSERT(env_data_section_size >= 2*EF_USER_SETTING_ENV_SIZE); + EF_ASSERT((env_data_section_size / erase_min_size) % 2 == 0); +#endif + env_start_addr = start_addr; env_total_size = total_size; @@ -127,7 +152,7 @@ EfErrCode ef_env_init(uint32_t start_addr, size_t total_size, size_t erase_min_s 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", start_addr, total_size); + EF_DEBUG("ENV start address is 0x%08X, size is %d bytes.\n", start_addr, total_size); ef_load_env(); @@ -152,6 +177,11 @@ EfErrCode ef_env_set_default(void){ /* set ENV detail part end address is at ENV detail part start address */ set_env_detail_end_addr(get_env_detail_addr()); +#ifdef EF_ENV_USING_PFS_MODE + /* set saved count to default 0 */ + env_cache[ENV_PARAM_PART_INDEX_SAVED_COUNT] = 0; +#endif + /* create default ENV */ for (i = 0; i < default_env_set_size; i++) { create_env(default_env_set[i].key, default_env_set[i].value); @@ -242,7 +272,6 @@ static size_t get_env_detail_size(void) { */ /* must be initialized */ static size_t get_env_user_used_size(void) { - return get_env_detail_end_addr() - get_cur_using_data_addr(); } @@ -252,7 +281,20 @@ static size_t get_env_user_used_size(void) { * @return write bytes */ size_t ef_get_env_write_bytes(void) { +#ifndef EF_ENV_USING_PFS_MODE return get_env_detail_end_addr() - get_env_start_addr(); +#else + if (get_cur_using_data_addr() + < get_env_start_addr() + flash_erase_min_size + env_data_section_size / 2) { + /* current using is ENV area0 */ + return flash_erase_min_size + 2 * (get_env_detail_end_addr() - (get_env_start_addr() + +flash_erase_min_size)); + } else { + /* current using is ENV area1 */ + return flash_erase_min_size + 2 * (get_env_detail_end_addr() - (get_env_start_addr() + + flash_erase_min_size + env_data_section_size / 2)); + } +#endif } /** @@ -523,14 +565,22 @@ void ef_print_env(void) { } } } + +#ifndef EF_ENV_USING_PFS_MODE ef_print("\nENV size: %ld/%ld bytes, write bytes %ld/%ld, mode: wear leveling.\n", get_env_user_used_size(), EF_USER_SETTING_ENV_SIZE, ef_get_env_write_bytes(), ef_get_env_total_size()); +#else + ef_print("\nENV size: %ld/%ld bytes, write bytes %ld/%ld, saved count: %ld, mode: wear leveling and power fail safeguard.\n", + get_env_user_used_size(), EF_USER_SETTING_ENV_SIZE, ef_get_env_write_bytes(), + ef_get_env_total_size(), env_cache[ENV_PARAM_PART_INDEX_SAVED_COUNT]); +#endif } /** * Load flash ENV to ram. */ +#ifndef EF_ENV_USING_PFS_MODE void ef_load_env(void) { uint32_t *env_cache_bak, env_end_addr, using_data_addr; @@ -573,22 +623,138 @@ void ef_load_env(void) { } } +#else +void ef_load_env(void) { + /* ENV area0 current using address default value */ + uint32_t area0_default_cur_using_addr = get_env_start_addr() + flash_erase_min_size; + /* ENV area1 current using address default value */ + uint32_t area1_default_cur_using_addr = area0_default_cur_using_addr + env_data_section_size / 2; + uint32_t area0_cur_using_addr, area1_cur_using_addr, area0_end_addr, area1_end_addr; + uint32_t area0_crc, area1_crc, area0_saved_count, area1_saved_count; + bool area0_is_valid = true, area1_is_valid = true; + + /* read ENV area0 and area1 current using address */ + ef_port_read(get_env_start_addr(), &area0_cur_using_addr, 4); + ef_port_read(get_env_start_addr() + 4, &area1_cur_using_addr, 4); + /* if ENV is not initialize or flash has dirty data, set it isn't valid */ + if ((area0_cur_using_addr == 0xFFFFFFFF) + || (area0_cur_using_addr > get_env_start_addr() + ef_get_env_total_size()) + || (area0_cur_using_addr < get_env_start_addr() + flash_erase_min_size)) { + area0_is_valid = false; + } + if ((area1_cur_using_addr == 0xFFFFFFFF) + || (area1_cur_using_addr > get_env_start_addr() + ef_get_env_total_size()) + || (area1_cur_using_addr < get_env_start_addr() + flash_erase_min_size)) { + area1_is_valid = false; + } + /* check area0 end address when it is valid */ + if (area0_is_valid) { + /* read ENV area end address from flash */ + ef_port_read(area0_cur_using_addr + ENV_PARAM_PART_INDEX_END_ADDR * 4, &area0_end_addr, 4); + if ((area0_end_addr == 0xFFFFFFFF) || (area0_end_addr < area0_cur_using_addr) + || (area0_end_addr > area0_cur_using_addr + EF_USER_SETTING_ENV_SIZE)) { + area0_is_valid = false; + } + } + /* check area1 end address when it is valid */ + if (area1_is_valid) { + /* read ENV area end address from flash */ + ef_port_read(area1_cur_using_addr + ENV_PARAM_PART_INDEX_END_ADDR * 4, &area1_end_addr, 4); + if ((area1_end_addr == 0xFFFFFFFF) || (area1_end_addr < area1_cur_using_addr) + || (area1_end_addr > area1_cur_using_addr + EF_USER_SETTING_ENV_SIZE)) { + area1_is_valid = false; + } + } + /* check area0 CRC when it is valid */ + if (area0_is_valid) { + /* read ENV area0 crc32 code from flash */ + ef_port_read(area0_cur_using_addr + ENV_PARAM_PART_INDEX_DATA_CRC * 4, &area0_crc, 4); + /* read ENV from ENV area0 */ + ef_port_read(area0_cur_using_addr, env_cache, area0_end_addr - area0_cur_using_addr); + /* current using data section address is area0 current using data section address */ + set_cur_using_data_addr(area0_cur_using_addr); + if (!env_crc_is_ok()) { + area0_is_valid = false; + } + } + /* check area1 CRC when it is valid */ + if (area1_is_valid) { + /* read ENV area1 crc32 code from flash */ + ef_port_read(area1_cur_using_addr + ENV_PARAM_PART_INDEX_DATA_CRC * 4, &area1_crc, 4); + /* read ENV from ENV area1 */ + ef_port_read(area1_cur_using_addr, env_cache, area1_end_addr - area1_cur_using_addr); + /* current using data section address is area1 current using data section address */ + set_cur_using_data_addr(area1_cur_using_addr); + if (!env_crc_is_ok()) { + area1_is_valid = false; + } + } + /* all ENV area CRC is OK then compare saved count */ + if (area0_is_valid && area1_is_valid) { + /* read ENV area saved count from flash */ + ef_port_read(area0_cur_using_addr + ENV_PARAM_PART_INDEX_SAVED_COUNT * 4, + &area0_saved_count, 4); + ef_port_read(area1_cur_using_addr + ENV_PARAM_PART_INDEX_SAVED_COUNT * 4, + &area1_saved_count, 4); + /* the bigger saved count area is valid */ + if ((area0_saved_count > area1_saved_count)||((area0_saved_count == 0)&&(area1_saved_count == 0xFFFFFFFF))) { + area1_is_valid = false; + } else { + area0_is_valid = false; + } + } + if (area0_is_valid) { + /* current using data section address is area0 current using data section address */ + set_cur_using_data_addr(area0_cur_using_addr); + /* next save ENV area address is area1 current using address default value */ + next_save_area_addr = area1_default_cur_using_addr; + /* read all ENV from area0 */ + ef_port_read(area0_cur_using_addr, env_cache, area0_end_addr - area0_cur_using_addr); + } else if (area1_is_valid) { + /* next save ENV area address is area0 current using address default value */ + next_save_area_addr = area0_default_cur_using_addr; + } else { + /* current using data section address is area1 current using address default value */ + set_cur_using_data_addr(area1_default_cur_using_addr); + /* next save ENV area address default is area0 current using address default value */ + next_save_area_addr = area0_default_cur_using_addr; + /* save current using data section address to flash*/ + save_cur_using_data_addr(area0_default_cur_using_addr); + save_cur_using_data_addr(area1_default_cur_using_addr); + /* set the ENV to default */ + ef_env_set_default(); + } +} +#endif /** * Save ENV to flash. */ EfErrCode ef_save_env(void) { EfErrCode result = EF_NO_ERR; - uint32_t cur_data_addr_bak = get_cur_using_data_addr(), move_offset_addr; - size_t env_detail_size = get_env_detail_size(); + uint32_t cur_using_addr_bak, move_offset_addr; + size_t env_used_size = get_env_user_used_size(); + +#ifndef EF_ENV_USING_PFS_MODE + cur_using_addr_bak = get_cur_using_data_addr(); +#else + cur_using_addr_bak = next_save_area_addr; + /* replace next_save_area_addr with cur_using_data_addr */ + next_save_area_addr = get_cur_using_data_addr(); + set_cur_using_data_addr(cur_using_addr_bak); + /* change the ENV detail end address to next save area address */ + set_env_detail_end_addr(get_cur_using_data_addr() + env_used_size); + /* ENV area saved count +1 */ + env_cache[ENV_PARAM_PART_INDEX_SAVED_COUNT]++; +#endif /* wear leveling process, automatic move ENV to next available position */ - while (get_cur_using_data_addr() + env_detail_size + while (get_cur_using_data_addr() + env_used_size < get_env_start_addr() + ef_get_env_total_size()) { /* calculate and cache CRC32 code */ env_cache[ENV_PARAM_PART_INDEX_DATA_CRC] = calc_env_crc(); /* erase ENV */ - result = ef_port_erase(get_cur_using_data_addr(), ENV_PARAM_PART_BYTE_SIZE + env_detail_size); + result = ef_port_erase(get_cur_using_data_addr(), env_used_size); switch (result) { case EF_NO_ERR: { EF_INFO("Erased ENV OK.\n"); @@ -609,8 +775,7 @@ EfErrCode ef_save_env(void) { } } /* write ENV to flash */ - result = ef_port_write(get_cur_using_data_addr(), env_cache, - ENV_PARAM_PART_BYTE_SIZE + env_detail_size); + result = ef_port_write(get_cur_using_data_addr(), env_cache, env_used_size); switch (result) { case EF_NO_ERR: { EF_INFO("Saved ENV OK.\n"); @@ -636,10 +801,10 @@ EfErrCode ef_save_env(void) { } } - if (get_cur_using_data_addr() + env_detail_size + if (get_cur_using_data_addr() + env_used_size < get_env_start_addr() + ef_get_env_total_size()) { /* current using data section address has changed, save it */ - if (get_cur_using_data_addr() != cur_data_addr_bak) { + if (get_cur_using_data_addr() != cur_using_addr_bak) { save_cur_using_data_addr(get_cur_using_data_addr()); } } else { @@ -664,7 +829,7 @@ static uint32_t calc_env_crc(void) { * The 4 is ENV end address bytes size. */ crc32 = ef_calc_crc32(crc32, &env_cache[ENV_PARAM_PART_INDEX_END_ADDR], 4); crc32 = ef_calc_crc32(crc32, &env_cache[ENV_PARAM_PART_WORD_SIZE], get_env_detail_size()); - EF_DEBUG("Calculate Env CRC32 number is 0x%08X.\n", crc32); + EF_DEBUG("Calculate ENV CRC32 number is 0x%08X.\n", crc32); return crc32; } @@ -676,7 +841,7 @@ static uint32_t calc_env_crc(void) { */ static bool env_crc_is_ok(void) { if (calc_env_crc() == env_cache[ENV_PARAM_PART_INDEX_DATA_CRC]) { - EF_DEBUG("Verify Env CRC32 result is OK.\n"); + EF_DEBUG("Verify ENV CRC32 result is OK.\n"); return true; } else { return false; @@ -690,8 +855,10 @@ static bool env_crc_is_ok(void) { * * @return result */ +#ifndef EF_ENV_USING_PFS_MODE static EfErrCode save_cur_using_data_addr(uint32_t cur_data_addr) { EfErrCode result = EF_NO_ERR; + /* erase ENV system section */ result = ef_port_erase(get_env_start_addr(), 4); if (result == EF_NO_ERR) { @@ -707,6 +874,38 @@ static EfErrCode save_cur_using_data_addr(uint32_t cur_data_addr) { } return result; } +#else +static EfErrCode save_cur_using_data_addr(uint32_t cur_data_addr) { + EfErrCode result = EF_NO_ERR; + uint32_t cur_using_addr[2]; + + /* read area0 and area1 current using data section address for backup */ + ef_port_read(get_env_start_addr(), &cur_using_addr[0], 4); + ef_port_read(get_env_start_addr() + 4, &cur_using_addr[1], 4); + + if (cur_data_addr < get_env_start_addr() + flash_erase_min_size + env_data_section_size / 2){ + /* current using data section is in ENV area0 */ + cur_using_addr[0] = cur_data_addr; + } else { + /* current using data section is in ENV area1 */ + cur_using_addr[1] = cur_data_addr; + } + /* erase ENV system section */ + result = ef_port_erase(get_env_start_addr(), 8); + if (result == EF_NO_ERR) { + /* write area0 and area1 current using data section address to flash */ + result = ef_port_write(get_env_start_addr(), cur_using_addr, 8); + if (result == EF_WRITE_ERR) { + EF_INFO("Error: Write system section fault!\n"); + EF_INFO("Note: The ENV can not be used.\n"); + } + } else { + EF_INFO("Error: Erased system section fault!\n"); + EF_INFO("Note: The ENV can not be used\n"); + } + return result; +} +#endif #endif /* EF_ENV_USING_WL_MODE */