subsys: fs: Add Flash Circular Buffer

Zephyr already supports NFFS as a storage layer, but it might
be a little bit too heavyweight for certain applications in
memory-restricted ICs.

This module is response for need of Lightweight flash storage
capability. FCB is ported form MyNewt as native zephyr module.

Signed-off-by: Andrzej Puzdrowski <andrzej.puzdrowski@nordicsemi.no>
This commit is contained in:
Andrzej Puzdrowski 2017-12-13 15:53:20 +01:00 committed by Anas Nashif
commit b7f1289847
13 changed files with 908 additions and 9 deletions

134
include/fcb.h Normal file
View file

@ -0,0 +1,134 @@
/*
* Copyright (c) 2017 Nordic Semiconductor ASA
* Copyright (c) 2015 Runtime Inc
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __FCB_H_
#define __FCB_H_
#ifdef __cplusplus
extern "C" {
#endif
/*
* Flash circular buffer.
*/
#include <inttypes.h>
#include <limits.h>
#include "flash_map.h"
#include <kernel.h>
#define FCB_MAX_LEN (CHAR_MAX | CHAR_MAX << 7) /* Max length of element */
/*
* Entry location is pointer to area (within fcb->f_sectors), and offset
* within that area.
*/
struct fcb_entry {
struct flash_area *fe_area; /* ptr to area within fcb->f_sectors */
u32_t fe_elem_off; /* start of entry */
u32_t fe_data_off; /* start of data */
u16_t fe_data_len; /* size of data area */
};
struct fcb {
/* Caller of fcb_init fills this in */
u32_t f_magic; /* As placed on the disk */
u8_t f_version; /* Current version number of the data */
u8_t f_sector_cnt; /* Number of elements in sector array */
u8_t f_scratch_cnt; /* How many sectors should be kept empty */
struct flash_area *f_sectors; /* Array of sectors, must be contiguous */
/* Flash circular buffer internal state */
struct k_mutex f_mtx; /* Locking for accessing the FCB data */
struct flash_area *f_oldest;
struct fcb_entry f_active;
u16_t f_active_id;
u8_t f_align; /* writes to flash have to aligned to this */
};
/*
* Error codes.
*/
#define FCB_OK 0
#define FCB_ERR_ARGS -1
#define FCB_ERR_FLASH -2
#define FCB_ERR_NOVAR -3
#define FCB_ERR_NOSPACE -4
#define FCB_ERR_NOMEM -5
#define FCB_ERR_CRC -6
#define FCB_ERR_MAGIC -7
int fcb_init(struct fcb *fcb);
/*
* fcb_log is needed as the number of entries in a log
*/
struct fcb_log {
struct fcb fl_fcb;
u8_t fl_entries;
};
int log_fcb_init(struct fcb_log *fcblog, struct fcb *fcb, u16_t entries);
/*
* fcb_append() appends an entry to circular buffer. When writing the
* contents for the entry, use loc->fl_area and loc->fl_data_off with
* flash_area_write(). When you're finished, call fcb_append_finish() with
* loc as argument.
*/
int fcb_append(struct fcb *fcb, u16_t len, struct fcb_entry *loc);
int fcb_append_finish(struct fcb *fcb, struct fcb_entry *append_loc);
/*
* Walk over all log entries in FCB, or entries in a given flash_area.
* cb gets called for every entry. If cb wants to stop the walk, it should
* return non-zero value.
*
* Entry data can be read using flash_area_read(), using
* loc->fe_area, loc->fe_data_off, and loc->fe_data_len as arguments.
*/
typedef int (*fcb_walk_cb)(struct fcb_entry *loc, void *arg);
int fcb_walk(struct fcb *fcb, struct flash_area *fa, fcb_walk_cb cb,
void *cb_arg);
int fcb_getnext(struct fcb *fcb, struct fcb_entry *loc);
/*
* Erases the data from oldest sector.
*/
int fcb_rotate(struct fcb *fcb);
/*
* Start using the scratch block.
*/
int fcb_append_to_scratch(struct fcb *fcb);
/*
* How many sectors are unused.
*/
int fcb_free_sector_cnt(struct fcb *fcb);
/*
* Whether FCB has any data.
*/
int fcb_is_empty(struct fcb *fcb);
/*
* Element at offset *entries* from last position (backwards).
*/
int fcb_offset_last_n(struct fcb *fcb, u8_t entries,
struct fcb_entry *last_n_entry);
/*
* Clears FCB passed to it
*/
int fcb_clear(struct fcb *fcb);
#ifdef __cplusplus
}
#endif
#endif /* __FCB_H_ */

View file

@ -5,7 +5,7 @@ add_subdirectory_ifdef(CONFIG_CONSOLE_PULL console)
add_subdirectory_ifdef(CONFIG_CONSOLE_SHELL shell)
add_subdirectory_ifdef(CONFIG_CPLUSPLUS cpp)
add_subdirectory_ifdef(CONFIG_DISK_ACCESS disk)
add_subdirectory_ifdef(CONFIG_FILE_SYSTEM fs)
add_subdirectory(fs)
add_subdirectory_ifdef(CONFIG_MCUBOOT_IMG_MANAGER dfu)
add_subdirectory_ifdef(CONFIG_NET_BUF net)
add_subdirectory_ifdef(CONFIG_USB usb)

View file

@ -1,10 +1,14 @@
zephyr_link_interface_ifdef(CONFIG_FAT_FILESYSTEM_ELM ELMFAT)
zephyr_link_interface_ifdef(CONFIG_FILE_SYSTEM_NFFS NFFS)
if(CONFIG_FILE_SYSTEM)
zephyr_link_interface_ifdef(CONFIG_FAT_FILESYSTEM_ELM ELMFAT)
zephyr_link_interface_ifdef(CONFIG_FILE_SYSTEM_NFFS NFFS)
zephyr_library()
zephyr_library_sources_ifdef(CONFIG_FAT_FILESYSTEM_ELM fat_fs.c)
zephyr_library_sources_ifdef(CONFIG_FILE_SYSTEM_NFFS nffs_fs.c)
zephyr_library_sources_ifdef(CONFIG_FILE_SYSTEM_SHELL shell.c)
zephyr_library()
zephyr_library_sources_ifdef(CONFIG_FAT_FILESYSTEM_ELM fat_fs.c)
zephyr_library_sources_ifdef(CONFIG_FILE_SYSTEM_NFFS nffs_fs.c)
zephyr_library_sources_ifdef(CONFIG_FILE_SYSTEM_SHELL shell.c)
zephyr_library_link_libraries_ifdef(CONFIG_FAT_FILESYSTEM_ELM ELMFAT)
zephyr_library_link_libraries_ifdef(CONFIG_FILE_SYSTEM_NFFS NFFS)
zephyr_library_link_libraries_ifdef(CONFIG_FAT_FILESYSTEM_ELM ELMFAT)
zephyr_library_link_libraries_ifdef(CONFIG_FILE_SYSTEM_NFFS NFFS)
endif()
add_subdirectory_ifdef(CONFIG_FCB ./fcb)

View file

@ -90,4 +90,6 @@ endmenu
endif # FILE_SYSTEM
source "subsys/fs/fcb/Kconfig"
endmenu

View file

@ -0,0 +1,8 @@
zephyr_sources(
fcb_append.c
fcb.c
fcb_elem_info.c
fcb_getnext.c
fcb_rotate.c
fcb_walk.c
)

18
subsys/fs/fcb/Kconfig Normal file
View file

@ -0,0 +1,18 @@
# Kconfig - Flash Circular Buffer module
#
# Copyright (c) 2017 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
#
#
# Flash Circular Buffer
#
config FCB
bool
prompt "Flash Circular Buffer support"
default n
depends on FLASH_MAP
help
Enable support of Flash Circular Buffer.

252
subsys/fs/fcb/fcb.c Normal file
View file

@ -0,0 +1,252 @@
/*
* Copyright (c) 2017 Nordic Semiconductor ASA
* Copyright (c) 2015 Runtime Inc
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <limits.h>
#include <stdlib.h>
#include "fcb.h"
#include "fcb_priv.h"
#include "string.h"
int
fcb_init(struct fcb *fcb)
{
struct flash_area *fap;
int rc;
int i;
int max_align = 1;
int align;
int oldest = -1, newest = -1;
struct flash_area *oldest_fap = NULL, *newest_fap = NULL;
struct fcb_disk_area fda;
if (!fcb->f_sectors || fcb->f_sector_cnt - fcb->f_scratch_cnt < 1) {
return FCB_ERR_ARGS;
}
/* Fill last used, first used */
for (i = 0; i < fcb->f_sector_cnt; i++) {
fap = &fcb->f_sectors[i];
align = flash_area_align(fap);
if (align > max_align) {
max_align = flash_area_align(fap);
}
rc = fcb_sector_hdr_read(fcb, fap, &fda);
if (rc < 0) {
return rc;
}
if (rc == 0) {
continue;
}
if (oldest < 0) {
oldest = newest = fda.fd_id;
oldest_fap = newest_fap = fap;
continue;
}
if (FCB_ID_GT(fda.fd_id, newest)) {
newest = fda.fd_id;
newest_fap = fap;
} else if (FCB_ID_GT(oldest, fda.fd_id)) {
oldest = fda.fd_id;
oldest_fap = fap;
}
}
if (oldest < 0) {
/*
* No initialized areas.
*/
oldest_fap = newest_fap = &fcb->f_sectors[0];
rc = fcb_sector_hdr_init(fcb, oldest_fap, 0);
if (rc) {
return rc;
}
newest = oldest = 0;
}
fcb->f_align = max_align;
fcb->f_oldest = oldest_fap;
fcb->f_active.fe_area = newest_fap;
fcb->f_active.fe_elem_off = sizeof(struct fcb_disk_area);
fcb->f_active_id = newest;
while (1) {
rc = fcb_getnext_in_area(fcb, &fcb->f_active);
if (rc == FCB_ERR_NOVAR) {
rc = FCB_OK;
break;
}
if (rc != 0) {
break;
}
}
k_mutex_init(&fcb->f_mtx);
return rc;
}
int
fcb_free_sector_cnt(struct fcb *fcb)
{
int i;
struct flash_area *fa;
fa = fcb->f_active.fe_area;
for (i = 0; i < fcb->f_sector_cnt; i++) {
fa = fcb_getnext_area(fcb, fa);
if (fa == fcb->f_oldest) {
break;
}
}
return i;
}
int
fcb_is_empty(struct fcb *fcb)
{
return (fcb->f_active.fe_area == fcb->f_oldest &&
fcb->f_active.fe_elem_off == sizeof(struct fcb_disk_area));
}
/**
* Length of an element is encoded in 1 or 2 bytes.
* 1 byte for lengths < 128 bytes, and 2 bytes for < 16384.
*/
int
fcb_put_len(u8_t *buf, u16_t len)
{
if (len < 0x80) {
buf[0] = len;
return 1;
} else if (len < FCB_MAX_LEN) {
buf[0] = (len & 0x7f) | 0x80;
buf[1] = len >> 7;
return 2;
} else {
return FCB_ERR_ARGS;
}
}
int
fcb_get_len(u8_t *buf, u16_t *len)
{
int rc;
if (buf[0] & 0x80) {
if (buf[0] == 0xff && buf[1] == 0xff) {
return FCB_ERR_NOVAR;
}
*len = (buf[0] & 0x7f) | (buf[1] << 7);
rc = 2;
} else {
*len = buf[0];
rc = 1;
}
return rc;
}
/**
* Initialize erased sector for use.
*/
int
fcb_sector_hdr_init(struct fcb *fcb, struct flash_area *fap, u16_t id)
{
struct fcb_disk_area fda;
int rc;
fda.fd_magic = fcb->f_magic;
fda.fd_ver = fcb->f_version;
fda._pad = 0xff;
fda.fd_id = id;
rc = flash_area_write(fap, 0, &fda, sizeof(fda));
if (rc) {
return FCB_ERR_FLASH;
}
return 0;
}
/**
* Checks whether FCB sector contains data or not.
* Returns <0 in error.
* Returns 0 if sector is unused;
* Returns 1 if sector has data.
*/
int fcb_sector_hdr_read(struct fcb *fcb, struct flash_area *fap,
struct fcb_disk_area *fdap)
{
struct fcb_disk_area fda;
int rc;
if (!fdap) {
fdap = &fda;
}
rc = flash_area_read(fap, 0, fdap, sizeof(*fdap));
if (rc) {
return FCB_ERR_FLASH;
}
if (fdap->fd_magic == 0xffffffff) {
return 0;
}
if (fdap->fd_magic != fcb->f_magic) {
return FCB_ERR_MAGIC;
}
return 1;
}
/**
* Finds the fcb entry that gives back upto n entries at the end.
* @param0 ptr to fcb
* @param1 n number of fcb entries the user wants to get
* @param2 ptr to the fcb_entry to be returned
* @return 0 on there are any fcbs aviable; -ENOENT otherwise
*/
int
fcb_offset_last_n(struct fcb *fcb, u8_t entries,
struct fcb_entry *last_n_entry)
{
struct fcb_entry loc;
int i;
/* assure a minimum amount of entries */
if (!entries) {
entries = 1;
}
i = 0;
memset(&loc, 0, sizeof(loc));
while (!fcb_getnext(fcb, &loc)) {
if (i == 0) {
/* Start from the beginning of fcb entries */
*last_n_entry = loc;
}
/* Update last_n_entry after n entries and keep updating */
else if (i > (entries - 1)) {
fcb_getnext(fcb, last_n_entry);
}
i++;
}
return (i == 0) ? -ENOENT : 0;
}
/**
* Clear fcb
* @param fcb
* @return 0 on success; non-zero on failure
*/
int
fcb_clear(struct fcb *fcb)
{
int rc;
rc = 0;
while (!fcb_is_empty(fcb)) {
rc = fcb_rotate(fcb);
if (rc) {
break;
}
}
return rc;
}

133
subsys/fs/fcb/fcb_append.c Normal file
View file

@ -0,0 +1,133 @@
/*
* Copyright (c) 2017 Nordic Semiconductor ASA
* Copyright (c) 2015 Runtime Inc
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include "fcb.h"
#include "fcb_priv.h"
static struct flash_area *
fcb_new_area(struct fcb *fcb, int cnt)
{
struct flash_area *fa;
struct flash_area *rfa;
int i;
rfa = NULL;
i = 0;
fa = fcb->f_active.fe_area;
do {
fa = fcb_getnext_area(fcb, fa);
if (!rfa) {
rfa = fa;
}
if (fa == fcb->f_oldest) {
return NULL;
}
} while (i++ < cnt);
return rfa;
}
/*
* Take one of the scratch blocks into use, if at all possible.
*/
int
fcb_append_to_scratch(struct fcb *fcb)
{
struct flash_area *fa;
int rc;
fa = fcb_new_area(fcb, 0);
if (!fa) {
return FCB_ERR_NOSPACE;
}
rc = fcb_sector_hdr_init(fcb, fa, fcb->f_active_id + 1);
if (rc) {
return rc;
}
fcb->f_active.fe_area = fa;
fcb->f_active.fe_elem_off = sizeof(struct fcb_disk_area);
fcb->f_active_id++;
return FCB_OK;
}
int
fcb_append(struct fcb *fcb, u16_t len, struct fcb_entry *append_loc)
{
struct fcb_entry *active;
struct flash_area *fa;
u8_t tmp_str[2];
int cnt;
int rc;
cnt = fcb_put_len(tmp_str, len);
if (cnt < 0) {
return cnt;
}
cnt = fcb_len_in_flash(fcb, cnt);
len = fcb_len_in_flash(fcb, len) + fcb_len_in_flash(fcb, FCB_CRC_SZ);
rc = k_mutex_lock(&fcb->f_mtx, K_FOREVER);
if (rc) {
return FCB_ERR_ARGS;
}
active = &fcb->f_active;
if (active->fe_elem_off + len + cnt > active->fe_area->fa_size) {
fa = fcb_new_area(fcb, fcb->f_scratch_cnt);
if (!fa || (fa->fa_size <
sizeof(struct fcb_disk_area) + len + cnt)) {
rc = FCB_ERR_NOSPACE;
goto err;
}
rc = fcb_sector_hdr_init(fcb, fa, fcb->f_active_id + 1);
if (rc) {
goto err;
}
fcb->f_active.fe_area = fa;
fcb->f_active.fe_elem_off = sizeof(struct fcb_disk_area);
fcb->f_active_id++;
}
rc = flash_area_write(active->fe_area, active->fe_elem_off, tmp_str,
cnt);
if (rc) {
rc = FCB_ERR_FLASH;
goto err;
}
append_loc->fe_area = active->fe_area;
append_loc->fe_elem_off = active->fe_elem_off;
append_loc->fe_data_off = active->fe_elem_off + cnt;
active->fe_elem_off = append_loc->fe_data_off + len;
k_mutex_unlock(&fcb->f_mtx);
return FCB_OK;
err:
k_mutex_unlock(&fcb->f_mtx);
return rc;
}
int
fcb_append_finish(struct fcb *fcb, struct fcb_entry *loc)
{
int rc;
u8_t crc8;
off_t off;
rc = fcb_elem_crc8(fcb, loc, &crc8);
if (rc) {
return rc;
}
off = loc->fe_data_off + fcb_len_in_flash(fcb, loc->fe_data_len);
rc = flash_area_write(loc->fe_area, off, &crc8, sizeof(crc8));
if (rc) {
return FCB_ERR_FLASH;
}
return 0;
}

View file

@ -0,0 +1,88 @@
/*
* Copyright (c) 2017 Nordic Semiconductor ASA
* Copyright (c) 2015 Runtime Inc
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <crc8.h>
#include "fcb.h"
#include "fcb_priv.h"
/*
* Given offset in flash area, fill in rest of the fcb_entry, and crc8 over
* the data.
*/
int
fcb_elem_crc8(struct fcb *fcb, struct fcb_entry *loc, u8_t *c8p)
{
u8_t tmp_str[FCB_TMP_BUF_SZ];
int cnt;
int blk_sz;
u8_t crc8;
u16_t len;
u32_t off;
u32_t end;
int rc;
if (loc->fe_elem_off + 2 > loc->fe_area->fa_size) {
return FCB_ERR_NOVAR;
}
rc = flash_area_read(loc->fe_area, loc->fe_elem_off, tmp_str, 2);
if (rc) {
return FCB_ERR_FLASH;
}
cnt = fcb_get_len(tmp_str, &len);
if (cnt < 0) {
return cnt;
}
loc->fe_data_off = loc->fe_elem_off + fcb_len_in_flash(fcb, cnt);
loc->fe_data_len = len;
crc8 = CRC8_CCITT_INITIAL_VALUE;
crc8 = crc8_ccitt(crc8, tmp_str, cnt);
off = loc->fe_data_off;
end = loc->fe_data_off + len;
for (; off < end; off += blk_sz) {
blk_sz = end - off;
if (blk_sz > sizeof(tmp_str)) {
blk_sz = sizeof(tmp_str);
}
rc = flash_area_read(loc->fe_area, off, tmp_str, blk_sz);
if (rc) {
return FCB_ERR_FLASH;
}
crc8 = crc8_ccitt(crc8, tmp_str, blk_sz);
}
*c8p = crc8;
return 0;
}
int fcb_elem_info(struct fcb *fcb, struct fcb_entry *loc)
{
int rc;
u8_t crc8;
u8_t fl_crc8;
off_t off;
rc = fcb_elem_crc8(fcb, loc, &crc8);
if (rc) {
return rc;
}
off = loc->fe_data_off + fcb_len_in_flash(fcb, loc->fe_data_len);
rc = flash_area_read(loc->fe_area, off, &fl_crc8, sizeof(fl_crc8));
if (rc) {
return FCB_ERR_FLASH;
}
if (fl_crc8 != crc8) {
return FCB_ERR_CRC;
}
return 0;
}

121
subsys/fs/fcb/fcb_getnext.c Normal file
View file

@ -0,0 +1,121 @@
/*
* Copyright (c) 2017 Nordic Semiconductor ASA
* Copyright (c) 2015 Runtime Inc
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include "fcb.h"
#include "fcb_priv.h"
int
fcb_getnext_in_area(struct fcb *fcb, struct fcb_entry *loc)
{
int rc;
rc = fcb_elem_info(fcb, loc);
if (rc == 0 || rc == FCB_ERR_CRC) {
do {
loc->fe_elem_off = loc->fe_data_off +
fcb_len_in_flash(fcb, loc->fe_data_len) +
fcb_len_in_flash(fcb, FCB_CRC_SZ);
rc = fcb_elem_info(fcb, loc);
if (rc != FCB_ERR_CRC) {
break;
}
} while (rc == FCB_ERR_CRC);
}
return rc;
}
struct flash_area *
fcb_getnext_area(struct fcb *fcb, struct flash_area *fap)
{
fap++;
if (fap >= &fcb->f_sectors[fcb->f_sector_cnt]) {
fap = &fcb->f_sectors[0];
}
return fap;
}
int
fcb_getnext_nolock(struct fcb *fcb, struct fcb_entry *loc)
{
int rc;
if (loc->fe_area == NULL) {
/*
* Find the first one we have in flash.
*/
loc->fe_area = fcb->f_oldest;
}
if (loc->fe_elem_off == 0) {
/*
* If offset is zero, we serve the first entry from the area.
*/
loc->fe_elem_off = sizeof(struct fcb_disk_area);
rc = fcb_elem_info(fcb, loc);
switch (rc) {
case 0:
return 0;
case FCB_ERR_CRC:
break;
default:
goto next_sector;
}
} else {
rc = fcb_getnext_in_area(fcb, loc);
if (rc == 0) {
return 0;
}
if (rc == FCB_ERR_NOVAR) {
goto next_sector;
}
}
while (rc == FCB_ERR_CRC) {
rc = fcb_getnext_in_area(fcb, loc);
if (rc == 0) {
return 0;
}
if (rc != FCB_ERR_CRC) {
/*
* Moving to next sector.
*/
next_sector:
if (loc->fe_area == fcb->f_active.fe_area) {
return FCB_ERR_NOVAR;
}
loc->fe_area = fcb_getnext_area(fcb, loc->fe_area);
loc->fe_elem_off = sizeof(struct fcb_disk_area);
rc = fcb_elem_info(fcb, loc);
switch (rc) {
case 0:
return 0;
case FCB_ERR_CRC:
break;
default:
goto next_sector;
}
}
}
return 0;
}
int
fcb_getnext(struct fcb *fcb, struct fcb_entry *loc)
{
int rc;
rc = k_mutex_lock(&fcb->f_mtx, K_FOREVER);
if (rc) {
return FCB_ERR_ARGS;
}
rc = fcb_getnext_nolock(fcb, loc);
k_mutex_unlock(&fcb->f_mtx);
return rc;
}

53
subsys/fs/fcb/fcb_priv.h Normal file
View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2017 Nordic Semiconductor ASA
* Copyright (c) 2015 Runtime Inc
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __FCB_PRIV_H_
#define __FCB_PRIV_H_
#ifdef __cplusplus
extern "C" {
#endif
#define FCB_CRC_SZ sizeof(u8_t)
#define FCB_TMP_BUF_SZ 32
#define FCB_ID_GT(a, b) (((int16_t)(a) - (int16_t)(b)) > 0)
struct fcb_disk_area {
u32_t fd_magic;
u8_t fd_ver;
u8_t _pad;
u16_t fd_id;
};
int fcb_put_len(u8_t *buf, u16_t len);
int fcb_get_len(u8_t *buf, u16_t *len);
static inline int fcb_len_in_flash(struct fcb *fcb, u16_t len)
{
if (fcb->f_align <= 1) {
return len;
}
return (len + (fcb->f_align - 1)) & ~(fcb->f_align - 1);
}
int fcb_getnext_in_area(struct fcb *fcb, struct fcb_entry *loc);
struct flash_area *fcb_getnext_area(struct fcb *fcb, struct flash_area *fap);
int fcb_getnext_nolock(struct fcb *fcb, struct fcb_entry *loc);
int fcb_elem_info(struct fcb *fcb, struct fcb_entry *loc);
int fcb_elem_crc8(struct fcb *fcb, struct fcb_entry *loc, u8_t *crc8p);
int fcb_sector_hdr_init(struct fcb *fcb, struct flash_area *fap, u16_t id);
int fcb_sector_hdr_read(struct fcb *fcb, struct flash_area *fap,
struct fcb_disk_area *fdap);
#ifdef __cplusplus
}
#endif
#endif /* __FCB_PRIV_H_ */

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2017 Nordic Semiconductor ASA
* Copyright (c) 2015 Runtime Inc
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "fcb.h"
#include "fcb_priv.h"
int
fcb_rotate(struct fcb *fcb)
{
struct flash_area *fap;
int rc = 0;
rc = k_mutex_lock(&fcb->f_mtx, K_FOREVER);
if (rc) {
return FCB_ERR_ARGS;
}
rc = flash_area_erase(fcb->f_oldest, 0, fcb->f_oldest->fa_size);
if (rc) {
rc = FCB_ERR_FLASH;
goto out;
}
if (fcb->f_oldest == fcb->f_active.fe_area) {
/*
* Need to create a new active area, as we're wiping
* the current.
*/
fap = fcb_getnext_area(fcb, fcb->f_oldest);
rc = fcb_sector_hdr_init(fcb, fap, fcb->f_active_id + 1);
if (rc) {
goto out;
}
fcb->f_active.fe_area = fap;
fcb->f_active.fe_elem_off = sizeof(struct fcb_disk_area);
fcb->f_active_id++;
}
fcb->f_oldest = fcb_getnext_area(fcb, fcb->f_oldest);
out:
k_mutex_unlock(&fcb->f_mtx);
return rc;
}

41
subsys/fs/fcb/fcb_walk.c Normal file
View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2017 Nordic Semiconductor ASA
* Copyright (c) 2015 Runtime Inc
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "fcb.h"
#include "fcb_priv.h"
/*
* Call 'cb' for every element in flash circular buffer. If fap is specified,
* only elements with that flash_area are reported.
*/
int
fcb_walk(struct fcb *fcb, struct flash_area *fap, fcb_walk_cb cb, void *cb_arg)
{
struct fcb_entry loc;
int rc;
loc.fe_area = fap;
loc.fe_elem_off = 0;
rc = k_mutex_lock(&fcb->f_mtx, K_FOREVER);
if (rc) {
return FCB_ERR_ARGS;
}
while ((rc = fcb_getnext_nolock(fcb, &loc)) != FCB_ERR_NOVAR) {
k_mutex_unlock(&fcb->f_mtx);
if (fap && loc.fe_area != fap) {
return 0;
}
rc = cb(&loc, cb_arg);
if (rc) {
return rc;
}
k_mutex_lock(&fcb->f_mtx, K_FOREVER);
}
k_mutex_unlock(&fcb->f_mtx);
return 0;
}