Flash Circular Buffer (FCB)
Flash circular buffer provides an abstraction through which you can treat flash like a FIFO. You append entries to the end, and read data from the beginning.
Note
As of Zephyr release 2.1 the NVS storage API is recommended over FCB for use as a back-end for the settings API.
Description
Entries in the flash contain the length of the entry, the data within the entry, and checksum over the entry contents.
Storage of entries in flash is done in a FIFO fashion. When you request space for the next entry, space is located at the end of the used area. When you start reading, the first entry served is the oldest entry in flash.
Entries can be appended to the end of the area until storage space is exhausted. You have control over what happens next; either erase oldest block of data, thereby freeing up some space, or stop writing new data until existing data has been collected. FCB treats underlying storage as an array of flash sectors; when it erases old data, it does this a sector at a time.
Entries in the flash are checksummed. That is how FCB detects whether writing entry to flash completed ok. It will skip over entries which don’t have a valid checksum.
Usage
To add an entry to circular buffer:
Call
fcb_append()
to get the location where data can be written. If this fails due to lack of space, you can callfcb_rotate()
to erase the oldest sector which will make the space. And then callfcb_append()
again.Use
flash_area_write()
to write entry contents.Call
fcb_append_finish()
when done. This completes the writing of the entry by calculating the checksum.
To read contents of the circular buffer:
Call
fcb_walk()
with a pointer to your callback function.Within callback function copy in data from the entry using
flash_area_read()
. You can tell when all data from within a sector has been read by monitoring the returned entry’s area pointer. Then you can callfcb_rotate()
, if you’re done with that data.
Alternatively:
Call
fcb_getnext()
with 0 in entry offset to get the pointer to the oldest entry.Use
flash_area_read()
to read entry contents.Call
fcb_getnext()
with pointer to current entry to get the next one. And so on.
API Reference
The FCB subsystem APIs are provided by fcb.h
:
Data structures
- group fcb_data_structures
Defines
-
FCB_MAX_LEN
Max length of element
-
FCB_ENTRY_FA_DATA_OFF(entry)
Helper macro for calculating the data offset related to the fcb flash_area start offset.
- Parameters
entry – fcb entry structure
-
struct fcb_entry
- #include <fcb.h>
FCB entry info structure. This data structure describes the element location in the flash.
You would use it to figure out what parameters to pass to flash_area_read() to read element contents. Or to flash_area_write() when adding a new element. Entry location is pointer to area (within fcb->f_sectors), and offset within that area.
Public Members
-
struct flash_sector *fe_sector
Pointer to info about sector where data are placed
-
uint32_t fe_elem_off
Offset from the start of the sector to beginning of element.
-
uint32_t fe_data_off
Offset from the start of the sector to the start of element.
-
uint16_t fe_data_len
Size of data area in fcb entry
-
struct flash_sector *fe_sector
-
struct fcb_entry_ctx
- #include <fcb.h>
Structure for transferring complete information about FCB entry location within flash memory.
Public Members
-
const struct flash_area *fap
Flash area where the entry is placed
-
const struct flash_area *fap
-
struct fcb
- #include <fcb.h>
FCB instance structure.
The following data structure describes the FCB itself. First part should be filled in by the user before calling fcb_init. The second part is used by FCB for its internal bookkeeping.
Public Members
-
uint32_t f_magic
Magic value, should not be 0xFFFFFFFF. It is xored with inversion of f_erase_value and placed in the beginning of FCB flash sector. FCB uses this when determining whether sector contains valid data or not. Giving it value of 0xFFFFFFFF means leaving bytes of the filed in “erased” state.
-
uint8_t f_version
Current version number of the data
-
uint8_t f_sector_cnt
Number of elements in sector array
-
uint8_t f_scratch_cnt
Number of sectors to keep empty. This can be used if you need to have scratch space for garbage collecting when FCB fills up.
-
struct flash_sector *f_sectors
Array of sectors, must be contiguous
-
struct flash_sector *f_oldest
Pointer to flash sector containing the oldest data, internal state
-
uint16_t f_active_id
Flash location where the newest data is, internal state
-
uint8_t f_align
writes to flash have to aligned to this, internal state
-
const struct flash_area *fap
Flash area used by the fcb instance, , internal state. This can be transfer to FCB user
-
uint8_t f_erase_value
The value flash takes when it is erased. This is read from flash parameters and initialized upon call to fcb_init.
-
uint32_t f_magic
-
FCB_MAX_LEN
API functions
- group fcb_api
Flash Circular Buffer APIs.
Typedefs
-
typedef int (*fcb_walk_cb)(struct fcb_entry_ctx *loc_ctx, void *arg)
FCB Walk callback function type.
Type of function which is expected to be called while walking over fcb entries thanks to a fcb_walk call.
Entry data can be read using flash_area_read(), using loc_ctx fields as arguments. If cb wants to stop the walk, it should return non-zero value.
- Param loc_ctx
[in] entry location information (full context)
- Param arg
[inout] callback context, transferred from fcb_walk.
- Return
0 continue walking, non-zero stop walking.
Functions
-
int fcb_init(int f_area_id, struct fcb *fcb)
Initialize FCB instance.
- Parameters
f_area_id – [in] ID of flash area where fcb storage resides.
fcb – [inout] FCB instance structure.
- Returns
0 on success, non-zero on failure.
-
int fcb_append(struct fcb *fcb, uint16_t len, struct fcb_entry *loc)
Appends an entry to circular buffer.
When writing the contents for the entry, use loc->fe_sector and loc->fe_data_off with flash_area_write() to fcb flash_area. When you’re finished, call fcb_append_finish() with loc as argument.
- Parameters
fcb – [in] FCB instance structure.
len – [in] Length of data which are expected to be written as the entry payload.
loc – [out] entry location information
- Returns
0 on success, non-zero on failure.
-
int fcb_append_finish(struct fcb *fcb, struct fcb_entry *append_loc)
Finishes entry append operation.
- Parameters
fcb – [in] FCB instance structure.
append_loc – [in] entry location information
- Returns
0 on success, non-zero on failure.
-
int fcb_walk(struct fcb *fcb, struct flash_sector *sector, fcb_walk_cb cb, void *cb_arg)
Walk over all entries in the FCB sector
- Parameters
sector – [in] fcb sector to be walked. If null, traverse entire storage.
fcb – [in] FCB instance structure.
cb – [in] pointer to the function which gets called for every entry. If cb wants to stop the walk, it should return non-zero value.
cb_arg – [inout] callback context, transferred to the callback implementation.
- Returns
0 on success, negative on failure (or transferred form callback return-value), positive transferred form callback return-value
-
int fcb_getnext(struct fcb *fcb, struct fcb_entry *loc)
Get next fcb entry location.
Function to obtain fcb entry location in relation to entry pointed by
loc. If loc->fe_sector is set and loc->fe_elem_off is not 0 function fetches next fcb entry location. If loc->fe_sector is NULL function fetches the oldest entry location within FCB storage. loc->fe_sector is set and loc->fe_elem_off is 0 function fetches the first entry location in the fcb sector.
- Parameters
fcb – [in] FCB instance structure.
loc – [inout] entry location information
- Returns
0 on success, non-zero on failure.
-
int fcb_free_sector_cnt(struct fcb *fcb)
Get free sector count.
- Parameters
fcb – [in] FCB instance structure.
- Returns
Number of free sectors.
-
int fcb_is_empty(struct fcb *fcb)
Check whether FCB has any data.
- Parameters
fcb – [in] FCB instance structure.
- Returns
Positive value if fcb is empty, otherwise 0.
-
int fcb_offset_last_n(struct fcb *fcb, uint8_t entries, struct fcb_entry *last_n_entry)
Finds the fcb entry that gives back up to n entries at the end.
- Parameters
fcb – [in] FCB instance structure.
entries – [in] number of fcb entries the user wants to get
last_n_entry – [out] last_n_entry the fcb_entry to be returned
- Returns
0 on there are any fcbs available; -ENOENT otherwise
-
typedef int (*fcb_walk_cb)(struct fcb_entry_ctx *loc_ctx, void *arg)