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 call fcb_rotate() to erase the oldest sector which will make the space. And then call fcb_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 call fcb_rotate(), if you’re done with that data.

Alternatively:

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

FCB_FLAGS_CRC_DISABLED

Flag to disable CRC for the fcb_entries in flash.

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 fcb_entry_ctx
#include <fcb.h>

Structure for transferring complete information about FCB entry location within flash memory.

Public Members

struct fcb_entry loc

FCB entry info.

const struct flash_area *fap

Flash area where the entry is placed.

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 k_mutex f_mtx

Locking for accessing the FCB data, internal state.

struct flash_sector *f_oldest

Pointer to flash sector containing the oldest data, internal state.

struct fcb_entry f_active

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.

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_rotate(struct fcb *fcb)

Rotate fcb sectors.

Function erases the data from oldest sector. Upon that the next sector becomes the oldest. Active sector is also switched if needed.

Parameters:
  • fcb[in] FCB instance structure.

int fcb_append_to_scratch(struct fcb *fcb)

Start using the scratch block.

Take one of the scratch blocks into use. So a scratch sector becomes active sector to which entries can be appended.

Parameters:
  • fcb[in] FCB instance structure.

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

int fcb_clear(struct fcb *fcb)

Clear fcb instance storage.

Parameters:
  • fcb[in] FCB instance structure.

Returns:

0 on success; non-zero on failure