mirror of
https://github.com/rvtr/GodMode9i.git
synced 2025-06-18 19:05:30 -04:00
Dump GBA RTC data in metadata and saves (#205)
* Add barebones RTC (actually GPIO) detect * RTC reading gotta clean up * Nicer printing * Add date sanity check (detect RTC presence) * Append RTC data to dumped saves mGBA-style if present * Actually allow restoring save with RTC included
This commit is contained in:
parent
854b16d8a1
commit
24d3a0ae66
@ -6,24 +6,22 @@
|
||||
#include <string>
|
||||
#include <time.h>
|
||||
|
||||
/**
|
||||
* Get the current time formatted for the top bar.
|
||||
* @return std::string containing the time.
|
||||
*/
|
||||
std::string RetTime()
|
||||
{
|
||||
return RetTime(STR_TIME_FORMAT.c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current time formatted as specified.
|
||||
* @return std::string containing the time.
|
||||
*/
|
||||
std::string RetTime(const char *format)
|
||||
std::string RetTime(const char *format, time_t *raw)
|
||||
{
|
||||
time_t raw;
|
||||
time(&raw);
|
||||
const struct tm *Time = localtime(&raw);
|
||||
if (!format)
|
||||
{
|
||||
format = STR_TIME_FORMAT.c_str();
|
||||
}
|
||||
time_t systime;
|
||||
if (!raw) {
|
||||
raw = &systime;
|
||||
time(raw);
|
||||
}
|
||||
const struct tm *Time = localtime(raw);
|
||||
|
||||
char tmp[64];
|
||||
strftime(tmp, sizeof(tmp), format, Time);
|
||||
|
@ -4,15 +4,11 @@
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* Get the current time formatted for the top bar.
|
||||
* Format the time as specified.
|
||||
* If no format is specified, use format for the top bar.
|
||||
* If no time is specified, use the system time.
|
||||
* @return std::string containing the time.
|
||||
*/
|
||||
std::string RetTime();
|
||||
|
||||
/**
|
||||
* Get the current time formatted as specified.
|
||||
* @return std::string containing the time.
|
||||
*/
|
||||
std::string RetTime(const char *format);
|
||||
std::string RetTime(const char *format = nullptr, time_t *raw = nullptr);
|
||||
|
||||
#endif // DATE_H
|
||||
|
@ -964,6 +964,14 @@ void gbaCartSaveDump(const char *filename) {
|
||||
|
||||
FILE *destinationFile = fopen(filename, "wb");
|
||||
fwrite(buffer, 1, size, destinationFile);
|
||||
|
||||
u8 cartRtc[RTC_SIZE];
|
||||
if (gbaGetRtc(cartRtc)) {
|
||||
fwrite(cartRtc, 1, RTC_SIZE, destinationFile);
|
||||
u64 systime = time(nullptr);
|
||||
fwrite(&systime, 1, 8, destinationFile);
|
||||
}
|
||||
|
||||
fclose(destinationFile);
|
||||
delete[] buffer;
|
||||
}
|
||||
@ -996,7 +1004,7 @@ void gbaCartSaveRestore(const char *filename) {
|
||||
fseek(sourceFile, 0, SEEK_END);
|
||||
size_t length = ftell(sourceFile);
|
||||
fseek(sourceFile, 0, SEEK_SET);
|
||||
if(length != size) {
|
||||
if(length != size && length != size + 16) {
|
||||
fclose(sourceFile);
|
||||
|
||||
dumpFailMsg(STR_SAVE_SIZE_MISMATCH_CART);
|
||||
@ -1254,6 +1262,15 @@ void gbaCartDump(void) {
|
||||
if(saveType == SAVE_GBA_FLASH_64 || saveType == SAVE_GBA_FLASH_128)
|
||||
fprintf(destinationFile, "Save chip ID : 0x%04X\n", gbaGetFlashId());
|
||||
|
||||
u8 cartRtc[RTC_SIZE];
|
||||
if (gbaGetRtc(cartRtc)) {
|
||||
struct tm cartTm = gbaRtcToTm(cartRtc);
|
||||
time_t cartTime = mktime(&cartTm);
|
||||
fprintf(destinationFile,
|
||||
"Cart time : %s\n",
|
||||
RetTime("%Y-%m-%d %H:%M:%S", &cartTime).c_str());
|
||||
}
|
||||
|
||||
fprintf(destinationFile,
|
||||
"Timestamp : %s\n"
|
||||
"GM9i Version : " VER_NUMBER "\n",
|
||||
|
@ -196,7 +196,8 @@ FileOperation fileBrowse_A(DirEntry* entry, char path[PATH_MAX]) {
|
||||
if(extension(entry->name, {"sav", "sav1", "sav2", "sav3", "sav4", "sav5", "sav6", "sav7", "sav8", "sav9"})) {
|
||||
if(!(io_dldi_data->ioInterface.features & FEATURE_SLOT_NDS) || entry->size <= (1 << 20))
|
||||
operations.push_back(FileOperation::restoreSaveNds);
|
||||
if(isRegularDS && (entry->size == 512 || entry->size == 8192 || entry->size == 32768 || entry->size == 65536 || entry->size == 131072))
|
||||
if(isRegularDS && (entry->size == 512 || entry->size == 8192 || entry->size == 32768 || entry->size == 65536 || entry->size == 131072
|
||||
|| entry->size == 528 || entry->size == 8208 || entry->size == 32784 || entry->size == 65552 || entry->size == 131088))
|
||||
operations.push_back(FileOperation::restoreSaveGba);
|
||||
}
|
||||
if(currentDrive != Drive::fatImg && extension(entry->name, {"img", "sd", "sav", "pub", "pu1", "pu2", "pu3", "pu4", "pu5", "pu6", "pu7", "pu8", "pu9", "prv", "pr1", "pr2", "pr3", "pr4", "pr5", "pr6", "pr7", "pr8", "pr9", "0000"})) {
|
||||
|
@ -45,8 +45,6 @@
|
||||
inline u32 min(u32 i, u32 j) { return (i < j) ? i : j;}
|
||||
inline u32 max(u32 i, u32 j) { return (i > j) ? i : j;}
|
||||
|
||||
|
||||
|
||||
// -----------------------------------------------------
|
||||
#define MAGIC_EEPR 0x52504545
|
||||
#define MAGIC_SRAM 0x4d415253
|
||||
@ -54,7 +52,6 @@ inline u32 max(u32 i, u32 j) { return (i > j) ? i : j;}
|
||||
|
||||
#define MAGIC_H1M_ 0x5f4d3148
|
||||
|
||||
|
||||
// -----------------------------------------------------------
|
||||
bool gbaIsGame()
|
||||
{
|
||||
@ -380,3 +377,115 @@ bool gbaFormatSave(saveTypeGBA type)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#define GPIO_DAT (*(vu16*) 0x080000c4)
|
||||
#define GPIO_DIR (*(vu16*) 0x080000c6)
|
||||
#define GPIO_CNT (*(vu16*) 0x080000c8)
|
||||
|
||||
#define RTC_CMD_READ(x) (((x)<<1) | 0x61)
|
||||
#define RTC_CMD_WRITE(x) (((x)<<1) | 0x60)
|
||||
|
||||
static void rtcEnable()
|
||||
{
|
||||
GPIO_CNT = 1;
|
||||
}
|
||||
|
||||
static void rtcDisable()
|
||||
{
|
||||
GPIO_CNT = 0;
|
||||
}
|
||||
|
||||
static void rtcWriteCmd(u8 cmd)
|
||||
{
|
||||
int l;
|
||||
u16 b;
|
||||
u16 v = cmd <<1;
|
||||
for(l=7; l>=0; l--)
|
||||
{
|
||||
b = (v>>l) & 0x2;
|
||||
GPIO_DAT = b | 4;
|
||||
GPIO_DAT = b | 4;
|
||||
GPIO_DAT = b | 4;
|
||||
GPIO_DAT = b | 5;
|
||||
}
|
||||
}
|
||||
|
||||
static void rtcWriteData(u8 data)
|
||||
{
|
||||
int l;
|
||||
u16 b;
|
||||
u16 v = data <<1;
|
||||
for(l=0; l<8; l++)
|
||||
{
|
||||
b = (v>>l) & 0x2;
|
||||
GPIO_DAT = b | 4;
|
||||
GPIO_DAT = b | 4;
|
||||
GPIO_DAT = b | 4;
|
||||
GPIO_DAT = b | 5;
|
||||
}
|
||||
}
|
||||
static u8 rtcReadData()
|
||||
{
|
||||
int j,l;
|
||||
u16 b;
|
||||
int v = 0;
|
||||
for(l=0; l<8; l++)
|
||||
{
|
||||
for(j=0;j<5; j++)
|
||||
GPIO_DAT = 4;
|
||||
GPIO_DAT = 5;
|
||||
b = GPIO_DAT;
|
||||
v = v | ((b & 2)<<l);
|
||||
}
|
||||
v = v>>1;
|
||||
return v;
|
||||
}
|
||||
|
||||
bool gbaGetRtc(u8 *rtc)
|
||||
{
|
||||
rtcEnable();
|
||||
|
||||
int i;
|
||||
GPIO_DAT = 1;
|
||||
GPIO_DIR = 7;
|
||||
GPIO_DAT = 1;
|
||||
GPIO_DAT = 5;
|
||||
rtcWriteCmd(RTC_CMD_READ(2));
|
||||
GPIO_DIR = 5;
|
||||
for(i=0; i<4; i++)
|
||||
rtc[i] = rtcReadData();
|
||||
GPIO_DIR = 5;
|
||||
for(i=4; i<7; i++)
|
||||
rtc[i] = rtcReadData();
|
||||
|
||||
GPIO_DAT = 1;
|
||||
GPIO_DIR = 7;
|
||||
GPIO_DAT = 1;
|
||||
GPIO_DAT = 5;
|
||||
rtcWriteCmd(RTC_CMD_READ(4));
|
||||
GPIO_DIR = 5;
|
||||
rtc[7] = rtcReadData();
|
||||
|
||||
rtcDisable();
|
||||
|
||||
// Month must be 1 to 12 in BCD for valid RTC
|
||||
// If month is 0, invalid RTC
|
||||
return rtc[RTC_MONTH] >= 0x01 && rtc[RTC_MONTH] <= 0x12;
|
||||
}
|
||||
|
||||
static uint8_t unBCD(uint8_t byte) {
|
||||
return (byte >> 4) * 10 + (byte & 0xF);
|
||||
}
|
||||
|
||||
struct tm gbaRtcToTm(const u8 *rtc)
|
||||
{
|
||||
struct tm res;
|
||||
res.tm_year = unBCD(rtc[RTC_YEAR]) + 100;
|
||||
res.tm_mon = unBCD(rtc[RTC_MONTH]) - 1;
|
||||
res.tm_mday = unBCD(rtc[RTC_DAY]);
|
||||
res.tm_hour = unBCD(rtc[RTC_HOUR]);
|
||||
res.tm_min = unBCD(rtc[RTC_MINUTE]);
|
||||
res.tm_sec = unBCD(rtc[RTC_SECOND]);
|
||||
res.tm_isdst = -1;
|
||||
return res;
|
||||
}
|
@ -34,6 +34,17 @@ enum saveTypeGBA {
|
||||
SAVE_GBA_FLASH_128 // 128k
|
||||
};
|
||||
|
||||
enum GbaRtc {
|
||||
RTC_YEAR,
|
||||
RTC_MONTH,
|
||||
RTC_DAY,
|
||||
RTC_WEEKDAY,
|
||||
RTC_HOUR,
|
||||
RTC_MINUTE,
|
||||
RTC_SECOND,
|
||||
RTC_CONTROL,
|
||||
RTC_SIZE
|
||||
};
|
||||
|
||||
// --------------------
|
||||
bool gbaIsGame();
|
||||
@ -46,5 +57,7 @@ bool gbaReadSave(u8 *dst, u32 src, u32 len, saveTypeGBA type);
|
||||
bool gbaWriteSave(u32 dst, u8 *src, u32 len, saveTypeGBA type);
|
||||
bool gbaFormatSave(saveTypeGBA type);
|
||||
|
||||
bool gbaGetRtc(u8 *rtc);
|
||||
struct tm gbaRtcToTm(const u8 *rtc);
|
||||
|
||||
#endif // __GBA_H__
|
Loading…
Reference in New Issue
Block a user