/***********************************************************************************************//**
|
* \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.
|
**************************************************************************************************/
|
#ifndef _MTD_KVSTORE_
|
#define _MTD_KVSTORE_
|
|
#include <stdint.h>
|
#include <stdlib.h>
|
#include "mtd_kv_port.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);
|
|
void host_kvstore_init(void);
|
|
cy_rslt_t app_kv_write(const char* key, const uint8_t* data, uint32_t size);
|
|
cy_rslt_t app_kv_read(const char* key, uint8_t* data, uint32_t* size);
|
|
cy_rslt_t app_kv_delete(const char* key);
|
|
#if defined(__cplusplus)
|
}
|
#endif
|
|
#endif
|
/** \} group_kvstore */
|