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