diff options
Diffstat (limited to 'src/NDSCart_SRAMManager.cpp')
-rw-r--r-- | src/NDSCart_SRAMManager.cpp | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/src/NDSCart_SRAMManager.cpp b/src/NDSCart_SRAMManager.cpp new file mode 100644 index 0000000..88ff40b --- /dev/null +++ b/src/NDSCart_SRAMManager.cpp @@ -0,0 +1,147 @@ +/* + Copyright 2016-2020 Arisotura + + This file is part of melonDS. + + melonDS is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include "NDSCart_SRAMManager.h" +#include "Platform.h" + +namespace NDSCart_SRAMManager +{ + Platform::Thread* FlushThread; + bool FlushThreadRunning; + Platform::Mutex* SecondaryBufferLock; + + char Path[1024]; + + u8* Buffer; + u32 Length; + + u8* SecondaryBuffer; + u32 SecondaryBufferLength; + + time_t TimeAtLastFlushRequest; + + // We keep versions in case the user closes the application before + // a flush cycle is finished. + u32 PreviousFlushVersion; + u32 FlushVersion; + + void FlushThreadFunc(); + void FlushSecondaryBufferToFile(); + + bool Init() + { + FlushThread = Platform::Thread_Create(FlushThreadFunc); + FlushThreadRunning = true; + + SecondaryBufferLock = Platform::Mutex_Create(); + + return true; + } + + void DeInit() + { + if (FlushThreadRunning) + { + FlushThreadRunning = false; + Platform::Thread_Wait(FlushThread); + Platform::Thread_Free(FlushThread); + FlushSecondaryBufferToFile(); + } + + delete SecondaryBuffer; + + Platform::Mutex_Free(SecondaryBufferLock); + } + + void Setup(const char* path, u8* buffer, u32 length) + { + // Flush SRAM in case there is unflushed data from previous state. + FlushSecondaryBufferToFile(); + + Platform::Mutex_Lock(SecondaryBufferLock); + + strncpy(Path, path, 1023); + Path[1023] = '\0'; + + Buffer = buffer; + Length = length; + + delete SecondaryBuffer; // Delete secondary buffer, there might be previous state. + + SecondaryBuffer = new u8[length]; + SecondaryBufferLength = length; + + FlushVersion = 0; + PreviousFlushVersion = 0; + TimeAtLastFlushRequest = 0; + + Platform::Mutex_Unlock(SecondaryBufferLock); + } + + void RequestFlush() + { + Platform::Mutex_Lock(SecondaryBufferLock); + printf("NDS SRAM: Flush requested\n"); + memcpy(SecondaryBuffer, Buffer, Length); + FlushVersion++; + TimeAtLastFlushRequest = time(NULL); + Platform::Mutex_Unlock(SecondaryBufferLock); + } + + void FlushThreadFunc() + { + for (;;) + { + Platform::Sleep(100 * 1000); // 100ms + + if (!FlushThreadRunning) return; + + // We debounce for two seconds after last flush request to ensure that writing has finished. + if (TimeAtLastFlushRequest == 0 || difftime(time(NULL), TimeAtLastFlushRequest) < 2) + { + continue; + } + + FlushSecondaryBufferToFile(); + } + } + + void FlushSecondaryBufferToFile() + { + if (FlushVersion == PreviousFlushVersion) + { + return; + } + + Platform::Mutex_Lock(SecondaryBufferLock); + FILE* f = Platform::OpenFile(Path, "wb"); + if (f) + { + printf("NDS SRAM: Written\n"); + fwrite(SecondaryBuffer, SecondaryBufferLength, 1, f); + fclose(f); + } + PreviousFlushVersion = FlushVersion; + TimeAtLastFlushRequest = 0; + Platform::Mutex_Unlock(SecondaryBufferLock); + } +} |