From 237a0e70fd5b8404bcff6d0f8a5ff14d42a4687f Mon Sep 17 00:00:00 2001 From: armink Date: Thu, 12 Feb 2015 16:51:07 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E3=80=90=E5=A2=9E=E5=8A=A0=E3=80=91?= =?UTF-8?q?=E7=A3=A8=E6=8D=9F=E5=B9=B3=E8=A1=A1(=E5=86=99=E5=B9=B3?= =?UTF-8?q?=E8=A1=A1)=E6=A8=A1=E5=BC=8F=E5=88=B0Flash=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E5=8F=98=E9=87=8F=EF=BC=8C=E7=9B=AE=E5=89=8DFlash=E7=8E=AF?= =?UTF-8?q?=E5=A2=83=E5=8F=98=E9=87=8F=E5=85=B1=E6=94=AF=E6=8C=81=E4=B8=A4?= =?UTF-8?q?=E7=A7=8D=E6=A8=A1=E5=BC=8F=EF=BC=8C=E9=BB=98=E8=AE=A4=E6=98=AF?= =?UTF-8?q?=E5=B8=B8=E8=A7=84=E6=A8=A1=E5=BC=8F=EF=BC=9B=202=E3=80=81?= =?UTF-8?q?=E3=80=90=E5=AE=8C=E5=96=84=E3=80=91=E4=BB=A3=E7=A0=81=E4=B8=AD?= =?UTF-8?q?=E7=9A=84=E6=B3=A8=E9=87=8A=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: armink --- .../components/flash/port/flash_port.c | 14 +- flash/inc/flash.h | 7 +- flash/port/flash_port.c | 16 +- flash/src/flash.c | 20 +- flash/src/flash_env.c | 42 +- flash/src/flash_env_wl.c | 681 ++++++++++++++++++ flash/src/flash_iap.c | 2 +- flash/src/flash_utils.c | 2 +- 8 files changed, 742 insertions(+), 42 deletions(-) create mode 100644 flash/src/flash_env_wl.c diff --git a/demo/stm32f10x/components/flash/port/flash_port.c b/demo/stm32f10x/components/flash/port/flash_port.c index e35d440..1545ac1 100644 --- a/demo/stm32f10x/components/flash/port/flash_port.c +++ b/demo/stm32f10x/components/flash/port/flash_port.c @@ -1,7 +1,7 @@ /* * This file is part of the EasyFlash Library. * - * Copyright (C) 2013 by Armink + * Copyright (C) 2015 by Armink * * Function: Portable interface for each platform. * Created on: 2015-01-16 @@ -21,8 +21,10 @@ /* Environment variables start address */ #define FLASH_ENV_START_ADDR (FLASH_BASE + 100 * 1024) /* from the chip position: 100KB */ +/* the minimum size of flash erasure */ +#define FLASH_ERASE_MIN_SIZE PAGE_SIZE /* it is one page for STM32 */ /* Environment variables bytes size */ -#define FLASH_ENV_SECTION_SIZE (1*PAGE_SIZE) /* one page */ +#define FLASH_ENV_SECTION_SIZE (4*PAGE_SIZE) /* 4 pages */ /* print debug information of flash */ #define FLASH_PRINT_DEBUG @@ -42,19 +44,21 @@ static char log_buf[RT_CONSOLEBUF_SIZE]; * * @param env_addr environment variables start address * @param env_size environment variables bytes size (@note must be word alignment) + * @param erase_min_size the minimum size of Flash erasure * @param default_env default environment variables set for user * @param default_env_size default environment variables size * * @return result */ -FlashErrCode flash_port_init(uint32_t *env_addr, size_t *env_size, flash_env const **default_env, - size_t *default_env_size) { +FlashErrCode flash_port_init(uint32_t *env_addr, size_t *env_size, size_t *erase_min_size, + flash_env const **default_env, size_t *default_env_size) { FlashErrCode result = FLASH_NO_ERR; - FLASH_ASSERT((*env_size) % 4 == 0); + FLASH_ASSERT(FLASH_ENV_SECTION_SIZE % 4 == 0); *env_addr = FLASH_ENV_START_ADDR; *env_size = FLASH_ENV_SECTION_SIZE; + *erase_min_size = FLASH_ERASE_MIN_SIZE; *default_env = default_env_set; *default_env_size = sizeof(default_env_set)/sizeof(default_env_set[0]); diff --git a/flash/inc/flash.h b/flash/inc/flash.h index a3fbce9..97229cc 100644 --- a/flash/inc/flash.h +++ b/flash/inc/flash.h @@ -1,7 +1,7 @@ /* * This file is part of the EasyFlash Library. * - * Copyright (C) 2013 by Armink + * Copyright (C) 2014 by Armink * * Function: Is is an head file in this library. You can see all be called functions. * Created on: 2014-09-10 @@ -15,6 +15,9 @@ /* using CRC32 check when load environment variable from Flash */ #define FLASH_ENV_USING_CRC_CHECK +/* using wear leveling mode or normal mode */ +/* #define FLASH_ENV_USING_WEAR_LEVELING_MODE */ +#define FLASH_ENV_USING_NORMAL_MODE /* Flash debug print function. Must be implement by user. */ #define FLASH_DEBUG(...) flash_log_debug(__FILE__, __LINE__, __VA_ARGS__) @@ -28,7 +31,7 @@ if (!(EXPR)) \ while (1); \ } /* EasyFlash software version number */ -#define FLASH_SW_VERSION "1.02.11" +#define FLASH_SW_VERSION "1.02.12" typedef struct _flash_env{ char *key; diff --git a/flash/port/flash_port.c b/flash/port/flash_port.c index 83634e0..d577016 100644 --- a/flash/port/flash_port.c +++ b/flash/port/flash_port.c @@ -1,7 +1,7 @@ /* * This file is part of the EasyFlash Library. * - * Copyright (C) 2013 by Armink + * Copyright (C) 2015 by Armink * * Function: Portable interface for each platform. * Created on: 2015-01-16 @@ -9,9 +9,11 @@ #include "flash.h" -/* Environment variables start address */ +/* environment variables start address */ #define FLASH_ENV_START_ADDR /* @note you must define it for a value */ -/* Environment variables bytes size */ +/* the minimum size of flash erasure */ +#define #define FLASH_ERASE_MIN_SIZE /* @note you must define it for a value */ +/* environment variables bytes size */ #define FLASH_ENV_SECTION_SIZE /* @note you must define it for a value */ /* print debug information of flash */ #define FLASH_PRINT_DEBUG @@ -26,19 +28,21 @@ static const flash_env default_env_set[] = { * * @param env_addr environment variables start address * @param env_size environment variables bytes size (@note must be word alignment) + * @param erase_min_size the minimum size of Flash erasure * @param default_env default environment variables set for user * @param default_env_size default environment variables size * * @return result */ -FlashErrCode flash_port_init(uint32_t *env_addr, size_t *env_size, flash_env const **default_env, - size_t *default_env_size) { +FlashErrCode flash_port_init(uint32_t *env_addr, size_t *env_size, size_t *erase_min_size, + flash_env const **default_env, size_t *default_env_size) { FlashErrCode result = FLASH_NO_ERR; - FLASH_ASSERT((*env_size) % 4 == 0); + FLASH_ASSERT(FLASH_ENV_SECTION_SIZE % 4 == 0); *env_addr = FLASH_ENV_START_ADDR; *env_size = FLASH_ENV_SECTION_SIZE; + *erase_min_size = FLASH_ERASE_MIN_SIZE; *default_env = default_env_set; *default_env_size = sizeof(default_env_set)/sizeof(default_env_set[0]); diff --git a/flash/src/flash.c b/flash/src/flash.c index 4437eb4..096a211 100644 --- a/flash/src/flash.c +++ b/flash/src/flash.c @@ -1,18 +1,18 @@ /* * This file is part of the EasyFlash Library. * - * Copyright (C) 2013 by Armink + * Copyright (C) 2014 by Armink * * Function: Initialize interface for this library. * Created on: 2014-09-09 */ -/* +/** * All Backup Area Flash storage index - * |----------------------------| Storage Size + * |----------------------------| Storage Size * | Environment variables area | FLASH_ENV_SECTION_SIZE @see FLASH_ENV_SECTION_SIZE - * | 1.system section | FLASH_ENV_SYSTEM_SIZE @see FLASH_ENV_SYSTEM_SIZE + * | 1.system section | FLASH_ENV_SYSTEM_SIZE * | 2:data section | FLASH_ENV_SECTION_SIZE - FLASH_ENV_SYSTEM_SIZE * |----------------------------| * |(IAP)Downloaded application | IAP already downloaded application size @@ -26,7 +26,7 @@ * 3.Remain * * Environment variables area has 2 section - * 1.system section.(unit: word, storage Environment variables parameter) + * 1.system section.(unit: 4 bytes, storage Environment variables's parameter) * 2.data section.(storage all environment variables) * */ @@ -39,21 +39,21 @@ */ FlashErrCode flash_init(void) { extern FlashErrCode flash_port_init(uint32_t *env_addr, size_t *env_size, - flash_env const **default_env, size_t *default_env_size); + size_t *erase_min_size, flash_env const **default_env, size_t *default_env_size); extern FlashErrCode flash_env_init(uint32_t start_addr, size_t total_size, - flash_env const *default_env, size_t default_env_size); + size_t erase_min_size, flash_env const *default_env, size_t default_env_size); extern FlashErrCode flash_iap_init(uint32_t start_addr); uint32_t env_start_addr; - size_t env_total_size, default_env_set_size; + size_t env_total_size, erase_min_size, default_env_set_size; const flash_env *default_env_set; FlashErrCode result = FLASH_NO_ERR; - result = flash_port_init(&env_start_addr, &env_total_size, &default_env_set, + result = flash_port_init(&env_start_addr, &env_total_size, &erase_min_size, &default_env_set, &default_env_set_size); if (result == FLASH_NO_ERR) { - result = flash_env_init(env_start_addr, env_total_size, default_env_set, + result = flash_env_init(env_start_addr, env_total_size, erase_min_size, default_env_set, default_env_set_size); } diff --git a/flash/src/flash_env.c b/flash/src/flash_env.c index d2b377d..c2ca79c 100644 --- a/flash/src/flash_env.c +++ b/flash/src/flash_env.c @@ -1,9 +1,9 @@ /* * This file is part of the EasyFlash Library. * - * Copyright (C) 2013 by Armink + * Copyright (C) 2014 by Armink * - * Function: Environment variables operating interface. + * Function: Environment variables operating interface. (normal mode) * Created on: 2014-10-06 */ @@ -11,16 +11,18 @@ #include #include -/* Environment variables area has 2 section - * 1.system section.(units: word, storage Environment variables configuration) - * 2.data section.(storage all environment variables. Storage format is key=value\0 . - * All environment variables must be 4 bytes alignment. The remaining part must fill '\0'.) - */ +#ifdef FLASH_ENV_USING_NORMAL_MODE -/* default environment variables set, must be initialized by user */ -static flash_env const *default_env_set = NULL; -/* default environment variables set size, must be initialized by user */ -static size_t default_env_set_size = NULL; +/** + * Environment variables area has 2 sections + * 1. System section + * It storage environment variables parameters. (Units: Word) + * 2. Data section + * It storage all environment variables. Storage format is key=value\0. + * All environment variables must be 4 bytes alignment. The remaining part must fill '\0'. + * + * @note Word = 4 Bytes in this file + */ /* flash ENV system section index and size */ enum { @@ -34,12 +36,15 @@ enum { /* flash environment variables system section word size */ FLASH_ENV_SYSTEM_WORD_SIZE, - /* flash environment variables system section word size */ + /* flash environment variables system section byte size */ FLASH_ENV_SYSTEM_BYTE_SIZE = FLASH_ENV_SYSTEM_WORD_SIZE * 4, }; - -/* flash environment variables section total size */ +/* default environment variables set, must be initialized by user */ +static flash_env const *default_env_set = NULL; +/* default environment variables set size, must be initialized by user */ +static size_t default_env_set_size = NULL; +/* flash environment variables all section total size */ static size_t env_total_size = NULL; /* environment variables RAM cache */ static uint32_t *env_cache = NULL; @@ -65,19 +70,20 @@ static bool_t env_crc_is_ok(void); * * @param start_addr environment variables start address in flash * @param total_size environment variables section total size (@note must be word alignment) + * @param erase_min_size the minimum size of flash erasure * @param default_env default environment variables set for user * @param default_env_size default environment variables set size * * @return result */ -FlashErrCode flash_env_init(uint32_t start_addr, size_t total_size, flash_env const *default_env, - size_t default_env_size) { +FlashErrCode flash_env_init(uint32_t start_addr, size_t total_size, size_t erase_min_size, + flash_env const *default_env, size_t default_env_size) { FlashErrCode result = FLASH_NO_ERR; FLASH_ASSERT(start_addr); FLASH_ASSERT(total_size); FLASH_ASSERT(default_env); - FLASH_ASSERT(default_env); + FLASH_ASSERT(default_env_size < total_size); /* must be word alignment for environment variables */ FLASH_ASSERT(total_size % 4 == 0); /* make true only be initialized once */ @@ -569,3 +575,5 @@ static bool_t env_crc_is_ok(void) { } } #endif + +#endif diff --git a/flash/src/flash_env_wl.c b/flash/src/flash_env_wl.c new file mode 100644 index 0000000..18b9b5b --- /dev/null +++ b/flash/src/flash_env_wl.c @@ -0,0 +1,681 @@ +/* + * This file is part of the EasyFlash Library. + * + * Copyright (C) 2015 by Armink + * + * Function: Environment variables operating interface. (wear leveling mode) + * Created on: 2015-02-11 + */ + +#include "flash.h" +#include +#include + +#ifdef FLASH_ENV_USING_WEAR_LEVELING_MODE + +/** + * Environment variables area has 2 sections + * 1. System section + * Storage Environment variables current using data section address. + * Units: Word. Total size: @see FLASH_ERASE_MIN_SIZE. + * 2. Data section + * The data section storage environment variables'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. + * 2.1 Environment variables parameters part + * It storage environment variables's parameters. + * 2.2 Environment variables detail part + * It storage all environment variables. Storage format is key=value\0. + * All environment variables must be 4 bytes alignment. The remaining part must fill '\0'. + * + * @note Word = 4 Bytes in this file + */ + +/* flash ENV parameters part index and size */ +enum { + /* data section environment variables detail part end address index */ + ENV_PARAM_PART_INDEX_END_ADDR = 0, + +#ifdef FLASH_ENV_USING_CRC_CHECK + /* data section CRC32 code index */ + ENV_PARAM_PART_INDEX_DATA_CRC, +#endif + + /* environment variables parameters part word size */ + ENV_PARAM_PART_WORD_SIZE, + /* environment variables parameters part byte size */ + ENV_PARAM_PART_BYTE_SIZE = ENV_PARAM_PART_WORD_SIZE * 4, +}; + +/* default environment variables set, must be initialized by user */ +static flash_env const *default_env_set = NULL; +/* default environment variables set size, must be initialized by user */ +static size_t default_env_set_size = NULL; +/* flash environment variables all section total size */ +static size_t env_total_size = NULL; +/* the minimum size of flash erasure */ +static size_t flash_erase_min_size = NULL; +/* environment variables RAM cache */ +static uint32_t *env_cache = NULL; +/* environment variables start address in flash */ +static uint32_t env_start_addr = NULL; +/* current using data section address */ +static uint32_t cur_using_data_addr = NULL; + +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); +static uint32_t get_env_detail_end_addr(void); +static void set_cur_using_data_addr(uint32_t using_data_addr); +static void set_env_detail_end_addr(uint32_t end_addr); +static FlashErrCode write_env(const char *key, const char *value); +static uint32_t *find_env(const char *key); +static size_t get_env_detail_size(void); +static FlashErrCode create_env(const char *key, const char *value); +static FlashErrCode save_cur_using_data_addr(uint32_t cur_data_addr); + +#ifdef FLASH_ENV_USING_CRC_CHECK +static uint32_t calc_env_crc(void); +static bool_t env_crc_is_ok(void); +#endif + +/** + * Flash environment variables initialize. + * + * @param start_addr environment variables start address in flash + * @param total_size environment variables section total size (@note must be word alignment) + * @param erase_min_size the minimum size of flash erasure + * @param default_env default environment variables set for user + * @param default_env_size default environment variables set size + * + * @return result + */ +FlashErrCode flash_env_init(uint32_t start_addr, size_t total_size, size_t erase_min_size, + flash_env const *default_env, size_t default_env_size) { + FlashErrCode result = FLASH_NO_ERR; + + FLASH_ASSERT(start_addr); + FLASH_ASSERT(total_size); + FLASH_ASSERT(erase_min_size); + FLASH_ASSERT(default_env); + FLASH_ASSERT(default_env_size < total_size); + /* must be word alignment for environment variables */ + FLASH_ASSERT(total_size % 4 == 0); + /* make true only be initialized once */ + FLASH_ASSERT(!env_cache); + + env_start_addr = start_addr; + env_total_size = total_size; + flash_erase_min_size = erase_min_size; + default_env_set = default_env; + default_env_set_size = default_env_size; + + FLASH_DEBUG("Env start address is 0x%08X, size is %d bytes.\n", start_addr, total_size); + + /* create environment variables ram cache */ + env_cache = (uint32_t *) flash_malloc(sizeof(uint8_t) * total_size); + FLASH_ASSERT(env_cache); + + flash_load_env(); + + return result; +} + +/** + * Environment variables set default. + * + * @return result + */ +FlashErrCode flash_env_set_default(void){ + FlashErrCode result = FLASH_NO_ERR; + size_t i; + + FLASH_ASSERT(env_cache); + FLASH_ASSERT(default_env_set); + FLASH_ASSERT(default_env_set_size); + + /* set ENV detail part end address is at ENV detail part start address */ + set_env_detail_end_addr(get_env_detail_addr()); + + /* create default environment variables */ + for (i = 0; i < default_env_set_size; i++) { + create_env(default_env_set[i].key, default_env_set[i].value); + } + + flash_save_env(); + + return result; +} + +/** + * Get environment variables start address in flash. + * + * @return environment variables start address in flash + */ +static uint32_t get_env_start_addr(void) { + FLASH_ASSERT(env_start_addr); + return env_start_addr; +} +/** + * Get current using data section address. + * + * @return current using data section address + */ +static uint32_t get_cur_using_data_addr(void) { + FLASH_ASSERT(cur_using_data_addr); + return cur_using_data_addr; +} + +/** + * Set current using data section address. + * + * @param using_data_addr current using data section address + */ +static void set_cur_using_data_addr(uint32_t using_data_addr) { + cur_using_data_addr = using_data_addr; +} + +/** + * Get environment variables detail part start address. + * + * @return detail part start address + */ +static uint32_t get_env_detail_addr(void) { + FLASH_ASSERT(cur_using_data_addr); + return cur_using_data_addr + ENV_PARAM_PART_BYTE_SIZE; +} + +/** + * Get environment variables detail part end address. + * It's the first word in environment variables. + * + * @return environment variables end address + */ +static uint32_t get_env_detail_end_addr(void) { + /* it is the first word */ + return env_cache[ENV_PARAM_PART_INDEX_END_ADDR]; +} + +/** + * Set environment variables detail part end address. + * It's the first word in environment variables. + * + * @param end_addr environment variables end address + */ +static void set_env_detail_end_addr(uint32_t end_addr) { + env_cache[ENV_PARAM_PART_INDEX_END_ADDR] = end_addr; +} + +/** + * Get current environment variables detail part size. + * + * @return size + */ +static size_t get_env_detail_size(void) { + return get_env_detail_end_addr() - get_env_detail_addr(); +} + +/** + * Get current environment variables section total size. + * + * @return size + */ +size_t flash_get_env_total_size(void) { + /* must be initialized */ + FLASH_ASSERT(env_total_size); + + return env_total_size; +} + +/** + * Get current environment variables used byte size. + * + * @return size + */ +uint32_t flash_get_env_used_size(void) { + return get_env_detail_end_addr() - get_env_start_addr(); +} + +/** + * Write an environment variable at the end of cache. + * + * @param key environment variable name + * @param value environment variable value + * + * @return result + */ +static FlashErrCode write_env(const char *key, const char *value) { + FlashErrCode result = FLASH_NO_ERR; + uint16_t env_str_index = 0, env_str_length, i; + char *env_str; + + /* calculate environment variables storage length, contain '=' and '\0'. */ + env_str_length = strlen(key) + strlen(value) + 2; + if (env_str_length % 4 != 0) { + env_str_length = (env_str_length / 4 + 1) * 4; + } + /* check capacity of environment variables */ + if (env_str_length + get_env_detail_size() >= flash_get_env_total_size()) { + return FLASH_ENV_FULL; + } + /* use ram to process string key=value\0 */ + env_str = flash_malloc(env_str_length * sizeof(char)); + FLASH_ASSERT(env_str); + memset(env_str, 0, env_str_length * sizeof(char)); + /* copy key name */ + for (env_str_index = 0; env_str_index < strlen(key); env_str_index++) { + env_str[env_str_index] = key[env_str_index]; + } + /* copy equal sign */ + env_str[env_str_index] = '='; + env_str_index++; + /* copy value */ + for (i = 0; i < strlen(value); env_str_index++, i++) { + env_str[env_str_index] = value[i]; + } + + //TODO ¿¼ÂǿɷñÓÅ»¯ + memcpy((char *) env_cache + ENV_PARAM_PART_BYTE_SIZE + get_env_detail_size(), + (uint32_t *) env_str, env_str_length); + set_env_detail_end_addr(get_env_detail_end_addr() + env_str_length); + + /* free ram */ + flash_free(env_str); + env_str = NULL; + + return result; +} + +/** + * Find environment variables. + * + * @param key environment variables name + * + * @return index of environment variables in ram cache + */ +static uint32_t *find_env(const char *key) { + uint32_t *env_cache_addr = NULL; + char *env_start, *env_end, *env, *env_bak; + + FLASH_ASSERT(cur_using_data_addr); + + if (*key == NULL) { + FLASH_INFO("Flash environment variables name must be not empty!\n"); + return NULL; + } + + /* from data section start to data section end */ + env_start = (char *) ((char *) env_cache + ENV_PARAM_PART_BYTE_SIZE); + env_end = (char *) ((char *) env_cache + ENV_PARAM_PART_BYTE_SIZE + get_env_detail_size()); + + /* environment variables is null */ + if (env_start == env_end) { + return NULL; + } + + env = env_start; + while (env < env_end) { + /* storage model is key=value\0 */ + env_bak = strstr(env, key); + /* the key name length must be equal */ + if (env_bak && (env_bak[strlen(key)] == '=')) { + env_cache_addr = (uint32_t *) env; + break; + } else { + /* next environment variables */ + env += strlen(env) + 1; + } + } + return env_cache_addr; +} + +/** + * If the environment variable is not exist, create it. + * @see flash_write_env + * + * @param key environment variable name + * @param value environment variable value + * + * @return result + */ +static FlashErrCode create_env(const char *key, const char *value) { + FlashErrCode result = FLASH_NO_ERR; + + FLASH_ASSERT(key); + FLASH_ASSERT(value); + + if (*key == NULL) { + FLASH_INFO("Flash environment variables name must be not empty!\n"); + return FLASH_ENV_NAME_ERR; + } + + if (strstr(key, "=")) { + FLASH_INFO("Flash environment variables name can't contain '='.\n"); + return FLASH_ENV_NAME_ERR; + } + + /* find environment variables */ + if (find_env(key)) { + FLASH_INFO("The name of \"%s\" is already exist.\n", key); + return FLASH_ENV_NAME_EXIST; + } + /* write environment variables to flash */ + result = write_env(key, value); + + return result; +} + +/** + * Delete an environment variable in cache. + * + * @param key environment variable name + * + * @return result + */ +FlashErrCode flash_del_env(const char *key){ + FlashErrCode result = FLASH_NO_ERR; + char *del_env_str = NULL; + uint32_t del_env_length, remain_env_length; + + FLASH_ASSERT(key); + FLASH_ASSERT(env_cache); + + if (*key == NULL) { + FLASH_INFO("Flash environment variables name must be not NULL!\n"); + return FLASH_ENV_NAME_ERR; + } + + if (strstr(key, "=")) { + FLASH_INFO("Flash environment variables name or value can't contain '='.\n"); + return FLASH_ENV_NAME_ERR; + } + + /* find environment variables */ + del_env_str = (char *) find_env(key); + if (!del_env_str) { + FLASH_INFO("Not find \"%s\" in environment variables.\n", key); + return FLASH_ENV_NAME_ERR; + } + del_env_length = strlen(del_env_str); + /* '\0' also must be as environment variable length */ + del_env_length ++; + /* the address must multiple of 4 */ + if (del_env_length % 4 != 0) { + del_env_length = (del_env_length / 4 + 1) * 4; + } + /* calculate remain environment variables length */ + remain_env_length = get_env_detail_size() - ((uint32_t) del_env_str - (uint32_t) env_cache); + /* remain environment variables move forward */ + memcpy(del_env_str, del_env_str + del_env_length, remain_env_length); + /* reset environment variables detail part end address */ + set_env_detail_end_addr(get_env_detail_end_addr() - del_env_length); + + return result; +} + +/** + * Set an environment variable. If it value is NULL, delete it. + * If not find it in environment variables table, then create it. + * + * @param key environment variable name + * @param value environment variable value + * + * @return result + */ +FlashErrCode flash_set_env(const char *key, const char *value) { + FlashErrCode result = FLASH_NO_ERR; + + FLASH_ASSERT(env_cache); + + /* if value is null, delete it */ + if (*value == NULL) { + result = flash_del_env(key); + } else { + /* if find this variables, then delete it and recreate it */ + if (find_env(key)) { + result = flash_del_env(key); + } + if (result == FLASH_NO_ERR) { + result = create_env(key, value); + } + } + return result; +} + +/** + * Get an environment variable value by key name. + * + * @param key environment variable name + * + * @return value + */ +char *flash_get_env(const char *key) { + uint32_t *env_cache_addr = NULL; + char *value = NULL; + + FLASH_ASSERT(env_cache); + + /* find environment variables */ + env_cache_addr = find_env(key); + if (env_cache_addr == NULL) { + return NULL; + } + /* get value address */ + value = strstr((char *) env_cache_addr, "="); + if (value != NULL) { + /* the equal sign next character is value */ + value++; + } + return value; +} +/** + * Print environment variables. + */ +void flash_print_env(void) { + uint32_t *env_cache_detail_addr = env_cache + ENV_PARAM_PART_WORD_SIZE, + *env_cache_end_addr = + (uint32_t *) (env_cache + ENV_PARAM_PART_WORD_SIZE + get_env_detail_size() / 4); + uint8_t j; + char c; + + FLASH_ASSERT(env_cache); + + for (; env_cache_detail_addr < env_cache_end_addr; env_cache_detail_addr += 1) { + for (j = 0; j < 4; j++) { + c = (*env_cache_detail_addr) >> (8 * j); + flash_print("%c", c); + if (c == NULL) { + flash_print("\n"); + break; + } + } + } + flash_print("\nEnvironment variables size: %ld/%ld bytes\n", flash_get_env_used_size(), + flash_get_env_total_size()); +} + +/** + * Load flash environment variables to ram. + */ +void flash_load_env(void) { + uint32_t *env_cache_bak, env_end_addr, using_data_addr; + + FLASH_ASSERT(env_cache); + + /* read current using data section address */ + flash_read(get_env_start_addr(), &using_data_addr, 4); + /* if environment variables is not initialize, set default for it */ + if (using_data_addr == 0xFFFFFFFF) { + /* initialize current using data section address */ + set_cur_using_data_addr(get_env_start_addr() + flash_erase_min_size); + /* save current using data section address to flash*/ + save_cur_using_data_addr(get_cur_using_data_addr()); + /* set default environment variables */ + flash_env_set_default(); + } else { + /* set current using data section address */ + set_cur_using_data_addr(using_data_addr); + /* read environment variables detail part end address from flash */ + flash_read(get_cur_using_data_addr() + ENV_PARAM_PART_INDEX_END_ADDR * 4, &env_end_addr, 4); + /* set environment variables detail part end address */ + set_env_detail_end_addr(env_end_addr); + + env_cache_bak = env_cache + ENV_PARAM_PART_WORD_SIZE; + /* read all environment variables from flash */ + flash_read(get_env_detail_addr(), env_cache_bak, get_env_detail_size()); + +#ifdef FLASH_ENV_USING_CRC_CHECK + /* read environment variables CRC code from flash */ + flash_read(get_cur_using_data_addr() + ENV_PARAM_PART_INDEX_DATA_CRC * 4, + &env_cache[ENV_PARAM_PART_INDEX_DATA_CRC] , 4); + + /* if environment variables CRC32 check is fault, set default for it */ + if (!env_crc_is_ok()) { + FLASH_INFO("Warning: Environment variables CRC check failed. Set it to default.\n"); + flash_env_set_default(); + } +#endif + + } +} + +/** + * Save environment variables to flash. + */ +FlashErrCode flash_save_env(void) { + FlashErrCode result = FLASH_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(); + + FLASH_ASSERT(env_cache); + + /* wear leveling process, automatic move environment variables to next available position */ + while (get_cur_using_data_addr() + env_detail_size + < get_env_start_addr() + flash_get_env_total_size()) { + +#ifdef FLASH_ENV_USING_CRC_CHECK + /* calculate and cache CRC32 code */ + env_cache[ENV_PARAM_PART_INDEX_DATA_CRC] = calc_env_crc(); +#endif + /* erase environment variables */ + result = flash_erase(get_cur_using_data_addr(), ENV_PARAM_PART_BYTE_SIZE + env_detail_size); + switch (result) { + case FLASH_NO_ERR: { + FLASH_INFO("Erased environment variables OK.\n"); + break; + } + case FLASH_ERASE_ERR: { + FLASH_INFO("Warning: Erased environment variables fault!\n"); + FLASH_INFO("Moving environment variables to next available position.\n"); + /* calculate move offset address */ + move_offset_addr = (env_detail_size / flash_erase_min_size + 1) * flash_erase_min_size; + /* calculate and set next available data section address */ + set_cur_using_data_addr(get_cur_using_data_addr() + move_offset_addr); + /* calculate and set next available environment variables detail part end address */ + set_env_detail_end_addr(get_env_detail_end_addr() + move_offset_addr); + continue; + } + } + /* write environment variables to flash */ + result = flash_write(get_cur_using_data_addr(), env_cache, + ENV_PARAM_PART_BYTE_SIZE + env_detail_size); + switch (result) { + case FLASH_NO_ERR: { + FLASH_INFO("Saved environment variables OK.\n"); + break; + } + case FLASH_WRITE_ERR: { + FLASH_INFO("Warning: Saved environment variables fault!\n"); + FLASH_INFO("Moving environment variables to next available position.\n"); + /* calculate move offset address */ + move_offset_addr = (env_detail_size / flash_erase_min_size + 1) * flash_erase_min_size; + /* calculate and set next available data section address */ + set_cur_using_data_addr(get_cur_using_data_addr() + move_offset_addr); + /* calculate and set next available environment variables detail part end address */ + set_env_detail_end_addr(get_env_detail_end_addr() + move_offset_addr); + continue; + } + } + /* save environment variables success */ + if (result == FLASH_NO_ERR) { + break; + } + } + + if (get_cur_using_data_addr() + env_detail_size + < get_env_start_addr() + flash_get_env_total_size()) { + /* current using data section address has changed, save it */ + if (get_cur_using_data_addr() != cur_data_addr_bak) { + save_cur_using_data_addr(get_cur_using_data_addr()); + } + } else { + result = FLASH_ENV_FULL; + FLASH_INFO("Error: The flash has no available space to save environment variables.\n"); + /* clear current using data section address on flash */ + save_cur_using_data_addr(0xFFFFFFFF); + } + + return result; +} + +#ifdef FLASH_ENV_USING_CRC_CHECK +/** + * Calculate the cached environment variables CRC32 value. + * + * @return CRC32 value + */ +static uint32_t calc_env_crc(void) { + uint32_t crc32 = 0; + + extern uint32_t calc_crc32(uint32_t crc, const void *buf, size_t size); + /* Calculate the environment variables end address and all environment variables data CRC32. + * The 4 is environment variables end address bytes size. */ + crc32 = calc_crc32(crc32, &env_cache[ENV_PARAM_PART_INDEX_END_ADDR], 4); + crc32 = calc_crc32(crc32, &env_cache[ENV_PARAM_PART_WORD_SIZE], get_env_detail_size()); + FLASH_DEBUG("Calculate Env CRC32 number is 0x%08X.\n", crc32); + + return crc32; +} +#endif + +#ifdef FLASH_ENV_USING_CRC_CHECK +/** + * Check the environment variables CRC32 + * + * @return true is ok + */ +static bool_t env_crc_is_ok(void) { + if (calc_env_crc() == env_cache[ENV_PARAM_PART_INDEX_DATA_CRC]) { + FLASH_DEBUG("Verify Env CRC32 result is OK.\n"); + return TRUE; + } else { + return FALSE; + } +} +#endif + +/** + * Save current using data section address to flash. + * + * @param cur_data_addr current using data section address + * + * @return result + */ +static FlashErrCode save_cur_using_data_addr(uint32_t cur_data_addr) { + FlashErrCode result = FLASH_NO_ERR; + /* erase environment variables system section */ + result = flash_erase(get_env_start_addr(), 4); + if (result == FLASH_NO_ERR) { + /* write current using data section address to flash */ + result = flash_write(get_env_start_addr(), &cur_data_addr, 4); + if (result == FLASH_WRITE_ERR) { + FLASH_INFO("Error: Write system section fault!\n"); + FLASH_INFO("Note: The environment variables can not be used.\n"); + } + } else { + FLASH_INFO("Error: Erased system section fault!\n"); + FLASH_INFO("Note: The environment variables can not be used\n"); + } + return result; +} +#endif diff --git a/flash/src/flash_iap.c b/flash/src/flash_iap.c index 809f980..068df8a 100644 --- a/flash/src/flash_iap.c +++ b/flash/src/flash_iap.c @@ -1,7 +1,7 @@ /* * This file is part of the EasyFlash Library. * - * Copyright (C) 2013 by Armink + * Copyright (C) 2015 by Armink * * Function: IAP(In-Application Programming) operating interface. * Created on: 2015-01-05 diff --git a/flash/src/flash_utils.c b/flash/src/flash_utils.c index 994e0e5..617d466 100644 --- a/flash/src/flash_utils.c +++ b/flash/src/flash_utils.c @@ -1,7 +1,7 @@ /* * This file is part of the EasyFlash Library. * - * Copyright (C) 2013 by Armink + * Copyright (C) 2015 by Armink * * Function: Some utils for this library. * Created on: 2015-01-14