File PersistentStorage.h¶
File List > external-docs > libDaisy > src > util > PersistentStorage.h
Go to the documentation of this file
Source Code¶
#pragma once
#include "daisy_core.h"
#include "per/qspi.h"
#include "sys/dma.h"
namespace daisy
{
template <typename SettingStruct>
class PersistentStorage
{
public:
enum class State
{
UNKNOWN = 0,
FACTORY = 1,
USER = 2,
};
PersistentStorage(QSPIHandle &qspi)
: qspi_(qspi),
address_offset_(0),
default_settings_(),
settings_(),
state_(State::UNKNOWN)
{
}
void Init(const SettingStruct &defaults, uint32_t address_offset = 0)
{
default_settings_ = defaults;
settings_ = defaults;
address_offset_ = address_offset & (uint32_t)(~0xff);
auto storage_data
= reinterpret_cast<SaveStruct *>(qspi_.GetData(address_offset_));
// check to see if the state is already in use.
State cur_state = storage_data->storage_state;
if(cur_state != State::FACTORY && cur_state != State::USER)
{
// Initialize the Data store State::FACTORY, and the DefaultSettings
state_ = State::FACTORY;
StoreSettingsIfChanged();
}
else
{
state_ = cur_state;
settings_ = storage_data->user_data;
}
}
State GetState() const { return state_; }
SettingStruct &GetSettings() { return settings_; }
void Save()
{
state_ = State::USER;
StoreSettingsIfChanged();
}
void RestoreDefaults()
{
settings_ = default_settings_;
state_ = State::FACTORY;
StoreSettingsIfChanged();
}
private:
struct SaveStruct
{
State storage_state;
SettingStruct user_data;
};
void StoreSettingsIfChanged()
{
SaveStruct s;
s.storage_state = state_;
s.user_data = settings_;
void *data_ptr = qspi_.GetData(address_offset_);
#if !UNIT_TEST
// Caching behavior is different when running programs outside internal flash
// so we need to explicitly invalidate the QSPI mapped memory to ensure we are
// comparing the local settings with the most recently persisted settings.
if(System::GetProgramMemoryRegion()
!= System::MemoryRegion::INTERNAL_FLASH)
{
dsy_dma_invalidate_cache_for_buffer((uint8_t *)data_ptr, sizeof(s));
}
#endif
// Only actually save if the new data is different
// Use the `==operator` in custom SettingStruct to fine tune
// what may or may not trigger the erase/save.
auto storage_data = reinterpret_cast<SaveStruct *>(data_ptr);
if(settings_ != storage_data->user_data)
{
qspi_.Erase(address_offset_, address_offset_ + sizeof(s));
qspi_.Write(address_offset_, sizeof(s), (uint8_t *)&s);
}
}
QSPIHandle & qspi_;
uint32_t address_offset_;
SettingStruct default_settings_;
SettingStruct settings_;
State state_;
};
} // namespace daisy