1 /*
2  * NVS Sample for Zephyr using high level API, the sample illustrates the usage
3  * of NVS for storing data of different kind (strings, binary blobs, unsigned
4  * 32 bit integer) and also how to read them back from flash. The reading of
5  * data is illustrated for both a basic read (latest added value) as well as
6  * reading back the history of data (previously added values). Next to reading
7  * and writing data it also shows how data can be deleted from flash.
8  *
9  * The sample stores the following items:
10  * 1. A string representing an IP-address: stored at id=1, data="192.168.1.1"
11  * 2. A binary blob representing a key: stored at id=2, data=FF FE FD FC FB FA
12  *    F9 F8
13  * 3. A reboot counter (32bit): stored at id=3, data=reboot_counter
14  * 4. A string: stored at id=4, data="DATA" (used to illustrate deletion of
15  * items)
16  *
17  * At first boot the sample checks if the data is available in flash and adds
18  * the items if they are not in flash.
19  *
20  * Every reboot increases the values of the reboot_counter and updates it in
21  * flash.
22  *
23  * At the 10th reboot the string item with id=4 is deleted (or marked for
24  * deletion).
25  *
26  * At the 11th reboot the string item with id=4 can no longer be read with the
27  * basic nvs_read() function as it has been deleted. It is possible to read the
28  * value with nvs_read_hist()
29  *
30  * At the 78th reboot the first sector is full and a new sector is taken into
31  * use. The data with id=1, id=2 and id=3 is copied to the new sector. As a
32  * result of this the history of the reboot_counter will be removed but the
33  * latest values of address, key and reboot_counter is kept.
34  *
35  * Copyright (c) 2018 Laczen
36  *
37  * SPDX-License-Identifier: Apache-2.0
38  */
39 
40 
41 #include <zephyr/kernel.h>
42 #include <zephyr/sys/reboot.h>
43 #include <zephyr/device.h>
44 #include <string.h>
45 #include <zephyr/drivers/flash.h>
46 #include <zephyr/storage/flash_map.h>
47 #include <zephyr/fs/nvs.h>
48 
49 static struct nvs_fs fs;
50 
51 #define NVS_PARTITION		storage_partition
52 #define NVS_PARTITION_DEVICE	FIXED_PARTITION_DEVICE(NVS_PARTITION)
53 #define NVS_PARTITION_OFFSET	FIXED_PARTITION_OFFSET(NVS_PARTITION)
54 
55 #define ADDRESS_ID 1
56 #define KEY_ID 2
57 #define RBT_CNT_ID 3
58 #define STRING_ID 4
59 #define LONG_ID 5
60 
61 
main(void)62 int main(void)
63 {
64 	int rc = 0, cnt = 0, cnt_his = 0;
65 	char buf[16];
66 	uint8_t key[8], longarray[128];
67 	uint32_t reboot_counter = 0U, reboot_counter_his;
68 	struct flash_pages_info info;
69 
70 	/* define the nvs file system by settings with:
71 	 *	sector_size equal to the pagesize,
72 	 *	3 sectors
73 	 *	starting at NVS_PARTITION_OFFSET
74 	 */
75 	fs.flash_device = NVS_PARTITION_DEVICE;
76 	if (!device_is_ready(fs.flash_device)) {
77 		printk("Flash device %s is not ready\n", fs.flash_device->name);
78 		return 0;
79 	}
80 	fs.offset = NVS_PARTITION_OFFSET;
81 	rc = flash_get_page_info_by_offs(fs.flash_device, fs.offset, &info);
82 	if (rc) {
83 		printk("Unable to get page info, rc=%d\n", rc);
84 		return 0;
85 	}
86 	fs.sector_size = info.size;
87 	fs.sector_count = 3U;
88 
89 	rc = nvs_mount(&fs);
90 	if (rc) {
91 		printk("Flash Init failed, rc=%d\n", rc);
92 		return 0;
93 	}
94 
95 	/* ADDRESS_ID is used to store an address, lets see if we can
96 	 * read it from flash, since we don't know the size read the
97 	 * maximum possible
98 	 */
99 	rc = nvs_read(&fs, ADDRESS_ID, &buf, sizeof(buf));
100 	if (rc > 0) { /* item was found, show it */
101 		printk("Id: %d, Address: %s\n", ADDRESS_ID, buf);
102 	} else   {/* item was not found, add it */
103 		strcpy(buf, "192.168.1.1");
104 		printk("No address found, adding %s at id %d\n", buf,
105 		       ADDRESS_ID);
106 		(void)nvs_write(&fs, ADDRESS_ID, &buf, strlen(buf)+1);
107 	}
108 	/* KEY_ID is used to store a key, lets see if we can read it from flash
109 	 */
110 	rc = nvs_read(&fs, KEY_ID, &key, sizeof(key));
111 	if (rc > 0) { /* item was found, show it */
112 		printk("Id: %d, Key: ", KEY_ID);
113 		for (int n = 0; n < 8; n++) {
114 			printk("%x ", key[n]);
115 		}
116 		printk("\n");
117 	} else   {/* item was not found, add it */
118 		printk("No key found, adding it at id %d\n", KEY_ID);
119 		key[0] = 0xFF;
120 		key[1] = 0xFE;
121 		key[2] = 0xFD;
122 		key[3] = 0xFC;
123 		key[4] = 0xFB;
124 		key[5] = 0xFA;
125 		key[6] = 0xF9;
126 		key[7] = 0xF8;
127 		(void)nvs_write(&fs, KEY_ID, &key, sizeof(key));
128 	}
129 	/* RBT_CNT_ID is used to store the reboot counter, lets see
130 	 * if we can read it from flash
131 	 */
132 	rc = nvs_read(&fs, RBT_CNT_ID, &reboot_counter, sizeof(reboot_counter));
133 	if (rc > 0) { /* item was found, show it */
134 		printk("Id: %d, Reboot_counter: %d\n",
135 			RBT_CNT_ID, reboot_counter);
136 	} else   {/* item was not found, add it */
137 		printk("No Reboot counter found, adding it at id %d\n",
138 		       RBT_CNT_ID);
139 		(void)nvs_write(&fs, RBT_CNT_ID, &reboot_counter,
140 			  sizeof(reboot_counter));
141 	}
142 	/* STRING_ID is used to store data that will be deleted,lets see
143 	 * if we can read it from flash, since we don't know the size read the
144 	 * maximum possible
145 	 */
146 	rc = nvs_read(&fs, STRING_ID, &buf, sizeof(buf));
147 	if (rc > 0) {
148 		/* item was found, show it */
149 		printk("Id: %d, Data: %s\n",
150 			STRING_ID, buf);
151 		/* remove the item if reboot_counter = 10 */
152 		if (reboot_counter == 10U) {
153 			(void)nvs_delete(&fs, STRING_ID);
154 		}
155 	} else   {
156 		/* entry was not found, add it if reboot_counter = 0*/
157 		if (reboot_counter == 0U) {
158 			printk("Id: %d not found, adding it\n",
159 			STRING_ID);
160 			strcpy(buf, "DATA");
161 			(void)nvs_write(&fs, STRING_ID, &buf, strlen(buf) + 1);
162 		}
163 	}
164 
165 	/* LONG_ID is used to store a larger dataset ,lets see if we can read
166 	 * it from flash
167 	 */
168 	rc = nvs_read(&fs, LONG_ID, &longarray, sizeof(longarray));
169 	if (rc > 0) {
170 		/* item was found, show it */
171 		printk("Id: %d, Longarray: ", LONG_ID);
172 		for (int n = 0; n < sizeof(longarray); n++) {
173 			printk("%x ", longarray[n]);
174 		}
175 		printk("\n");
176 	} else   {
177 		/* entry was not found, add it if reboot_counter = 0*/
178 		if (reboot_counter == 0U) {
179 			printk("Longarray not found, adding it as id %d\n",
180 			       LONG_ID);
181 			for (int n = 0; n < sizeof(longarray); n++) {
182 				longarray[n] = n;
183 			}
184 			(void)nvs_write(
185 				&fs, LONG_ID, &longarray, sizeof(longarray));
186 		}
187 	}
188 
189 	cnt = CONFIG_NVS_SAMPLE_REBOOT_COUNTDOWN;
190 	while (1) {
191 		k_msleep(CONFIG_NVS_SAMPLE_SLEEP_TIME);
192 		if (reboot_counter < CONFIG_NVS_SAMPLE_MAX_REBOOT) {
193 			if (cnt == CONFIG_NVS_SAMPLE_REBOOT_COUNTDOWN) {
194 				/* print some history information about
195 				 * the reboot counter
196 				 * Check the counter history in flash
197 				 */
198 				printk("Reboot counter history: ");
199 				while (1) {
200 					rc = nvs_read_hist(
201 						&fs, RBT_CNT_ID,
202 						&reboot_counter_his,
203 						sizeof(reboot_counter_his),
204 						cnt_his);
205 					if (rc < 0) {
206 						break;
207 					}
208 					printk("...%d", reboot_counter_his);
209 					cnt_his++;
210 				}
211 				if (cnt_his == 0) {
212 					printk("\n Error, no Reboot counter");
213 				} else {
214 					printk("\nOldest reboot counter: %d",
215 					       reboot_counter_his);
216 				}
217 				printk("\nRebooting in ");
218 			}
219 			printk("...%d", cnt);
220 			cnt--;
221 			if (cnt == 0) {
222 				printk("\n");
223 				reboot_counter++;
224 				(void)nvs_write(
225 					&fs, RBT_CNT_ID, &reboot_counter,
226 					sizeof(reboot_counter));
227 				if (reboot_counter == CONFIG_NVS_SAMPLE_MAX_REBOOT) {
228 					printk("Doing last reboot...\n");
229 				}
230 				sys_reboot(0);
231 			}
232 		} else {
233 			printk("Reboot counter reached max value.\n");
234 			printk("Reset to 0 and exit test.\n");
235 			reboot_counter = 0U;
236 			(void)nvs_write(&fs, RBT_CNT_ID, &reboot_counter,
237 			  sizeof(reboot_counter));
238 			break;
239 		}
240 	}
241 	return 0;
242 }
243