367 lines
13 KiB
C++
367 lines
13 KiB
C++
#include "settingspersister.h"
|
|
|
|
// system includes
|
|
#include <type_traits>
|
|
|
|
// esp-idf includes
|
|
#include <esp_log.h>
|
|
#include <nvs_flash.h>
|
|
#include <lwip/apps/snmp.h>
|
|
#include <esp_sntp.h>
|
|
|
|
// 3rdparty lib includes
|
|
#include <fmt/core.h>
|
|
#include <cpputils.h>
|
|
#include <espchrono.h>
|
|
|
|
// local includes
|
|
#include "profilesettings.h"
|
|
#ifdef FEATURE_BLUETOOTH
|
|
#include "bluetoothmode.h"
|
|
#endif
|
|
#include "unifiedmodelmode.h"
|
|
#include "globals.h"
|
|
|
|
bool SettingsPersister::init()
|
|
{
|
|
if (esp_err_t result = nvs_flash_init();
|
|
cpputils::is_in(result, ESP_ERR_NVS_NO_FREE_PAGES, ESP_ERR_NVS_NEW_VERSION_FOUND))
|
|
{
|
|
ESP_LOGE("BOBBY", "nvs_flash_init() failed with %s, trying to erase...", esp_err_to_name(result));
|
|
return erase();
|
|
}
|
|
else if (result != ESP_OK)
|
|
{
|
|
ESP_LOGE("BOBBY", "nvs_flash_init() failed with %s", esp_err_to_name(result));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SettingsPersister::erase()
|
|
{
|
|
closeProfile();
|
|
|
|
bool result{true};
|
|
|
|
if (esp_err_t result = nvs_flash_erase(); result != ESP_OK)
|
|
{
|
|
ESP_LOGE("BOBBY", "nvs_flash_erase() failed with %s", esp_err_to_name(result));
|
|
result = false;
|
|
}
|
|
|
|
if (esp_err_t result = nvs_flash_init(); result != ESP_OK)
|
|
{
|
|
ESP_LOGE("BOBBY", "nvs_flash_init() failed with %s", esp_err_to_name(result));
|
|
result = false;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool SettingsPersister::openProfile(uint8_t index)
|
|
{
|
|
closeProfile();
|
|
|
|
nvs_handle handle;
|
|
const auto name = fmt::format("bobbycar{}", index);
|
|
if (esp_err_t result = nvs_open(name.c_str(), NVS_READWRITE, &handle); result != ESP_OK)
|
|
{
|
|
ESP_LOGE("BOBBY", "nvs_open() PROFILE %s failed with %s", name.c_str(), esp_err_to_name(result));
|
|
return false;
|
|
}
|
|
|
|
m_profile = {handle, index};
|
|
|
|
return true;
|
|
}
|
|
|
|
void SettingsPersister::closeProfile()
|
|
{
|
|
if (!m_profile)
|
|
return;
|
|
|
|
nvs_close(m_profile->handle);
|
|
|
|
m_profile = std::nullopt;
|
|
}
|
|
|
|
template<typename T> struct nvsGetterHelper;
|
|
template<> struct nvsGetterHelper<int8_t> { static constexpr auto nvs_get = &nvs_get_i8; };
|
|
template<> struct nvsGetterHelper<uint8_t> { static constexpr auto nvs_get = &nvs_get_u8; };
|
|
template<> struct nvsGetterHelper<int16_t> { static constexpr auto nvs_get = &nvs_get_i16; };
|
|
template<> struct nvsGetterHelper<uint16_t> { static constexpr auto nvs_get = &nvs_get_u16; };
|
|
template<> struct nvsGetterHelper<int32_t> { static constexpr auto nvs_get = &nvs_get_i32; };
|
|
template<> struct nvsGetterHelper<uint32_t> { static constexpr auto nvs_get = &nvs_get_u32; };
|
|
template<> struct nvsGetterHelper<std::string> { static esp_err_t nvs_get(nvs_handle handle, const char* key, std::string* out_value)
|
|
{
|
|
size_t length;
|
|
if (const esp_err_t result = nvs_get_str(handle, key, nullptr, &length); result != ESP_OK)
|
|
return result;
|
|
|
|
char buf[length];
|
|
if (const esp_err_t result = nvs_get_str(handle, key, buf, &length); result != ESP_OK)
|
|
return result;
|
|
|
|
*out_value = buf;
|
|
|
|
return ESP_OK;
|
|
}};
|
|
template<> struct nvsGetterHelper<bool> { static esp_err_t nvs_get(nvs_handle handle, const char* key, bool* out_value)
|
|
{
|
|
uint8_t tempValue;
|
|
esp_err_t err = nvs_get_u8(handle, key, &tempValue);
|
|
if (err == ESP_OK)
|
|
*out_value = tempValue;
|
|
return err;
|
|
}};
|
|
template<> struct nvsGetterHelper<bobbycar::protocol::ControlType> { static esp_err_t nvs_get(nvs_handle handle, const char* key, bobbycar::protocol::ControlType* out_value)
|
|
{
|
|
uint8_t tempValue;
|
|
esp_err_t err = nvs_get_u8(handle, key, &tempValue);
|
|
if (err == ESP_OK)
|
|
*out_value = bobbycar::protocol::ControlType(tempValue);
|
|
return err;
|
|
}};
|
|
template<> struct nvsGetterHelper<bobbycar::protocol::ControlMode> { static esp_err_t nvs_get(nvs_handle handle, const char* key, bobbycar::protocol::ControlMode* out_value)
|
|
{
|
|
uint8_t tempValue;
|
|
esp_err_t err = nvs_get_u8(handle, key, &tempValue);
|
|
if (err == ESP_OK)
|
|
*out_value = bobbycar::protocol::ControlMode(tempValue);
|
|
return err;
|
|
}};
|
|
template<> struct nvsGetterHelper<LarsmModeMode> { static esp_err_t nvs_get(nvs_handle handle, const char* key, LarsmModeMode* out_value)
|
|
{
|
|
uint8_t tempValue;
|
|
esp_err_t err = nvs_get_u8(handle, key, &tempValue);
|
|
if (err == ESP_OK)
|
|
*out_value = LarsmModeMode(tempValue);
|
|
return err;
|
|
}};
|
|
#ifdef FEATURE_BLUETOOTH
|
|
template<> struct nvsGetterHelper<BluetoothMode> { static esp_err_t nvs_get(nvs_handle handle, const char* key, BluetoothMode* out_value)
|
|
{
|
|
uint8_t tempValue;
|
|
esp_err_t err = nvs_get_u8(handle, key, &tempValue);
|
|
if (err == ESP_OK)
|
|
*out_value = BluetoothMode(tempValue);
|
|
return err;
|
|
}};
|
|
#endif
|
|
template<> struct nvsGetterHelper<UnifiedModelMode> { static esp_err_t nvs_get(nvs_handle handle, const char* key, UnifiedModelMode* out_value)
|
|
{
|
|
uint8_t tempValue;
|
|
esp_err_t err = nvs_get_u8(handle, key, &tempValue);
|
|
if (err == ESP_OK)
|
|
*out_value = UnifiedModelMode(tempValue);
|
|
return err;
|
|
}};
|
|
template<> struct nvsGetterHelper<wifi_mode_t> { static esp_err_t nvs_get(nvs_handle handle, const char* key, wifi_mode_t* out_value)
|
|
{
|
|
uint8_t tempValue;
|
|
esp_err_t err = nvs_get_u8(handle, key, &tempValue);
|
|
if (err == ESP_OK)
|
|
*out_value = wifi_mode_t(tempValue);
|
|
return err;
|
|
}};
|
|
template<> struct nvsGetterHelper<espchrono::DayLightSavingMode> { static esp_err_t nvs_get(nvs_handle handle, const char* key, espchrono::DayLightSavingMode* out_value)
|
|
{
|
|
uint8_t tempValue;
|
|
esp_err_t err = nvs_get_u8(handle, key, &tempValue);
|
|
if (err == ESP_OK)
|
|
*out_value = espchrono::DayLightSavingMode(tempValue);
|
|
return err;
|
|
}};
|
|
template<> struct nvsGetterHelper<espchrono::milliseconds32> { static esp_err_t nvs_get(nvs_handle handle, const char* key, espchrono::milliseconds32* out_value)
|
|
{
|
|
int32_t tempValue;
|
|
esp_err_t err = nvs_get_i32(handle, key, &tempValue);
|
|
if (err == ESP_OK)
|
|
*out_value = espchrono::milliseconds32(tempValue);
|
|
return err;
|
|
}};
|
|
template<> struct nvsGetterHelper<espchrono::seconds32> { static esp_err_t nvs_get(nvs_handle handle, const char* key, espchrono::seconds32* out_value)
|
|
{
|
|
int32_t tempValue;
|
|
esp_err_t err = nvs_get_i32(handle, key, &tempValue);
|
|
if (err == ESP_OK)
|
|
*out_value = espchrono::seconds32(tempValue);
|
|
return err;
|
|
}};
|
|
template<> struct nvsGetterHelper<espchrono::minutes32> { static esp_err_t nvs_get(nvs_handle handle, const char* key, espchrono::minutes32* out_value)
|
|
{
|
|
int32_t tempValue;
|
|
esp_err_t err = nvs_get_i32(handle, key, &tempValue);
|
|
if (err == ESP_OK)
|
|
*out_value = espchrono::minutes32(tempValue);
|
|
return err;
|
|
}};
|
|
template<> struct nvsGetterHelper<espchrono::hours32> { static esp_err_t nvs_get(nvs_handle handle, const char* key, espchrono::hours32* out_value)
|
|
{
|
|
int32_t tempValue;
|
|
esp_err_t err = nvs_get_i32(handle, key, &tempValue);
|
|
if (err == ESP_OK)
|
|
*out_value = espchrono::hours32(tempValue);
|
|
return err;
|
|
}};
|
|
template<> struct nvsGetterHelper<sntp_sync_mode_t> { static esp_err_t nvs_get(nvs_handle handle, const char* key, sntp_sync_mode_t* out_value)
|
|
{
|
|
uint8_t tempValue;
|
|
esp_err_t err = nvs_get_u8(handle, key, &tempValue);
|
|
if (err == ESP_OK)
|
|
*out_value = sntp_sync_mode_t(tempValue);
|
|
return err;
|
|
}};
|
|
template<> struct nvsGetterHelper<std::array<int8_t, 4>> { static esp_err_t nvs_get(nvs_handle handle, const char* key, std::array<int8_t, 4>* out_value)
|
|
{
|
|
uint32_t tempValue;
|
|
esp_err_t err = nvs_get_u32(handle, key, &tempValue);
|
|
if (err == ESP_OK)
|
|
*out_value = std::bit_cast<std::array<int8_t, 4>>(tempValue);
|
|
return err;
|
|
}};
|
|
template<> struct nvsGetterHelper<std::array<uint8_t, 4>> { static esp_err_t nvs_get(nvs_handle handle, const char* key, std::array<uint8_t, 4>* out_value)
|
|
{
|
|
uint32_t tempValue;
|
|
esp_err_t err = nvs_get_u32(handle, key, &tempValue);
|
|
if (err == ESP_OK)
|
|
*out_value = std::bit_cast<std::array<uint8_t, 4>>(tempValue);
|
|
return err;
|
|
}};
|
|
|
|
template<typename T>
|
|
bool SettingsPersister::load(T &settings)
|
|
{
|
|
bool result{true};
|
|
|
|
if (m_profile)
|
|
{
|
|
profileSettings.executeForEveryProfileSetting([&](const char *key, auto &value)
|
|
{
|
|
if (esp_err_t result = nvsGetterHelper<std::decay_t<decltype(value)>>::nvs_get(m_profile->handle, key, &value); result != ESP_OK)
|
|
{
|
|
if (result != ESP_ERR_NVS_NOT_FOUND)
|
|
ESP_LOGE("BOBBY", "nvs_get() PROFILE %s failed with %s", key, esp_err_to_name(result));
|
|
result = false;
|
|
}
|
|
});
|
|
}
|
|
else
|
|
{
|
|
ESP_LOGW("BOBBY", "no profile open currently!");
|
|
result = false;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
template bool SettingsPersister::load<ProfileSettings>(ProfileSettings &profileSettings);
|
|
|
|
template<typename T> struct nvsSetterHelper;
|
|
template<> struct nvsSetterHelper<int8_t> { static constexpr auto nvs_set = &nvs_set_i8; };
|
|
template<> struct nvsSetterHelper<uint8_t> { static constexpr auto nvs_set = &nvs_set_u8; };
|
|
template<> struct nvsSetterHelper<int16_t> { static constexpr auto nvs_set = &nvs_set_i16; };
|
|
template<> struct nvsSetterHelper<uint16_t> { static constexpr auto nvs_set = &nvs_set_u16; };
|
|
template<> struct nvsSetterHelper<int32_t> { static constexpr auto nvs_set = &nvs_set_i32; };
|
|
template<> struct nvsSetterHelper<uint32_t> { static constexpr auto nvs_set = &nvs_set_u32; };
|
|
template<> struct nvsSetterHelper<bool> { static constexpr auto nvs_set = &nvs_set_u8; };
|
|
template<> struct nvsSetterHelper<std::string> { static esp_err_t nvs_set(nvs_handle handle, const char* key, const std::string &value)
|
|
{
|
|
return nvs_set_str(handle, key, value.c_str());
|
|
}};
|
|
template<> struct nvsSetterHelper<bobbycar::protocol::ControlType> { static esp_err_t nvs_set(nvs_handle handle, const char* key, bobbycar::protocol::ControlType value)
|
|
{
|
|
return nvs_set_u8(handle, key, uint8_t(value));
|
|
}};
|
|
template<> struct nvsSetterHelper<bobbycar::protocol::ControlMode> { static esp_err_t nvs_set(nvs_handle handle, const char* key, bobbycar::protocol::ControlMode value)
|
|
{
|
|
return nvs_set_u8(handle, key, uint8_t(value));
|
|
}};
|
|
template<> struct nvsSetterHelper<LarsmModeMode> { static esp_err_t nvs_set(nvs_handle handle, const char* key, LarsmModeMode value)
|
|
{
|
|
return nvs_set_u8(handle, key, uint8_t(value));
|
|
}};
|
|
#ifdef FEATURE_BLUETOOTH
|
|
template<> struct nvsSetterHelper<BluetoothMode> { static esp_err_t nvs_set(nvs_handle handle, const char* key, BluetoothMode value)
|
|
{
|
|
return nvs_set_u8(handle, key, uint8_t(value));
|
|
}};
|
|
#endif
|
|
template<> struct nvsSetterHelper<UnifiedModelMode> { static esp_err_t nvs_set(nvs_handle handle, const char* key, UnifiedModelMode value)
|
|
{
|
|
return nvs_set_u8(handle, key, uint8_t(value));
|
|
}};
|
|
template<> struct nvsSetterHelper<wifi_mode_t> { static esp_err_t nvs_set(nvs_handle handle, const char* key, wifi_mode_t value)
|
|
{
|
|
return nvs_set_u8(handle, key, uint8_t(value));
|
|
}};
|
|
template<> struct nvsSetterHelper<espchrono::DayLightSavingMode> { static esp_err_t nvs_set(nvs_handle handle, const char* key, espchrono::DayLightSavingMode value)
|
|
{
|
|
return nvs_set_u8(handle, key, uint8_t(value));
|
|
}};
|
|
template<> struct nvsSetterHelper<espchrono::milliseconds32> { static esp_err_t nvs_set(nvs_handle handle, const char* key, espchrono::milliseconds32 value)
|
|
{
|
|
return nvs_set_i32(handle, key, value.count());
|
|
}};
|
|
template<> struct nvsSetterHelper<espchrono::seconds32> { static esp_err_t nvs_set(nvs_handle handle, const char* key, espchrono::seconds32 value)
|
|
{
|
|
return nvs_set_i32(handle, key, value.count());
|
|
}};
|
|
template<> struct nvsSetterHelper<espchrono::minutes32> { static esp_err_t nvs_set(nvs_handle handle, const char* key, espchrono::minutes32 value)
|
|
{
|
|
return nvs_set_i32(handle, key, value.count());
|
|
}};
|
|
template<> struct nvsSetterHelper<espchrono::hours32> { static esp_err_t nvs_set(nvs_handle handle, const char* key, espchrono::hours32 value)
|
|
{
|
|
return nvs_set_i32(handle, key, value.count());
|
|
}};
|
|
template<> struct nvsSetterHelper<sntp_sync_mode_t> { static esp_err_t nvs_set(nvs_handle handle, const char* key, sntp_sync_mode_t value)
|
|
{
|
|
return nvs_set_u8(handle, key, uint8_t(value));
|
|
}};
|
|
template<> struct nvsSetterHelper<std::array<int8_t, 4>> { static esp_err_t nvs_set(nvs_handle handle, const char* key, std::array<int8_t, 4> value)
|
|
{
|
|
return nvs_set_u32(handle, key, std::bit_cast<uint32_t>(value));
|
|
}};
|
|
template<> struct nvsSetterHelper<std::array<uint8_t, 4>> { static esp_err_t nvs_set(nvs_handle handle, const char* key, std::array<uint8_t, 4> value)
|
|
{
|
|
return nvs_set_u32(handle, key, std::bit_cast<uint32_t>(value));
|
|
}};
|
|
|
|
template<typename T>
|
|
bool SettingsPersister::save(T &settings)
|
|
{
|
|
bool result{true};
|
|
|
|
if (m_profile)
|
|
{
|
|
profileSettings.executeForEveryProfileSetting([&](const char *key, const auto &value)
|
|
{
|
|
if (esp_err_t result = nvsSetterHelper<std::decay_t<decltype(value)>>::nvs_set(m_profile->handle, key, value); result != ESP_OK)
|
|
{
|
|
ESP_LOGE("BOBBY", "nvs_set() PROFILE %s failed with %s", key, esp_err_to_name(result));
|
|
result = false;
|
|
}
|
|
});
|
|
}
|
|
else
|
|
{
|
|
ESP_LOGW("BOBBY", "no profile open currently!");
|
|
result = false;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
template bool SettingsPersister::save<ProfileSettings>(ProfileSettings &settings);
|
|
|
|
std::optional<uint8_t> SettingsPersister::currentlyOpenProfileIndex() const
|
|
{
|
|
if (m_profile)
|
|
return m_profile->profileIndex;
|
|
|
|
return std::nullopt;
|
|
}
|