Improve live clock performance when loading pattern data. If the clock is playing, only load pattern and tempo, do not load global settings which impact performance.
Refactor the save / load state use of disabling interrupts by wrapping all private methods from inside the public method. This ensures we will not have a race condition if an interrupt is called in between the private method calls.
This commit is contained in:
@ -244,10 +244,18 @@ void HandleEncoderPressed() {
|
||||
if (app.selected_param == PARAM_MAIN_LOAD_DATA) {
|
||||
if (app.selected_sub_param < StateManager::MAX_SAVE_SLOTS) {
|
||||
app.selected_save_slot = app.selected_sub_param;
|
||||
// Load pattern data into app state.
|
||||
stateManager.loadData(app, app.selected_save_slot);
|
||||
// Load global performance settings if they have changed.
|
||||
if (gravity.clock.Tempo() != app.tempo) {
|
||||
gravity.clock.SetTempo(app.tempo);
|
||||
}
|
||||
// Load global settings only if clock is not active.
|
||||
if (gravity.clock.IsPaused()) {
|
||||
InitGravity(app);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (app.selected_param == PARAM_MAIN_RESET_STATE) {
|
||||
if (app.selected_sub_param == 0) { // Reset
|
||||
stateManager.reset(app);
|
||||
|
||||
@ -35,20 +35,23 @@ const int StateManager::EEPROM_DATA_START_ADDR = sizeof(StateManager::Metadata);
|
||||
StateManager::StateManager() : _isDirty(false), _lastChangeTime(0) {}
|
||||
|
||||
bool StateManager::initialize(AppState &app) {
|
||||
noInterrupts();
|
||||
bool success = false;
|
||||
if (_isDataValid()) {
|
||||
// Load global settings.
|
||||
_loadMetadata(app);
|
||||
// Load app data from the transient slot.
|
||||
_loadState(app, TRANSIENT_SLOT);
|
||||
return true;
|
||||
success = true;
|
||||
}
|
||||
// EEPROM does not contain save data for this firmware & version.
|
||||
else {
|
||||
// Erase EEPROM and initialize state. Save default pattern to all save
|
||||
// slots.
|
||||
factoryReset(app);
|
||||
return false;
|
||||
}
|
||||
interrupts();
|
||||
return success;
|
||||
}
|
||||
|
||||
bool StateManager::loadData(AppState &app, byte slot_index) {
|
||||
@ -56,38 +59,49 @@ bool StateManager::loadData(AppState &app, byte slot_index) {
|
||||
if (slot_index >= MAX_SAVE_SLOTS + 1)
|
||||
return false;
|
||||
|
||||
noInterrupts();
|
||||
|
||||
// Load the state data from the specified EEPROM slot and update the app state
|
||||
// save slot.
|
||||
_loadState(app, slot_index);
|
||||
app.selected_save_slot = slot_index;
|
||||
// Persist this change in the global metadata.
|
||||
_saveMetadata(app);
|
||||
// Persist this change in the global metadata on next update.
|
||||
_isDirty = true;
|
||||
|
||||
interrupts();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Save app state to user specified save slot.
|
||||
void StateManager::saveData(const AppState &app) {
|
||||
noInterrupts();
|
||||
// Check if slot_index is within max range + 1 for transient.
|
||||
if (app.selected_save_slot >= MAX_SAVE_SLOTS + 1)
|
||||
if (app.selected_save_slot >= MAX_SAVE_SLOTS + 1) {
|
||||
interrupts();
|
||||
return;
|
||||
}
|
||||
|
||||
_saveState(app, app.selected_save_slot);
|
||||
_saveMetadata(app);
|
||||
_isDirty = false;
|
||||
interrupts();
|
||||
}
|
||||
|
||||
// Save transient state if it has changed and enough time has passed since last
|
||||
// save.
|
||||
void StateManager::update(const AppState &app) {
|
||||
if (_isDirty && (millis() - _lastChangeTime > SAVE_DELAY_MS)) {
|
||||
noInterrupts();
|
||||
_saveState(app, TRANSIENT_SLOT);
|
||||
_saveMetadata(app);
|
||||
_isDirty = false;
|
||||
interrupts();
|
||||
}
|
||||
}
|
||||
|
||||
void StateManager::reset(AppState &app) {
|
||||
noInterrupts();
|
||||
|
||||
AppState default_app;
|
||||
app.tempo = default_app.tempo;
|
||||
app.selected_param = default_app.selected_param;
|
||||
@ -105,6 +119,7 @@ void StateManager::reset(AppState &app) {
|
||||
_loadMetadata(app);
|
||||
|
||||
_isDirty = false;
|
||||
interrupts();
|
||||
}
|
||||
|
||||
void StateManager::markDirty() {
|
||||
@ -142,7 +157,6 @@ void StateManager::_saveState(const AppState &app, byte slot_index) {
|
||||
if (app.selected_save_slot >= MAX_SAVE_SLOTS + 1)
|
||||
return;
|
||||
|
||||
noInterrupts();
|
||||
static EepromData save_data;
|
||||
|
||||
save_data.tempo = app.tempo;
|
||||
@ -169,7 +183,6 @@ void StateManager::_saveState(const AppState &app, byte slot_index) {
|
||||
|
||||
int address = EEPROM_DATA_START_ADDR + (slot_index * sizeof(EepromData));
|
||||
EEPROM.put(address, save_data);
|
||||
interrupts();
|
||||
}
|
||||
|
||||
void StateManager::_loadState(AppState &app, byte slot_index) {
|
||||
@ -177,7 +190,6 @@ void StateManager::_loadState(AppState &app, byte slot_index) {
|
||||
if (slot_index >= MAX_SAVE_SLOTS + 1)
|
||||
return;
|
||||
|
||||
noInterrupts();
|
||||
static EepromData load_data;
|
||||
int address = EEPROM_DATA_START_ADDR + (slot_index * sizeof(EepromData));
|
||||
EEPROM.get(address, load_data);
|
||||
@ -201,11 +213,9 @@ void StateManager::_loadState(AppState &app, byte slot_index) {
|
||||
ch.setCv1Dest(static_cast<CvDestination>(saved_ch_state.cv1_dest));
|
||||
ch.setCv2Dest(static_cast<CvDestination>(saved_ch_state.cv2_dest));
|
||||
}
|
||||
interrupts();
|
||||
}
|
||||
|
||||
void StateManager::_saveMetadata(const AppState &app) {
|
||||
noInterrupts();
|
||||
Metadata current_meta;
|
||||
strcpy(current_meta.sketch_name, SKETCH_NAME);
|
||||
strcpy(current_meta.version, SEMANTIC_VERSION);
|
||||
@ -216,15 +226,12 @@ void StateManager::_saveMetadata(const AppState &app) {
|
||||
current_meta.rotate_display = app.rotate_display;
|
||||
|
||||
EEPROM.put(METADATA_START_ADDR, current_meta);
|
||||
interrupts();
|
||||
}
|
||||
|
||||
void StateManager::_loadMetadata(AppState &app) {
|
||||
noInterrupts();
|
||||
Metadata metadata;
|
||||
EEPROM.get(METADATA_START_ADDR, metadata);
|
||||
app.selected_save_slot = metadata.selected_save_slot;
|
||||
app.encoder_reversed = metadata.encoder_reversed;
|
||||
app.rotate_display = metadata.rotate_display;
|
||||
interrupts();
|
||||
}
|
||||
@ -244,10 +244,18 @@ void HandleEncoderPressed() {
|
||||
if (app.selected_param == PARAM_MAIN_LOAD_DATA) {
|
||||
if (app.selected_sub_param < StateManager::MAX_SAVE_SLOTS) {
|
||||
app.selected_save_slot = app.selected_sub_param;
|
||||
// Load pattern data into app state.
|
||||
stateManager.loadData(app, app.selected_save_slot);
|
||||
// Load global performance settings if they have changed.
|
||||
if (gravity.clock.Tempo() != app.tempo) {
|
||||
gravity.clock.SetTempo(app.tempo);
|
||||
}
|
||||
// Load global settings only if clock is not active.
|
||||
if (gravity.clock.IsPaused()) {
|
||||
InitGravity(app);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (app.selected_param == PARAM_MAIN_RESET_STATE) {
|
||||
if (app.selected_sub_param == 0) { // Reset
|
||||
stateManager.reset(app);
|
||||
|
||||
@ -35,20 +35,23 @@ const int StateManager::EEPROM_DATA_START_ADDR = sizeof(StateManager::Metadata);
|
||||
StateManager::StateManager() : _isDirty(false), _lastChangeTime(0) {}
|
||||
|
||||
bool StateManager::initialize(AppState &app) {
|
||||
noInterrupts();
|
||||
bool success = false;
|
||||
if (_isDataValid()) {
|
||||
// Load global settings.
|
||||
_loadMetadata(app);
|
||||
// Load app data from the transient slot.
|
||||
_loadState(app, TRANSIENT_SLOT);
|
||||
return true;
|
||||
success = true;
|
||||
}
|
||||
// EEPROM does not contain save data for this firmware & version.
|
||||
else {
|
||||
// Erase EEPROM and initialize state. Save default pattern to all save
|
||||
// slots.
|
||||
factoryReset(app);
|
||||
return false;
|
||||
}
|
||||
interrupts();
|
||||
return success;
|
||||
}
|
||||
|
||||
bool StateManager::loadData(AppState &app, byte slot_index) {
|
||||
@ -56,38 +59,49 @@ bool StateManager::loadData(AppState &app, byte slot_index) {
|
||||
if (slot_index >= MAX_SAVE_SLOTS + 1)
|
||||
return false;
|
||||
|
||||
noInterrupts();
|
||||
|
||||
// Load the state data from the specified EEPROM slot and update the app state
|
||||
// save slot.
|
||||
_loadState(app, slot_index);
|
||||
app.selected_save_slot = slot_index;
|
||||
// Persist this change in the global metadata.
|
||||
_saveMetadata(app);
|
||||
// Persist this change in the global metadata on next update.
|
||||
_isDirty = true;
|
||||
|
||||
interrupts();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Save app state to user specified save slot.
|
||||
void StateManager::saveData(const AppState &app) {
|
||||
noInterrupts();
|
||||
// Check if slot_index is within max range + 1 for transient.
|
||||
if (app.selected_save_slot >= MAX_SAVE_SLOTS + 1)
|
||||
if (app.selected_save_slot >= MAX_SAVE_SLOTS + 1) {
|
||||
interrupts();
|
||||
return;
|
||||
}
|
||||
|
||||
_saveState(app, app.selected_save_slot);
|
||||
_saveMetadata(app);
|
||||
_isDirty = false;
|
||||
interrupts();
|
||||
}
|
||||
|
||||
// Save transient state if it has changed and enough time has passed since last
|
||||
// save.
|
||||
void StateManager::update(const AppState &app) {
|
||||
if (_isDirty && (millis() - _lastChangeTime > SAVE_DELAY_MS)) {
|
||||
noInterrupts();
|
||||
_saveState(app, TRANSIENT_SLOT);
|
||||
_saveMetadata(app);
|
||||
_isDirty = false;
|
||||
interrupts();
|
||||
}
|
||||
}
|
||||
|
||||
void StateManager::reset(AppState &app) {
|
||||
noInterrupts();
|
||||
|
||||
AppState default_app;
|
||||
app.tempo = default_app.tempo;
|
||||
app.selected_param = default_app.selected_param;
|
||||
@ -105,6 +119,7 @@ void StateManager::reset(AppState &app) {
|
||||
_loadMetadata(app);
|
||||
|
||||
_isDirty = false;
|
||||
interrupts();
|
||||
}
|
||||
|
||||
void StateManager::markDirty() {
|
||||
@ -142,7 +157,6 @@ void StateManager::_saveState(const AppState &app, byte slot_index) {
|
||||
if (app.selected_save_slot >= MAX_SAVE_SLOTS + 1)
|
||||
return;
|
||||
|
||||
noInterrupts();
|
||||
static EepromData save_data;
|
||||
|
||||
save_data.tempo = app.tempo;
|
||||
@ -170,7 +184,6 @@ void StateManager::_saveState(const AppState &app, byte slot_index) {
|
||||
|
||||
int address = EEPROM_DATA_START_ADDR + (slot_index * sizeof(EepromData));
|
||||
EEPROM.put(address, save_data);
|
||||
interrupts();
|
||||
}
|
||||
|
||||
void StateManager::_loadState(AppState &app, byte slot_index) {
|
||||
@ -178,7 +191,6 @@ void StateManager::_loadState(AppState &app, byte slot_index) {
|
||||
if (slot_index >= MAX_SAVE_SLOTS + 1)
|
||||
return;
|
||||
|
||||
noInterrupts();
|
||||
static EepromData load_data;
|
||||
int address = EEPROM_DATA_START_ADDR + (slot_index * sizeof(EepromData));
|
||||
EEPROM.get(address, load_data);
|
||||
@ -203,11 +215,9 @@ void StateManager::_loadState(AppState &app, byte slot_index) {
|
||||
ch.setCv1Dest(static_cast<CvDestination>(saved_ch_state.cv1_dest));
|
||||
ch.setCv2Dest(static_cast<CvDestination>(saved_ch_state.cv2_dest));
|
||||
}
|
||||
interrupts();
|
||||
}
|
||||
|
||||
void StateManager::_saveMetadata(const AppState &app) {
|
||||
noInterrupts();
|
||||
Metadata current_meta;
|
||||
strcpy(current_meta.sketch_name, SKETCH_NAME);
|
||||
strcpy(current_meta.version, SEMANTIC_VERSION);
|
||||
@ -218,15 +228,12 @@ void StateManager::_saveMetadata(const AppState &app) {
|
||||
current_meta.rotate_display = app.rotate_display;
|
||||
|
||||
EEPROM.put(METADATA_START_ADDR, current_meta);
|
||||
interrupts();
|
||||
}
|
||||
|
||||
void StateManager::_loadMetadata(AppState &app) {
|
||||
noInterrupts();
|
||||
Metadata metadata;
|
||||
EEPROM.get(METADATA_START_ADDR, metadata);
|
||||
app.selected_save_slot = metadata.selected_save_slot;
|
||||
app.encoder_reversed = metadata.encoder_reversed;
|
||||
app.rotate_display = metadata.rotate_display;
|
||||
interrupts();
|
||||
}
|
||||
Reference in New Issue
Block a user