diff --git a/VortexEngine/src/Modes/Modes.cpp b/VortexEngine/src/Modes/Modes.cpp index 84e7eab596..fadb8adcb4 100644 --- a/VortexEngine/src/Modes/Modes.cpp +++ b/VortexEngine/src/Modes/Modes.cpp @@ -38,7 +38,9 @@ bool Modes::init() return true; #endif ByteStream headerBuffer; - Storage::read(0, headerBuffer); + // the save header is stored in the global storage space because it + // contains device-wide settings shared by all profiles + Storage::readGlobal(headerBuffer); unserializeSaveHeader(headerBuffer); m_loaded = false; #ifdef VORTEX_LIB @@ -145,11 +147,11 @@ bool Modes::saveHeader() if (!serializeSaveHeader(headerBuffer)) { return false; } - // serialize the number of modes - if (!headerBuffer.serialize8(m_numModes)) { - return false; - } - if (!Storage::write(0, headerBuffer)) { + // NOTE: the save header does not contain the number of modes anymore, + // that is stored in the mode header of each storage page instead + // the save header is written to the global storage space so that it is + // shared by all profiles instead of being duplicated in each one + if (!Storage::writeGlobal(headerBuffer)) { return false; } return true; @@ -159,20 +161,15 @@ bool Modes::loadHeader() { ByteStream headerBuffer; // only read storage if the modebuffer isn't filled - if (!Storage::read(0, headerBuffer) || !headerBuffer.size()) { + if (!Storage::readGlobal(headerBuffer) || !headerBuffer.size()) { DEBUG_LOG("Empty buffer read from storage"); // this kinda sucks whatever they had loaded is gone return false; } - // this erases what is stored before we know whether there is data - // but it's the easiest way to just re-load new data from storage - clearModes(); - // read the header and load the data + // read the header if (!unserializeSaveHeader(headerBuffer)) { return false; } - // NOTE: We do not bother loading the number of modes because - // we can't really do anything with it anyway return true; } @@ -182,6 +179,15 @@ bool Modes::saveStorage() { DEBUG_LOG("Saving modes..."); saveHeader(); + // save the mode header of this page which contains the number of modes + // stored here, the modes themselves are saved in slots 1 and up + ByteStream modeHeader(MAX_MODE_SIZE); + if (!modeHeader.serialize8(m_numModes)) { + return false; + } + if (!Storage::writeModeHeader(modeHeader)) { + return false; + } // make sure the current mode is saved in case it has changed somehow saveCurMode(); // uninstantiate cur mode so we have stack space to serialize @@ -221,13 +227,11 @@ bool Modes::saveStorage() bool Modes::loadStorage() { - // NOTE: We could call loadHeader here but then we wouldn't have the headerBuffer - // and in turn wouldn't be able to unserialize the number of modes. The number - // of modes is a weird case, it's technically part of the mode list not the - // header but it is stored in the same storage slot as the header - ByteStream headerBuffer; - // only read storage if the modebuffer isn't filled - if (!Storage::read(0, headerBuffer) || !headerBuffer.size()) { + // NOTE: The save header is global and was already loaded in init(), the + // mode header at slot 0 of this page holds the number of modes + // stored in this profile + ByteStream modeHeader; + if (!Storage::readModeHeader(modeHeader) || !modeHeader.size()) { DEBUG_LOG("Empty buffer read from storage"); // this kinda sucks whatever they had loaded is gone return false; @@ -235,13 +239,9 @@ bool Modes::loadStorage() // this erases what is stored before we know whether there is data // but it's the easiest way to just re-load new data from storage clearModes(); - // read the header and load the data - if (!unserializeSaveHeader(headerBuffer)) { - return false; - } - // unserialize the number of modes next + // unserialize the number of modes out of the mode header uint8_t numModes = 0; - if (!headerBuffer.unserialize8(&numModes)) { + if (!modeHeader.unserialize8(&numModes)) { return false; } if (!numModes) { @@ -740,8 +740,8 @@ bool Modes::setFlag(uint8_t flag, bool enable, bool save) } // otherwise need to update the global flags field of the save header in storage ByteStream headerBuffer; - // read out the storage header so we can update the flag field - if (!Storage::read(0, headerBuffer) || !headerBuffer.size()) { + // read out the global storage header so we can update the flag field + if (!Storage::readGlobal(headerBuffer) || !headerBuffer.size()) { // if cannot read the save header then just save it normally return saveHeader(); } @@ -762,8 +762,8 @@ bool Modes::setFlag(uint8_t flag, bool enable, bool save) // need to force the crc to recalc since we modified the data, just mark the // CRC as dirty and Storage::write() will re-calculate the CRC if it's dirty headerBuffer.setCRCDirty(); - // write the save header back to storage - return Storage::write(0, headerBuffer); + // write the save header back to the global storage space + return Storage::writeGlobal(headerBuffer); } #ifdef VORTEX_LIB diff --git a/VortexEngine/src/Storage/Storage.cpp b/VortexEngine/src/Storage/Storage.cpp index 8f20ae27c8..6b4ff15988 100644 --- a/VortexEngine/src/Storage/Storage.cpp +++ b/VortexEngine/src/Storage/Storage.cpp @@ -25,6 +25,11 @@ #define DEFAULT_STORAGE_FILENAME "FlashStorage.flash" +// the storage page reserved for the global storage space where the save +// header is kept, this must be a page number that no profile will ever +// use so that it can never collide with any of the storage pages +#define GLOBAL_STORAGE_PAGE 15 + #ifdef VORTEX_LIB std::string Storage::m_storageFilename; #define STORAGE_FILENAME m_storageFilename.c_str() @@ -63,6 +68,43 @@ uint8_t Storage::getStoragePage() return m_storagePage; } +// store a serial buffer to the global storage space, this simply targets +// slot 0 of the reserved global page so that the save header is not +// affected by whichever storage page is currently selected +bool Storage::writeGlobal(ByteStream &buffer) +{ + uint8_t currentPage = m_storagePage; + m_storagePage = GLOBAL_STORAGE_PAGE; + bool ok = write(0, buffer); + m_storagePage = currentPage; + return ok; +} + +// read a serial buffer from the global storage space +bool Storage::readGlobal(ByteStream &buffer) +{ + uint8_t currentPage = m_storagePage; + m_storagePage = GLOBAL_STORAGE_PAGE; + bool ok = read(0, buffer); + m_storagePage = currentPage; + return ok; +} + +// store a serial buffer to the mode header slot of the currently selected +// storage page +bool Storage::writeModeHeader(ByteStream &buffer) +{ + // slot 0 of each page is the mode header which holds the number of + // modes stored in that page, the modes themselves are in slots 1 and up + return write(0, buffer); +} + +// read the mode header from the currently selected storage page +bool Storage::readModeHeader(ByteStream &buffer) +{ + return read(0, buffer); +} + // store a serial buffer to storage bool Storage::write(uint16_t slot, ByteStream &buffer) { @@ -103,7 +145,7 @@ bool Storage::write(uint16_t slot, ByteStream &buffer) return false; } DWORD written = 0; - DWORD offset = (slot * MAX_MODE_SIZE) + (m_storagePage * (MAX_MODE_SIZE * MAX_MODES)); + DWORD offset = (slot * MAX_MODE_SIZE) + (m_storagePage * (MAX_MODE_SIZE * NUM_MODE_SLOTS)); SetFilePointer(hFile, offset, NULL, FILE_BEGIN); if (!WriteFile(hFile, buffer.rawData(), MAX_MODE_SIZE, &written, NULL)) { // error @@ -115,7 +157,7 @@ bool Storage::write(uint16_t slot, ByteStream &buffer) if (!f) { return false; } - long offset = (slot * MAX_MODE_SIZE) + (m_storagePage * (MAX_MODE_SIZE * MAX_MODES)); + long offset = (slot * MAX_MODE_SIZE) + (m_storagePage * (MAX_MODE_SIZE * NUM_MODE_SLOTS)); fseek(f, offset, SEEK_SET); if (!fwrite(buffer.rawData(), sizeof(char), MAX_MODE_SIZE, f)) { return false; @@ -169,7 +211,7 @@ bool Storage::read(uint16_t slot, ByteStream &buffer) return false; } DWORD bytesRead = 0; - DWORD offset = (slot * MAX_MODE_SIZE) + (m_storagePage * (MAX_MODE_SIZE * MAX_MODES)); + DWORD offset = (slot * MAX_MODE_SIZE) + (m_storagePage * (MAX_MODE_SIZE * NUM_MODE_SLOTS)); SetFilePointer(hFile, offset, NULL, FILE_BEGIN); if (!ReadFile(hFile, buffer.rawData(), MAX_MODE_SIZE, &bytesRead, NULL)) { // error @@ -181,7 +223,7 @@ bool Storage::read(uint16_t slot, ByteStream &buffer) if (!f) { return false; } - long offset = (slot * MAX_MODE_SIZE) + (m_storagePage * (MAX_MODE_SIZE * MAX_MODES)); + long offset = (slot * MAX_MODE_SIZE) + (m_storagePage * (MAX_MODE_SIZE * NUM_MODE_SLOTS)); fseek(f, offset, SEEK_SET); if (!fread(buffer.rawData(), sizeof(char), MAX_MODE_SIZE, f)) { return false; diff --git a/VortexEngine/src/Storage/Storage.h b/VortexEngine/src/Storage/Storage.h index 60a1b755df..a2df2a9cd7 100644 --- a/VortexEngine/src/Storage/Storage.h +++ b/VortexEngine/src/Storage/Storage.h @@ -28,6 +28,20 @@ class Storage // read a serial buffer from storage static bool read(uint16_t slot, ByteStream &buffer); + // store a serial buffer to the global storage space which is not affected + // by the selected storage page, this is where the single global save + // header lives as it is shared by all profiles + static bool writeGlobal(ByteStream &buffer); + // read a serial buffer from the global storage space + static bool readGlobal(ByteStream &buffer); + + // store a serial buffer to the mode header slot of the currently selected + // storage page, the mode header sits at slot 0 of each page and contains + // the number of modes stored in that page + static bool writeModeHeader(ByteStream &buffer); + // read the mode header from the currently selected storage page + static bool readModeHeader(ByteStream &buffer); + // the last save size (use STORAGE_SIZE For total space) static uint32_t lastSaveSize();