// // Created by MightyPork on 2018/11/18. // #include #include #include #include "settings.h" #include "utils.h" static const char * TAG = "settings.c"; static uint16_t app_boot_count = 0; #undef X #define X(pre,name,post,def,gen_nvs,nvs_format,save_prefix) .name = def, const struct cspemu_settings defaults = { SETTINGS_XTABLE() }; struct cspemu_settings g_Settings; struct cspemu_globals g_State = { .wifi_inited = false, }; static nvs_handle storage = 0; extern nvs_handle g_nvs_storage __attribute__((alias("storage"))); void settings_init(void) { ESP_ERROR_CHECK(nvs_open("cspemu", NVS_READWRITE, &storage)); } union fu { float f; uint32_t u; }; /** Read float from NVS. See `nvs_get_u32` for more info. */ static esp_err_t nvs_get_f32 (nvs_handle_t handle, const char* key, float* out_value) { uint32_t u = 0; esp_err_t rv = nvs_get_u32(handle, key, &u); if (rv != ESP_OK) { return rv; } union fu reinterpret = { .u = u, }; *out_value = reinterpret.f; return ESP_OK; } /** Write float to NVS. See `nvs_set_u32` for more info. */ static esp_err_t nvs_set_f32 (nvs_handle_t handle, const char* key, float value) { union fu reinterpret = { .f = value, }; return nvs_set_u32(handle, key, reinterpret.u); } /** Dummy read from NVS; placeholder for XTABLE entries with manually implemented getters */ static esp_err_t nvs_get_none(nvs_handle handle, const char* key, void* out_value) { return ESP_OK; } /** Dummy write to NVS; placeholder for XTABLE entries with manually implemented setters */ static esp_err_t nvs_set_none(nvs_handle handle, const char* key, void* value) { return ESP_OK; } void settings_load(void) { esp_err_t rv; memcpy(&g_Settings, &defaults, sizeof(struct cspemu_settings)); // abort on failure other than "not found" #define NVSCHECK(callback) \ do { \ rv = callback; \ if (rv != ESP_OK && rv != ESP_ERR_NVS_NOT_FOUND) { \ ESP_LOGE(TAG, "NVS ERR %d", rv); \ abort(); \ } \ } while(0) NVSCHECK(nvs_get_u16(storage, "bootcount", &app_boot_count)); ESP_LOGI(TAG, "NVS restored bootcount %d", app_boot_count); app_boot_count++; NVSCHECK(nvs_set_u16(storage, "bootcount", app_boot_count)); // version will be used for settings format upgrades uint8_t version = 0; NVSCHECK(nvs_get_u8(storage, "version", &version)); #undef X #define X(pre, name, post, def, gen_nvs, nvs_format, save_prefix) \ if (gen_nvs) { \ NVSCHECK(nvs_get_##nvs_format(storage, STR(name), save_prefix g_Settings. name)); \ } SETTINGS_XTABLE() // custom values #define ensure_str_terminated(str, len) if (strnlen((str), (len)) >= (len)) { (str)[(len)-1] = 0; } { size_t capacity = CONSOLE_PW_LEN; NVSCHECK(nvs_get_str(storage, "tcpp_pw", g_Settings.console_pw, &capacity)); ensure_str_terminated(g_Settings.console_pw, CONSOLE_PW_LEN); } { size_t capacity = NTP_SRV_LEN; NVSCHECK(nvs_get_str(storage, "ntp_srv", g_Settings.ntp_srv, &capacity)); ensure_str_terminated(g_Settings.ntp_srv, NTP_SRV_LEN); } { size_t capacity = 10; NVSCHECK(nvs_get_blob(storage, "co2_calib", g_Settings.co2_calib, &capacity)); } { size_t capacity = BSEC_MAX_STATE_BLOB_SIZE; NVSCHECK(nvs_get_blob(storage, "bsec_state", g_Settings.bsec_state, &capacity)); } } void settings_persist(enum settings_key_enum what) { esp_err_t rv; // char name[24]; #undef NVSCHECK #define NVSCHECK(callback) \ do { \ rv = (callback); \ if (rv != ESP_OK) { \ ESP_LOGE(TAG, "NVS ERR %d", rv); \ abort(); \ } \ } while(0) #undef X #define X(pre,name,post,def,gen_nvs,nvs_format,save_prefix) \ if ((gen_nvs) && ((what)==SETTINGS_ALL || (what)==SETTINGS_## name)) { \ NVSCHECK(nvs_set_##nvs_format(storage, STR(name), g_Settings. name)); \ } SETTINGS_XTABLE() // custom values if (what==SETTINGS_ALL || what==SETTINGS_console_pw) { NVSCHECK(nvs_set_str(storage, "tcpp_pw", g_Settings.console_pw)); } if (what==SETTINGS_ALL || what==SETTINGS_ntp_srv) { NVSCHECK(nvs_set_str(storage, "ntp_srv", g_Settings.ntp_srv)); } if (what==SETTINGS_ALL || what==SETTINGS_co2_calib) { NVSCHECK(nvs_set_blob(storage, "co2_calib", (void*) g_Settings.co2_calib, 5*sizeof(uint16_t))); } if (what==SETTINGS_ALL || what==SETTINGS_bsec_state) { NVSCHECK(nvs_set_blob(storage, "bsec_state", (void*) g_Settings.bsec_state, BSEC_MAX_STATE_BLOB_SIZE)); } } uint16_t app_get_bootcount() { return app_boot_count; }