/* * NVS Sample for Zephyr using high level API, the sample illustrates the usage * of NVS for storing data of different kind (strings, binary blobs, unsigned * 32 bit integer) and also how to read them back from flash. The reading of * data is illustrated for both a basic read (latest added value) as well as * reading back the history of data (previously added values). Next to reading * and writing data it also shows how data can be deleted from flash. * * The sample stores the following items: * 1. A string representing an IP-address: stored at id=1, data="192.168.1.1" * 2. A binary blob representing a key: stored at id=2, data=FF FE FD FC FB FA * F9 F8 * 3. A reboot counter (32bit): stored at id=3, data=reboot_counter * 4. A string: stored at id=4, data="DATA" (used to illustrate deletion of * items) * * At first boot the sample checks if the data is available in flash and adds * the items if they are not in flash. * * Every reboot increases the values of the reboot_counter and updates it in * flash. * * At the 10th reboot the string item with id=4 is deleted (or marked for * deletion). * * At the 11th reboot the string item with id=4 can no longer be read with the * basic nvs_read() function as it has been deleted. It is possible to read the * value with nvs_read_hist() * * At the 78th reboot the first sector is full and a new sector is taken into * use. The data with id=1, id=2 and id=3 is copied to the new sector. As a * result of this the history of the reboot_counter will be removed but the * latest values of address, key and reboot_counter is kept. * * Copyright (c) 2018 Laczen * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include static struct nvs_fs fs; #define NVS_PARTITION storage_partition #define NVS_PARTITION_DEVICE FIXED_PARTITION_DEVICE(NVS_PARTITION) #define NVS_PARTITION_OFFSET FIXED_PARTITION_OFFSET(NVS_PARTITION) /* 1000 msec = 1 sec */ #define SLEEP_TIME 100 /* maximum reboot counts, make high enough to trigger sector change (buffer */ /* rotation). */ #define MAX_REBOOT 400 #define ADDRESS_ID 1 #define KEY_ID 2 #define RBT_CNT_ID 3 #define STRING_ID 4 #define LONG_ID 5 int main(void) { int rc = 0, cnt = 0, cnt_his = 0; char buf[16]; uint8_t key[8], longarray[128]; uint32_t reboot_counter = 0U, reboot_counter_his; struct flash_pages_info info; /* define the nvs file system by settings with: * sector_size equal to the pagesize, * 3 sectors * starting at NVS_PARTITION_OFFSET */ fs.flash_device = NVS_PARTITION_DEVICE; if (!device_is_ready(fs.flash_device)) { printk("Flash device %s is not ready\n", fs.flash_device->name); return 0; } fs.offset = NVS_PARTITION_OFFSET; rc = flash_get_page_info_by_offs(fs.flash_device, fs.offset, &info); if (rc) { printk("Unable to get page info\n"); return 0; } fs.sector_size = info.size; fs.sector_count = 3U; rc = nvs_mount(&fs); if (rc) { printk("Flash Init failed\n"); return 0; } /* ADDRESS_ID is used to store an address, lets see if we can * read it from flash, since we don't know the size read the * maximum possible */ rc = nvs_read(&fs, ADDRESS_ID, &buf, sizeof(buf)); if (rc > 0) { /* item was found, show it */ printk("Id: %d, Address: %s\n", ADDRESS_ID, buf); } else {/* item was not found, add it */ strcpy(buf, "192.168.1.1"); printk("No address found, adding %s at id %d\n", buf, ADDRESS_ID); (void)nvs_write(&fs, ADDRESS_ID, &buf, strlen(buf)+1); } /* KEY_ID is used to store a key, lets see if we can read it from flash */ rc = nvs_read(&fs, KEY_ID, &key, sizeof(key)); if (rc > 0) { /* item was found, show it */ printk("Id: %d, Key: ", KEY_ID); for (int n = 0; n < 8; n++) { printk("%x ", key[n]); } printk("\n"); } else {/* item was not found, add it */ printk("No key found, adding it at id %d\n", KEY_ID); key[0] = 0xFF; key[1] = 0xFE; key[2] = 0xFD; key[3] = 0xFC; key[4] = 0xFB; key[5] = 0xFA; key[6] = 0xF9; key[7] = 0xF8; (void)nvs_write(&fs, KEY_ID, &key, sizeof(key)); } /* RBT_CNT_ID is used to store the reboot counter, lets see * if we can read it from flash */ rc = nvs_read(&fs, RBT_CNT_ID, &reboot_counter, sizeof(reboot_counter)); if (rc > 0) { /* item was found, show it */ printk("Id: %d, Reboot_counter: %d\n", RBT_CNT_ID, reboot_counter); } else {/* item was not found, add it */ printk("No Reboot counter found, adding it at id %d\n", RBT_CNT_ID); (void)nvs_write(&fs, RBT_CNT_ID, &reboot_counter, sizeof(reboot_counter)); } /* STRING_ID is used to store data that will be deleted,lets see * if we can read it from flash, since we don't know the size read the * maximum possible */ rc = nvs_read(&fs, STRING_ID, &buf, sizeof(buf)); if (rc > 0) { /* item was found, show it */ printk("Id: %d, Data: %s\n", STRING_ID, buf); /* remove the item if reboot_counter = 10 */ if (reboot_counter == 10U) { (void)nvs_delete(&fs, STRING_ID); } } else { /* entry was not found, add it if reboot_counter = 0*/ if (reboot_counter == 0U) { printk("Id: %d not found, adding it\n", STRING_ID); strcpy(buf, "DATA"); (void)nvs_write(&fs, STRING_ID, &buf, strlen(buf) + 1); } } /* LONG_ID is used to store a larger dataset ,lets see if we can read * it from flash */ rc = nvs_read(&fs, LONG_ID, &longarray, sizeof(longarray)); if (rc > 0) { /* item was found, show it */ printk("Id: %d, Longarray: ", LONG_ID); for (int n = 0; n < sizeof(longarray); n++) { printk("%x ", longarray[n]); } printk("\n"); } else { /* entry was not found, add it if reboot_counter = 0*/ if (reboot_counter == 0U) { printk("Longarray not found, adding it as id %d\n", LONG_ID); for (int n = 0; n < sizeof(longarray); n++) { longarray[n] = n; } (void)nvs_write( &fs, LONG_ID, &longarray, sizeof(longarray)); } } cnt = 5; while (1) { k_msleep(SLEEP_TIME); if (reboot_counter < MAX_REBOOT) { if (cnt == 5) { /* print some history information about * the reboot counter * Check the counter history in flash */ printk("Reboot counter history: "); while (1) { rc = nvs_read_hist( &fs, RBT_CNT_ID, &reboot_counter_his, sizeof(reboot_counter_his), cnt_his); if (rc < 0) { break; } printk("...%d", reboot_counter_his); cnt_his++; } if (cnt_his == 0) { printk("\n Error, no Reboot counter"); } else { printk("\nOldest reboot counter: %d", reboot_counter_his); } printk("\nRebooting in "); } printk("...%d", cnt); cnt--; if (cnt == 0) { printk("\n"); reboot_counter++; (void)nvs_write( &fs, RBT_CNT_ID, &reboot_counter, sizeof(reboot_counter)); if (reboot_counter == MAX_REBOOT) { printk("Doing last reboot...\n"); } sys_reboot(0); } } else { printk("Reboot counter reached max value.\n"); printk("Reset to 0 and exit test.\n"); reboot_counter = 0U; (void)nvs_write(&fs, RBT_CNT_ID, &reboot_counter, sizeof(reboot_counter)); break; } } return 0; }