1 /*
2  * Copyright (c) 2018-2022 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdio.h>
8 #include <zephyr/ztest.h>
9 
10 #include <zephyr/kernel.h>
11 #include <zephyr/sys/reboot.h>
12 #include <string.h>
13 
14 #include <zephyr/settings/settings.h>
15 #include <zephyr/storage/flash_map.h>
16 #include <zephyr/drivers/flash.h>
17 
18 #define TEST_PARTITION		storage_partition
19 #define CODE_PARTITION		slot0_partition
20 
21 #define TEST_PARTITION_ID	FIXED_PARTITION_ID(TEST_PARTITION)
22 
23 #define CODE_PARTITION_NODE	DT_NODELABEL(CODE_PARTITION)
24 #define CODE_PARTITION_ID	FIXED_PARTITION_ID(CODE_PARTITION)
25 #define CODE_PARTITION_EXISTS	FIXED_PARTITION_EXISTS(CODE_PARTITION)
26 
27 static uint32_t val32;
28 
29 #if defined(CONFIG_SOC_SERIES_STM32L0X) || defined(CONFIG_SOC_SERIES_STM32L0X)
30 #define ERASED_VAL 0x00
31 #else
32 #define ERASED_VAL 0xFF
33 #endif
34 
35 /* leverage that this area has to be embedded flash part */
36 #if CODE_PARTITION_EXISTS
37 #if DT_NODE_HAS_PROP(DT_GPARENT(CODE_PARTITION_NODE), write_block_size)
38 #define FLASH_WRITE_BLOCK_SIZE \
39 	DT_PROP(DT_GPARENT(CODE_PARTITION_NODE), write_block_size)
40 static const volatile __attribute__((section(".rodata")))
41 __aligned(FLASH_WRITE_BLOCK_SIZE)
42 uint8_t prepared_mark[FLASH_WRITE_BLOCK_SIZE] = {ERASED_VAL};
43 #else
44 #error "Test not prepared to run from flash with no write-block-size property in DTS"
45 #endif
46 #endif
47 
c1_set(const char * name,size_t len,settings_read_cb read_cb,void * cb_arg)48 static int c1_set(const char *name, size_t len, settings_read_cb read_cb,
49 		  void *cb_arg)
50 {
51 	int rc;
52 	const char *next;
53 
54 	if (settings_name_steq(name, "val32", &next) && !next) {
55 		rc = read_cb(cb_arg, &val32, sizeof(val32));
56 		zassert_true(rc >= 0, "SETTINGS_VALUE_SET callback");
57 		return 0;
58 	}
59 
60 	return -ENOENT;
61 }
62 
c1_export(int (* export_func)(const char * name,const void * value,size_t val_len))63 static int c1_export(int (*export_func)(const char *name,
64 					const void *value, size_t val_len))
65 {
66 	(void)export_func("hello/val32", &val32, sizeof(val32));
67 
68 	return 0;
69 }
70 
71 static struct settings_handler c1_settings = {
72 	.name = "hello",
73 	.h_set = c1_set,
74 	.h_export = c1_export,
75 };
76 
ZTEST(fcb_initialization,test_init)77 ZTEST(fcb_initialization, test_init)
78 {
79 	int err;
80 	uint32_t prev_int;
81 
82 	val32++;
83 
84 	err = settings_save();
85 	zassert_true(err == 0, "can't save settings");
86 
87 	prev_int = val32;
88 	val32 = 0U;
89 	err = settings_load();
90 	zassert_true(err == 0, "can't load settings");
91 	zassert_equal(prev_int, val32,
92 		      "load value doesn't match to what was saved");
93 }
94 
95 
test_prepare_storage(void)96 void test_prepare_storage(void)
97 {
98 #if CODE_PARTITION_EXISTS
99 /* This procedure uses mark which is stored inside SoC embedded program
100  * flash. It will not work on devices on which read/write to them is not
101  * possible.
102  */
103 	int err;
104 	const struct flash_area *fa;
105 	const struct device *dev;
106 	uint8_t new_val[FLASH_WRITE_BLOCK_SIZE];
107 
108 	if (prepared_mark[0] == ERASED_VAL) {
109 		TC_PRINT("First run: erasing the storage\r\n");
110 		err = flash_area_open(TEST_PARTITION_ID, &fa);
111 		zassert_true(err == 0, "Can't open storage flash area");
112 
113 		err = flash_area_flatten(fa, 0, fa->fa_size);
114 		zassert_true(err == 0, "Can't erase storage flash area");
115 
116 		err = flash_area_open(CODE_PARTITION_ID, &fa);
117 		zassert_true(err == 0, "Can't open storage flash area");
118 
119 		dev = flash_area_get_device(fa);
120 
121 		(void)memset(new_val, (~ERASED_VAL) & 0xFF,
122 			     FLASH_WRITE_BLOCK_SIZE);
123 		err = flash_write(dev, (off_t)&prepared_mark, &new_val,
124 				  sizeof(new_val));
125 		zassert_true(err == 0, "can't write prepared_mark");
126 	}
127 #else
128 	TC_PRINT("Storage preparation can't be performed\r\n");
129 	TC_PRINT("Erase storage manually before test flashing\r\n");
130 #endif
131 }
132 
test_init_setup(void)133 void *test_init_setup(void)
134 {
135 	int err;
136 
137 	test_prepare_storage();
138 
139 	err = settings_subsys_init();
140 	zassert_true(err == 0, "subsys init failed");
141 
142 	err = settings_register(&c1_settings);
143 	zassert_true(err == 0, "can't register the settings handler");
144 
145 	err = settings_load();
146 	zassert_true(err == 0, "can't load settings");
147 
148 	if (val32 < 1) {
149 		val32 = 1U;
150 		err = settings_save();
151 		zassert_true(err == 0, "can't save settings");
152 		k_sleep(K_MSEC(250));
153 		sys_reboot(SYS_REBOOT_COLD);
154 	}
155 	return NULL;
156 }
157 
158 ZTEST_SUITE(fcb_initialization, NULL, test_init_setup, NULL, NULL, NULL);
159