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:

  • 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.

struct fcb_entry_ctx
#include <fcb.h>

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

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.

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.

Return

0 continue walking, non-zero stop walking.

Parameters
  • [in] loc_ctx: entry location information (full context)

  • [inout] arg: callback context, transferred from fcb_walk.

Functions

int fcb_init(int f_area_id, struct fcb *fcb)

Initialize FCB instance.

Return

0 on success, non-zero on failure.

Parameters
  • [in] f_area_id: ID of flash area where fcb storage resides.

  • [inout] fcb: FCB instance structure.

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.

Return

0 on success, non-zero on failure.

Parameters
  • [in] fcb: FCB instance structure.

  • [in] len: Length of data which are expected to be written as the entry payload.

  • [out] loc: entry location information

int fcb_append_finish(struct fcb *fcb, struct fcb_entry *append_loc)

Finishes entry append operation.

Return

0 on success, non-zero on failure.

Parameters
  • [in] fcb: FCB instance structure.

  • [in] append_loc: entry location information

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

Return

0 on success, negative on failure (or transferred form callback return-value), positive transferred form callback return-value

Parameters
  • [in] sector: fcb sector to be walked. If null, traverse entire storage.

  • [in] fcb: FCB instance structure.

  • [in] cb: pointer to the function which gets called for every entry. If cb wants to stop the walk, it should return non-zero value.

  • [inout] cb_arg: callback context, transferred to the callback implementation.

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.

Return

0 on success, non-zero on failure.

Parameters
  • [in] fcb: FCB instance structure.

  • [inout] loc: entry location information

int fcb_rotate(struct fcb *fcb)
int fcb_append_to_scratch(struct fcb *fcb)
int fcb_free_sector_cnt(struct fcb *fcb)

Get free sector count.

Return

Number of free sectors.

Parameters
  • [in] fcb: FCB instance structure.

int fcb_is_empty(struct fcb *fcb)

Check whether FCB has any data.

Return

Positive value if fcb is empty, otherwise 0.

Parameters
  • [in] fcb: FCB instance structure.

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.

Return

0 on there are any fcbs available; -ENOENT otherwise

Parameters
  • [in] fcb: FCB instance structure.

  • [in] entries: number of fcb entries the user wants to get

  • [out] last_n_entry: last_n_entry the fcb_entry to be returned

int fcb_clear(struct fcb *fcb)

Clear fcb instance storage.

Return

0 on success; non-zero on failure

Parameters
  • [in] fcb: FCB instance structure.