From 84cafe238754498f1eabe405a58ade588084a92a Mon Sep 17 00:00:00 2001 From: Adam Wonak Date: Sat, 16 Aug 2025 09:51:05 -0700 Subject: [PATCH 1/6] Fix bug in metadata save/load state. The sketch_name char array was to short, causing a buffer overflow. --- firmware/Gravity/Gravity.ino | 8 +++++++- firmware/Gravity/save_state.cpp | 6 +++--- firmware/Gravity/save_state.h | 6 +++--- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/firmware/Gravity/Gravity.ino b/firmware/Gravity/Gravity.ino index aef4ab8..f9bd119 100644 --- a/firmware/Gravity/Gravity.ino +++ b/firmware/Gravity/Gravity.ino @@ -228,7 +228,13 @@ void HandleEncoderPressed() { if (app.selected_sub_param < StateManager::MAX_SAVE_SLOTS) { app.selected_save_slot = app.selected_sub_param; stateManager.loadData(app, app.selected_save_slot); - InitGravity(app); + if (gravity.clock.Tempo() != app.tempo) { + gravity.clock.SetTempo(app.tempo); + } + // If clock is active, just load the pattern, do not change other global state. + if (gravity.clock.IsPaused()) { + InitGravity(app); + } } break; case PARAM_MAIN_FACTORY_RESET: diff --git a/firmware/Gravity/save_state.cpp b/firmware/Gravity/save_state.cpp index ff00005..ef32b6c 100644 --- a/firmware/Gravity/save_state.cpp +++ b/firmware/Gravity/save_state.cpp @@ -2,7 +2,7 @@ * @file save_state.cpp * @author Adam Wonak (https://github.com/awonak/) * @brief Alt firmware version of Gravity by Sitka Instruments. - * @version 2.0.1 + * @version 2.0.0 * @date 2025-07-04 * * @copyright MIT - (c) 2025 - Adam Wonak - adam.wonak@gmail.com @@ -55,8 +55,8 @@ bool StateManager::loadData(AppState& app, byte slot_index) { // 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; return true; } diff --git a/firmware/Gravity/save_state.h b/firmware/Gravity/save_state.h index 29226e7..50f4f03 100644 --- a/firmware/Gravity/save_state.h +++ b/firmware/Gravity/save_state.h @@ -2,7 +2,7 @@ * @file save_state.h * @author Adam Wonak (https://github.com/awonak/) * @brief Alt firmware version of Gravity by Sitka Instruments. - * @version 2.0.1 + * @version 2.0.0 * @date 2025-07-04 * * @copyright MIT - (c) 2025 - Adam Wonak - adam.wonak@gmail.com @@ -52,8 +52,8 @@ class StateManager { // This struct holds the data that identifies the firmware version. struct Metadata { - char sketch_name[12]; - char version[5]; + char sketch_name[16]; + char version[16]; // Additional global/hardware settings byte selected_save_slot; bool encoder_reversed; From 64f467d6acfb7d516416a75d3129e0ad0ff5b894 Mon Sep 17 00:00:00 2001 From: Adam Wonak Date: Sat, 16 Aug 2025 09:55:43 -0700 Subject: [PATCH 2/6] Add missing metadata field in _loadMetadata --- firmware/Gravity/save_state.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/Gravity/save_state.cpp b/firmware/Gravity/save_state.cpp index ef32b6c..a70bb81 100644 --- a/firmware/Gravity/save_state.cpp +++ b/firmware/Gravity/save_state.cpp @@ -224,5 +224,6 @@ void StateManager::_loadMetadata(AppState& app) { 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(); } \ No newline at end of file From 87dacd869bb95c37b0d540fe3cfaf04c12f1b289 Mon Sep 17 00:00:00 2001 From: Adam Wonak Date: Sat, 16 Aug 2025 10:06:11 -0700 Subject: [PATCH 3/6] improve the usage of disabling interrupts to avoid a potential race condition with isr being called between private method execution. --- firmware/Gravity/save_state.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/firmware/Gravity/save_state.cpp b/firmware/Gravity/save_state.cpp index a70bb81..c9afcf0 100644 --- a/firmware/Gravity/save_state.cpp +++ b/firmware/Gravity/save_state.cpp @@ -33,54 +33,66 @@ 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) { // Check if slot_index is within max range + 1 for transient. 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 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) 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; @@ -98,6 +110,7 @@ void StateManager::reset(AppState& app) { _loadMetadata(app); _isDirty = false; + interrupts(); } void StateManager::markDirty() { @@ -134,7 +147,6 @@ void StateManager::_saveState(const AppState& app, byte slot_index) { // Check if slot_index is within max range + 1 for transient. if (app.selected_save_slot >= MAX_SAVE_SLOTS + 1) return; - noInterrupts(); static EepromData save_data; save_data.tempo = app.tempo; @@ -165,14 +177,12 @@ 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) { // Check if slot_index is within max range + 1 for transient. 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); @@ -200,11 +210,9 @@ void StateManager::_loadState(AppState& app, byte slot_index) { ch.setCv1Dest(static_cast(saved_ch_state.cv1_dest)); ch.setCv2Dest(static_cast(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); @@ -215,15 +223,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(); } \ No newline at end of file From 330f5e6cebd1691fdf5d4b23e7622b8d9d07859a Mon Sep 17 00:00:00 2001 From: Adam Wonak Date: Sat, 16 Aug 2025 10:47:06 -0700 Subject: [PATCH 4/6] improve docstring comments --- firmware/Gravity/Gravity.ino | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/firmware/Gravity/Gravity.ino b/firmware/Gravity/Gravity.ino index f9bd119..718bba8 100644 --- a/firmware/Gravity/Gravity.ino +++ b/firmware/Gravity/Gravity.ino @@ -227,11 +227,13 @@ void HandleEncoderPressed() { case 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); } - // If clock is active, just load the pattern, do not change other global state. + // Load global settings only clock is not active. if (gravity.clock.IsPaused()) { InitGravity(app); } From 909d589609605e8b9e346029c6e0a30275517730 Mon Sep 17 00:00:00 2001 From: Adam Wonak Date: Sat, 16 Aug 2025 10:58:42 -0700 Subject: [PATCH 5/6] make version consistent --- firmware/Gravity/Gravity.ino | 2 +- firmware/Gravity/save_state.cpp | 4 ++-- library.properties | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/firmware/Gravity/Gravity.ino b/firmware/Gravity/Gravity.ino index 718bba8..b79d2e9 100644 --- a/firmware/Gravity/Gravity.ino +++ b/firmware/Gravity/Gravity.ino @@ -2,7 +2,7 @@ * @file Gravity.ino * @author Adam Wonak (https://github.com/awonak/) * @brief Alt firmware version of Gravity by Sitka Instruments. - * @version v2.0.0 - June 2025 awonak - Full rewrite + * @version v2.0.1 - June 2025 awonak - Full rewrite * @version v1.0 - August 2023 Oleksiy H - Initial release * @date 2025-07-04 * diff --git a/firmware/Gravity/save_state.cpp b/firmware/Gravity/save_state.cpp index c9afcf0..564cf70 100644 --- a/firmware/Gravity/save_state.cpp +++ b/firmware/Gravity/save_state.cpp @@ -2,7 +2,7 @@ * @file save_state.cpp * @author Adam Wonak (https://github.com/awonak/) * @brief Alt firmware version of Gravity by Sitka Instruments. - * @version 2.0.0 + * @version 2.0.1 * @date 2025-07-04 * * @copyright MIT - (c) 2025 - Adam Wonak - adam.wonak@gmail.com @@ -17,7 +17,7 @@ // Define the constants for the current firmware. const char StateManager::SKETCH_NAME[] = "ALT GRAVITY"; -const char StateManager::SEMANTIC_VERSION[] = "2.0.0"; // NOTE: This should match the version in the library.properties file. +const char StateManager::SEMANTIC_VERSION[] = "2.0.1"; // NOTE: This should match the version in the library.properties file. // Number of available save slots. const byte StateManager::MAX_SAVE_SLOTS = 10; diff --git a/library.properties b/library.properties index bce41dd..afcb2f5 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=libGravity -version=2.0.0 +version=2.0.1 author=Adam Wonak maintainer=awonak sentence=Hardware abstraction library for Sitka Instruments Gravity eurorack module @@ -7,4 +7,4 @@ category=Other license=MIT url=https://github.com/awonak/libGravity architectures=avr -depends=uClock,RotaryEncoder,U8g2 \ No newline at end of file +depends=uClock,RotaryEncoder,U8g2,NeoHWSerial From b60dcc0e682836230ebe7f21f23e38c8b49dd4da Mon Sep 17 00:00:00 2001 From: Adam Wonak Date: Sat, 16 Aug 2025 11:00:31 -0700 Subject: [PATCH 6/6] one more --- firmware/Gravity/save_state.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/Gravity/save_state.h b/firmware/Gravity/save_state.h index 50f4f03..220af7a 100644 --- a/firmware/Gravity/save_state.h +++ b/firmware/Gravity/save_state.h @@ -2,7 +2,7 @@ * @file save_state.h * @author Adam Wonak (https://github.com/awonak/) * @brief Alt firmware version of Gravity by Sitka Instruments. - * @version 2.0.0 + * @version 2.0.1 * @date 2025-07-04 * * @copyright MIT - (c) 2025 - Adam Wonak - adam.wonak@gmail.com