From 6e0d2cd3b6915d93789873f5c0c00e13670faf47 Mon Sep 17 00:00:00 2001 From: armink Date: Thu, 11 May 2017 20:19:08 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E3=80=90=E4=BC=98=E5=8C=96=E3=80=91L?= =?UTF-8?q?og=20=E5=88=86=E5=8C=BA=E8=AF=86=E5=88=AB=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=EF=BC=8C=E5=A4=A7=E5=A4=A7=E6=8F=90=E5=8D=87=20Log=20=E5=88=86?= =?UTF-8?q?=E5=8C=BA=E5=88=9D=E5=A7=8B=E5=8C=96=E6=95=88=E7=8E=87=EF=BC=9B?= =?UTF-8?q?=202=E3=80=81=E3=80=90=E5=88=A0=E9=99=A4=E3=80=91=E9=83=A8?= =?UTF-8?q?=E5=88=86=E5=86=97=E4=BD=99=E6=96=AD=E8=A8=80=EF=BC=9B=203?= =?UTF-8?q?=E3=80=81=E3=80=90=E4=BF=AE=E5=A4=8D=E3=80=91=E5=87=A0=E5=A4=84?= =?UTF-8?q?=E5=8D=95=E8=AF=8D=E6=8B=BC=E5=86=99=E9=94=99=E8=AF=AF=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: armink --- LICENSE | 2 +- easyflash/inc/easyflash.h | 6 +- easyflash/src/ef_env.c | 10 +- easyflash/src/ef_env_wl.c | 6 +- easyflash/src/ef_iap.c | 3 +- easyflash/src/ef_log.c | 454 ++++++++++++++++++++++++++++++-------- easyflash/src/ef_utils.c | 69 +----- 7 files changed, 372 insertions(+), 178 deletions(-) diff --git a/LICENSE b/LICENSE index 2ca031c..9feba16 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014-2016 Armink (armink.ztl@gmail.com) +Copyright (c) 2014-2017 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 diff --git a/easyflash/inc/easyflash.h b/easyflash/inc/easyflash.h index 1efdc93..42b37e5 100644 --- a/easyflash/inc/easyflash.h +++ b/easyflash/inc/easyflash.h @@ -1,7 +1,7 @@ /* * This file is part of the EasyFlash Library. * - * Copyright (c) 2014-2016, Armink, + * Copyright (c) 2014-2017, Armink, * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -67,7 +67,7 @@ if (!(EXPR)) \ while (1); \ } /* EasyFlash software version number */ -#define EF_SW_VERSION "2.12.08" +#define EF_SW_VERSION "3.0.0" typedef struct _ef_env{ char *key; @@ -128,8 +128,6 @@ size_t ef_log_get_used_size(void); /* ef_utils.c */ uint32_t ef_calc_crc32(uint32_t crc, const void *buf, size_t size); -EfSecrorStatus 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); /* ef_port.c */ EfErrCode ef_port_read(uint32_t addr, uint32_t *buf, size_t size); diff --git a/easyflash/src/ef_env.c b/easyflash/src/ef_env.c index dbfc0c0..1383471 100644 --- a/easyflash/src/ef_env.c +++ b/easyflash/src/ef_env.c @@ -281,11 +281,11 @@ size_t ef_get_env_write_bytes(void) { */ static EfErrCode write_env(const char *key, const char *value) { EfErrCode result = EF_NO_ERR; - size_t ker_len = strlen(key), value_len = strlen(value), env_str_len; + size_t key_len = strlen(key), value_len = strlen(value), env_str_len; char *env_cache_bak = (char *)env_cache; /* calculate ENV storage length, contain '=' and '\0'. */ - env_str_len = ker_len + value_len + 2; + env_str_len = key_len + value_len + 2; if (env_str_len % 4 != 0) { env_str_len = (env_str_len / 4 + 1) * 4; } @@ -298,8 +298,8 @@ static EfErrCode write_env(const char *key, const char *value) { env_cache_bak += get_env_user_used_size(); /* copy key name */ - memcpy(env_cache_bak, key, ker_len); - env_cache_bak += ker_len; + memcpy(env_cache_bak, key, key_len); + env_cache_bak += key_len; /* copy equal sign */ *env_cache_bak = '='; env_cache_bak++; @@ -310,7 +310,7 @@ static EfErrCode write_env(const char *key, const char *value) { *env_cache_bak = '\0'; env_cache_bak ++; /* fill '\0' for word alignment */ - memset(env_cache_bak, 0, env_str_len - (ker_len + value_len + 2)); + memset(env_cache_bak, 0, env_str_len - (key_len + value_len + 2)); set_env_end_addr(get_env_end_addr() + env_str_len); /* ENV ram cache has changed */ env_cache_changed = true; diff --git a/easyflash/src/ef_env_wl.c b/easyflash/src/ef_env_wl.c index 512d5cb..7e1e01e 100644 --- a/easyflash/src/ef_env_wl.c +++ b/easyflash/src/ef_env_wl.c @@ -1,7 +1,7 @@ /* * This file is part of the EasyFlash Library. * - * Copyright (c) 2015-2016, Armink, + * Copyright (c) 2015-2017, Armink, * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -214,7 +214,6 @@ static uint32_t get_env_start_addr(void) { * @return current using data section address */ static uint32_t get_cur_using_data_addr(void) { - EF_ASSERT(cur_using_data_addr); return cur_using_data_addr; } @@ -233,7 +232,6 @@ static void set_cur_using_data_addr(uint32_t using_data_addr) { * @return detail part start address */ static uint32_t get_env_detail_addr(void) { - EF_ASSERT(cur_using_data_addr); return get_cur_using_data_addr() + ENV_PARAM_PART_BYTE_SIZE; } @@ -348,8 +346,6 @@ static char *find_env(const char *key) { char *env_start, *env_end, *env, *found_env = NULL; size_t key_len = strlen(key), env_len; - EF_ASSERT(cur_using_data_addr); - if (*key == NULL) { EF_INFO("Flash ENV name must be not empty!\n"); return NULL; diff --git a/easyflash/src/ef_iap.c b/easyflash/src/ef_iap.c index 16d1fd6..adbef5f 100644 --- a/easyflash/src/ef_iap.c +++ b/easyflash/src/ef_iap.c @@ -1,7 +1,7 @@ /* * This file is part of the EasyFlash Library. * - * Copyright (c) 2015-2016, Armink, + * Copyright (c) 2015-2017, Armink, * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -258,7 +258,6 @@ EfErrCode ef_copy_bl_from_bak(uint32_t bl_addr, size_t bl_size) { * @return size */ static uint32_t get_bak_app_start_addr(void) { - EF_ASSERT(bak_app_start_addr); return bak_app_start_addr; } diff --git a/easyflash/src/ef_log.c b/easyflash/src/ef_log.c index d627488..9ad6d69 100644 --- a/easyflash/src/ef_log.c +++ b/easyflash/src/ef_log.c @@ -1,7 +1,7 @@ /* * This file is part of the EasyFlash Library. * - * Copyright (c) 2015, Armink, + * Copyright (c) 2015-2017, Armink, * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -30,6 +30,38 @@ #ifdef EF_USING_LOG +/* magic code on every sector header. 'EF' is 0x4546 */ +#define LOG_SECTOR_MAGIC 0x4546 +/* sector header size, include the sector magic code and status magic code */ +#define LOG_SECTOR_HEADER_SIZE 4 + +/** + * Sector status magic code + * The sector status is 16-Bits after LOG_SECTOR_MAGIC at every sector header. + * ======================= + * | header(4B) | status | + * ----------------------- + * | 0x4546FFFF | empty | + * | 0x4546FFFE | using | + * | 0x4546FFFC | full | + * ======================= + * + * State transition relationship: empty->using->full + * The FULL status will change to EMPTY after sector clean. + */ +enum { + SECTOR_STATUS_MAGIC_EMPUT = 0xFFFF, + SECTOR_STATUS_MAGIC_USING = 0xFFFE, + SECTOR_STATUS_MAGIC_FULL = 0xFFFC, +}; + +typedef enum { + SECTOR_STATUS_EMPUT, + SECTOR_STATUS_USING, + SECTOR_STATUS_FULL, + SECTOR_STATUS_HEADER_ERROR, +} SectorStatus; + /* the stored logs start address and end address. It's like a ring buffer which implement by flash. */ static uint32_t log_start_addr = 0, log_end_addr = 0; /* saved log area address for flash */ @@ -69,6 +101,131 @@ EfErrCode ef_log_init(void) { return result; } +/** + * Get flash sector current status. + * + * @param addr sector address, this function will auto calculate the sector header address by this address. + * + * @return the flash sector current status + */ +static SectorStatus get_sector_status(uint32_t addr) { + uint32_t header = 0, header_addr = 0; + uint16_t sector_magic = 0, status_magic = 0; + + /* calculate the sector header address */ + header_addr = addr / EF_ERASE_MIN_SIZE * EF_ERASE_MIN_SIZE; + + if (ef_port_read(header_addr, &header, sizeof(header)) == EF_NO_ERR) { + sector_magic = header >> 16; + status_magic = header; + } else { + EF_DEBUG("Error: Read sector header data error.\n"); + return SECTOR_STATUS_HEADER_ERROR; + } + /* compare header magic code */ + if (sector_magic == LOG_SECTOR_MAGIC) { + switch (status_magic) { + case SECTOR_STATUS_MAGIC_EMPUT: + return SECTOR_STATUS_EMPUT; + case SECTOR_STATUS_MAGIC_USING: + return SECTOR_STATUS_USING; + case SECTOR_STATUS_MAGIC_FULL: + return SECTOR_STATUS_FULL; + default: + return SECTOR_STATUS_HEADER_ERROR; + } + } else { + return SECTOR_STATUS_HEADER_ERROR; + } +} + +/** + * Write flash sector current status. + * + * @param addr sector address, this function will auto calculate the sector header address by this address. + * @param status sector cur status + * + * @return result + */ +static EfErrCode write_sector_status(uint32_t addr, SectorStatus status) { + uint32_t header = 0, header_addr = 0; + uint16_t status_magic; + + /* calculate the sector header address */ + header_addr = addr / EF_ERASE_MIN_SIZE * EF_ERASE_MIN_SIZE; + + switch (status) { + case SECTOR_STATUS_EMPUT: { + status_magic = SECTOR_STATUS_MAGIC_EMPUT; + break; + } + case SECTOR_STATUS_USING: { + status_magic = SECTOR_STATUS_MAGIC_USING; + break; + } + case SECTOR_STATUS_FULL: { + status_magic = SECTOR_STATUS_MAGIC_FULL; + break; + } + } + header = (LOG_SECTOR_MAGIC << 16) | status_magic; + + return ef_port_write(header_addr, &header, sizeof(header)); +} + +/** + * Find the current flash sector using end address by continuous 0xFF. + * + * @param addr sector address + * + * @return current flash sector using end address + */ +static uint32_t find_sec_using_end_addr(uint32_t addr) { +/* read section data buffer size */ +#define READ_BUF_SIZE 32 + + uint32_t sector_start = addr, data_start = addr, continue_ff = 0, read_buf_size = 0, i; + uint8_t buf[READ_BUF_SIZE]; + + EF_ASSERT(READ_BUF_SIZE % 4 == 0); + /* calculate the sector start and data start address */ + sector_start = addr / EF_ERASE_MIN_SIZE * EF_ERASE_MIN_SIZE; + data_start = sector_start + LOG_SECTOR_HEADER_SIZE; + + /* counts continuous 0xFF which is end of sector */ + while (data_start < sector_start + EF_ERASE_MIN_SIZE) { + if (data_start + READ_BUF_SIZE < sector_start + EF_ERASE_MIN_SIZE) { + read_buf_size = READ_BUF_SIZE; + } else { + read_buf_size = sector_start + EF_ERASE_MIN_SIZE - data_start; + } + ef_port_read(data_start, (uint32_t *)buf, read_buf_size); + for (i = 0; i < read_buf_size; i++) { + if (buf[i] == 0xFF) { + continue_ff++; + } else { + continue_ff = 0; + } + } + data_start += read_buf_size; + } + /* calculate current flash sector using end address */ + if (continue_ff >= EF_ERASE_MIN_SIZE - LOG_SECTOR_HEADER_SIZE) { + /* from 0 to sec_size all sector is 0xFF, so the sector is empty */ + return sector_start + LOG_SECTOR_HEADER_SIZE; + } else if (continue_ff >= 4) { + /* form end_addr - 4 to sec_size length all area is 0xFF, so it's used part of the sector. + * the address must be word alignment. */ + if (continue_ff % 4 != 0) { + continue_ff = (continue_ff / 4 + 1) * 4; + } + return sector_start + EF_ERASE_MIN_SIZE - continue_ff; + } else { + /* all sector not has continuous 0xFF, so the sector is full */ + return sector_start + EF_ERASE_MIN_SIZE; + } +} + /** * Find the log store start address and end address. * It's like a ring buffer which implement by flash. @@ -94,7 +251,7 @@ EfErrCode ef_log_init(void) { */ static void find_start_and_end_addr(void) { size_t cur_size = 0; - EfSecrorStatus cur_sec_status, last_sec_status; + SectorStatus cur_sec_status, last_sec_status; uint32_t cur_using_sec_addr = 0; /* all status sector counts */ size_t empty_sec_counts = 0, using_sec_counts = 0, full_sector_counts = 0; @@ -104,23 +261,23 @@ static void find_start_and_end_addr(void) { uint8_t cur_log_sec_state = 0; /* get the first sector status */ - cur_sec_status = ef_get_sector_status(log_area_start_addr, EF_ERASE_MIN_SIZE); + cur_sec_status = get_sector_status(log_area_start_addr); last_sec_status = cur_sec_status; for (cur_size = EF_ERASE_MIN_SIZE; cur_size < LOG_AREA_SIZE; cur_size += EF_ERASE_MIN_SIZE) { /* get current sector status */ - cur_sec_status = ef_get_sector_status(log_area_start_addr + cur_size, EF_ERASE_MIN_SIZE); + cur_sec_status = get_sector_status(log_area_start_addr + cur_size); /* compare last and current status */ switch (last_sec_status) { - case EF_SECTOR_EMPTY: { + case SECTOR_STATUS_EMPUT: { switch (cur_sec_status) { - case EF_SECTOR_EMPTY: + case SECTOR_STATUS_EMPUT: break; - case EF_SECTOR_USING: + case SECTOR_STATUS_USING: EF_DEBUG("Error: Log area error! Now will clean all log area.\n"); ef_log_clean(); return; - case EF_SECTOR_FULL: + case SECTOR_STATUS_FULL: EF_DEBUG("Error: Log area error! Now will clean all log area.\n"); ef_log_clean(); return; @@ -128,19 +285,19 @@ static void find_start_and_end_addr(void) { empty_sec_counts++; break; } - case EF_SECTOR_USING: { + case SECTOR_STATUS_USING: { switch (cur_sec_status) { - case EF_SECTOR_EMPTY: + case SECTOR_STATUS_EMPUT: /* like state 1 */ cur_log_sec_state = 1; log_start_addr = log_area_start_addr; cur_using_sec_addr = log_area_start_addr + cur_size - EF_ERASE_MIN_SIZE; break; - case EF_SECTOR_USING: + case SECTOR_STATUS_USING: EF_DEBUG("Error: Log area error! Now will clean all log area.\n"); ef_log_clean(); return; - case EF_SECTOR_FULL: + case SECTOR_STATUS_FULL: /* like state 2 */ cur_log_sec_state = 2; log_start_addr = log_area_start_addr + cur_size; @@ -150,9 +307,9 @@ static void find_start_and_end_addr(void) { using_sec_counts++; break; } - case EF_SECTOR_FULL: { + case SECTOR_STATUS_FULL: { switch (cur_sec_status) { - case EF_SECTOR_EMPTY: + case SECTOR_STATUS_EMPUT: /* like state 1 */ if (cur_log_sec_state == 2) { EF_DEBUG("Error: Log area error! Now will clean all log area.\n"); @@ -161,12 +318,11 @@ static void find_start_and_end_addr(void) { } else { cur_log_sec_state = 1; log_start_addr = log_area_start_addr; - /* word alignment */ - log_end_addr = log_area_start_addr + cur_size - 4; + log_end_addr = log_area_start_addr + cur_size; cur_using_sec_addr = log_area_start_addr + cur_size - EF_ERASE_MIN_SIZE; } break; - case EF_SECTOR_USING: + case SECTOR_STATUS_USING: if(total_sec_num <= 2) { /* like state 1 */ cur_log_sec_state = 1; @@ -181,61 +337,122 @@ static void find_start_and_end_addr(void) { } } break; - case EF_SECTOR_FULL: + case SECTOR_STATUS_FULL: break; } full_sector_counts++; break; } + case SECTOR_STATUS_HEADER_ERROR: + EF_DEBUG("Error: Log sector header error! Now will clean all log area.\n"); + ef_log_clean(); + return; } last_sec_status = cur_sec_status; } /* the last sector status counts */ - if (cur_sec_status == EF_SECTOR_EMPTY) { + if (cur_sec_status == SECTOR_STATUS_EMPUT) { empty_sec_counts++; - } else if (cur_sec_status == EF_SECTOR_USING) { + } else if (cur_sec_status == SECTOR_STATUS_USING) { using_sec_counts++; - } else if (cur_sec_status == EF_SECTOR_FULL) { + } else if (cur_sec_status == SECTOR_STATUS_FULL) { full_sector_counts++; - } - - if (using_sec_counts > 1) { - EF_DEBUG("Error: Log area error! Now will clean all log area.\n"); + } else if (cur_sec_status == SECTOR_STATUS_HEADER_ERROR) { + EF_DEBUG("Error: Log sector header error! Now will clean all log area.\n"); ef_log_clean(); return; - } else if (empty_sec_counts == total_sec_num) { - log_start_addr = log_end_addr = log_area_start_addr; - } else if (full_sector_counts == total_sec_num) { + } + + if (using_sec_counts != 1) { /* this state is almost impossible */ - EF_DEBUG("Error: Log area error! Now will clean all log area.\n"); + EF_DEBUG("Error: There must be only one sector status is USING! Now will clean all log area.\n"); ef_log_clean(); - return; - } else if (((cur_log_sec_state == 1) && (cur_using_sec_addr != 0)) - || (cur_log_sec_state == 2)) { + } else { /* find the end address */ - log_end_addr = ef_find_sec_using_end_addr(cur_using_sec_addr, EF_ERASE_MIN_SIZE); + log_end_addr = find_sec_using_end_addr(cur_using_sec_addr); } } /** * Get log used flash total size. * - * @return log used flash total size + * @return log used flash total size. @note NOT contain sector headers */ size_t ef_log_get_used_size(void) { - EF_ASSERT(log_start_addr); - EF_ASSERT(log_end_addr); - + size_t header_total_num = 0, physical_size = 0; /* must be call this function after initialize OK */ - EF_ASSERT(init_ok); + if (!init_ok) { + return 0; + } if (log_start_addr < log_end_addr) { - return log_end_addr - log_start_addr + 4; - } else if (log_start_addr > log_end_addr) { - return LOG_AREA_SIZE - (log_start_addr - log_end_addr) + 4; + physical_size = log_end_addr - log_start_addr; } else { - return 0; + physical_size = LOG_AREA_SIZE - (log_start_addr - log_end_addr); + } + + header_total_num = physical_size / EF_ERASE_MIN_SIZE + 1; + + return physical_size - header_total_num * LOG_SECTOR_HEADER_SIZE; +} + +/** + * Sequential reading log data. It will ignore sector headers. + * + * @param addr address + * @param log log buffer + * @param size log size, not contain sector headers. + * + * @return result + */ +static EfErrCode log_seq_read(uint32_t addr, uint32_t *log, size_t size) { + EfErrCode result = EF_NO_ERR; + size_t read_size = 0, read_size_temp = 0; + + while (size) { + /* move to sector data address */ + if ((addr + read_size) % EF_ERASE_MIN_SIZE == 0) { + addr += LOG_SECTOR_HEADER_SIZE; + } + /* calculate current sector last data size */ + read_size_temp = EF_ERASE_MIN_SIZE - (addr % EF_ERASE_MIN_SIZE); + if (size < read_size_temp) { + read_size_temp = size; + } + result = ef_port_read(addr + read_size, log + read_size / 4, read_size_temp); + if (result != EF_NO_ERR) { + return result; + } + read_size += read_size_temp; + size -= read_size_temp; + } + + return result; +} + +/** + * Calculate flash physical address by log index. + * + * @param index log index + * + * @return flash physical address + */ +static uint32_t log_index2addr(size_t index) { + size_t header_total_offset = 0; + /* total include sector number */ + size_t sector_num = index / (EF_ERASE_MIN_SIZE - LOG_SECTOR_HEADER_SIZE) + 1; + + header_total_offset = sector_num * LOG_SECTOR_HEADER_SIZE; + if (log_start_addr < log_end_addr) { + return log_start_addr + index + header_total_offset; + } else { + if (log_start_addr + index + header_total_offset < log_area_start_addr + LOG_AREA_SIZE) { + return log_start_addr + index + header_total_offset; + } else { + return log_start_addr + index + header_total_offset - LOG_AREA_SIZE; + + } } } @@ -244,7 +461,7 @@ size_t ef_log_get_used_size(void) { * * @param index index for saved log. * Minimum index is 0. - * Maximum index is log used flash total size - 1. + * Maximum index is ef_log_get_used_size() - 1. * @param log the log which will read from flash * @param size read bytes size * @@ -254,20 +471,28 @@ EfErrCode ef_log_read(size_t index, uint32_t *log, size_t size) { EfErrCode result = EF_NO_ERR; size_t cur_using_size = ef_log_get_used_size(); size_t read_size_temp = 0; - - EF_ASSERT(size % 4 == 0); - EF_ASSERT(index + size <= cur_using_size); - /* must be call this function after initialize OK */ - EF_ASSERT(init_ok); + size_t header_total_num = 0; if (!size) { return result; } + EF_ASSERT(size % 4 == 0); + EF_ASSERT(index < cur_using_size); + + if (index + size > cur_using_size) { + EF_DEBUG("Warning: Log read size out of bound. Cut read size.\n"); + size = cur_using_size - index; + } + /* must be call this function after initialize OK */ + if (!init_ok) { + return EF_ENV_INIT_FAILED; + } + if (log_start_addr < log_end_addr) { - result = ef_port_read(log_area_start_addr + index, log, size); - } else if (log_start_addr > log_end_addr) { - if (log_start_addr + index + size <= log_area_start_addr + LOG_AREA_SIZE) { + log_seq_read(log_index2addr(index), log, size); + } else { + if (log_index2addr(index) + size <= log_area_start_addr + LOG_AREA_SIZE) { /* Flash log area * |--------------| * log_area_start_addr --> |##############| @@ -283,10 +508,10 @@ EfErrCode ef_log_read(size_t index, uint32_t *log, size_t size) { * |##############| * |--------------| * - * read from (log_start_addr + index) to (log_start_addr + index + size) + * read from (log_start_addr + log_index2addr(index)) to (log_start_addr + index + log_index2addr(index)) */ - result = ef_port_read(log_start_addr + index, log, size); - } else if (log_start_addr + index < log_area_start_addr + LOG_AREA_SIZE) { + result = log_seq_read(log_index2addr(index), log, size); + } else if (log_index2addr(index) < log_area_start_addr + LOG_AREA_SIZE) { /* Flash log area * |--------------| * log_area_start_addr --> |**************| <-- read end @@ -302,14 +527,16 @@ EfErrCode ef_log_read(size_t index, uint32_t *log, size_t size) { * |**************| * |--------------| * read will by 2 steps - * step1: read from (log_start_addr + index) to flash log area end address + * step1: read from (log_start_addr + log_index2addr(index)) to flash log area end address * step2: read from flash log area start address to read size's end address */ - read_size_temp = (log_area_start_addr + LOG_AREA_SIZE) - (log_start_addr + index); - result = ef_port_read(log_start_addr + index, log, read_size_temp); + read_size_temp = (log_area_start_addr + LOG_AREA_SIZE) - log_index2addr(index); + header_total_num = read_size_temp / EF_ERASE_MIN_SIZE; + /* Minus some ignored bytes */ + read_size_temp -= header_total_num * LOG_SECTOR_HEADER_SIZE; + result = log_seq_read(log_index2addr(index), log, read_size_temp); if (result == EF_NO_ERR) { - result = ef_port_read(log_area_start_addr, log + read_size_temp, - size - read_size_temp); + result = log_seq_read(log_area_start_addr, log + read_size_temp / 4, size - read_size_temp); } } else { /* Flash log area @@ -326,9 +553,9 @@ EfErrCode ef_log_read(size_t index, uint32_t *log, size_t size) { * |##############| * |##############| * |--------------| - * read from (log_start_addr + index - LOG_AREA_SIZE) to read size's end address + * read from (log_start_addr + log_index2addr(index) - LOG_AREA_SIZE) to read size's end address */ - result = ef_port_read(log_start_addr + index - LOG_AREA_SIZE, log, size); + result = log_seq_read(log_index2addr(index) - LOG_AREA_SIZE, log, size); } } @@ -345,31 +572,37 @@ 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 result = EF_NO_ERR; - size_t cur_using_size = ef_log_get_used_size(), write_size = 0, writable_size = 0; - uint32_t write_addr, erase_addr; + size_t write_size = 0, writable_size = 0; + uint32_t write_addr = log_end_addr, erase_addr; + SectorStatus sector_status; EF_ASSERT(size % 4 == 0); /* must be call this function after initialize OK */ - EF_ASSERT(init_ok); + if (!init_ok) { + return EF_ENV_INIT_FAILED; + } - /* write address is after log end address when LOG AREA isn't empty */ - if (log_start_addr != log_end_addr) { - write_addr = log_end_addr + 4; - } else { - write_addr = log_start_addr; + if ((sector_status = get_sector_status(write_addr)) == SECTOR_STATUS_HEADER_ERROR) { + return EF_WRITE_ERR; } - /* write the already erased but not used area */ - writable_size = EF_ERASE_MIN_SIZE - ((write_addr - log_area_start_addr) % EF_ERASE_MIN_SIZE); - if ((writable_size != EF_ERASE_MIN_SIZE) || (log_start_addr == log_end_addr)) { - if (size > writable_size) { + /* write some log when current sector status is USING and EMPTY */ + if ((sector_status == SECTOR_STATUS_USING) || (sector_status == SECTOR_STATUS_EMPUT)) { + /* write the already erased but not used area */ + writable_size = EF_ERASE_MIN_SIZE - ((write_addr - log_area_start_addr) % EF_ERASE_MIN_SIZE); + if (size >= writable_size) { result = ef_port_write(write_addr, log, writable_size); if (result != EF_NO_ERR) { goto exit; } + /* change the current sector status to FULL */ + result = write_sector_status(write_addr, SECTOR_STATUS_FULL); + if (result != EF_NO_ERR) { + goto exit; + } write_size += writable_size; } else { result = ef_port_write(write_addr, log, size); - log_end_addr = write_addr + size - 4; + log_end_addr = write_addr + size; goto exit; } } @@ -383,26 +616,39 @@ EfErrCode ef_log_write(const uint32_t *log, size_t size) { } /* erase sector */ result = ef_port_erase(erase_addr, EF_ERASE_MIN_SIZE); + if (result != EF_NO_ERR) { + goto exit; + } + /* change the sector status to USING when write begin sector start address */ + result = write_sector_status(write_addr, SECTOR_STATUS_USING); if (result == EF_NO_ERR) { - if (size - write_size > EF_ERASE_MIN_SIZE) { - result = ef_port_write(write_addr, log + write_size / 4, EF_ERASE_MIN_SIZE); - if (result != EF_NO_ERR) { - goto exit; - } - log_end_addr = write_addr + EF_ERASE_MIN_SIZE - 4; - write_size += EF_ERASE_MIN_SIZE; - write_addr += EF_ERASE_MIN_SIZE; - } else { - result = ef_port_write(write_addr, log + write_size / 4, size - write_size); - if (result != EF_NO_ERR) { - goto exit; - } - log_end_addr = write_addr + (size - write_size) - 4; - break; - } + write_addr += LOG_SECTOR_HEADER_SIZE; } else { goto exit; } + /* calculate current sector writable data size */ + writable_size = EF_ERASE_MIN_SIZE - LOG_SECTOR_HEADER_SIZE; + if (size - write_size >= writable_size) { + result = ef_port_write(write_addr, log + write_size / 4, writable_size); + if (result != EF_NO_ERR) { + goto exit; + } + /* change the current sector status to FULL */ + result = write_sector_status(write_addr, SECTOR_STATUS_FULL); + if (result != EF_NO_ERR) { + goto exit; + } + log_end_addr = write_addr + writable_size; + write_size += writable_size; + write_addr += writable_size; + } else { + result = ef_port_write(write_addr, log + write_size / 4, size - write_size); + if (result != EF_NO_ERR) { + goto exit; + } + log_end_addr = write_addr + (size - write_size); + break; + } } exit: @@ -419,6 +665,7 @@ exit: static uint32_t get_next_flash_sec_addr(uint32_t cur_addr) { size_t cur_sec_id = (cur_addr - log_area_start_addr) / EF_ERASE_MIN_SIZE; size_t sec_total_num = LOG_AREA_SIZE / EF_ERASE_MIN_SIZE; + if (cur_sec_id + 1 >= sec_total_num) { /* return to ring head */ return log_area_start_addr; @@ -434,14 +681,35 @@ static uint32_t get_next_flash_sec_addr(uint32_t cur_addr) { */ EfErrCode ef_log_clean(void) { EfErrCode result = EF_NO_ERR; - - EF_ASSERT(log_area_start_addr); + uint32_t write_addr = log_area_start_addr; /* clean address */ - log_start_addr = log_end_addr = log_area_start_addr; + log_start_addr = log_area_start_addr; + log_end_addr = log_start_addr + LOG_SECTOR_HEADER_SIZE; /* erase log flash area */ result = ef_port_erase(log_area_start_addr, LOG_AREA_SIZE); + if (result != EF_NO_ERR) { + goto exit; + } + /* setting first sector is USING */ + write_sector_status(write_addr, SECTOR_STATUS_USING); + if (result != EF_NO_ERR) { + goto exit; + } + write_addr += EF_ERASE_MIN_SIZE; + /* add sector header */ + while (true) { + write_sector_status(write_addr, SECTOR_STATUS_EMPUT); + if (result != EF_NO_ERR) { + goto exit; + } + write_addr += EF_ERASE_MIN_SIZE; + if (write_addr >= log_area_start_addr + LOG_AREA_SIZE) { + break; + } + } +exit: return result; } diff --git a/easyflash/src/ef_utils.c b/easyflash/src/ef_utils.c index 770e860..c6c9571 100644 --- a/easyflash/src/ef_utils.c +++ b/easyflash/src/ef_utils.c @@ -1,7 +1,7 @@ /* * This file is part of the EasyFlash Library. * - * Copyright (c) 2015-2016, Armink, + * Copyright (c) 2015-2017, Armink, * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -97,70 +97,3 @@ uint32_t ef_calc_crc32(uint32_t crc, const void *buf, size_t size) return crc ^ ~0U; } - -/** - * Get this flash sector current status. - * - * @param addr sector address - * @param sec_size sector address - * - * @return the flash sector current status - */ -EfSecrorStatus ef_get_sector_status(uint32_t addr, size_t sec_size) { - uint32_t cur_using_addr = ef_find_sec_using_end_addr(addr, sec_size); - /* get current status by current using address */ - if (cur_using_addr == 0 || cur_using_addr == addr - 4) { - return EF_SECTOR_EMPTY; - } else if (cur_using_addr == addr + sec_size - 4) { - return EF_SECTOR_FULL; - } else { - return EF_SECTOR_USING; - } -} - -/** - * Find the current flash sector using end address by continuous 0xFF. - * - * @param addr sector address - * @param sec_size sector address - * - * @return current flash sector using end address - */ -uint32_t ef_find_sec_using_end_addr(uint32_t addr, size_t sec_size) { -/* read section data buffer size */ -#define READ_BUF_SIZE 32 - - uint32_t start = addr, continue_ff = 0, read_buf_size = 0, i; - uint8_t buf[READ_BUF_SIZE]; - - EF_ASSERT(READ_BUF_SIZE % 4 == 0); - /* counts continuous 0xFF which is end of sector */ - while (start < addr + sec_size) { - if (start + READ_BUF_SIZE < addr + sec_size) { - read_buf_size = READ_BUF_SIZE; - } else { - read_buf_size = addr + sec_size - start; - } - ef_port_read(start, (uint32_t *)buf, read_buf_size); - for (i = 0; i < read_buf_size; i++) { - if (buf[i] == 0xFF) { - continue_ff++; - } else { - continue_ff = 0; - } - } - start += read_buf_size; - } - /* calculate current flash sector using end address */ - if (continue_ff == sec_size) { - /* from 0 to sec_size all sector is 0xFF, so the sector is empty */ - return addr >= 4 ? addr - 4 : 0; - } else if (continue_ff >= 4) { - /* form end_addr - 4 to sec_size length all area is 0xFF, so it's used part of the sector. - * the address must be word alignment. */ - return (addr + sec_size - continue_ff) * 4 / 4 - 4; - } else { - /* all sector not has continuous 0xFF, alignment by word */ - return addr + sec_size - 4; - } -}