-
Notifications
You must be signed in to change notification settings - Fork 1
/
configstore.h
354 lines (280 loc) · 10.2 KB
/
configstore.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
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
/*
* mµOS - my micro OS
*
* Copyright (C)
* 2018 Christian Thäter <[email protected]>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MUOS_CONFIGSTORE_H
#define MUOS_CONFIGSTORE_H
#ifndef MUOS_CONFIGSTORE_INCLUDE
#error MUOS_CONFIGSTORE_INCLUDE must be configured
#endif
#include MUOS_CONFIGSTORE_INCLUDE
#ifndef CONFIGSTORE_DATA
#error CONFIGSTORE_DATA must be defined in MUOS_CONFIGSTORE_INCLUDE
#endif
#include <muos/muos.h>
#include <muos/io.h>
/*
Wear leveling and fault tolerant config store.
the complete user defined configuration is expanded as one in-ram structure, extended by a
'generation' counter and a checksum.
In EEPROM it will be mapped as array much times as fit into the given size.
On loading the whole EEPROM is scanned for the highest generation version with intact checksum.
On saving the generation counter is incremented and the data is written next to the previous (wrap around)
position, or when MUOS_CONFIGSTORE_REDUNDANT is set, at the last AND next position. Writes will be verified,
a failed verification will advance the writing position once more and write again. When all writes (complete
wraparound) failed then an error is returned.
loading/saving is asynchronous but access to the configstore will be blocked (error return) while any
operation is in progress.
//PLANNED: interleaved/wraparound configstore
|1b1b1b1b|1b1b1b1b|...|
|.2b2b2b2b|2a2a2a2a|..|
|3a3a|3b3b3b3b|...3a3a|
*/
//configstore_api:
//: .Configuration Description
//: ----
//: #define CONFIGSTORE_DATA {__BACKSLASH__}
//FIXME: doc not correct lacks defaults validation
//: ENTRY(type, ary, name) {__BACKSLASH__}
//: ...
//: ----
//:
//: +type+::
//: C type of the data.
//:
//: +ary+::
//: Size for arrays. 0 for single variables. Otherwise one of
//: 2, 3, 4, 5, 6, 7,8, 16, 32, 64, 128, or ARRAY(n) to define the size
//: of an array.
//:
//: +name+::
//: C identifier for the variable.
//:
//: Configuration variables are defined by a C-Preprocessor defined DSL in a single included file.
//: The 'MUOS_CONFIGSTORE_INCLUDE' configuration from the 'Makefile' must point to this file.
//:
//: The user defines 'CONFIGSTORE_DATA' to a sequence of 'ENTRY(type, ary, name)'
//: definitions. MµOS uses this to expand the provided data into various datastructures.
//:
//PLANNED: make the descriptions/strings hierarchical to safe memory
typedef void (*muos_configstore_callback)(void);
typedef enum
{
CONFIGSTORE_UNKNOWN, // status not known yet, did not called load
CONFIGSTORE_INVALID, // load did not find a saved config, size mismatch
CONFIGSTORE_DEAD, // 'save' could not save+verify data, EEPROM is dead (but ram is ok)
CONFIGSTORE_VALID, // successfully loaded config
CONFIGSTORE_RLOCK, // readlocks start here, count up
CONFIGSTORE_RLOCK_MAX=254, // end of readlocks
CONFIGSTORE_WLOCK=255, // write lock
} muos_configstore_status;
// simple attributes/access control, only affects output and set commands
//TODO: implement me
typedef enum
{
CONFIGSTORE_DEFAULT = 0, // no attrs
CONFIGSTORE_WPROT = 1, // needs auth for set
CONFIGSTORE_RPROT = 2, // needs auth for output
CONFIGSTORE_HIDDEN = 4, // hide from listing
CONFIGSTORE_MUTABLE = 8, // can be set even even when readonly locked
} muos_configstore_attr;
muos_configstore_status
muos_configstore_get_status (void);
//bool muosconfig_loaded (intptr_t unused)
#define CONFIGSTORE_ARY_ARRAY(len) [len]
#define CONFIGSTORE_ARY_0
#define CONFIGSTORE_ARY_1 [1]
#define CONFIGSTORE_ARY_2 [2]
#define CONFIGSTORE_ARY_3 [3]
#define CONFIGSTORE_ARY_4 [4]
#define CONFIGSTORE_ARY_5 [5]
#define CONFIGSTORE_ARY_6 [6]
#define CONFIGSTORE_ARY_7 [7]
#define CONFIGSTORE_ARY_8 [8]
#define CONFIGSTORE_ARY_16 [16]
#define CONFIGSTORE_ARY_32 [32]
#define CONFIGSTORE_ARY_64 [64]
#define CONFIGSTORE_ARY_128 [128]
#define CONFIGSTORE_ARY(val) CONFIGSTORE_ARY_##val
//TODO: add callback when config gets changed for reinitializeing dependencies
//TODO: document implicit config_size
#define CONFIGSTORE_DATA_IMPL \
ENTRY(uint16_t, 0, config_size, 0, \
2, 65535, \
CONFIGSTORE_HIDDEN, \
"configuration structure size") \
CONFIGSTORE_DATA
struct muos_configstore_data
{
#define string char
#define ENTRY(type, ary, name, default, min, max, attr, descr) type name CONFIGSTORE_ARY(ary);
CONFIGSTORE_DATA_IMPL
#undef ENTRY
#undef string
};
enum muos_configstore_id
{
#define ENTRY(type, ary, name, default, min, max, attr, descr) CONFIGSTORE_ID_##name,
CONFIGSTORE_DATA_IMPL
#undef ENTRY
CONFIGSTORE_MAX_ID
};
// the types supported by the configstore
#define MUOS_CONFIGSTORE_TYPES \
TYPE(int8_t) \
TYPE(uint8_t) \
TYPE(int16_t) \
TYPE(uint16_t) \
TYPE(int32_t) \
TYPE(string) /* string as char array */
// no TYPE(uint32_t), so we can use strtol when setting
enum muos_configstore_type
{
#define TYPE(type) MUOS_CONFIGSTORE_TYPE_##type,
MUOS_CONFIGSTORE_TYPES
#undef TYPE
MUOS_CONFIGSTORE_MAX_TYPE
};
enum muos_configstore_type
muos_configstore_type (enum muos_configstore_id id);
uint8_t
muos_configstore_ary (enum muos_configstore_id id);
// API
muos_error
muos_configstore_output_name MUOS_IO_HWPARAM(enum muos_configstore_id id);
muos_error
muos_configstore_output_value MUOS_IO_HWPARAM(enum muos_configstore_id id, uint8_t index);
muos_error
muos_configstore_set (char* var, uint8_t index, char* val);
//configstore_api:
//: .Attributes, Authentication
//: ----
//: #ifdef MUOS_CONFIGSTORE_ATTRS
//: bool muos_configstore_authenticated
//: #endif
//: ----
//:
//: Flag if an user is authenticated. The application should set/clear this.
//: Only affects 'muos_configstore_set()' and 'muos_configstore_output_*()'
#ifdef MUOS_CONFIGSTORE_ATTRS
extern bool muos_configstore_authenticated;
#endif
// loading/saving
//configstore_api:
//: .Loading and Saving
//: ----
//: typedef void (*muos_configstore_callback)(void)
//:
//: muos_error
//: muos_configstore_load (muos_configstore_callback callback)
//:
//: muos_error
//: muos_configstore_save (muos_configstore_callback callback)
//: ----
//:
//: +callback+::
//: function called on completion.
//:
//: These functions locking the configstore when their own operation is
//: in progress. The store must not be locked on entering.
//: Both functions return 'muos_error_configstore' in case
//: the store was already locked. Other errors should be handled in 'callback'.
muos_error
muos_configstore_load (muos_configstore_callback callback);
muos_error
muos_configstore_save (muos_configstore_callback callback);
//configstore_api:
//: .Access
//: ----
//: const struct muos_configstore_data*
//: muos_configstore_lock (void)
//:
//: struct muos_configstore_data*
//: muos_configstore_wlock (void)
//:
//: void
//: muos_configstore_unlock (const struct muos_configstore_data** lock)
//:
//: void
//: muos_configstore_unwlock (struct muos_configstore_data** lock)
//:
//: struct muos_configstore_data*
//: muos_configstore_initial (void)
//: ----
//:
//: The configuration data implements a simple locking scheme with multiple
//: readers or a single writer. Each successful lock must be paired with a
//: unlock, no further consistency checks are made!
//:
//: Locking works only on valid data.
//:
//: There are approx. 250 read locks available. Exceeding this number makes the
//: lock fail.
//:
//: 'muos_configstore_lock ()';;
//: Checks for availability of the configstore.
//: On success it places a read lock on the configstore and returns a pointer
//: to a const 'muos_configstore_data' data structure which holds all the defined
//: elements. On failure +NULL+ is returned and one may inspect the configstore status.
//: No mutations must be made to the data.
//:
//: 'muos_configstore_wlock ()';;
//: Checks for availability of the configstore.
//: On success it places a write lock on the configstore and returns a pointer
//: to a 'muos_configstore_data' data structure which holds all the defined elements.
//: On failure +NULL+ is returned and one may inspect the configstore status.
//: The write lock blocks all other access to the configstore and may modify its contents.
//:
//: 'muos_configstore_initial ()';;
//: Works only when the configstore is 'invalid'. Places a write locks on the data which
//: must be unlocked afterwards. This is used when the configstore is uninitialized/prime
//: or damaged to populate it with defaults.
//:
//: 'muos_configstore_unlock ()' 'muos_configstore_unwlock ()';;
//: Frees the lock obtained by 'muos_configstore_lock()', 'muos_configstore_wlock()' or
//: 'muos_configstore_initial ()'. Care must be taken that lock is matched by a unlock.
//:
//:
const struct muos_configstore_data*
muos_configstore_lock (void);
void
muos_configstore_unlock (const struct muos_configstore_data** lock);
struct muos_configstore_data*
muos_configstore_wlock (void);
struct muos_configstore_data*
muos_configstore_initial (void);
static inline void
muos_configstore_unwlock (struct muos_configstore_data** lock)
{
muos_configstore_unlock ((const struct muos_configstore_data**) lock);
}
//TODO: docme
#ifdef MUOS_CONFIGSTORE_DEFAULTS
muos_error
muos_configstore_defaults (void);
#endif
// generic api
#if 0
enum muos_configstore_id
muos_configstore_lookup_id (const char* name);
size_t
muos_configstore_index (enum muos_configstore_id id);
#endif
// in ram API
// virtual API
#endif