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