

/* Non-Volatile Storage (NVS) Read and Write a Value - Example

   For other examples please check:
   https://github.com/espressif/esp-idf/tree/master/examples

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "esp_log.h"

#define PARTITION_PRODUCT					("product_data")
#define PARTITION_PROV						("prov_data")

static char* TAG = "example_blob";

void app_main()
{

	esp_err_t err;
	nvs_handle product_data_handle;
	nvs_handle prov_data_handle;
	nvs_handle nvs_handle;

	int32_t product_data_counter = 0; // value will default to 0, if not set yet in 'product_data' partition
	int32_t prov_data_counter = 10; // value will default to 0, if not set yet in 'prov_data' partition
	int32_t nvs_counter = 100; // value will default to 0, if not set yet in in 'nvs' partition


	// Initialize flash

	err = nvs_flash_init_partition(PARTITION_PRODUCT);
	if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
		// NVS partition was truncated and needs to be erased
		// Retry nvs_flash_init
		ESP_LOGE(TAG, "ESP_ERR_NVS_NO_FREE_PAGES in partition 'product_data', going to erase it\r\n");
		ESP_ERROR_CHECK(nvs_flash_erase_partition(PARTITION_PRODUCT));
		err = nvs_flash_init_partition(PARTITION_PRODUCT);
	}
    ESP_ERROR_CHECK( err );


    err = nvs_flash_init_partition(PARTITION_PROV);
    if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
		// NVS partition was truncated and needs to be erased
		// Retry nvs_flash_init
    	ESP_LOGE(TAG, "ESP_ERR_NVS_NO_FREE_PAGES in partition 'prov_data', going to erase it\r\n");
		ESP_ERROR_CHECK(nvs_flash_erase_partition(PARTITION_PROV));
		err = nvs_flash_init_partition(PARTITION_PROV);
	}
    ESP_ERROR_CHECK( err );

    err = nvs_flash_init();
	if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
		// NVS partition was truncated and needs to be erased
		// Retry nvs_flash_init
		ESP_LOGE(TAG, "ESP_ERR_NVS_NO_FREE_PAGES in partition 'nvs', going to erase it\r\n");
		ESP_ERROR_CHECK(nvs_flash_erase());
		err = nvs_flash_init();
	}
	ESP_ERROR_CHECK( err );





    // Open product_data partition
    printf("\n");
    err = nvs_open_from_partition(PARTITION_PRODUCT, "storage", NVS_READWRITE, &product_data_handle);		//indico il namespace
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Error (%d) opening product_data handle!\n", err);
    } else {
        printf("product_data partition opened\n");

        // Read from product_data partition

        err = nvs_get_i32(product_data_handle, "prod_data_cnt", &product_data_counter);
        switch (err) {
            case ESP_OK:
            	ESP_LOGI(TAG, "prod_data_cnt = %d\n", product_data_counter);
                break;
            case ESP_ERR_NVS_NOT_FOUND:
            	ESP_LOGI(TAG, "prod_data_cnt value is not initialized yet!, the value is %d\n", product_data_counter);
                break;
            default :
            	ESP_LOGE(TAG, "Error (%d) in prod_data_cnt reading!\n", err);
        }

        // Write in product_data partition
        product_data_counter++;
        err = nvs_set_i32(product_data_handle, "prod_data_cnt", product_data_counter);
        if(err != ESP_OK){
        	ESP_LOGE(TAG, "Write in product_data partition FAILED, err: %d\n", err);
        } else {
        	ESP_LOGI(TAG, "Write in product_data partition SUCCESS\n")
        }

        // Commit written value.
        // After setting any values, nvs_commit() must be called to ensure changes are written
        // to flash storage. Implementations may write to storage at other times,
        // but this is not guaranteed.
        err = nvs_commit(product_data_handle);
        if(err != ESP_OK){
			ESP_LOGE(TAG, "Commit in product_data partition FAILED\n");
		} else {
			ESP_LOGI(TAG, "Commit in product_data partition SUCCESS\n")
		}

        // Close
        nvs_close(product_data_handle);
    }

    printf("\n");




		// Open prov_data partition
		printf("\n");
		err = nvs_open_from_partition(PARTITION_PROV, "storage", NVS_READWRITE, &prov_data_handle);		//indico il namespace
		if (err != ESP_OK) {
		   ESP_LOGE(TAG, "Error (%d) opening prov_data handle!\n", err);
		} else {
			   printf("prov_data partition opened\n");

			   // Read from product_data partition

			   err = nvs_get_i32(prov_data_handle, "prov_data_cnt", &prov_data_counter);
			   switch (err) {
				   case ESP_OK:
					ESP_LOGI(TAG, "prov_data_cnt = %d\n", prov_data_counter);
					   break;
				   case ESP_ERR_NVS_NOT_FOUND:
					ESP_LOGI(TAG, "prov_data_cnt value is not initialized yet!, the value is %d\n", prov_data_counter);
					   break;
				   default :
					ESP_LOGE(TAG, "Error (%d) in prov_data_cnt reading!\n", err);
			   }

			   // Write in product_data partition
			   prov_data_counter++;
			   err = nvs_set_i32(prov_data_handle, "prov_data_cnt", prov_data_counter);
			   if(err != ESP_OK){
				   ESP_LOGE(TAG, "Write in prov_data partition FAILED, err: %d\n", err);
			   } else {
				   ESP_LOGI(TAG, "Write in prov_data partition SUCCESS\n")
			   }

			   // Commit written value.
			   // After setting any values, nvs_commit() must be called to ensure changes are written
			   // to flash storage. Implementations may write to storage at other times,
			   // but this is not guaranteed.
			   err = nvs_commit(prov_data_handle);
			   if(err != ESP_OK){
				  	ESP_LOGE(TAG, "Commit in prov_data partition FAILED\n");
			   } else {
					ESP_LOGI(TAG, "Commit in prov_data partition SUCCESS\n")
			   }

			   // Close
			   nvs_close(prov_data_handle);
		}

		printf("\n");



       // Open nvs partition
	   printf("\n");
	   err = nvs_open("storage", NVS_READWRITE, &nvs_handle);		//indico il namespace
	   if (err != ESP_OK) {
		   ESP_LOGE(TAG, "Error (%d) opening nvs handle!\n", err);
	   } else {
		   printf("nvs partition opened\n");

		   // Read from product_data partition

		   err = nvs_get_i32(nvs_handle, "nvs_counter", &nvs_counter);
		   switch (err) {
			   case ESP_OK:
				ESP_LOGI(TAG, "nvs_counter = %d\n", nvs_counter);
				   break;
			   case ESP_ERR_NVS_NOT_FOUND:
				ESP_LOGI(TAG, "nvs_counter value is not initialized yet!, the value is %d\n", nvs_counter);
				   break;
			   default :
				ESP_LOGE(TAG, "Error (%d) in nvs_counter reading!\n", err);
		   }

		   // Write in product_data partition
		   nvs_counter++;
		   err = nvs_set_i32(nvs_handle, "nvs_counter", nvs_counter);
		   if(err != ESP_OK){
			   ESP_LOGE(TAG, "Write in nvs partition FAILED\n");
		   } else {
			   ESP_LOGI(TAG, "Write in nvs partition SUCCESS\n")
		   }

		   // Commit written value.
		   // After setting any values, nvs_commit() must be called to ensure changes are written
		   // to flash storage. Implementations may write to storage at other times,
		   // but this is not guaranteed.
		   err = nvs_commit(nvs_handle);
		   if(err != ESP_OK){
			   ESP_LOGE(TAG, "Commit in nvs partition FAILED\n");
		   } else {
				ESP_LOGI(TAG, "Commit in nvs partition SUCCESS\n")
		   }

		   // Close
		   nvs_close(nvs_handle);
	   }

	   printf("\n");



    // Restart module
    for (int i = 5; i >= 0; i--) {
        printf("Restarting in %d seconds...\n", i);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
    printf("Restarting now.\n");
    fflush(stdout);
    esp_restart();
}
