1 /*
2 * Copyright (c) 2024 BayLibre SAS
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * ZMS Sample for Zephyr using high level API.
7 *
8 */
9
10 #include <zephyr/kernel.h>
11 #include <zephyr/sys/reboot.h>
12 #include <zephyr/device.h>
13 #include <string.h>
14 #include <zephyr/drivers/flash.h>
15 #include <zephyr/storage/flash_map.h>
16 #include <zephyr/fs/zms.h>
17
18 static struct zms_fs fs;
19
20 #define ZMS_PARTITION storage_partition
21 #define ZMS_PARTITION_DEVICE FIXED_PARTITION_DEVICE(ZMS_PARTITION)
22 #define ZMS_PARTITION_OFFSET FIXED_PARTITION_OFFSET(ZMS_PARTITION)
23
24 #define IP_ADDRESS_ID 1
25 #define KEY_VALUE_ID 0xbeefdead
26 #define CNT_ID 2
27 #define LONG_DATA_ID 3
28
delete_and_verify_items(struct zms_fs * fs,uint32_t id)29 static int delete_and_verify_items(struct zms_fs *fs, uint32_t id)
30 {
31 int rc = 0;
32
33 rc = zms_delete(fs, id);
34 if (rc) {
35 goto error1;
36 }
37 rc = zms_get_data_length(fs, id);
38 if (rc > 0) {
39 goto error2;
40 }
41
42 return 0;
43 error1:
44 printk("Error while deleting item rc=%d\n", rc);
45 return rc;
46 error2:
47 printk("Error, Delete failed item should not be present\n");
48 return -1;
49 }
50
delete_basic_items(struct zms_fs * fs)51 static int delete_basic_items(struct zms_fs *fs)
52 {
53 int rc = 0;
54
55 rc = delete_and_verify_items(fs, IP_ADDRESS_ID);
56 if (rc) {
57 printk("Error while deleting item %x rc=%d\n", IP_ADDRESS_ID, rc);
58 return rc;
59 }
60 rc = delete_and_verify_items(fs, KEY_VALUE_ID);
61 if (rc) {
62 printk("Error while deleting item %x rc=%d\n", KEY_VALUE_ID, rc);
63 return rc;
64 }
65 rc = delete_and_verify_items(fs, CNT_ID);
66 if (rc) {
67 printk("Error while deleting item %x rc=%d\n", CNT_ID, rc);
68 return rc;
69 }
70 rc = delete_and_verify_items(fs, LONG_DATA_ID);
71 if (rc) {
72 printk("Error while deleting item %x rc=%d\n", LONG_DATA_ID, rc);
73 }
74
75 return rc;
76 }
77
main(void)78 int main(void)
79 {
80 int rc = 0;
81 char buf[16];
82 uint8_t key[8] = {0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF}, longarray[128];
83 uint32_t i_cnt = 0U;
84 uint32_t i;
85 uint32_t id = 0;
86 ssize_t free_space = 0;
87 struct flash_pages_info info;
88
89 for (int n = 0; n < sizeof(longarray); n++) {
90 longarray[n] = n;
91 }
92
93 /* define the zms file system by settings with:
94 * sector_size equal to the pagesize,
95 * 3 sectors
96 * starting at ZMS_PARTITION_OFFSET
97 */
98 fs.flash_device = ZMS_PARTITION_DEVICE;
99 if (!device_is_ready(fs.flash_device)) {
100 printk("Storage device %s is not ready\n", fs.flash_device->name);
101 return 0;
102 }
103 fs.offset = ZMS_PARTITION_OFFSET;
104 rc = flash_get_page_info_by_offs(fs.flash_device, fs.offset, &info);
105 if (rc) {
106 printk("Unable to get page info, rc=%d\n", rc);
107 return 0;
108 }
109 fs.sector_size = info.size;
110 fs.sector_count = 3U;
111
112 for (i = 0; i < CONFIG_MAX_ITERATIONS; i++) {
113 rc = zms_mount(&fs);
114 if (rc) {
115 printk("Storage Init failed, rc=%d\n", rc);
116 return 0;
117 }
118
119 printk("ITERATION: %u\n", i);
120 /* IP_ADDRESS_ID is used to store an address, lets see if we can
121 * read it from flash, since we don't know the size read the
122 * maximum possible
123 */
124 rc = zms_read(&fs, IP_ADDRESS_ID, &buf, sizeof(buf));
125 if (rc > 0) {
126 /* item was found, show it */
127 buf[rc] = '\0';
128 printk("ID: %u, IP Address: %s\n", IP_ADDRESS_ID, buf);
129 }
130 /* Rewriting ADDRESS IP even if we found it */
131 strncpy(buf, "172.16.254.1", sizeof(buf) - 1);
132 printk("Adding IP_ADDRESS %s at id %u\n", buf, IP_ADDRESS_ID);
133 rc = zms_write(&fs, IP_ADDRESS_ID, &buf, strlen(buf));
134 if (rc < 0) {
135 printk("Error while writing Entry rc=%d\n", rc);
136 break;
137 }
138
139 /* KEY_VALUE_ID is used to store a key/value pair , lets see if we can read
140 * it from storage.
141 */
142 rc = zms_read(&fs, KEY_VALUE_ID, &key, sizeof(key));
143 if (rc > 0) { /* item was found, show it */
144 printk("Id: %x, Key: ", KEY_VALUE_ID);
145 for (uint8_t n = 0; n < 8; n++) {
146 printk("%x ", key[n]);
147 }
148 printk("\n");
149 }
150 /* Rewriting KEY_VALUE even if we found it */
151 printk("Adding key/value at id %x\n", KEY_VALUE_ID);
152 rc = zms_write(&fs, KEY_VALUE_ID, &key, sizeof(key));
153 if (rc < 0) {
154 printk("Error while writing Entry rc=%d\n", rc);
155 break;
156 }
157
158 /* CNT_ID is used to store the loop counter, lets see
159 * if we can read it from storage
160 */
161 rc = zms_read(&fs, CNT_ID, &i_cnt, sizeof(i_cnt));
162 if (rc > 0) { /* item was found, show it */
163 printk("Id: %d, loop_cnt: %u\n", CNT_ID, i_cnt);
164 if ((i > 0) && (i_cnt != (i - 1))) {
165 printk("Error loop_cnt %u must be %d\n", i_cnt, i - 1);
166 break;
167 }
168 }
169 printk("Adding counter at id %u\n", CNT_ID);
170 rc = zms_write(&fs, CNT_ID, &i, sizeof(i));
171 if (rc < 0) {
172 printk("Error while writing Entry rc=%d\n", rc);
173 break;
174 }
175
176 /* LONG_DATA_ID is used to store a larger dataset ,lets see if we can read
177 * it from flash
178 */
179 rc = zms_read(&fs, LONG_DATA_ID, &longarray, sizeof(longarray));
180 if (rc > 0) {
181 /* item was found, show it */
182 printk("Id: %d, Longarray: ", LONG_DATA_ID);
183 for (uint16_t n = 0; n < sizeof(longarray); n++) {
184 printk("%x ", longarray[n]);
185 }
186 printk("\n");
187 }
188 /* Rewrite the entry even if we found it */
189 printk("Adding Longarray at id %d\n", LONG_DATA_ID);
190 rc = zms_write(&fs, LONG_DATA_ID, &longarray, sizeof(longarray));
191 if (rc < 0) {
192 printk("Error while writing Entry rc=%d\n", rc);
193 break;
194 }
195
196 /* Each CONFIG_DELETE_ITERATION delete all basic items */
197 if (!(i % CONFIG_DELETE_ITERATION) && (i)) {
198 rc = delete_basic_items(&fs);
199 if (rc) {
200 break;
201 }
202 }
203 }
204
205 if (i != CONFIG_MAX_ITERATIONS) {
206 printk("Error: Something went wrong at iteration %u rc=%d\n", i, rc);
207 return 0;
208 }
209
210 while (1) {
211 /* fill all storage */
212 rc = zms_write(&fs, id, &id, sizeof(uint32_t));
213 if (rc < 0) {
214 break;
215 }
216 id++;
217 }
218
219 if (rc == -ENOSPC) {
220 /* Calculate free space and verify that it is 0 */
221 free_space = zms_calc_free_space(&fs);
222 if (free_space < 0) {
223 printk("Error while computing free space, rc=%d\n", free_space);
224 return 0;
225 }
226 if (free_space > 0) {
227 printk("Error: free_space should be 0, computed %u\n", free_space);
228 return 0;
229 }
230 printk("Memory is full let's delete all items\n");
231
232 /* Now delete all previously written items */
233 for (uint32_t n = 0; n < id; n++) {
234 rc = delete_and_verify_items(&fs, n);
235 if (rc) {
236 printk("Error deleting at id %u\n", n);
237 return 0;
238 }
239 }
240 rc = delete_basic_items(&fs);
241 if (rc) {
242 printk("Error deleting basic items\n");
243 return 0;
244 }
245 }
246
247 /*
248 * Let's compute free space in storage. But before doing that let's Garbage collect
249 * all sectors where we deleted all entries and then compute the free space
250 */
251 for (i = 0; i < fs.sector_count; i++) {
252 rc = zms_sector_use_next(&fs);
253 if (rc) {
254 printk("Error while changing sector rc=%d\n", rc);
255 }
256 }
257 free_space = zms_calc_free_space(&fs);
258 if (free_space < 0) {
259 printk("Error while computing free space, rc=%d\n", free_space);
260 return 0;
261 }
262 printk("Free space in storage is %u bytes\n", free_space);
263
264 /* Let's clean the storage now */
265 rc = zms_clear(&fs);
266 if (rc < 0) {
267 printk("Error while cleaning the storage, rc=%d\n", rc);
268 }
269
270 printk("Sample code finished Successfully\n");
271
272 return 0;
273 }
274