WXK
2025-01-21 8f1a91a8ec98e430cfe4357bda099d495917198e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
/***********************************************************************************************//**
 * \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 */