1 /*
2 * Copyright (c) 2019 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdio.h>
8 #include <string.h>
9
10 #include <zephyr/settings/settings.h>
11
12 #include <errno.h>
13 #include <zephyr/sys/printk.h>
14
15 #if defined(CONFIG_SETTINGS_FILE)
16 #include <zephyr/fs/fs.h>
17 #include <zephyr/fs/littlefs.h>
18 #endif
19
20 #define STORAGE_PARTITION storage_partition
21 #define STORAGE_PARTITION_ID FIXED_PARTITION_ID(STORAGE_PARTITION)
22
23 #define GAMMA_DEFAULT_VAl 0
24 #define FAIL_MSG "fail (err %d)\n"
25 #define SECTION_BEGIN_LINE \
26 "\n=================================================\n"
27 /* Default values are assigned to settings values consuments
28 * All of them will be overwritten if storage contain proper key-values
29 */
30 uint8_t angle_val;
31 uint64_t length_val = 100;
32 uint16_t length_1_val = 40;
33 uint32_t length_2_val = 60;
34 int32_t voltage_val = -3000;
35 char source_name_val[6] = "";
36
37 int alpha_handle_set(const char *name, size_t len, settings_read_cb read_cb,
38 void *cb_arg);
39 int alpha_handle_commit(void);
40 int alpha_handle_export(int (*cb)(const char *name,
41 const void *value, size_t val_len));
42
43 int beta_handle_set(const char *name, size_t len, settings_read_cb read_cb,
44 void *cb_arg);
45 int beta_handle_commit(void);
46 int beta_handle_export(int (*cb)(const char *name,
47 const void *value, size_t val_len));
48 int beta_handle_get(const char *name, char *val, int val_len_max);
49
50 /* dynamic main tree handler */
51 struct settings_handler alph_handler = {
52 .name = "alpha",
53 .h_get = NULL,
54 .h_set = alpha_handle_set,
55 .h_commit = alpha_handle_commit,
56 .h_export = alpha_handle_export
57 };
58
59 /* static subtree handler */
60 SETTINGS_STATIC_HANDLER_DEFINE(beta, "alpha/beta", beta_handle_get,
61 beta_handle_set, beta_handle_commit,
62 beta_handle_export);
63
alpha_handle_set(const char * name,size_t len,settings_read_cb read_cb,void * cb_arg)64 int alpha_handle_set(const char *name, size_t len, settings_read_cb read_cb,
65 void *cb_arg)
66 {
67 const char *next;
68 size_t next_len;
69 int rc;
70
71 if (settings_name_steq(name, "angle/1", &next) && !next) {
72 if (len != sizeof(angle_val)) {
73 return -EINVAL;
74 }
75 rc = read_cb(cb_arg, &angle_val, sizeof(angle_val));
76 printk("<alpha/angle/1> = %d\n", angle_val);
77 return 0;
78 }
79
80 next_len = settings_name_next(name, &next);
81
82 if (!next) {
83 return -ENOENT;
84 }
85
86 if (!strncmp(name, "length", next_len)) {
87 next_len = settings_name_next(name, &next);
88
89 if (!next) {
90 rc = read_cb(cb_arg, &length_val, sizeof(length_val));
91 printk("<alpha/length> = %" PRId64 "\n", length_val);
92 return 0;
93 }
94
95 if (!strncmp(next, "1", next_len)) {
96 rc = read_cb(cb_arg, &length_1_val,
97 sizeof(length_1_val));
98 printk("<alpha/length/1> = %d\n", length_1_val);
99 return 0;
100 }
101
102 if (!strncmp(next, "2", next_len)) {
103 rc = read_cb(cb_arg, &length_2_val,
104 sizeof(length_2_val));
105 printk("<alpha/length/2> = %d\n", length_2_val);
106 return 0;
107 }
108
109 return -ENOENT;
110 }
111
112 return -ENOENT;
113 }
114
beta_handle_set(const char * name,size_t len,settings_read_cb read_cb,void * cb_arg)115 int beta_handle_set(const char *name, size_t len, settings_read_cb read_cb,
116 void *cb_arg)
117 {
118 const char *next;
119 size_t name_len;
120 int rc;
121
122 name_len = settings_name_next(name, &next);
123
124 if (!next) {
125 if (!strncmp(name, "voltage", name_len)) {
126 rc = read_cb(cb_arg, &voltage_val, sizeof(voltage_val));
127 printk("<alpha/beta/voltage> = %d\n", voltage_val);
128 return 0;
129 }
130
131 if (!strncmp(name, "source", name_len)) {
132 if (len > sizeof(source_name_val) - 1) {
133 printk("<alpha/beta/source> is not compatible "
134 "with the application\n");
135 return -EINVAL;
136 }
137 rc = read_cb(cb_arg, source_name_val,
138 sizeof(source_name_val));
139 if (rc < 0) {
140 return rc;
141 } else if (rc > 0) {
142 printk("<alpha/beta/source> = %s\n",
143 source_name_val);
144 }
145 return 0;
146 }
147 }
148
149 return -ENOENT;
150 }
151
alpha_handle_commit(void)152 int alpha_handle_commit(void)
153 {
154 printk("loading all settings under <alpha> handler is done\n");
155 return 0;
156 }
157
alpha_handle_export(int (* cb)(const char * name,const void * value,size_t val_len))158 int alpha_handle_export(int (*cb)(const char *name,
159 const void *value, size_t val_len))
160 {
161 printk("export keys under <alpha> handler\n");
162 (void)cb("alpha/angle/1", &angle_val, sizeof(angle_val));
163 (void)cb("alpha/length", &length_val, sizeof(length_val));
164 (void)cb("alpha/length/1", &length_1_val, sizeof(length_1_val));
165 (void)cb("alpha/length/2", &length_2_val, sizeof(length_2_val));
166
167 return 0;
168 }
169
beta_handle_export(int (* cb)(const char * name,const void * value,size_t val_len))170 int beta_handle_export(int (*cb)(const char *name,
171 const void *value, size_t val_len))
172 {
173 printk("export keys under <beta> handler\n");
174 (void)cb("alpha/beta/voltage", &voltage_val, sizeof(voltage_val));
175 (void)cb("alpha/beta/source", source_name_val, strlen(source_name_val) +
176 1);
177
178 return 0;
179 }
180
beta_handle_commit(void)181 int beta_handle_commit(void)
182 {
183 printk("loading all settings under <beta> handler is done\n");
184 return 0;
185 }
186
beta_handle_get(const char * name,char * val,int val_len_max)187 int beta_handle_get(const char *name, char *val, int val_len_max)
188 {
189 const char *next;
190
191 if (settings_name_steq(name, "source", &next) && !next) {
192 val_len_max = MIN(val_len_max, strlen(source_name_val));
193 memcpy(val, source_name_val, val_len_max);
194 return val_len_max;
195 }
196
197 return -ENOENT;
198 }
199
example_save_and_load_basic(void)200 static void example_save_and_load_basic(void)
201 {
202 int i, rc;
203 int32_t val_s32;
204
205 printk(SECTION_BEGIN_LINE);
206 printk("basic load and save using registered handlers\n");
207 /* load all key-values at once
208 * In case a key-value doesn't exist in the storage
209 * default values should be assigned to settings consuments variable
210 * before any settings load call
211 */
212 printk("\nload all key-value pairs using registered handlers\n");
213 settings_load();
214
215 val_s32 = voltage_val - 25;
216 /* save certain key-value directly*/
217 printk("\nsave <alpha/beta/voltage> key directly: ");
218 rc = settings_save_one("alpha/beta/voltage", (const void *)&val_s32,
219 sizeof(val_s32));
220 if (rc) {
221 printk(FAIL_MSG, rc);
222 }
223
224 printk("OK.\n");
225
226 printk("\nload <alpha/beta> key-value pairs using registered "
227 "handlers\n");
228 settings_load_subtree("alpha/beta");
229
230 /* save only modified values
231 * or those that were not saved
232 * before
233 */
234 i = strlen(source_name_val);
235 if (i < sizeof(source_name_val) - 1) {
236 source_name_val[i] = 'a' + i;
237 source_name_val[i + 1] = 0;
238 } else {
239 source_name_val[0] = 0;
240 }
241
242 angle_val += 1;
243
244 printk("\nsave all key-value pairs using registered handlers\n");
245 settings_save();
246
247 if (++length_1_val > 100) {
248 length_1_val = 0;
249 }
250
251 if (--length_2_val > 100) {
252 length_2_val = 100;
253 }
254
255 /*---------------------------
256 * save only modified values
257 * or those that were deleted
258 * before
259 */
260 printk("\nload all key-value pairs using registered handlers\n");
261 settings_save();
262 }
263
264 struct direct_length_data {
265 uint64_t length;
266 uint16_t length_1;
267 uint32_t length_2;
268 };
269
direct_loader(const char * name,size_t len,settings_read_cb read_cb,void * cb_arg,void * param)270 static int direct_loader(const char *name, size_t len, settings_read_cb read_cb,
271 void *cb_arg, void *param)
272 {
273 const char *next;
274 size_t name_len;
275 int rc;
276 struct direct_length_data *dest = (struct direct_length_data *)param;
277
278 printk("direct load: ");
279
280 name_len = settings_name_next(name, &next);
281
282 if (name_len == 0) {
283 rc = read_cb(cb_arg, &(dest->length), sizeof(dest->length));
284 printk("<alpha/length>\n");
285 return 0;
286 }
287
288 name_len = settings_name_next(name, &next);
289 if (next) {
290 printk("nothing\n");
291 return -ENOENT;
292 }
293
294 if (!strncmp(name, "1", name_len)) {
295 rc = read_cb(cb_arg, &(dest->length_1), sizeof(dest->length_1));
296 printk("<alpha/length/1>\n");
297 return 0;
298 }
299
300 if (!strncmp(name, "2", name_len)) {
301 rc = read_cb(cb_arg, &(dest->length_2), sizeof(dest->length_2));
302 printk("<alpha/length/2>\n");
303 return 0;
304 }
305
306 printk("nothing\n");
307 return -ENOENT;
308 }
309
example_direct_load_subtree(void)310 static void example_direct_load_subtree(void)
311 {
312 struct direct_length_data dld;
313 int rc;
314
315 /* load subtree directly using call-specific handler `direct_loader'
316 * This handler loads subtree values to call-specific structure of type
317 * 'direct_length_data`.
318 */
319 printk(SECTION_BEGIN_LINE);
320 printk("loading subtree to destination provided by the caller\n\n");
321 rc = settings_load_subtree_direct("alpha/length", direct_loader,
322 (void *)&dld);
323 if (rc == 0) {
324 printk(" direct.length = %" PRId64 "\n", dld.length);
325 printk(" direct.length_1 = %d\n", dld.length_1);
326 printk(" direct.length_2 = %d\n", dld.length_2);
327 } else {
328 printk(" direct load fails unexpectedly\n");
329 }
330 }
331
332 struct direct_immediate_value {
333 size_t len;
334 void *dest;
335 uint8_t fetched;
336 };
337
direct_loader_immediate_value(const char * name,size_t len,settings_read_cb read_cb,void * cb_arg,void * param)338 static int direct_loader_immediate_value(const char *name, size_t len,
339 settings_read_cb read_cb, void *cb_arg,
340 void *param)
341 {
342 const char *next;
343 size_t name_len;
344 int rc;
345 struct direct_immediate_value *one_value =
346 (struct direct_immediate_value *)param;
347
348 name_len = settings_name_next(name, &next);
349
350 if (name_len == 0) {
351 if (len == one_value->len) {
352 rc = read_cb(cb_arg, one_value->dest, len);
353 if (rc >= 0) {
354 one_value->fetched = 1;
355 printk("immediate load: OK.\n");
356 return 0;
357 }
358
359 printk(FAIL_MSG, rc);
360 return rc;
361 }
362 return -EINVAL;
363 }
364
365 /* other keys aren't served by the callback
366 * Return success in order to skip them
367 * and keep storage processing.
368 */
369 return 0;
370 }
371
load_immediate_value(const char * name,void * dest,size_t len)372 int load_immediate_value(const char *name, void *dest, size_t len)
373 {
374 int rc;
375 struct direct_immediate_value dov;
376
377 dov.fetched = 0;
378 dov.len = len;
379 dov.dest = dest;
380
381 rc = settings_load_subtree_direct(name, direct_loader_immediate_value,
382 (void *)&dov);
383 if (rc == 0) {
384 if (!dov.fetched) {
385 rc = -ENOENT;
386 }
387 }
388
389 return rc;
390 }
391
example_without_handler(void)392 static void example_without_handler(void)
393 {
394 uint8_t val_u8;
395 int rc;
396
397 printk(SECTION_BEGIN_LINE);
398 printk("Service a key-value pair without dedicated handlers\n\n");
399 rc = load_immediate_value("gamma", &val_u8, sizeof(val_u8));
400 if (rc == -ENOENT) {
401 val_u8 = GAMMA_DEFAULT_VAl;
402 printk("<gamma> = %d (default)\n", val_u8);
403 } else if (rc == 0) {
404 printk("<gamma> = %d\n", val_u8);
405 } else {
406 printk("unexpected"FAIL_MSG, rc);
407 }
408
409 val_u8++;
410
411 printk("save <gamma> key directly: ");
412 rc = settings_save_one("gamma", (const void *)&val_u8,
413 sizeof(val_u8));
414 if (rc) {
415 printk(FAIL_MSG, rc);
416 } else {
417 printk("OK.\n");
418 }
419 }
420
example_initialization(void)421 static void example_initialization(void)
422 {
423 int rc;
424
425 #if defined(CONFIG_SETTINGS_FILE)
426 FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(cstorage);
427
428 /* mounting info */
429 static struct fs_mount_t littlefs_mnt = {
430 .type = FS_LITTLEFS,
431 .fs_data = &cstorage,
432 .storage_dev = (void *)STORAGE_PARTITION_ID,
433 .mnt_point = "/ff"
434 };
435
436 rc = fs_mount(&littlefs_mnt);
437 if (rc != 0) {
438 printk("mounting littlefs error: [%d]\n", rc);
439 } else {
440
441 rc = fs_unlink(CONFIG_SETTINGS_FILE_PATH);
442 if ((rc != 0) && (rc != -ENOENT)) {
443 printk("can't delete config file%d\n", rc);
444 } else {
445 printk("FS initialized: OK\n");
446 }
447 }
448 #endif
449
450 rc = settings_subsys_init();
451 if (rc) {
452 printk("settings subsys initialization: fail (err %d)\n", rc);
453 return;
454 }
455
456 printk("settings subsys initialization: OK.\n");
457
458 rc = settings_register(&alph_handler);
459 if (rc) {
460 printk("subtree <%s> handler registered: fail (err %d)\n",
461 alph_handler.name, rc);
462 }
463
464 printk("subtree <%s> handler registered: OK\n", alph_handler.name);
465 printk("subtree <alpha/beta> has static handler\n");
466 }
467
example_delete(void)468 static void example_delete(void)
469 {
470 uint64_t val_u64;
471 int rc;
472
473 printk(SECTION_BEGIN_LINE);
474 printk("Delete a key-value pair\n\n");
475
476 rc = load_immediate_value("alpha/length", &val_u64, sizeof(val_u64));
477 if (rc == 0) {
478 printk(" <alpha/length> value exist in the storage\n");
479 }
480
481 printk("delete <alpha/length>: ");
482 rc = settings_delete("alpha/length");
483 if (rc) {
484 printk(FAIL_MSG, rc);
485 } else {
486 printk("OK.\n");
487 }
488
489 rc = load_immediate_value("alpha/length", &val_u64, sizeof(val_u64));
490 if (rc == -ENOENT) {
491 printk(" Can't to load the <alpha/length> value as "
492 "expected\n");
493 }
494 }
495
example_runtime_usage(void)496 void example_runtime_usage(void)
497 {
498 int rc;
499 uint8_t injected_str[sizeof(source_name_val)] = "RT";
500
501 printk(SECTION_BEGIN_LINE);
502 printk("Inject the value to the setting destination in runtime\n\n");
503
504 rc = settings_runtime_set("alpha/beta/source", (void *) injected_str,
505 strlen(injected_str) + 1);
506
507 printk("injected <alpha/beta/source>: ");
508 if (rc) {
509 printk(FAIL_MSG, rc);
510 } else {
511 printk("OK.\n");
512 }
513
514 printk(" The settings destination off the key <alpha/beta/source> has "
515 "got value: \"%s\"\n\n", source_name_val);
516
517 /* set settings destination value "by hand" for next example */
518 (void) strcpy(source_name_val, "rtos");
519
520 printk(SECTION_BEGIN_LINE);
521 printk("Read a value from the setting destination in runtime\n\n");
522
523 rc = settings_runtime_get("alpha/beta/source", (void *) injected_str,
524 strlen(injected_str) + 1);
525 printk("fetched <alpha/beta/source>: ");
526 if (rc < 0) {
527 printk(FAIL_MSG, rc);
528 } else {
529 printk("OK.\n");
530 }
531
532 printk(" String value \"%s\" was retrieved from the settings "
533 "destination off the key <alpha/beta/source>\n",
534 source_name_val);
535 }
536
main(void)537 int main(void)
538 {
539
540 int i;
541
542 printk("\n*** Settings usage example ***\n\n");
543
544 /* settings initialization */
545 example_initialization();
546
547 for (i = 0; i < 6; i++) {
548 printk("\n##############\n");
549 printk("# iteration %d", i);
550 printk("\n##############\n");
551
552 /*---------------------------------------------
553 * basic save and load using registered handler
554 */
555 example_save_and_load_basic();
556
557 /*-------------------------------------------------
558 *load subtree directly using call-specific handler
559 */
560 example_direct_load_subtree();
561
562 /*-------------------------
563 * delete certain key-value
564 */
565 example_delete();
566
567 /*---------------------------------------
568 * a key-value without dedicated handler
569 */
570 example_without_handler();
571 }
572
573 /*------------------------------------------------------
574 * write and read settings destination using runtime API
575 */
576 example_runtime_usage();
577
578 printk("\n*** THE END ***\n");
579 return 0;
580 }
581