-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathkved.h
287 lines (236 loc) · 7.95 KB
/
kved.h
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
/*
kved (key/value embedded database), a simple key/value database
implementation for microcontrollers.
Copyright (c) 2022 Marcelo Barros de Almeida <[email protected]>
*/
#pragma once
/**
@file
@defgroup KVED KVED
@brief KVED (key/value embedded databse): simple key/value persistence for embedded applications.
@{
*/
#include "kved_config.h"
/* kved structure
<- 4 bytes -><- 4 bytes -> <= 8 bytes when using flash with word of 64 bits
+------------+------------+
| SIGNATURE | COUNTER | <= HEADER ID AND NEWER COPY IDENTIFICATION
+---------+--+------------+
|KEY ENTRY|TS| KEY VALUE | <= VALID KEY (KEY ENTRY, TYPE, SIZE AND VALUE)
+---------+--+------------+
|KEY ENTRY|TS| KEY VALUE |
+---------+--+------------+
|KEY ENTRY|TS| KEY VALUE |
+---------+--+------------+
|000 ... 0000| KEY VALUE | <= ERASED KEY
+------------+------------+
|FFF ... FFFF|FFF ... FFFF| <= EMPTY ENTRY
+------------+------------+
|FFF ... FFFF|FFF ... FFFF|
+------------+------------+
|FFF ... FFFF|FFF ... FFFF|
+------------+------------+
*/
#if KVED_FLASH_WORD_SIZE == 4
typedef uint32_t kved_word_t; /**< flash word data type */
#else
typedef uint64_t kved_word_t; /**< flash word data type */
#endif
#if KVED_FLASH_WORD_SIZE == 8
#define KVED_SIGNATURE_ENTRY 0xDEADBEEFDEADBEEFULL
#define KVED_DELETED_ENTRY 0x0000000000000000ULL
#define KVED_FREE_ENTRY 0xFFFFFFFFFFFFFFFFULL
#define KVED_HDR_ENTRY_MSK 0xFFFFFFFFFFFFFF00ULL
#else
#define KVED_SIGNATURE_ENTRY 0xDEADBEEFUL /**< kved signature */
#define KVED_DELETED_ENTRY 0x00000000UL /**< deleted entry identification */
#define KVED_FREE_ENTRY 0xFFFFFFFFUL /**< free entry identification */
#define KVED_HDR_ENTRY_MSK 0xFFFFFF00UL /**< label entry mask */
#endif
#define KVED_HDR_SIZE_IN_WORDS 2 /**< kved header size */
#define KVED_ENTRY_SIZE_IN_WORDS 2 /**< kved entry size */
#define KVED_HDR_MASK_KEY(k) ( (k) & KVED_HDR_ENTRY_MSK) /**< label entry mask */
#define KVED_HDR_MASK_TYPE(k) (((k) & 0xF0) >> 4) /**< type entry mask */
#define KVED_HDR_MASK_SIZE(k) (((k) & 0x0F)) /**< size entry mask */
#define KVED_FLASH_UINT_MAX ((kved_word_t)(~0)) /**< last valid unsigned int value for current flash word */
/** Maximum supported string length, per record, without termination */
#define KVED_MAX_STRING_SIZE (KVED_FLASH_WORD_SIZE)
/** Key size for data access, with terminator */
#define KVED_MAX_KEY_SIZE (KVED_FLASH_WORD_SIZE-1)
/** Index return value when a key is not found in the database */
#define KVED_INDEX_NOT_FOUND 0
/**
@brief Supported data types.
*/
typedef enum kved_data_types_e
{
KVED_DATA_TYPE_UINT8 = 0, /**< 8 bits, unsigned */
KVED_DATA_TYPE_INT8, /**< 8 bits, signed */
KVED_DATA_TYPE_UINT16, /**< 16 bits, unsigned */
KVED_DATA_TYPE_INT16, /**< 16 bits, signed */
KVED_DATA_TYPE_UINT32, /**< 32 bits, unsigned */
KVED_DATA_TYPE_INT32, /**< 32 bits, com sinal */
KVED_DATA_TYPE_FLOAT, /**< Single precision floating point (float) */
KVED_DATA_TYPE_STRING, /**< String up to @ref KVED_MAX_STRING_SIZE bytes, excluding terminator */
#if KVED_FLASH_WORD_SIZE == 8
KVED_DATA_TYPE_UINT64, /**< 64 bits, signed */
KVED_DATA_TYPE_INT64, /**< 64 bits, unsigned */
KVED_DATA_TYPE_DOUBLE, /**< Double precision floating point (double) */
#endif
} kved_data_types_t;
/**
@brief Union with supported data types
*/
typedef union kved_value_u
{
uint8_t u8; /**< unsigned 8 bits value */
int8_t i8; /**< signed 8 bits value */
uint16_t u16; /**< unsigned 16 bits value */
int16_t i16; /**< signed 16 bits value */
uint32_t u32; /**< unsigned 32 bits value */
int32_t i32; /**< signed 32 bits value */
float flt; /**< single precision float */
uint8_t str[KVED_MAX_STRING_SIZE]; /**< string */
#if KVED_FLASH_WORD_SIZE == 8
uint64_t u64; /**< unsigned 64 bits value */
int64_t i64; /**< signed 64 bits value */
double dbl; /**< double precision float */
#endif
} kved_value_t;
/**
@brief Structure for accessing the database containing information about key, type and value
*/
typedef struct kved_data_s
{
kved_value_t value; /**< User value */
uint8_t key[KVED_MAX_KEY_SIZE]; /**< String used as access key */
kved_data_types_t type; /**< Data type used according to @ref kved_data_types_t */
} kved_data_t;
/**
@brief Writes a new value to the database.
@param[in] data - information about the data to be written
@return true: recording successful.
@return false: error during the recording process.
@code
kved_data_t kv1 = {
.type = KVED_DATA_TYPE_UINT32,
.key = "ca1",
.value.u32 = 0x12345678
};
kved_data_t kv2 = {
.type = KVED_DATA_TYPE_STRING,
.key = "ID",
.value.str ="N01"
};
kved_data_write(&kv1);
kved_data_write(&kv2);
@endcode
*/
bool kved_data_write(kved_data_t *data);
/**
@brief Retrieves a previously saved value from database.
@param[out] data - Structure where the retrieved value will be stored (type and content)
@return true: read successfully.
@return false: error during the reading process.
@code
kved_data_t kv1 = {
.key = "ca1",
};
kved_data_t kv2 = {
.key = "ID",
};
if(kved_data_read(&kv1))
printf("Value: %d\n",kv1.value.u32);
if(kved_data_read(&kv2))
printf("Value: %4s\n",kv2.value.str);
@endcode
*/
bool kved_data_read(kved_data_t *data);
/**
@brief Deletes a previously saved value in the database, if it exists.
@param[in] data - Structure where the retrieved value will be stored (type and content)
@return true: deletion successful.
@return false: error during the erasuring process.
@code
kved_data_t kv1 = {
.key = "ca1",
};
if(kved_data_delete(&kv1))
printf("Entry erased");
@endcode
*/
bool kved_data_delete(kved_data_t *data);
/**
@brief Retrieves a previously saved value from database but using an index.
This function is used in conjunction with @ref kved_first_used_index_get and @ref kved_next_used_index_get
to iterate over the database.
@param[in] index - index of the value to retrieve
@param[out] data - structure where the retrieved value will be stored (type and content)
@return true: read successfully.
@return false: error during reading process.
@code
kved_data_t kv1;
uint16_t index = kved_first_used_index_get();
printf("Database keys:\n");
while(index != KVED_INDEX_NOT_FOUND)
{
kved_data_read_by_index(index,&data);
printf("- Key: %s\n",kv1.key);
index = kved_next_used_index_get(index);
}
@endcode
*/
bool kved_data_read_by_index(uint16_t index, kved_data_t *data);
/**
@brief Get the first valid index in the database.
@return returns @ref KVED_INDEX_NOT_FOUND (index not found, database empty) or an index value greater than zero
*/
uint16_t kved_first_used_index_get(void);
/**
@brief Given the last index, get the next valid index from the database.
@param[in] last_index - last valid index used
@return return @ref KVED_INDEX_NOT_FOUND when the end of the database is reached or a valid index value (greater than zero)
*/
uint16_t kved_next_used_index_get(uint16_t last_index);
/**
@brief Returns the number of database entries (used or not)
@return Number of entries
*/
uint16_t kved_total_entries_get(void);
/**
@brief Returns the number of used database entries
@return Number of entries
*/
uint16_t kved_used_entries_get(void);
/**
@brief Returns the number available entries in the database
@return Number of entries
*/
uint16_t kved_free_entries_get(void);
/**
@brief Print all values stored in the database
*/
void kved_dump(void);
/**
@brief Format the database, deleting all values
*/
void kved_format(void);
/**
@brief Given a key entry from database, decode it to data type and user key
@param[out] data - structure where data type and user key will be stored
@param[in] key - key entry
*/
void kved_key_decode(kved_data_t *data, kved_word_t key);
/**
@brief Given a data type and user key, encode it as a key entry to be written in the database
@param[in] data - user entry
@return Encoded key entry
*/
kved_word_t kved_key_encode(kved_data_t *data);
/**
@brief Initialize the database. Must be called before any use.
*/
void kved_init(void);
/**
@}
*/