/* * challenge_nvs.c * * Created on: 08.12.2022 * Author: jonas */ #include "challenge_nvs.h" #include "esp_log.h" #include "esp_system.h" #include "nvs_flash.h" #include "nvs.h" #include "McuUtility.h" #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" /* defines / constants */ #define TAG "CHALLENGE_NVS" /* tag for logging with ESP_LOG */ const char* NAMESPACE_NVS = "storage"; const char* ROBOT_MODE_KEY = "robot_mode"; const char* MQTT_IP_KEY = "mqtt_ip"; /* local vars */ bool initializedSuccessfully = false; SemaphoreHandle_t semaphore = NULL; /*! \brief Initialize the NVS storage. */ void Challenge_Nvs_Init(void){ ESP_LOGI(TAG, "Initializing..."); // initialize semaphore semaphore = xSemaphoreCreateRecursiveMutex(); if(semaphore == NULL){ ESP_LOGE(TAG, "Failed to initialize semaphore for Challenge NVS!"); }else{ vQueueAddToRegistry(semaphore, "challenge_nvs_semphr"); } // Initialize NVS esp_err_t err = nvs_flash_init(); if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { // NVS partition was truncated and needs to be erased // Retry nvs_flash_init ESP_ERROR_CHECK(nvs_flash_erase()); err = nvs_flash_init(); } ESP_ERROR_CHECK( err ); initializedSuccessfully = (err == ESP_OK); ESP_LOGI(TAG, "Initialized. Success=%s", initializedSuccessfully?"true":"false"); } /*! \brief Deinitialize the NVS storage. */ void Challenge_Nvs_Deinit(void){ ESP_LOGI(TAG, "Deinitializing..."); esp_err_t err = nvs_flash_deinit(); ESP_LOGI(TAG, "Deinitialized. Success=%s", err==ESP_OK?"true":"false"); vSemaphoreDelete(semaphore); } /* HELPERS FOR SEMAPHORE */ static bool Challenge_Nvs_AquireMutex(void){ if(xSemaphoreTakeRecursive(semaphore, pdMS_TO_TICKS(100)) != pdTRUE){ /* timeout */ ESP_LOGW(TAG, "Timemout while aquiring challenge NVS semaphore."); return false; } return true; } static void Challenge_Nvs_ReleaseMutex(void){ xSemaphoreGive(semaphore); } bool Challenge_Nvs_StoreRobotModeToNVS(bool mode){ bool success = false; if(Challenge_Nvs_AquireMutex()){ // Open ESP_LOGI(TAG, "Opening Non-Volatile Storage (NVS) handle... "); nvs_handle_t my_handle; esp_err_t err = nvs_open(NAMESPACE_NVS, NVS_READWRITE, &my_handle); if (err != ESP_OK) { ESP_LOGE(TAG, "Error (%s) opening NVS handle!\n", esp_err_to_name(err)); return false; } // Write uint8_t value = mode?1:0; ESP_LOGI(TAG, "Updating robotMode in NVS ... "); err = nvs_set_u8(my_handle, ROBOT_MODE_KEY, value); if(err != ESP_OK){ ESP_LOGE(TAG, "Failed to update robotMode in NVS. Error=(%s)", esp_err_to_name(err)); success = false; }else{ // successfully set // 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. ESP_LOGI(TAG, "Committing updates in NVS ... "); err = nvs_commit(my_handle); if(err != ESP_OK){ ESP_LOGE(TAG, "Failed to commit to NVS. Error=(%s)", esp_err_to_name(err)); success = false; }else{ ESP_LOGI(TAG, "Successfully committed changes to NVS."); success = true; } } // Close nvs_close(my_handle); Challenge_Nvs_ReleaseMutex(); } return success; } bool Challenge_Nvs_GetRobotModeFromNVS(bool *mode){ bool success = false; bool notInitialized = false; if(Challenge_Nvs_AquireMutex()){ // Open ESP_LOGI(TAG, "Opening Non-Volatile Storage (NVS) handle... "); nvs_handle_t my_handle; esp_err_t err = nvs_open(NAMESPACE_NVS, NVS_READWRITE, &my_handle); if (err != ESP_OK) { ESP_LOGE(TAG, "Error (%s) opening NVS handle!\n", esp_err_to_name(err)); return false; } // Read ESP_LOGI(TAG, "Reading robot mode from NVS ... "); uint8_t value = 0; err = nvs_get_u8(my_handle, ROBOT_MODE_KEY, &value); switch (err) { case ESP_OK: ESP_LOGI(TAG, "Reading robot mode done. Read robotMode = %i", value); *mode = (bool)(value==1?true:false); // set value at pointer location success = true; break; case ESP_ERR_NVS_NOT_FOUND: ESP_LOGI(TAG, "Reading robot mode done. The value is not initialized yet!"); notInitialized = true; break; default : ESP_LOGI(TAG, "Error reading robot mode. Error=(%s)", esp_err_to_name(err)); success = false; } // Close nvs_close(my_handle); if(notInitialized){ success = Challenge_Nvs_StoreRobotModeToNVS(false); // initialize to false *mode = false; // set out variable to false too } Challenge_Nvs_ReleaseMutex(); } return success; } bool Challenge_Nvs_StoreBrokerIpToNVS(char* ip){ bool success = false; if(Challenge_Nvs_AquireMutex()){ // Open ESP_LOGI(TAG, "Opening Non-Volatile Storage (NVS) handle... "); nvs_handle_t my_handle; esp_err_t err = nvs_open(NAMESPACE_NVS, NVS_READWRITE, &my_handle); if (err != ESP_OK) { ESP_LOGE(TAG, "Error (%s) opening NVS handle!\n", esp_err_to_name(err)); return false; } // Write ESP_LOGI(TAG, "Updating mqtt broker IP in NVS ... "); err = nvs_set_str(my_handle, MQTT_IP_KEY, ip); if(err != ESP_OK){ ESP_LOGE(TAG, "Failed to update mqtt broker IP in NVS. Error=(%s)", esp_err_to_name(err)); success = false; }else{ // successfully set // 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. ESP_LOGI(TAG, "Committing updates in NVS ... "); err = nvs_commit(my_handle); if(err != ESP_OK){ ESP_LOGE(TAG, "Failed to commit to NVS. Error=(%s)", esp_err_to_name(err)); success = false; }else{ ESP_LOGI(TAG, "Successfully committed changes to NVS."); success = true; } } // Close nvs_close(my_handle); Challenge_Nvs_ReleaseMutex(); } return success; } bool Challenge_Nvs_GetBrokerIpFromNVS(char *ip, size_t length){ bool success = false; bool notInitialized = false; if(Challenge_Nvs_AquireMutex()){ // Open ESP_LOGI(TAG, "Opening Non-Volatile Storage (NVS) handle... "); nvs_handle_t my_handle; esp_err_t err = nvs_open(NAMESPACE_NVS, NVS_READWRITE, &my_handle); if (err != ESP_OK) { ESP_LOGE(TAG, "Error (%s) opening NVS handle!\n", esp_err_to_name(err)); return false; } // Read ESP_LOGI(TAG, "Reading mqtt broker IP from NVS ... "); size_t required_size; nvs_get_str(my_handle, MQTT_IP_KEY, NULL, &required_size); // retrieve required size char* value = pvPortMalloc(required_size); err = nvs_get_str(my_handle, MQTT_IP_KEY, value, &required_size); switch (err) { case ESP_OK: ESP_LOGI(TAG, "Reading mqtt broker ip done. Read IP = %s", value); McuUtility_strcpy((unsigned char*)ip, length, (unsigned char *)value); // copy ip to destination success = true; break; case ESP_ERR_NVS_NOT_FOUND: ESP_LOGI(TAG, "Reading mqtt broker ip done. The value is not initialized yet!"); notInitialized = true; break; default : ESP_LOGI(TAG, "Error reading mqtt broker ip. Error=(%s)", esp_err_to_name(err)); success = false; } // Close nvs_close(my_handle); if(notInitialized){ success = Challenge_Nvs_StoreBrokerIpToNVS("10.0.1.1"); // initialize to default IP } Challenge_Nvs_ReleaseMutex(); } return success; }