Skip to content
Permalink
9a75a83d22
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
419 lines (380 sloc) 18.1 KB
/***********************************************************************************************//**
* \file mtb_kvstore.h
*
* \brief
* Utility library for storing key value pairs in memory.
*
***************************************************************************************************
* \copyright
* Copyright 2018-2022 Cypress Semiconductor Corporation (an Infineon company) or
* an affiliate of Cypress Semiconductor Corporation
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**************************************************************************************************/
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include "cy_result.h"
#if defined(CY_RTOS_AWARE) || defined(COMPONENT_RTOS_AWARE)
#include "cyabs_rtos.h"
#endif
#if defined(__cplusplus)
extern "C" {
#endif
/**
* \addtogroup group_kvstore Key Value Storage Library
* \{
* This library provides a convenient way to store information as key-value pairs in non-volatile
* storage.
*
* \section section_kvstore_getting_started Getting Started
* This section provides steps for getting started with this library by providing examples
* using the [Serial Flash](https://github.com/infineon/serial-flash) (v1.X) and
* [HAL Flash driver](https://github.com/infineon/mtb-hal-cat1)
* (v1.X) libraries. Note that this section assumes that the required libraries are already
* included in the application. For more information on how to include libaries in the
* application please refer to the [ModusToolbox™ User Guide]
* (https://www.cypress.com/products/modustoolbox-software-environment)
*
* -# Include the kv-store library header in the application.
* \snippet kvstore_snip_serial.c snippet_mtb_kvstore_include
*
* -# Implement the block device interface. The following snippets can be copied into
* the application. If neither the serial-flash nor HAL flash driver is being used to communicate
* with the
* storage device, the application must provide a custom implementation of the block device
* interface.
* - Example implementation using serial-flash library.
* \snippet kvstore_snip_serial.c snippet_mtb_kvstore_ser_flash_bd
* - Example implementation using hal flash driver.
* \snippet kvstore_snip_flash.c snippet_mtb_kvstore_flash_bd
*
* -# Initialize the block device.
* - Example initialization for serial-flash library. This example configures
* the serial-flash using the memory configuration from the BSP. Please refer
* to the serial-flash [API Reference Guide]
* (https://infineon.github.io/serial-flash/html/index.html)
* for further details.
* \snippet kvstore_snip_serial.c snippet_mtb_kvstore_ser_flash_init
*
* - Example initialization for hal flash driver. This example initializes
* the working flash if available otherwise it initializes the main flash.
* Please refer to the HAL [API Reference Guide]
* (https://infineon.github.io/mtb-hal-cat1/html/modules.html)
* for further details.
* \snippet kvstore_snip_flash.c snippet_mtb_kvstore_flash_init
*
* -# Initialize the kv-store library.
* - Set the start address and length.
* - If using the serial-flash library, for this example we define the space
* provided to the kv-store library to be the size of 2 sectors.
* \snippet kvstore_snip_serial.c snippet_mtb_kvstore_ser_flash_addr_len
* - If using the hal flash driver, for this example the address space
* provided starts 16 pages from the end of the flash. Note that
* if the device does not have a working flash (i.e. using main flash) care must
* be taken to ensure that the space allocated below is not used by anything
* (for eg. Application image).
* \snippet kvstore_snip_flash.c snippet_mtb_kvstore_flash_addr_len
* - Call \ref mtb_kvstore_init by passing the start address, length and block device.
* \snippet kvstore_snip_serial.c snippet_mtb_kvstore_init
*
* -# The library should now be ready to perform operations.
* - Write operation.
* \snippet kvstore_snip_serial.c snippet_mtb_kvstore_write
* - Read operation.
* \snippet kvstore_snip_serial.c snippet_mtb_kvstore_read
* - Delete operation.
* \snippet kvstore_snip_serial.c snippet_mtb_kvstore_delete
*/
#if !defined(MTB_KVSTORE_MAX_KEY_SIZE)
/** Maximum key size permitted. */
#define MTB_KVSTORE_MAX_KEY_SIZE (64U)
#endif
#if (defined(CY_RTOS_AWARE) || defined(COMPONENT_RTOS_AWARE)) && \
!defined(MTB_KVSTORE_MUTEX_TIMEOUT_MS)
/** Timeout in ms for mutex timeout when using an RTOS. */
#define MTB_KVSTORE_MUTEX_TIMEOUT_MS (50U)
#endif
/** When passed as an argument to \ref mtb_kvstore_ensure_capacity,
* indicates that cleanup tasks should always be performed regardless
* of the amount of space which is currently free, to ensure the maximum
* possible amount of free space is available
*/
#define MTB_KVSTORE_ENSURE_MAX (0xFFFFFFFFu)
/** An invalid parameter value is passed in. */
#define MTB_KVSTORE_BAD_PARAM_ERROR \
CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_MIDDLEWARE_KVSTORE, 0)
/** The storage area passed in is not aligned to erase sector boundary. See
* notes in \ref mtb_kvstore_init for more information on constraints.
*/
#define MTB_KVSTORE_ALIGNMENT_ERROR \
CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_MIDDLEWARE_KVSTORE, 1)
/** Memory allocation failed. There is not enough space available on the heap. */
#define MTB_KVSTORE_MEM_ALLOC_ERROR \
CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_MIDDLEWARE_KVSTORE, 2)
/** Invalid data was detected. The record may be corrupted. */
#define MTB_KVSTORE_INVALID_DATA_ERROR \
CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_MIDDLEWARE_KVSTORE, 3)
/** Erased data was detected. The record may be corrupted */
#define MTB_KVSTORE_ERASED_DATA_ERROR \
CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_MIDDLEWARE_KVSTORE, 4)
/** Item was not found in the storage. */
#define MTB_KVSTORE_ITEM_NOT_FOUND_ERROR \
CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_MIDDLEWARE_KVSTORE, 5)
/** The storage is full. */
#define MTB_KVSTORE_STORAGE_FULL_ERROR \
CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_MIDDLEWARE_KVSTORE, 6)
/** Buffer provided is too small for value found. */
#define MTB_KVSTORE_BUFFER_TOO_SMALL \
CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_MIDDLEWARE_KVSTORE, 7)
/** Function prototype for reading data from the block device.
*
* @param[in] context Context object that is passed into \ref mtb_kvstore_init
* @param[in] addr Address to read the data from the block device. This address
* is passed in as start_addr + offset.
* @param[in] length Length of the data that needs to be read.
* @param[out] buf Buffer to read the data.
* @return Result of the read operation.
*/
typedef cy_rslt_t (* mtb_kvstore_bd_read)(void* context, uint32_t addr, uint32_t length,
uint8_t* buf);
/** Function prototype for writing data to the block device.
*
* @param[in] context Context object that is passed into \ref mtb_kvstore_init
* @param[in] addr Address to program the data into the block device. This address
* is passed in as start_addr + offset.
* @param[in] length Length of the data that needs to be written
* @param[out] buf Data that needs to be written
* @return Result of the program operation.
*/
typedef cy_rslt_t (* mtb_kvstore_bd_program)(void* context, uint32_t addr, uint32_t length,
const uint8_t* buf);
/** Function prototype for read from the block device.
*
* @param[in] context Context object that is passed into \ref mtb_kvstore_init
* @param[in] addr Address to read the data from the device. This address
* is passed in as start_addr + offset.
* @param[in] length Length of the data that needs to be erased.
* @return Result of the erase operation.
*/
typedef cy_rslt_t (* mtb_kvstore_bd_erase)(void* context, uint32_t addr, uint32_t length);
/** Function prototype to get the read size of the block device for a specific address.
*
* @param[in] context Context object that is passed into \ref mtb_kvstore_init
* @param[in] addr Address for which the read size is queried. This address
* is passed in as start_addr + offset.
* @return Read size of the memory device.
*/
typedef uint32_t (* mtb_kvstore_bd_read_size)(void* context, uint32_t addr);
/** Function prototype to get the program size of the block device for a specific address
*
* @param[in] context Context object that is passed into \ref mtb_kvstore_init
* @param[in] addr Address for which the program size is queried. This address
* is passed in as start_addr + offset.
* @return Program size of the memory device.
*/
typedef uint32_t (* mtb_kvstore_bd_program_size)(void* context, uint32_t addr);
/** Function prototype to get the erase size of the block device for a specific address
*
* @param[in] context Context object that is passed into \ref mtb_kvstore_init
* @param[in] addr Address for which the erase size is queried. This address is passed in a
* start_addr + offset.
* @return Erase size of the memory device.
*/
typedef uint32_t (* mtb_kvstore_bd_erase_size)(void* context, uint32_t addr);
/** Block device interface */
typedef struct
{
mtb_kvstore_bd_read read; /**< Function to read from device */
mtb_kvstore_bd_program program; /**< Function to program to device */
mtb_kvstore_bd_erase erase; /**< Function to erase device */
mtb_kvstore_bd_read_size read_size; /**< Function to get read size for an address */
mtb_kvstore_bd_program_size program_size; /**< Function to get program size for an address */
mtb_kvstore_bd_erase_size erase_size; /**< Function to get erase size for an address */
void* context; /**< Context object that can be used in the block
device implementation */
} mtb_kvstore_bd_t;
/** \cond INTERNAL */
/** Ram table entry structure */
typedef struct
{
uint16_t hash;
uint32_t offset;
} mtb_kvstore_ram_table_entry_t;
/** KV store context */
typedef struct
{
uint32_t start_addr;
uint32_t length;
const mtb_kvstore_bd_t* bd;
mtb_kvstore_ram_table_entry_t* ram_table;
uint32_t num_entries;
uint32_t max_entries;
uint8_t* transaction_buffer;
size_t transaction_buffer_size;
char key_buffer[MTB_KVSTORE_MAX_KEY_SIZE];
uint32_t active_area_addr;
uint32_t gc_area_addr;
uint32_t free_space_offset;
uint16_t active_area_version;
uint32_t consumed_size;
#if defined(CY_RTOS_AWARE) || defined(COMPONENT_RTOS_AWARE)
cy_mutex_t mtb_kvstore_mutex;
#endif
} mtb_kvstore_t;
/** \endcond */
/** Initialize a instance kv-store library
*
* @param[out] obj Pointer to a kv-store object. The caller must allocate the memory
* for this object but the init function will initialize its contents.
* @param[in] start_addr Start address for the memory. All addresses when performing memory
* operations will be offset from this address. See notes for constraints.
* @param[in] length Total space available in bytes. See notes for constraints.
* @param[in] block_device Block device interface for the underlying memory to be used.
*
* Address space considerations
* \note The start_addr and start_addr + length must be aligned to the erase sector boundary.
* \note An even number of erase sectors must be provided as storage. (2 * N * erase sector size)
* where N is the number of sectors.
* \note The implementation assumes that the value of the storage in the erased state is either 0x00
* or 0xFF.
* \note The space provided to the library provided must have the uniform characteristics (erase,
* program and read size). A space spanning regions with different characteristics in a
* hybrid sector device is not supported and if provided may lead to undefined behavior.
*
* RTOS considerations
* \note In a RTOS environment the library must be initialized after the RTOS kernel has started.
*
* @return Result of the initialization operation.
*/
cy_rslt_t mtb_kvstore_init(mtb_kvstore_t* obj, uint32_t start_addr, uint32_t length,
const mtb_kvstore_bd_t* block_device);
/** Store a key value pair
*
* @param[in] obj Pointer to a kv-store object
* @param[in] key Lookup key for the data.
* @param[in] data Pointer to the start of the data to be stored.
* @param[in] size Total size of the data in bytes.
*
* @return Result of the write operation.
*/
cy_rslt_t mtb_kvstore_write(mtb_kvstore_t* obj, const char* key, const uint8_t* data,
uint32_t size);
/** Read data associated with a key
*
* @param[in] obj Pointer to a kv-store object
* @param[in] key Lookup key for the data.
* @param[out] data Pointer to the start of the buffer for the data to be read into.
* @param[in,out] size [in] Total size of the data in bytes. [out] Actual size of the data in
* storage. If a data buffer is provided then the size cannot be NULL or 0.
*
* \note It is valid to set both `data` and `size` to NULL to check if the key exists in
* the storage.
*
* @return Result of the read operation.
*/
cy_rslt_t mtb_kvstore_read(mtb_kvstore_t* obj, const char* key, uint8_t* data,
uint32_t* size);
/** Read data associated with a key. If buffer is too small, will partially read and fill buffer.
* No corruption checking is performed.
*
* @param[in] obj Pointer to a kv-store object
* @param[in] key Lookup key for the data.
* @param[out] data Pointer to the start of the buffer for the data to be read into.
* @param[in,out] size [in] Total size of the data in bytes. [out] Number of bytes read into
* buffer. If a data buffer is provided then the size cannot be NULL
* or 0.
* @param[in] offset_bytes Number of bytes to skip at the start the value read into data
*
* @return Result of the read operation.
*/
cy_rslt_t mtb_kvstore_read_partial(mtb_kvstore_t* obj, const char* key, uint8_t* data,
uint32_t* size, const uint32_t offset_bytes);
/** Check if a key is stored in memory
*
* @param[in] obj Pointer to a kv-store object
* @param[in] key Lookup key
*
* @return Result of the key_exists operation
*/
cy_rslt_t mtb_kvstore_key_exists(mtb_kvstore_t* obj, const char* key);
/** Get the size in bytes of data in memory corresponding to a given key.
*
* @param[in] obj Pointer to a kv-store object
* @param[in] key Lookup key for the data
* @param[out] size Size of data in bytes
*
* @return Result of the value size operation
*/
cy_rslt_t mtb_kvstore_value_size(mtb_kvstore_t* obj, const char* key, uint32_t* size);
/** Delete a key value pair
*
* \note This function will return CY_RSLT_SUCCESS if the key cannot be found in the storage.
*
* @param[in] obj Pointer to a kv-store object.
* @param[in] key Lookup key to delete key value pair.
*
* @return Result of the delete operation.
*/
cy_rslt_t mtb_kvstore_delete(mtb_kvstore_t* obj, const char* key);
/** Query the size consumed in the kv-store storage.
*
* @param[in] obj Pointer to a kv-store object.
* @return Size of storage consumed in bytes.
*/
uint32_t mtb_kvstore_size(mtb_kvstore_t* obj);
/** Query the free space available in the kv-store storage.
*
* @param[in] obj Pointer to a kv-store object
*
* @return Size of storage free in bytes.
*/
uint32_t mtb_kvstore_remaining_size(mtb_kvstore_t* obj);
/** Tries to make the specified amount of space available
* for immediate use. If necessary, internal cleanup operations
* will be executed to make additional space available, so this
* is a potentially long-running operation.
*
* @param[in] obj Pointer to a kv-store object
* @param[in] size Amount of space to ensure is available, in bytes.
* To always perform cleanup operations regardless
* of the amount of space currently free,
* use \ref MTB_KVSTORE_ENSURE_MAX.
*
* @return Result of the operation. If `size` is not \ref MTB_KVSTORE_ENSURE_MAX
* and it is not possible to make the requested amount of space
* available, returns \ref MTB_KVSTORE_STORAGE_FULL_ERROR.
*/
cy_rslt_t mtb_kvstore_ensure_capacity(mtb_kvstore_t* obj, uint32_t size);
/** Reset kv-store storage.
*
* This function erases all the data in the storage.
*
* @param[in] obj Pointer to a kv-store object
*
* @return Result of the reset operation
*/
cy_rslt_t mtb_kvstore_reset(mtb_kvstore_t* obj);
/** Delete kv-store instance.
*
* This function frees any program memory allocated by the library.
*
* @param[in] obj Pointer to a kv-store object
*/
void mtb_kvstore_deinit(mtb_kvstore_t* obj);
#if defined(__cplusplus)
}
#endif
/** \} group_kvstore */