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