Fix metadata loading issues with Initialization and refactor Factory Reset. (#19)

Reviewed-on: https://git.pinkduck.xyz/awonak/libGravity/pulls/19
This commit is contained in:
2025-07-23 03:32:16 +00:00
parent c5bddef66d
commit ec34bc3a7b
4 changed files with 37 additions and 33 deletions

View File

@ -222,10 +222,9 @@ void HandleEncoderPressed() {
} }
} }
if (app.selected_param == PARAM_MAIN_FACTORY_RESET) { if (app.selected_param == PARAM_MAIN_FACTORY_RESET) {
if (app.selected_sub_param == 0) { // Reset if (app.selected_sub_param == 0) { // Erase
Bootsplash(); Bootsplash();
stateManager.factoryReset(); stateManager.factoryReset(app);
stateManager.reset(app);
InitGravity(app); InitGravity(app);
} }
} }

View File

@ -476,13 +476,13 @@ void Bootsplash() {
gravity.display.setFont(TEXT_FONT); gravity.display.setFont(TEXT_FONT);
textWidth = gravity.display.getStrWidth(SKETCH_NAME); textWidth = gravity.display.getStrWidth(SKETCH_NAME);
gravity.display.drawStr(24 + (textWidth / 2), 24, SKETCH_NAME); gravity.display.drawStr(16 + (textWidth / 2), 20, SKETCH_NAME);
textWidth = gravity.display.getStrWidth(SEMANTIC_VERSION); textWidth = gravity.display.getStrWidth(SEMANTIC_VERSION);
gravity.display.drawStr(24 + (textWidth / 2), 36, SEMANTIC_VERSION); gravity.display.drawStr(16 + (textWidth / 2), 32, SEMANTIC_VERSION);
textWidth = gravity.display.getStrWidth("LOADING...."); textWidth = gravity.display.getStrWidth("LOADING....");
gravity.display.drawStr(34 + (textWidth / 2), 48, "LOADING...."); gravity.display.drawStr(26 + (textWidth / 2), 44, "LOADING....");
} while (gravity.display.nextPage()); } while (gravity.display.nextPage());
} }

View File

@ -23,20 +23,16 @@ StateManager::StateManager() : _isDirty(false), _lastChangeTime(0) {}
bool StateManager::initialize(AppState& app) { bool StateManager::initialize(AppState& app) {
if (_isDataValid()) { if (_isDataValid()) {
// Load data from the transient slot. // Load global settings.
return loadData(app, TRANSIENT_SLOT); _loadMetadata(app);
// Load app data from the transient slot.
_loadState(app, TRANSIENT_SLOT);
return true;
} }
// EEPROM does not contain save data for this firmware & version. // EEPROM does not contain save data for this firmware & version.
else { else {
// Erase EEPROM and initialize state. Save default pattern to all save slots. // Erase EEPROM and initialize state. Save default pattern to all save slots.
factoryReset(); factoryReset(app);
// Initialize eeprom and save default patter to all save slots.
_saveMetadata(app);
reset(app);
for (int i = 0; i < MAX_SAVE_SLOTS; i++) {
_saveState(app, i);
}
_saveState(app, TRANSIENT_SLOT);
return false; return false;
} }
} }
@ -45,8 +41,11 @@ bool StateManager::loadData(AppState& app, byte slot_index) {
// Check if slot_index is within max range + 1 for transient. // Check if slot_index is within max range + 1 for transient.
if (slot_index >= MAX_SAVE_SLOTS + 1) return false; if (slot_index >= MAX_SAVE_SLOTS + 1) return false;
// Load the state data from the specified EEPROM slot and update the app state save slot.
_loadState(app, slot_index); _loadState(app, slot_index);
_loadMetadata(app); app.selected_save_slot = slot_index;
// Persist this change in the global metadata.
_saveMetadata(app);
return true; return true;
} }
@ -57,6 +56,7 @@ void StateManager::saveData(const AppState& app) {
if (app.selected_save_slot >= MAX_SAVE_SLOTS + 1) return; if (app.selected_save_slot >= MAX_SAVE_SLOTS + 1) return;
_saveState(app, app.selected_save_slot); _saveState(app, app.selected_save_slot);
_saveMetadata(app);
_isDirty = false; _isDirty = false;
} }
@ -70,12 +70,12 @@ void StateManager::update(const AppState& app) {
} }
void StateManager::reset(AppState& app) { void StateManager::reset(AppState& app) {
app.tempo = Clock::DEFAULT_TEMPO; AppState default_app;
app.selected_param = 0; app.tempo = default_app.tempo;
app.selected_channel = 0; app.selected_param = default_app.selected_param;
app.selected_source = Clock::SOURCE_INTERNAL; app.selected_channel = default_app.selected_channel;
app.selected_pulse = Clock::PULSE_PPQN_24; app.selected_source = default_app.selected_source;
app.selected_save_slot = 0; app.selected_pulse = default_app.selected_pulse;
for (int i = 0; i < Gravity::OUTPUT_COUNT; i++) { for (int i = 0; i < Gravity::OUTPUT_COUNT; i++) {
app.channel[i].Init(); app.channel[i].Init();
@ -93,19 +93,27 @@ void StateManager::markDirty() {
} }
// Erases all data in the EEPROM by writing 0 to every address. // Erases all data in the EEPROM by writing 0 to every address.
void StateManager::factoryReset() { void StateManager::factoryReset(AppState& app) {
noInterrupts(); noInterrupts();
for (unsigned int i = 0; i < EEPROM.length(); i++) { for (unsigned int i = 0; i < EEPROM.length(); i++) {
EEPROM.write(i, 0); EEPROM.write(i, 0);
} }
// Initialize eeprom and save default patter to all save slots.
_saveMetadata(app);
reset(app);
for (int i = 0; i < MAX_SAVE_SLOTS; i++) {
app.selected_save_slot = i;
_saveState(app, i);
}
_saveState(app, TRANSIENT_SLOT);
interrupts(); interrupts();
} }
bool StateManager::_isDataValid() { bool StateManager::_isDataValid() {
Metadata load_meta; Metadata metadata;
EEPROM.get(METADATA_START_ADDR, load_meta); EEPROM.get(METADATA_START_ADDR, metadata);
bool name_match = (strcmp(load_meta.sketch_name, SKETCH_NAME) == 0); bool name_match = (strcmp(metadata.sketch_name, SKETCH_NAME) == 0);
bool version_match = (strcmp(load_meta.version, SEMANTIC_VERSION) == 0); bool version_match = (strcmp(metadata.version, SEMANTIC_VERSION) == 0);
return name_match && version_match; return name_match && version_match;
} }
@ -117,7 +125,6 @@ void StateManager::_saveState(const AppState& app, byte slot_index) {
static EepromData save_data; static EepromData save_data;
save_data.tempo = app.tempo; save_data.tempo = app.tempo;
save_data.encoder_reversed = app.encoder_reversed;
save_data.selected_param = app.selected_param; save_data.selected_param = app.selected_param;
save_data.selected_channel = app.selected_channel; save_data.selected_channel = app.selected_channel;
save_data.selected_source = static_cast<byte>(app.selected_source); save_data.selected_source = static_cast<byte>(app.selected_source);
@ -161,7 +168,6 @@ void StateManager::_loadState(AppState& app, byte slot_index) {
app.selected_channel = load_data.selected_channel; app.selected_channel = load_data.selected_channel;
app.selected_source = static_cast<Clock::Source>(load_data.selected_source); app.selected_source = static_cast<Clock::Source>(load_data.selected_source);
app.selected_pulse = static_cast<Clock::Pulse>(load_data.selected_pulse); app.selected_pulse = static_cast<Clock::Pulse>(load_data.selected_pulse);
app.selected_save_slot = slot_index;
for (int i = 0; i < Gravity::OUTPUT_COUNT; i++) { for (int i = 0; i < Gravity::OUTPUT_COUNT; i++) {
auto& ch = app.channel[i]; auto& ch = app.channel[i];

View File

@ -20,7 +20,7 @@ struct AppState;
// Define the constants for the current firmware. // Define the constants for the current firmware.
const char SKETCH_NAME[] = "ALT GRAVITY"; const char SKETCH_NAME[] = "ALT GRAVITY";
const char SEMANTIC_VERSION[] = "V2.0.0BETA1"; const char SEMANTIC_VERSION[] = "V2.0.0BETA2";
// Number of available save slots. // Number of available save slots.
const byte MAX_SAVE_SLOTS = 10; // Count of save slots 0 - 9 to save/load presets. const byte MAX_SAVE_SLOTS = 10; // Count of save slots 0 - 9 to save/load presets.
@ -54,7 +54,7 @@ class StateManager {
// Indicate that state has changed and we should save. // Indicate that state has changed and we should save.
void markDirty(); void markDirty();
// Erase all data stored in the EEPROM. // Erase all data stored in the EEPROM.
void factoryReset(); void factoryReset(AppState& app);
// This struct holds the data that identifies the firmware version. // This struct holds the data that identifies the firmware version.
struct Metadata { struct Metadata {
@ -78,7 +78,6 @@ class StateManager {
// This struct holds all the parameters we want to save. // This struct holds all the parameters we want to save.
struct EepromData { struct EepromData {
int tempo; int tempo;
bool encoder_reversed;
byte selected_param; byte selected_param;
byte selected_channel; byte selected_channel;
byte selected_source; byte selected_source;