Skip to content

Commit 5bebbbf

Browse files
rghaddabgithub-actions[bot]
authored andcommitted
[nrf fromtree] samples: fs: zms: add a sample app for ZMS storage system
This adds a user application that shows the usage of ZMS The sample app shows three main functions of ZMS: - read/write/delete key/value pairs - fill all storage and delete it - calculate free remaining space Signed-off-by: Riadh Ghaddab <[email protected]> (cherry picked from commit fb7dae7) (cherry picked from commit 7584f50)
1 parent d4c1e9b commit 5bebbbf

File tree

5 files changed

+388
-0
lines changed

5 files changed

+388
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.20.0)
4+
5+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
6+
project(zms)
7+
8+
9+
target_sources(app PRIVATE src/main.c)
10+
target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/fs/zms)

samples/subsys/fs/zms/README.rst

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
.. zephyr:code-sample:: zms
2+
:name: Zephyr Memory Storage (ZMS)
3+
:relevant-api: zms_high_level_api
4+
5+
Store and retrieve data from storage using the ZMS API.
6+
7+
Overview
8+
********
9+
The sample shows how to use ZMS to store ID/VALUE pairs and reads them back.
10+
Deleting an ID/VALUE pair is also shown in this sample.
11+
12+
The sample stores the following items:
13+
14+
#. A string representing an IP address: stored at id=1, data="192.168.1.1"
15+
#. A binary blob representing a key/value pair: stored at id=0xbeefdead,
16+
data={0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF}
17+
#. A variable (32bit): stored at id=2, data=cnt
18+
#. A long set of data (128 bytes)
19+
20+
A loop is executed where we mount the storage system, and then write all set
21+
of data.
22+
23+
Each DELETE_ITERATION period, we delete all set of data and verify that it has been deleted.
24+
We generate as well incremented ID/value pairs, we store them until storage is full, then we
25+
delete them and verify that storage is empty.
26+
27+
Requirements
28+
************
29+
30+
* A board with flash support or native_sim target
31+
32+
Building and Running
33+
********************
34+
35+
This sample can be found under :zephyr_file:`samples/subsys/fs/zms` in the Zephyr tree.
36+
37+
The sample can be built for several platforms, but for the moment it has been tested only
38+
on native_sim target
39+
40+
.. zephyr-app-commands::
41+
:zephyr-app: samples/subsys/fs/zms
42+
:goals: build
43+
:compact:
44+
45+
After running the generated image on a native_sim target, the output on the console shows the
46+
multiple Iterations of read/write/delete exectuted.
47+
48+
Sample Output
49+
=============
50+
51+
.. code-block:: console
52+
53+
*** Booting Zephyr OS build v3.7.0-2383-g624f75400242 ***
54+
[00:00:00.000,000] <inf> fs_zms: 3 Sectors of 4096 bytes
55+
[00:00:00.000,000] <inf> fs_zms: alloc wra: 0, fc0
56+
[00:00:00.000,000] <inf> fs_zms: data wra: 0, 0
57+
ITERATION: 0
58+
Adding IP_ADDRESS 172.16.254.1 at id 1
59+
Adding key/value at id beefdead
60+
Adding counter at id 2
61+
Adding Longarray at id 3
62+
[00:00:00.000,000] <inf> fs_zms: 3 Sectors of 4096 bytes
63+
[00:00:00.000,000] <inf> fs_zms: alloc wra: 0, f80
64+
[00:00:00.000,000] <inf> fs_zms: data wra: 0, 8c
65+
ITERATION: 1
66+
ID: 1, IP Address: 172.16.254.1
67+
Adding IP_ADDRESS 172.16.254.1 at id 1
68+
Id: beefdead, Key: de ad be ef de ad be ef
69+
Adding key/value at id beefdead
70+
Id: 2, loop_cnt: 0
71+
Adding counter at id 2
72+
Id: 3, Longarray: 0 1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 5
73+
4 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f
74+
Adding Longarray at id 3
75+
.
76+
.
77+
.
78+
.
79+
.
80+
.
81+
[00:00:00.000,000] <inf> fs_zms: 3 Sectors of 4096 bytes
82+
[00:00:00.000,000] <inf> fs_zms: alloc wra: 0, f40
83+
[00:00:00.000,000] <inf> fs_zms: data wra: 0, 80
84+
ITERATION: 299
85+
ID: 1, IP Address: 172.16.254.1
86+
Adding IP_ADDRESS 172.16.254.1 at id 1
87+
Id: beefdead, Key: de ad be ef de ad be ef
88+
Adding key/value at id beefdead
89+
Id: 2, loop_cnt: 298
90+
Adding counter at id 2
91+
Id: 3, Longarray: 0 1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 5
92+
4 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f
93+
Adding Longarray at id 3
94+
Memory is full let's delete all items
95+
Free space in storage is 8064 bytes
96+
Sample code finished Successfully

samples/subsys/fs/zms/prj.conf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CONFIG_FLASH=y
2+
CONFIG_FLASH_MAP=y
3+
4+
CONFIG_ZMS=y
5+
CONFIG_LOG=y

samples/subsys/fs/zms/sample.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
sample:
2+
name: ZMS Sample
3+
4+
tests:
5+
sample.zms.basic:
6+
tags: zms
7+
depends_on: zms
8+
platform_allow:
9+
- qemu_x86
10+
- native_posix

samples/subsys/fs/zms/src/main.c

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
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+
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+
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+
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, i;
87+
uint32_t id = 0;
88+
ssize_t free_space = 0;
89+
struct flash_pages_info info;
90+
91+
for (int n = 0; n < sizeof(longarray); n++) {
92+
longarray[n] = n;
93+
}
94+
95+
/* define the zms file system by settings with:
96+
* sector_size equal to the pagesize,
97+
* 3 sectors
98+
* starting at ZMS_PARTITION_OFFSET
99+
*/
100+
fs.flash_device = ZMS_PARTITION_DEVICE;
101+
if (!device_is_ready(fs.flash_device)) {
102+
printk("Storage device %s is not ready\n", fs.flash_device->name);
103+
return 0;
104+
}
105+
fs.offset = ZMS_PARTITION_OFFSET;
106+
rc = flash_get_page_info_by_offs(fs.flash_device, fs.offset, &info);
107+
if (rc) {
108+
printk("Unable to get page info, rc=%d\n", rc);
109+
return 0;
110+
}
111+
fs.sector_size = info.size;
112+
fs.sector_count = 3U;
113+
114+
for (i = 0; i < MAX_ITERATIONS; i++) {
115+
rc = zms_mount(&fs);
116+
if (rc) {
117+
printk("Storage Init failed, rc=%d\n", rc);
118+
return 0;
119+
}
120+
121+
printk("ITERATION: %u\n", i);
122+
/* IP_ADDRESS_ID is used to store an address, lets see if we can
123+
* read it from flash, since we don't know the size read the
124+
* maximum possible
125+
*/
126+
rc = zms_read(&fs, IP_ADDRESS_ID, &buf, sizeof(buf));
127+
if (rc > 0) {
128+
/* item was found, show it */
129+
buf[rc] = '\0';
130+
printk("ID: %u, IP Address: %s\n", IP_ADDRESS_ID, buf);
131+
}
132+
/* Rewriting ADDRESS IP even if we found it */
133+
strncpy(buf, "172.16.254.1", sizeof(buf) - 1);
134+
printk("Adding IP_ADDRESS %s at id %u\n", buf, IP_ADDRESS_ID);
135+
rc = zms_write(&fs, IP_ADDRESS_ID, &buf, strlen(buf));
136+
if (rc < 0) {
137+
printk("Error while writing Entry rc=%d\n", rc);
138+
break;
139+
}
140+
141+
/* KEY_VALUE_ID is used to store a key/value pair , lets see if we can read
142+
* it from storage.
143+
*/
144+
rc = zms_read(&fs, KEY_VALUE_ID, &key, sizeof(key));
145+
if (rc > 0) { /* item was found, show it */
146+
printk("Id: %x, Key: ", KEY_VALUE_ID);
147+
for (int n = 0; n < 8; n++) {
148+
printk("%x ", key[n]);
149+
}
150+
printk("\n");
151+
}
152+
/* Rewriting KEY_VALUE even if we found it */
153+
printk("Adding key/value at id %x\n", KEY_VALUE_ID);
154+
rc = zms_write(&fs, KEY_VALUE_ID, &key, sizeof(key));
155+
if (rc < 0) {
156+
printk("Error while writing Entry rc=%d\n", rc);
157+
break;
158+
}
159+
160+
/* CNT_ID is used to store the loop counter, lets see
161+
* if we can read it from storage
162+
*/
163+
rc = zms_read(&fs, CNT_ID, &i_cnt, sizeof(i_cnt));
164+
if (rc > 0) { /* item was found, show it */
165+
printk("Id: %d, loop_cnt: %u\n", CNT_ID, i_cnt);
166+
if (i_cnt != (i - 1)) {
167+
break;
168+
}
169+
}
170+
printk("Adding counter at id %u\n", CNT_ID);
171+
rc = zms_write(&fs, CNT_ID, &i, sizeof(i));
172+
if (rc < 0) {
173+
printk("Error while writing Entry rc=%d\n", rc);
174+
break;
175+
}
176+
177+
/* LONG_DATA_ID is used to store a larger dataset ,lets see if we can read
178+
* it from flash
179+
*/
180+
rc = zms_read(&fs, LONG_DATA_ID, &longarray, sizeof(longarray));
181+
if (rc > 0) {
182+
/* item was found, show it */
183+
printk("Id: %d, Longarray: ", LONG_DATA_ID);
184+
for (int n = 0; n < sizeof(longarray); n++) {
185+
printk("%x ", longarray[n]);
186+
}
187+
printk("\n");
188+
}
189+
/* Rewrite the entry even if we found it */
190+
printk("Adding Longarray at id %d\n", LONG_DATA_ID);
191+
rc = zms_write(&fs, LONG_DATA_ID, &longarray, sizeof(longarray));
192+
if (rc < 0) {
193+
printk("Error while writing Entry rc=%d\n", rc);
194+
break;
195+
}
196+
197+
/* Each DELETE_ITERATION delete all basic items */
198+
if (!(i % DELETE_ITERATION) && (i)) {
199+
rc = delete_basic_items(&fs);
200+
if (rc) {
201+
break;
202+
}
203+
}
204+
}
205+
206+
if (i != MAX_ITERATIONS) {
207+
printk("Error: Something went wrong at iteration %u rc=%d\n", i - 1, rc);
208+
return 0;
209+
}
210+
211+
while (1) {
212+
/* fill all storage */
213+
rc = zms_write(&fs, id, &id, sizeof(uint32_t));
214+
if (rc < 0) {
215+
break;
216+
}
217+
id++;
218+
}
219+
220+
if (rc == -ENOSPC) {
221+
/* Calculate free space and verify that it is 0 */
222+
free_space = zms_calc_free_space(&fs);
223+
if (free_space < 0) {
224+
printk("Error while computing free space, rc=%d\n", free_space);
225+
return 0;
226+
}
227+
if (free_space > 0) {
228+
printk("Error: free_space should be 0, computed %u\n", free_space);
229+
return 0;
230+
}
231+
printk("Memory is full let's delete all items\n");
232+
233+
/* Now delete all previously written items */
234+
for (uint32_t n = 0; n < id; n++) {
235+
rc = delete_and_verify_items(&fs, n);
236+
if (rc) {
237+
printk("Error deleting at id %u\n", n);
238+
return 0;
239+
}
240+
}
241+
rc = delete_basic_items(&fs);
242+
if (rc) {
243+
printk("Error deleting basic items\n");
244+
return 0;
245+
}
246+
}
247+
248+
/*
249+
* Let's compute free space in storage. But before doing that let's Garbage collect
250+
* all sectors where we deleted all entries and then compute the free space
251+
*/
252+
for (uint32_t i = 0; i < fs.sector_count; i++) {
253+
rc = zms_sector_use_next(&fs);
254+
if (rc) {
255+
printk("Error while changing sector rc=%d\n", rc);
256+
}
257+
}
258+
free_space = zms_calc_free_space(&fs);
259+
if (free_space < 0) {
260+
printk("Error while computing free space, rc=%d\n", free_space);
261+
return 0;
262+
}
263+
printk("Free space in storage is %u bytes\n", free_space);
264+
printk("Sample code finished Successfully\n");
265+
266+
return 0;
267+
}

0 commit comments

Comments
 (0)