/* * Copyright (c) 2017-2020 Nordic Semiconductor ASA * Copyright (c) 2015 Runtime Inc * * SPDX-License-Identifier: Apache-2.0 */ #ifndef ZEPHYR_INCLUDE_FS_FCB_H_ #define ZEPHYR_INCLUDE_FS_FCB_H_ /* * Flash circular buffer. */ #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** * @defgroup fcb Flash Circular Buffer (FCB) * @ingroup file_system_storage * @{ * @} */ /** * @defgroup fcb_data_structures Flash Circular Buffer Data Structures * @ingroup fcb * @{ */ #define FCB_MAX_LEN (CHAR_MAX | CHAR_MAX << 7) /**< Max length of element */ /** * @brief 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 { 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*/ }; /** * @brief Helper macro for calculating the data offset related to * the fcb flash_area start offset. * * @param entry fcb entry structure */ #define FCB_ENTRY_FA_DATA_OFF(entry) (entry.fe_sector->fs_off +\ entry.fe_data_off) /** * @brief Structure for transferring complete information about FCB entry * location within flash memory. */ struct fcb_entry_ctx { struct fcb_entry loc; /**< FCB entry info */ const struct flash_area *fap; /**< Flash area where the entry is placed */ }; /** * @brief FCB instance structure * * The following data structure describes the FCB itself. First part should * be filled in by the user before calling @ref fcb_init. The second part is * used by FCB for its internal bookkeeping. */ struct fcb { /* Caller of fcb_init fills this in */ 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 */ /* Flash circular buffer internal state */ 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. */ }; /** * @} */ /** * @brief Flash Circular Buffer APIs * @defgroup fcb_api fcb API * @ingroup fcb * @{ */ /** * Initialize FCB instance. * * @param[in] f_area_id ID of flash area where fcb storage resides. * @param[in,out] fcb FCB instance structure. * * @return 0 on success, non-zero on failure. */ int fcb_init(int f_area_id, struct fcb *fcb); /** * 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. * * @param[in] fcb FCB instance structure. * @param[in] len Length of data which are expected to be written as the entry * payload. * @param[out] loc entry location information * * @return 0 on success, non-zero on failure. */ int fcb_append(struct fcb *fcb, uint16_t len, struct fcb_entry *loc); /** * Finishes entry append operation. * * @param[in] fcb FCB instance structure. * @param[in] append_loc entry location information * * @return 0 on success, non-zero on failure. */ int fcb_append_finish(struct fcb *fcb, struct fcb_entry *append_loc); /** * FCB Walk callback function type. * * Type of function which is expected to be called while walking over fcb * entries thanks to a @ref 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[in] loc_ctx entry location information (full context) * @param[in,out] arg callback context, transferred from @ref fcb_walk. * * @return 0 continue walking, non-zero stop walking. */ typedef int (*fcb_walk_cb)(struct fcb_entry_ctx *loc_ctx, void *arg); /** * Walk over all entries in the FCB sector * * @param[in] sector fcb sector to be walked. If null, traverse entire * storage. * @param[in] fcb FCB instance structure. * @param[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. * @param[in,out] cb_arg callback context, transferred to the callback * implementation. * * @return 0 on success, negative on failure (or transferred form callback * return-value), positive transferred form callback return-value */ int fcb_walk(struct fcb *fcb, struct flash_sector *sector, fcb_walk_cb cb, void *cb_arg); /** * 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. * * @param[in] fcb FCB instance structure. * @param[in,out] loc entry location information * * @return 0 on success, non-zero on failure. */ int fcb_getnext(struct fcb *fcb, struct fcb_entry *loc); /* * 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. * * @param[in] fcb FCB instance structure. */ int fcb_rotate(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. * * @param[in] fcb FCB instance structure. * * @return 0 on success, non-zero on failure. */ int fcb_append_to_scratch(struct fcb *fcb); /** * Get free sector count. * * @param[in] fcb FCB instance structure. * * @return Number of free sectors. */ int fcb_free_sector_cnt(struct fcb *fcb); /** * Check whether FCB has any data. * * @param[in] fcb FCB instance structure. * * @return Positive value if fcb is empty, otherwise 0. */ int fcb_is_empty(struct fcb *fcb); /** * Finds the fcb entry that gives back up to n entries at the end. * * @param[in] fcb FCB instance structure. * @param[in] entries number of fcb entries the user wants to get * @param[out] last_n_entry last_n_entry the fcb_entry to be returned * * @return 0 on there are any fcbs available; -ENOENT otherwise */ int fcb_offset_last_n(struct fcb *fcb, uint8_t entries, struct fcb_entry *last_n_entry); /** * Clear fcb instance storage. * * @param[in] fcb FCB instance structure. * * @return 0 on success; non-zero on failure */ int fcb_clear(struct fcb *fcb); /** * @} */ /** * @brief Flash Circular internal * @defgroup fcb_internall fcb non-API prototypes * @ingroup fcb * @{ */ /** * Read raw data from the fcb flash sector. * * @param[in] fcb FCB instance structure. * @param[in] sector FCB sector. * @param[in] off Read offset form sector begin. * @param[out] dst Destination buffer. * @param[in] len Read-out size. * * @return 0 on success, negative errno code on fail. */ int fcb_flash_read(const struct fcb *fcb, const struct flash_sector *sector, off_t off, void *dst, size_t len); /** * Write raw data to the fcb flash sector. * * @param[in] fcb FCB instance structure. * @param[in] sector FCB sector. * @param[in] off Write offset form sector begin. * @param[out] src Source buffer. * @param[in] len Read-out size. * * @return 0 on success, negative errno code on fail. */ int fcb_flash_write(const struct fcb *fcb, const struct flash_sector *sector, off_t off, const void *src, size_t len); /** * @} */ #ifdef __cplusplus } #endif #endif /* ZEPHYR_INCLUDE_FS_FCB_H_ */