mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-08 04:27:12 +03:00
In order to use this new release, it is recommended to erase the flash and replace the recovery partition with one that is at least at this level.
660 lines
20 KiB
C
660 lines
20 KiB
C
/*
|
|
* Squeezelite for esp32
|
|
*
|
|
* (c) Sebastien 2019
|
|
* Philippe G. 2019, philippe_44@outlook.com
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
//#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
|
|
#include "config.h"
|
|
#include "nvs_utilities.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "esp_system.h"
|
|
#include "esp_log.h"
|
|
#include "esp_console.h"
|
|
#include "esp_vfs_dev.h"
|
|
#include "driver/uart.h"
|
|
#include "linenoise/linenoise.h"
|
|
#include "argtable3/argtable3.h"
|
|
#include "cmd_decl.h"
|
|
#include "esp_vfs_fat.h"
|
|
#include "nvs.h"
|
|
#include "nvs_flash.h"
|
|
#include "nvs_utilities.h"
|
|
#include "cJSON.h"
|
|
#include "freertos/timers.h"
|
|
#include "freertos/event_groups.h"
|
|
|
|
|
|
#define CONFIG_COMMIT_DELAY 1000
|
|
#define LOCK_MAX_WAIT 20*CONFIG_COMMIT_DELAY
|
|
static const char * TAG = "config";
|
|
static cJSON * nvs_json=NULL;
|
|
static TimerHandle_t timer;
|
|
static SemaphoreHandle_t config_mutex = NULL;
|
|
static EventGroupHandle_t config_group;
|
|
/* @brief indicate that the ESP32 is currently connected. */
|
|
static const int CONFIG_PENDING_CHANGE_BIT = BIT0;
|
|
static const int CONFIG_LOAD_BIT = BIT1;
|
|
|
|
bool config_lock(TickType_t xTicksToWait);
|
|
void config_unlock();
|
|
extern esp_err_t nvs_load_config();
|
|
void config_raise_change(bool flag);
|
|
cJSON_bool config_is_entry_changed(cJSON * entry);
|
|
bool config_set_group_bit(int bit_num,bool flag);
|
|
cJSON * config_set_value_safe(nvs_type_t nvs_type, const char *key, void * value);
|
|
static void vCallbackFunction( TimerHandle_t xTimer );
|
|
void config_set_entry_changed_flag(cJSON * entry, cJSON_bool flag);
|
|
|
|
static void * malloc_fn(size_t sz){
|
|
void * ptr = heap_caps_malloc(sz, MALLOC_CAP_SPIRAM);
|
|
if(ptr==NULL){
|
|
ESP_LOGE(TAG,"malloc_fn: unable to allocate memory!");
|
|
}
|
|
return ptr;
|
|
}
|
|
static void * free_fn(void * ptr){
|
|
if(ptr!=NULL){
|
|
free(ptr);
|
|
}
|
|
else {
|
|
ESP_LOGW(TAG,"free_fn: Cannot free null pointer!");
|
|
}
|
|
return NULL;
|
|
}
|
|
void init_cJSON(){
|
|
static cJSON_Hooks hooks;
|
|
// initialize cJSON hooks it uses SPIRAM memory
|
|
// as opposed to IRAM
|
|
hooks.malloc_fn=&malloc_fn;
|
|
hooks.free_fn=&free_fn;
|
|
cJSON_InitHooks(&hooks);
|
|
}
|
|
void config_init(){
|
|
ESP_LOGD(TAG, "Creating mutex for Config");
|
|
config_mutex = xSemaphoreCreateMutex();
|
|
ESP_LOGD(TAG, "Creating event group");
|
|
config_group = xEventGroupCreate();
|
|
ESP_LOGD(TAG, "Loading config from nvs");
|
|
|
|
init_cJSON();
|
|
if(nvs_json !=NULL){
|
|
cJSON_Delete(nvs_json);
|
|
}
|
|
nvs_json = cJSON_CreateObject();
|
|
|
|
config_set_group_bit(CONFIG_LOAD_BIT,true);
|
|
nvs_load_config();
|
|
config_set_group_bit(CONFIG_LOAD_BIT,false);
|
|
config_start_timer();
|
|
}
|
|
|
|
void config_start_timer(){
|
|
ESP_LOGD(TAG, "Starting config timer");
|
|
timer = xTimerCreate("configTimer", CONFIG_COMMIT_DELAY / portTICK_RATE_MS, pdFALSE, NULL, vCallbackFunction);
|
|
if( xTimerStart( timer , CONFIG_COMMIT_DELAY/ portTICK_RATE_MS ) != pdPASS ) {
|
|
ESP_LOGE(TAG, "config commitment timer failed to start.");
|
|
}
|
|
|
|
}
|
|
cJSON * config_set_value_safe(nvs_type_t nvs_type, const char *key, void * value){
|
|
char * num_buffer = NULL;
|
|
num_buffer = malloc(NUM_BUFFER_LEN);
|
|
memset(num_buffer,0x00,NUM_BUFFER_LEN);
|
|
cJSON * entry = cJSON_CreateObject();
|
|
|
|
if(entry == NULL) {
|
|
ESP_LOGE(TAG, "Unable to allocate memory for entry %s",key);
|
|
return NULL;
|
|
}
|
|
cJSON_AddNumberToObject(entry,"type", nvs_type );
|
|
switch (nvs_type) {
|
|
case NVS_TYPE_I8:
|
|
snprintf(num_buffer, NUM_BUFFER_LEN-1, "%i", *(int8_t*)value);
|
|
cJSON_AddNumberToObject(entry,"value", *(int8_t*)value );
|
|
break;
|
|
case NVS_TYPE_I16:
|
|
snprintf(num_buffer, NUM_BUFFER_LEN-1, "%i", *(int16_t*)value);
|
|
cJSON_AddNumberToObject(entry,"value", *(int16_t*)value );
|
|
break;
|
|
case NVS_TYPE_I32:
|
|
snprintf(num_buffer, NUM_BUFFER_LEN-1, "%i", *(int32_t*)value);
|
|
cJSON_AddNumberToObject(entry,"value", *(int32_t*)value );
|
|
break;
|
|
case NVS_TYPE_U8:
|
|
snprintf(num_buffer, NUM_BUFFER_LEN-1, "%u", *(uint8_t*)value);
|
|
cJSON_AddNumberToObject(entry,"value", *(uint8_t*)value );
|
|
break;
|
|
case NVS_TYPE_U16:
|
|
snprintf(num_buffer, NUM_BUFFER_LEN-1, "%u", *(uint16_t*)value);
|
|
cJSON_AddNumberToObject(entry,"value", *(uint16_t*)value );
|
|
break;
|
|
case NVS_TYPE_U32:
|
|
snprintf(num_buffer, NUM_BUFFER_LEN-1, "%u", *(uint32_t*)value);
|
|
cJSON_AddNumberToObject(entry,"value", *(uint32_t*)value );
|
|
break;
|
|
case NVS_TYPE_STR:
|
|
cJSON_AddStringToObject(entry, "value", (char *)value);
|
|
break;
|
|
case NVS_TYPE_I64:
|
|
case NVS_TYPE_U64:
|
|
default:
|
|
ESP_LOGE(TAG, "nvs type %u not supported", nvs_type);
|
|
break;
|
|
}
|
|
cJSON * existing = cJSON_GetObjectItemCaseSensitive(nvs_json, key);
|
|
if(existing!=NULL ) {
|
|
ESP_LOGV(TAG, "Changing existing entry [%s].", key);
|
|
char * exist_str = cJSON_PrintUnformatted(existing);
|
|
if(exist_str!=NULL){
|
|
ESP_LOGV(TAG,"Existing entry: %s", exist_str);
|
|
free(exist_str);
|
|
}
|
|
else {
|
|
ESP_LOGV(TAG,"Failed to print existing entry");
|
|
}
|
|
// set commit flag as equal so we can compare
|
|
cJSON * chg_flag =cJSON_AddBoolToObject(entry,"chg",config_is_entry_changed(existing));
|
|
if(!cJSON_Compare(entry,existing,false)){
|
|
char * entry_str = cJSON_PrintUnformatted(entry);
|
|
if(entry_str!=NULL){
|
|
ESP_LOGD(TAG,"New config object: \n%s", entry_str );
|
|
free(entry_str);
|
|
}
|
|
else {
|
|
ESP_LOGD(TAG,"Failed to print entry");
|
|
}
|
|
ESP_LOGI(TAG, "Setting changed flag config [%s]", key);
|
|
config_set_entry_changed_flag(entry,true);
|
|
ESP_LOGI(TAG, "Updating config [%s]", key);
|
|
cJSON_ReplaceItemInObject(nvs_json,key, entry);
|
|
entry_str = cJSON_PrintUnformatted(entry);
|
|
if(entry_str!=NULL){
|
|
ESP_LOGD(TAG,"New config: %s", entry_str );
|
|
free(entry_str);
|
|
}
|
|
else {
|
|
ESP_LOGD(TAG,"Failed to print entry");
|
|
}
|
|
}
|
|
else {
|
|
ESP_LOGD(TAG, "Config not changed. ");
|
|
}
|
|
}
|
|
else {
|
|
// This is a new entry.
|
|
config_set_entry_changed_flag(entry,true);
|
|
cJSON_AddItemToObject(nvs_json, key, entry);
|
|
}
|
|
free(num_buffer);
|
|
|
|
return entry;
|
|
}
|
|
|
|
nvs_type_t config_get_entry_type(cJSON * entry){
|
|
if(entry==NULL){
|
|
ESP_LOGE(TAG,"null pointer received!");
|
|
return 0;
|
|
}
|
|
cJSON * entry_type = cJSON_GetObjectItemCaseSensitive(entry, "type");
|
|
if(entry_type ==NULL ) {
|
|
ESP_LOGE(TAG, "Entry type not found in nvs cache for existing setting.");
|
|
return 0;
|
|
}
|
|
return entry_type->valuedouble;
|
|
}
|
|
void config_set_entry_changed_flag(cJSON * entry, cJSON_bool flag){
|
|
ESP_LOGV(TAG, "config_set_entry_changed_flag: begin");
|
|
if(entry==NULL){
|
|
ESP_LOGE(TAG,"null pointer received!");
|
|
return;
|
|
}
|
|
bool bIsConfigLoading=((xEventGroupGetBits(config_group) & CONFIG_LOAD_BIT)!=0);
|
|
bool changedFlag=bIsConfigLoading?false:flag;
|
|
ESP_LOGV(TAG, "config_set_entry_changed_flag: retrieving chg flag from entry");
|
|
cJSON * changed = cJSON_GetObjectItemCaseSensitive(entry, "chg");
|
|
if(changed ==NULL ) {
|
|
ESP_LOGV(TAG, "config_set_entry_changed_flag: chg flag not found. Adding. ");
|
|
cJSON_AddBoolToObject(entry,"chg",changedFlag);
|
|
}
|
|
else {
|
|
ESP_LOGV(TAG, "config_set_entry_changed_flag: Existing change flag found. ");
|
|
if(cJSON_IsTrue(changed) && changedFlag){
|
|
ESP_LOGW(TAG, "Commit flag not changed!");
|
|
}
|
|
else{
|
|
ESP_LOGV(TAG, "config_set_entry_changed_flag: Updating change flag to %s",changedFlag?"TRUE":"FALSE");
|
|
changed->type = changedFlag?cJSON_True:cJSON_False ;
|
|
}
|
|
}
|
|
|
|
if(changedFlag) {
|
|
ESP_LOGV(TAG, "config_set_entry_changed_flag: Calling config_raise_change. ");
|
|
config_raise_change(true);
|
|
}
|
|
ESP_LOGV(TAG, "config_set_entry_changed_flag: done. ");
|
|
}
|
|
cJSON_bool config_is_entry_changed(cJSON * entry){
|
|
if(entry==NULL){
|
|
ESP_LOGE(TAG,"null pointer received!");
|
|
return true;
|
|
}
|
|
cJSON * changed = cJSON_GetObjectItemCaseSensitive(entry, "chg");
|
|
if(changed ==NULL ) {
|
|
ESP_LOGE(TAG, "Change flag not found! ");
|
|
return true;
|
|
}
|
|
return cJSON_IsTrue(changed);
|
|
}
|
|
void * config_safe_alloc_get_entry_value(nvs_type_t nvs_type, cJSON * entry){
|
|
void * value=NULL;
|
|
if(entry==NULL){
|
|
ESP_LOGE(TAG,"null pointer received!");
|
|
}
|
|
ESP_LOGV(TAG, "getting config value type %s", type_to_str(nvs_type));
|
|
cJSON * entry_value = cJSON_GetObjectItemCaseSensitive(entry, "value");
|
|
if(entry_value==NULL ) {
|
|
char * entry_str = cJSON_PrintUnformatted(entry);
|
|
if(entry_str!=NULL){
|
|
ESP_LOGE(TAG, "Missing config value!. Object: \n%s", entry_str);
|
|
free(entry_str);
|
|
}
|
|
else{
|
|
ESP_LOGE(TAG, "Missing config value");
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
nvs_type_t type = config_get_entry_type(entry);
|
|
if(nvs_type != type){
|
|
// requested value type different than the stored type
|
|
char * entry_str = cJSON_PrintUnformatted(entry);
|
|
if(entry_str!=NULL){
|
|
ESP_LOGE(TAG, "Requested value type %s, found value type %s instead, Object: \n%s", type_to_str(nvs_type), type_to_str(type),entry_str);
|
|
free(entry_str);
|
|
}
|
|
else{
|
|
ESP_LOGE(TAG, "Requested value type %s, found value type %s instead", type_to_str(nvs_type), type_to_str(type));
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
if (nvs_type == NVS_TYPE_I8) {
|
|
value=malloc(sizeof(int8_t));
|
|
*(int8_t *)value = (int8_t)entry_value->valuedouble;
|
|
} else if (nvs_type == NVS_TYPE_U8) {
|
|
value=malloc(sizeof(uint8_t));
|
|
*(uint8_t *)value = (uint8_t)entry_value->valuedouble;
|
|
} else if (nvs_type == NVS_TYPE_I16) {
|
|
value=malloc(sizeof(int16_t));
|
|
*(int16_t *)value = (int16_t)entry_value->valuedouble;
|
|
} else if (nvs_type == NVS_TYPE_U16) {
|
|
value=malloc(sizeof(uint16_t));
|
|
*(uint16_t *)value = (uint16_t)entry_value->valuedouble;
|
|
} else if (nvs_type == NVS_TYPE_I32) {
|
|
value=malloc(sizeof(int32_t));
|
|
*(int32_t *)value = (int32_t)entry_value->valuedouble;
|
|
} else if (nvs_type == NVS_TYPE_U32) {
|
|
value=malloc(sizeof(uint32_t));
|
|
*(uint32_t *)value = (uint32_t)entry_value->valuedouble;
|
|
} else if (nvs_type == NVS_TYPE_I64) {
|
|
value=malloc(sizeof(int64_t));
|
|
*(int64_t *)value = (int64_t)entry_value->valuedouble;
|
|
} else if (nvs_type == NVS_TYPE_U64) {
|
|
value=malloc(sizeof(uint64_t));
|
|
*(uint64_t *)value = (uint64_t)entry_value->valuedouble;
|
|
} else if (nvs_type == NVS_TYPE_STR) {
|
|
if(!cJSON_IsString(entry_value)){
|
|
char * entry_str = cJSON_PrintUnformatted(entry);
|
|
if(entry_str!=NULL){
|
|
ESP_LOGE(TAG, "requested value type string, config type is different. key: %s, value: %s, type %d, Object: \n%s",
|
|
entry_value->string,
|
|
entry_value->valuestring,
|
|
entry_value->type,
|
|
entry_str);
|
|
free(entry_str);
|
|
}
|
|
else {
|
|
ESP_LOGE(TAG, "requested value type string, config type is different. key: %s, value: %s, type %d",
|
|
entry_value->string,
|
|
entry_value->valuestring,
|
|
entry_value->type);
|
|
}
|
|
}
|
|
else {
|
|
value=(void *)strdup(cJSON_GetStringValue(entry_value));
|
|
if(value==NULL){
|
|
char * entry_str = cJSON_PrintUnformatted(entry);
|
|
if(entry_str!=NULL){
|
|
ESP_LOGE(TAG, "strdup failed on value for object \n%s",entry_str);
|
|
free(entry_str);
|
|
}
|
|
else {
|
|
ESP_LOGE(TAG, "strdup failed on value");
|
|
}
|
|
}
|
|
}
|
|
} else if (nvs_type == NVS_TYPE_BLOB) {
|
|
ESP_LOGE(TAG, "Unsupported type NVS_TYPE_BLOB");
|
|
}
|
|
return value;
|
|
}
|
|
|
|
void config_commit_to_nvs(){
|
|
ESP_LOGI(TAG,"Committing configuration to nvs. Locking config object.");
|
|
ESP_LOGV(TAG,"config_commit_to_nvs. Locking config object.");
|
|
if(!config_lock(LOCK_MAX_WAIT/portTICK_PERIOD_MS)){
|
|
ESP_LOGE(TAG, "config_commit_to_nvs: Unable to lock config for commit ");
|
|
return ;
|
|
}
|
|
if(nvs_json==NULL){
|
|
ESP_LOGE(TAG, ": cJSON nvs cache object not set.");
|
|
return;
|
|
}
|
|
ESP_LOGV(TAG,"config_commit_to_nvs. Config Locked!");
|
|
cJSON * entry=nvs_json->child;
|
|
while(entry!= NULL){
|
|
char * entry_str = cJSON_PrintUnformatted(entry);
|
|
if(entry_str!=NULL){
|
|
ESP_LOGV(TAG,"config_commit_to_nvs processing item %s",entry_str);
|
|
free(entry_str);
|
|
}
|
|
|
|
if(config_is_entry_changed(entry)){
|
|
ESP_LOGD(TAG, "Committing entry %s value to nvs.",(entry->string==NULL)?"UNKNOWN":entry->string);
|
|
nvs_type_t type = config_get_entry_type(entry);
|
|
void * value = config_safe_alloc_get_entry_value(type, entry);
|
|
if(value!=NULL){
|
|
esp_err_t err = store_nvs_value(type,entry->string,value);
|
|
free(value);
|
|
if(err!=ESP_OK){
|
|
char * entry_str = cJSON_PrintUnformatted(entry);
|
|
if(entry_str!=NULL){
|
|
ESP_LOGE(TAG, "Error comitting value to nvs for key %s, Object: \n%s",entry->string,entry_str);
|
|
free(entry_str);
|
|
}
|
|
else {
|
|
ESP_LOGE(TAG, "Error comitting value to nvs for key %s",entry->string);
|
|
}
|
|
}
|
|
else {
|
|
config_set_entry_changed_flag(entry, false);
|
|
}
|
|
}
|
|
else {
|
|
char * entry_str = cJSON_PrintUnformatted(entry);
|
|
if(entry_str!=NULL){
|
|
ESP_LOGE(TAG, "Unable to retrieve value. Error comitting value to nvs for key %s, Object: \n%s",entry->string,entry_str);
|
|
free(entry_str);
|
|
}
|
|
else {
|
|
ESP_LOGE(TAG, "Unable to retrieve value. Error comitting value to nvs for key %s",entry->string);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
ESP_LOGV(TAG,"config_commit_to_nvs. Item already committed. Ignoring.");
|
|
}
|
|
taskYIELD(); /* allows the freeRTOS scheduler to take over if needed. */
|
|
entry = entry->next;
|
|
}
|
|
ESP_LOGV(TAG,"config_commit_to_nvs. Resetting the global commit flag.");
|
|
config_raise_change(false);
|
|
ESP_LOGV(TAG,"config_commit_to_nvs. Releasing the lock object.");
|
|
config_unlock();
|
|
}
|
|
bool config_has_changes(){
|
|
return (xEventGroupGetBits(config_group) & CONFIG_PENDING_CHANGE_BIT)!=0;
|
|
}
|
|
|
|
|
|
bool wait_for_commit(){
|
|
bool needs_commit=(xEventGroupGetBits(config_group) & CONFIG_PENDING_CHANGE_BIT)!=0;
|
|
if(needs_commit){
|
|
ESP_LOGD(TAG,"Waiting for config commit ...");
|
|
needs_commit = (xEventGroupWaitBits(config_group, CONFIG_PENDING_CHANGE_BIT,pdFALSE, pdTRUE, (CONFIG_COMMIT_DELAY*5) / portTICK_PERIOD_MS) & CONFIG_PENDING_CHANGE_BIT)!=0;
|
|
if(needs_commit){
|
|
ESP_LOGE(TAG,"Timeout waiting for config commit.");
|
|
}
|
|
else
|
|
{
|
|
ESP_LOGI(TAG,"Config committed!");
|
|
}
|
|
}
|
|
return needs_commit;
|
|
}
|
|
|
|
bool config_lock(TickType_t xTicksToWait) {
|
|
ESP_LOGV(TAG, "Locking config json object");
|
|
if( xSemaphoreTake( config_mutex, xTicksToWait ) == pdTRUE ) {
|
|
ESP_LOGV(TAG, "config Json object locked!");
|
|
return true;
|
|
}
|
|
else {
|
|
ESP_LOGE(TAG, "Semaphore take failed. Unable to lock config Json object mutex");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void config_unlock() {
|
|
ESP_LOGV(TAG, "Unlocking json buffer!");
|
|
xSemaphoreGive( config_mutex );
|
|
}
|
|
|
|
static void vCallbackFunction( TimerHandle_t xTimer ) {
|
|
static int cnt=0;
|
|
if(config_has_changes()){
|
|
ESP_LOGI(TAG, "configuration has some uncommitted entries");
|
|
config_commit_to_nvs();
|
|
}
|
|
else{
|
|
if(++cnt>=15){
|
|
ESP_LOGV(TAG,"commit timer: commit flag not set");
|
|
cnt=0;
|
|
}
|
|
}
|
|
xTimerReset( xTimer, 10 );
|
|
}
|
|
void config_raise_change(bool flag){
|
|
if(config_set_group_bit(CONFIG_PENDING_CHANGE_BIT,flag))
|
|
{
|
|
ESP_LOGD(TAG,"Config change indicator was %s",flag?"Set":"Cleared");
|
|
}
|
|
}
|
|
bool config_set_group_bit(int bit_num,bool flag){
|
|
bool result = true;
|
|
int curFlags=xEventGroupGetBits(config_group);
|
|
if((curFlags & CONFIG_LOAD_BIT) && bit_num == CONFIG_PENDING_CHANGE_BIT ){
|
|
ESP_LOGD(TAG,"Loading config, ignoring changes");
|
|
result = false;
|
|
}
|
|
if(result){
|
|
bool curBit=(xEventGroupGetBits(config_group) & bit_num);
|
|
if(curBit == flag){
|
|
ESP_LOGV(TAG,"Flag %d already %s", bit_num, flag?"Set":"Cleared");
|
|
result = false;
|
|
}
|
|
}
|
|
if(result){
|
|
ESP_LOGV(TAG,"%s Flag %d ", flag?"Setting":"Clearing",bit_num);
|
|
if(!flag){
|
|
xEventGroupClearBits(config_group, bit_num);
|
|
}
|
|
else {
|
|
xEventGroupSetBits(config_group, bit_num);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
void config_set_default(nvs_type_t type, const char *key, void * default_value, size_t blob_size) {
|
|
if(!config_lock(LOCK_MAX_WAIT/portTICK_PERIOD_MS)){
|
|
ESP_LOGE(TAG, "Unable to lock config");
|
|
return;
|
|
}
|
|
|
|
ESP_LOGV(TAG, "Checking if key %s exists in nvs cache for type %s.", key,type_to_str(type));
|
|
cJSON * entry = cJSON_GetObjectItemCaseSensitive(nvs_json, key);
|
|
|
|
if(entry !=NULL){
|
|
ESP_LOGV(TAG, "Entry found.");
|
|
}
|
|
else {
|
|
// Value was not found
|
|
ESP_LOGW(TAG, "Adding default value for [%s].", key);
|
|
entry=config_set_value_safe(type, key, default_value);
|
|
if(entry == NULL){
|
|
ESP_LOGE(TAG, "Failed to add value to cache!");
|
|
}
|
|
char * entry_str = cJSON_PrintUnformatted(entry);
|
|
if(entry_str!=NULL){
|
|
ESP_LOGD(TAG, "Value added to default for object: \n%s",entry_str);
|
|
free(entry_str);
|
|
}
|
|
}
|
|
|
|
config_unlock();
|
|
|
|
}
|
|
|
|
void config_delete_key(const char *key){
|
|
nvs_handle nvs;
|
|
ESP_LOGD(TAG, "Deleting nvs entry for [%s]", key);
|
|
if(!config_lock(LOCK_MAX_WAIT/portTICK_PERIOD_MS)){
|
|
ESP_LOGE(TAG, "Unable to lock config for delete");
|
|
return false;
|
|
}
|
|
esp_err_t err = nvs_open_from_partition(settings_partition, current_namespace, NVS_READWRITE, &nvs);
|
|
if (err == ESP_OK) {
|
|
err = nvs_erase_key(nvs, key);
|
|
if (err == ESP_OK) {
|
|
ESP_LOGD(TAG, "key [%s] erased from nvs.",key);
|
|
err = nvs_commit(nvs);
|
|
if (err == ESP_OK) {
|
|
ESP_LOGD(TAG, "nvs erase committed.");
|
|
}
|
|
else {
|
|
ESP_LOGE(TAG, "Unable to commit nvs erase operation for key [%s]. %s.",key,esp_err_to_name(err));
|
|
}
|
|
}
|
|
else {
|
|
ESP_LOGE(TAG, "Unable to delete nvs key [%s]. %s. ",key, esp_err_to_name(err));
|
|
}
|
|
nvs_close(nvs);
|
|
}
|
|
else {
|
|
ESP_LOGE(TAG, "Error opening nvs: %s. Unable to delete nvs key [%s].",esp_err_to_name(err),key);
|
|
}
|
|
cJSON * entry = cJSON_GetObjectItemCaseSensitive(nvs_json, key);
|
|
if(entry !=NULL){
|
|
ESP_LOGI(TAG, "Removing config key [%s]", entry->string);
|
|
cJSON_Delete(entry);
|
|
}
|
|
else {
|
|
ESP_LOGW(TAG, "Unable to remove config key [%s]: not found.", key);
|
|
}
|
|
config_unlock();
|
|
}
|
|
void * config_alloc_get(nvs_type_t nvs_type, const char *key) {
|
|
return config_alloc_get_default(nvs_type, key, NULL, 0);
|
|
}
|
|
void * config_alloc_get_default(nvs_type_t nvs_type, const char *key, void * default_value, size_t blob_size) {
|
|
|
|
void * value = NULL;
|
|
ESP_LOGV(TAG, "Retrieving key %s from nvs cache for type %s.", key,type_to_str(nvs_type));
|
|
if(nvs_json==NULL){
|
|
ESP_LOGE(TAG,"configuration not loaded!");
|
|
return value;
|
|
}
|
|
if(!config_lock(LOCK_MAX_WAIT/portTICK_PERIOD_MS)){
|
|
ESP_LOGE(TAG, "Unable to lock config");
|
|
return value;
|
|
}
|
|
ESP_LOGD(TAG,"Getting config entry for key %s",key);
|
|
cJSON * entry = cJSON_GetObjectItemCaseSensitive(nvs_json, key);
|
|
if(entry !=NULL){
|
|
ESP_LOGV(TAG, "Entry found, getting value.");
|
|
value = config_safe_alloc_get_entry_value(nvs_type, entry);
|
|
}
|
|
else if(default_value!=NULL){
|
|
// Value was not found
|
|
ESP_LOGW(TAG, "Adding new config value for key [%s]",key);
|
|
entry=config_set_value_safe(nvs_type, key, default_value);
|
|
if(entry == NULL){
|
|
ESP_LOGE(TAG, "Failed to add value to cache");
|
|
}
|
|
else {
|
|
char * entry_str = cJSON_PrintUnformatted(entry);
|
|
if(entry_str!=NULL){
|
|
ESP_LOGV(TAG, "Value added configuration object for key [%s]: \n%s", entry->string,entry_str);
|
|
free(entry_str);
|
|
}
|
|
else {
|
|
ESP_LOGV(TAG, "Value added configuration object for key [%s]", entry->string);
|
|
}
|
|
value = config_safe_alloc_get_entry_value(nvs_type, entry);
|
|
}
|
|
}
|
|
else{
|
|
ESP_LOGW(TAG,"Value not found for key %s",key);
|
|
}
|
|
config_unlock();
|
|
return value;
|
|
}
|
|
char * config_alloc_get_json(bool bFormatted){
|
|
char * json_buffer = NULL;
|
|
if(!config_lock(LOCK_MAX_WAIT/portTICK_PERIOD_MS)){
|
|
ESP_LOGE(TAG, "Unable to lock config after %d ms",LOCK_MAX_WAIT);
|
|
return strdup("{\"error\":\"Unable to lock configuration object.\"}");
|
|
}
|
|
if(bFormatted){
|
|
json_buffer= cJSON_Print(nvs_json);
|
|
}
|
|
else {
|
|
json_buffer= cJSON_PrintUnformatted(nvs_json);
|
|
}
|
|
config_unlock();
|
|
return json_buffer;
|
|
}
|
|
esp_err_t config_set_value(nvs_type_t nvs_type, const char *key, void * value){
|
|
esp_err_t result = ESP_OK;
|
|
if(!config_lock(LOCK_MAX_WAIT/portTICK_PERIOD_MS)){
|
|
ESP_LOGE(TAG, "Unable to lock config after %d ms",LOCK_MAX_WAIT);
|
|
result = ESP_FAIL;
|
|
}
|
|
cJSON * entry = config_set_value_safe(nvs_type, key, value);
|
|
if(entry == NULL){
|
|
result = ESP_FAIL;
|
|
}
|
|
else{
|
|
char * entry_str = cJSON_PrintUnformatted(entry);
|
|
if(entry_str!=NULL){
|
|
ESP_LOGV(TAG,"config_set_value result: \n%s",entry_str);
|
|
free(entry_str);
|
|
}
|
|
else {
|
|
ESP_LOGV(TAG,"config_set_value completed");
|
|
}
|
|
|
|
}
|
|
config_unlock();
|
|
return result;
|
|
}
|
|
|