diff --git a/desmume/src/GPU_osd.cpp b/desmume/src/GPU_osd.cpp index a235f839a..167dc531b 100644 --- a/desmume/src/GPU_osd.cpp +++ b/desmume/src/GPU_osd.cpp @@ -34,6 +34,7 @@ #include "aggdraw.h" #include "movie.h" +#include "rtc.h" #include "NDSSystem.h" #include "mic.h" #include "saves.h" diff --git a/desmume/src/commandline.cpp b/desmume/src/commandline.cpp index 9b274bc9d..7cedea909 100644 --- a/desmume/src/commandline.cpp +++ b/desmume/src/commandline.cpp @@ -189,7 +189,7 @@ void CommandLine::process_movieCommands() } else if(record_movie_file != "") { - FCEUI_SaveMovie(record_movie_file.c_str(), L"", 0, NULL); + FCEUI_SaveMovie(record_movie_file.c_str(), L"", 0, NULL, FCEUI_MovieGetRTCDefault()); } } diff --git a/desmume/src/gtk/main.cpp b/desmume/src/gtk/main.cpp index c3eac9f92..a6e71e1d0 100644 --- a/desmume/src/gtk/main.cpp +++ b/desmume/src/gtk/main.cpp @@ -763,7 +763,7 @@ static void RecordMovieDialog() switch(gtk_dialog_run(GTK_DIALOG(pFileSelection))) { case GTK_RESPONSE_OK: sPath = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(pFileSelection)); - FCEUI_SaveMovie(sPath,L"",0,NULL); + FCEUI_SaveMovie(sPath,L"",0,NULL, FCEUI_MovieGetRTCDefault()); g_free(sPath); break; default: diff --git a/desmume/src/movie.cpp b/desmume/src/movie.cpp index 74b74231d..6df7487db 100644 --- a/desmume/src/movie.cpp +++ b/desmume/src/movie.cpp @@ -22,6 +22,8 @@ #define WIN32_LEAN_AND_MEAN #include #include +#include +#include #include "utils/guid.h" #include "utils/xstring.h" #include "movie.h" @@ -166,12 +168,37 @@ void MovieRecord::dump(MovieData* md, EMUFILE* fp, int index) fp->fputc('\n'); } +time_t FCEUI_MovieGetRTCDefault() +{ + time_t timer; + + // compatible with old desmume + struct tm t; + t.tm_year = 109; // 2009 + t.tm_mon = 0; // 1 (Jan) + t.tm_mday = 1; + t.tm_wday = 4; + t.tm_hour = 12; + t.tm_min = 0; + t.tm_sec = 0; + t.tm_isdst= -1; + timer = gmmktime(&t); + + // current time + //timer = time(NULL); + //struct tm *tp = localtime(&timer); + //timer = gmmktime(tp); + + return timer; +} + MovieData::MovieData() : version(MOVIE_VERSION) , emuVersion(EMU_DESMUME_VERSION_NUMERIC()) , romChecksum(0) , rerecordCount(0) , binaryFlag(false) + , rtcStart(FCEUI_MovieGetRTCDefault()) { } @@ -199,6 +226,30 @@ void MovieData::installValue(std::string& key, std::string& val) romSerial = val; else if(key == "guid") guid = Desmume_Guid::fromString(val); + else if(key == "rtcStart") { + // sloppy format check and parse + char *validFormatStr = "####-##-##T##:##:##Z"; + bool validFormat = true; + for (int i = 0; validFormatStr[i] != '\0'; i++) { + if (validFormatStr[i] != val[i] && + !(validFormatStr[i] == '#' && isdigit(val[i]))) { + validFormat = false; + break; + } + } + if (validFormat) { + struct tm t; + const char *s = val.data(); + t.tm_year = atoi(&s[0]) - 1900; + t.tm_mon = atoi(&s[5]) - 1; + t.tm_mday = atoi(&s[8]); + t.tm_hour = atoi(&s[11]); + t.tm_min = atoi(&s[14]); + t.tm_sec = atoi(&s[17]); + t.tm_isdst= -1; + rtcStart = gmmktime(&t); + } + } else if(key == "comment") comments.push_back(mbstowcs(val)); else if(key == "binary") @@ -242,12 +293,17 @@ int MovieData::dump(EMUFILE* fp, bool binary) if(CommonSettings.UseExtBIOS) fp->fprintf("swiFromBios %d\n", CommonSettings.SWIFromBIOS); + char timestr[32]; + struct tm *tm = gmtime(&rtcStart); + strftime(timestr, 32, "%Y-%m-%dT%H:%M:%SZ", tm); + fp->fprintf("rtcStart %s\n", timestr); + for(uint32 i=0;ifprintf("comment %s\n", wcstombs(comments[i]).c_str()); if(binary) fp->fprintf("binary 1\n"); - + if(savestate.size() != 0) fp->fprintf("savestate %s\n", BytesToString(&savestate[0],savestate.size()).c_str()); if(sram.size() != 0) @@ -495,7 +551,6 @@ const char* _CDECL_ FCEUI_LoadMovie(const char *fname, bool _read_only, bool tas movie_readonly = _read_only; movieMode = MOVIEMODE_PLAY; currRerecordCount = currMovieData.rerecordCount; - InitMovieTime(); MMU_new.backupDevice.movie_mode(); if(currMovieData.sram.size() != 0) { @@ -564,7 +619,7 @@ bool MovieData::loadSramFrom(std::vector* buf) //begin recording a new movie //TODO - BUG - the record-from-another-savestate doesnt work. -void _CDECL_ FCEUI_SaveMovie(const char *fname, std::wstring author, int flag, std::string sramfname) +void _CDECL_ FCEUI_SaveMovie(const char *fname, std::wstring author, int flag, std::string sramfname, time_t rtcstart) { //if(!FCEU_IsValidUI(FCEUI_RECORDMOVIE)) // return; @@ -585,7 +640,8 @@ void _CDECL_ FCEUI_SaveMovie(const char *fname, std::wstring author, int flag, s currMovieData.romChecksum = gameInfo.crc; currMovieData.romSerial = gameInfo.ROMserial; currMovieData.romFilename = path.GetRomName(); - + currMovieData.rtcStart = rtcstart; + NDS_Reset(); //todo ? @@ -608,7 +664,6 @@ void _CDECL_ FCEUI_SaveMovie(const char *fname, std::wstring author, int flag, s movieMode = MOVIEMODE_RECORD; movie_readonly = false; currRerecordCount = 0; - InitMovieTime(); MMU_new.backupDevice.movie_mode(); if(currMovieData.sram.size() != 0) diff --git a/desmume/src/movie.h b/desmume/src/movie.h index 1183f3537..8730b3d92 100644 --- a/desmume/src/movie.h +++ b/desmume/src/movie.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "emufile.h" #include "utils/guid.h" @@ -128,6 +129,8 @@ public: int rerecordCount; Desmume_Guid guid; + s64 rtcStart; // (time_t) it always means gmtime, not localtime. + //was the frame data stored in binary? bool binaryFlag; @@ -192,7 +195,7 @@ extern MovieData currMovieData; //adelikat: main needs this for frame counter d extern bool movie_reset_command; bool FCEUI_MovieGetInfo(EMUFILE* fp, MOVIE_INFO& info, bool skipFrameCount); -void _CDECL_ FCEUI_SaveMovie(const char *fname, std::wstring author, int flag, std::string sramfname); +void _CDECL_ FCEUI_SaveMovie(const char *fname, std::wstring author, int flag, std::string sramfname, time_t rtcstart); const char* _CDECL_ FCEUI_LoadMovie(const char *fname, bool _read_only, bool tasedit, int _pauseframe); // returns NULL on success, errmsg on failure void FCEUI_StopMovie(); void FCEUMOV_AddInputState(); @@ -205,4 +208,5 @@ bool LoadFM2(MovieData& movieData, EMUFILE* fp, int size, bool stopAfterHeader); extern bool movie_readonly; extern bool ShowInputDisplay; void FCEUI_MakeBackupMovie(bool dispMessage); +time_t FCEUI_MovieGetRTCDefault(); #endif diff --git a/desmume/src/rtc.cpp b/desmume/src/rtc.cpp index 280db25da..11fc44c7a 100644 --- a/desmume/src/rtc.cpp +++ b/desmume/src/rtc.cpp @@ -28,7 +28,6 @@ #include "common.h" #include "debug.h" #include "armcpu.h" -#include #include #include "saves.h" #ifdef WIN32 @@ -36,6 +35,23 @@ #endif #include "movie.h" +static time_t CalcTimeDifference(void) +{ + time_t t1, t2; + tm *tm_tmp; + + time(&t1); + tm_tmp = gmtime(&t1); + t2 = mktime(tm_tmp); + + return (t2 - t1); +} + +time_t gmmktime(struct tm *timeptr) +{ + return mktime(timeptr) - CalcTimeDifference(); +} + typedef struct { // RTC registers @@ -94,50 +110,38 @@ static const u8 kDefaultCmdBitsSize[8] = {8, 8, 56, 24, 0, 24, 8, 8}; #define toBCD(x) ((x / 10) << 4) | (x % 10); -struct movietime { - - int sec; - int minute; - int hour; - int monthday; - int month; - int year; - int weekday; -}; - -struct movietime movie; - bool moviemode=false; -void InitMovieTime(void) +struct tm* rtcGetTime(void) { - movie.year=9; - movie.month=1; - movie.monthday=1; - movie.weekday=4; -} + if(movieMode == MOVIEMODE_INACTIVE) { + time_t timer; + time(&timer); + return localtime(&timer); + } + else { + //now, you might think it is silly to go through all these conniptions + //when we could just assume that there are 60fps and base the seconds on frameCounter/60 + //but, we were imagining that one day we might need more precision -static void MovieTime(void) { + const u32 arm9rate_unitsperframe = 560190<<1; + const u32 arm9rate_unitspersecond = (u32)(arm9rate_unitsperframe * 59.8261); - //now, you might think it is silly to go through all these conniptions - //when we could just assume that there are 60fps and base the seconds on frameCounter/60 - //but, we were imagining that one day we might need more precision + u64 totalcycles = (u64)arm9rate_unitsperframe * currFrameCounter; + u64 totalseconds=totalcycles/arm9rate_unitspersecond; - const u32 arm9rate_unitsperframe = 560190<<1; - const u32 arm9rate_unitspersecond = (u32)(arm9rate_unitsperframe * 59.8261); - const u64 noon = (u64)arm9rate_unitspersecond * 60 * 60 * 12; - - u64 frameCycles = (u64)arm9rate_unitsperframe * currFrameCounter; - u64 totalcycles = frameCycles + noon; - u64 totalseconds=totalcycles/arm9rate_unitspersecond; + time_t timer; + struct tm t; - movie.sec=(int)(totalseconds % 60); - movie.minute=(int)(totalseconds/60); - movie.hour=movie.minute/60; - - //convert to sane numbers - movie.minute=movie.minute % 60; - movie.hour=movie.hour % 24; + // store start time into structure tm + timer = (time_t) currMovieData.rtcStart; + memcpy(&t, gmtime(&timer), sizeof(struct tm)); + // advance it according to the frame counter + t.tm_sec += totalseconds; + // then, normalize it + timer = gmmktime(&t); + return gmtime(&timer); + } } static void rtcRecv() @@ -160,67 +164,26 @@ static void rtcRecv() case 2: // date & time { //INFO("RTC: read date & time\n"); - time_t tm; - time(&tm); - struct tm *tm_local= localtime(&tm); - tm_local->tm_year %= 100; - tm_local->tm_mon++; - - if(movieMode != MOVIEMODE_INACTIVE) { - - MovieTime(); - - rtc.data[0]=toBCD(movie.year); - rtc.data[1]=toBCD(movie.month); - rtc.data[2]=toBCD(movie.monthday); - rtc.data[3]=(movie.weekday + 7) & 7; - if (rtc.data[3] == 7) rtc.data[3] = 6; - if (!(rtc.regStatus1 & 0x02)) movie.hour %= 12; - rtc.data[4] = ((movie.hour < 12) ? 0x00 : 0x40) | toBCD(movie.hour); - rtc.data[5]=toBCD(movie.minute); - rtc.data[6]=toBCD(movie.sec); - break; - } - else { - - rtc.data[0] = toBCD(tm_local->tm_year); - rtc.data[1] = toBCD(tm_local->tm_mon); - rtc.data[2] = toBCD(tm_local->tm_mday); - rtc.data[3] = (tm_local->tm_wday + 7) & 7; - if (rtc.data[3] == 7) rtc.data[3] = 6; - if (!(rtc.regStatus1 & 0x02)) tm_local->tm_hour %= 12; - rtc.data[4] = ((tm_local->tm_hour < 12) ? 0x00 : 0x40) | toBCD(tm_local->tm_hour); - rtc.data[5] = toBCD(tm_local->tm_min); - rtc.data[6] = toBCD(tm_local->tm_sec); - break; - } + struct tm *tm = rtcGetTime(); + rtc.data[0] = toBCD(tm->tm_year % 100); + rtc.data[1] = toBCD(tm->tm_mon + 1); + rtc.data[2] = toBCD(tm->tm_mday); + rtc.data[3] = (tm->tm_wday + 7) & 7; + if (rtc.data[3] == 7) rtc.data[3] = 6; + if (!(rtc.regStatus1 & 0x02)) tm->tm_hour %= 12; + rtc.data[4] = ((tm->tm_hour < 12) ? 0x00 : 0x40) | toBCD(tm->tm_hour); + rtc.data[5] = toBCD(tm->tm_min); + rtc.data[6] = toBCD(tm->tm_sec); break; } case 3: // time { //INFO("RTC: read time\n"); - time_t tm; - time(&tm); - struct tm *tm_local= localtime(&tm); - - if(movieMode != MOVIEMODE_INACTIVE) { - - MovieTime(); - - if (!(rtc.regStatus1 & 0x02)) movie.hour %= 12; - rtc.data[0] = ((movie.hour < 12) ? 0x00 : 0x40) | toBCD(movie.hour); - rtc.data[1] = toBCD(movie.minute); - rtc.data[2] = toBCD(movie.sec); - break; - } - else { - - if (!(rtc.regStatus1 & 0x02)) tm_local->tm_hour %= 12; - rtc.data[0] = ((tm_local->tm_hour < 12) ? 0x00 : 0x40) | toBCD(tm_local->tm_hour); - rtc.data[1] = toBCD(tm_local->tm_min); - rtc.data[2] = toBCD(tm_local->tm_sec); - break; - } + struct tm *tm = rtcGetTime(); + if (!(rtc.regStatus1 & 0x02)) tm->tm_hour %= 12; + rtc.data[0] = ((tm->tm_hour < 12) ? 0x00 : 0x40) | toBCD(tm->tm_hour); + rtc.data[1] = toBCD(tm->tm_min); + rtc.data[2] = toBCD(tm->tm_sec); break; } case 4: // freq/alarm 1 diff --git a/desmume/src/rtc.h b/desmume/src/rtc.h index f1b6765ae..1248503de 100644 --- a/desmume/src/rtc.h +++ b/desmume/src/rtc.h @@ -25,11 +25,14 @@ #ifndef _RTC_H_ #define _RTC_H_ #include +#include #include "types.h" +extern time_t gmmktime(struct tm *timeptr); + +struct tm* rtcGetTime(void); + extern void rtcInit(); extern u16 rtcRead(); extern void rtcWrite(u16 val); - -void InitMovieTime(void); #endif diff --git a/desmume/src/windows/replay.cpp b/desmume/src/windows/replay.cpp index df141bdd8..805e3dd5f 100644 --- a/desmume/src/windows/replay.cpp +++ b/desmume/src/windows/replay.cpp @@ -20,11 +20,13 @@ #include #include +#include #include "resource.h" #include "replay.h" #include "common.h" #include "main.h" #include "movie.h" +#include "rtc.h" #include "utils/xstring.h" bool replayreadonly=1; @@ -248,12 +250,28 @@ static INT_PTR CALLBACK RecordDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, static struct CreateMovieParameters* p = NULL; std::wstring author = L""; std::string fname; + SYSTEMTIME systime; switch(uMsg) { - case WM_INITDIALOG: + case WM_INITDIALOG: { CheckDlgButton(hwndDlg, IDC_START_FROM_SRAM, ((flag == 1) ? BST_CHECKED : BST_UNCHECKED)); SetFocus(GetDlgItem(hwndDlg, IDC_EDIT_FILENAME)); + + time_t timer = FCEUI_MovieGetRTCDefault(); + struct tm *t = gmtime(&timer); + ZeroMemory(&systime, sizeof(systime)); + systime.wYear = t->tm_year + 1900; + systime.wMonth = t->tm_mon + 1; + systime.wDay = t->tm_mday; + systime.wDayOfWeek = t->tm_wday; + systime.wHour = t->tm_hour; + systime.wMinute = t->tm_min; + systime.wSecond = t->tm_sec; + systime.wMilliseconds = 0; + DateTime_SetSystemtime(GetDlgItem(hwndDlg, IDC_DTP_DATE), GDT_VALID, &systime); + DateTime_SetSystemtime(GetDlgItem(hwndDlg, IDC_DTP_TIME), GDT_VALID, &systime); return false; + } case WM_COMMAND: switch(LOWORD(wParam)) @@ -264,7 +282,22 @@ static INT_PTR CALLBACK RecordDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, std::string sramfname = GetDlgItemText(hwndDlg,IDC_EDIT_SRAMFILENAME); if (fname.length()) { - FCEUI_SaveMovie(fname.c_str(), author, flag, sramfname); + time_t rtcstart; + struct tm t; + + DateTime_GetSystemtime(GetDlgItem(hwndDlg, IDC_DTP_DATE), &systime); + t.tm_year = systime.wYear - 1900; + t.tm_mon = systime.wMonth - 1; + t.tm_mday = systime.wDay; + t.tm_wday = systime.wDayOfWeek; + DateTime_GetSystemtime(GetDlgItem(hwndDlg, IDC_DTP_TIME), &systime); + t.tm_hour = systime.wHour; + t.tm_min = systime.wMinute; + t.tm_sec = systime.wSecond; + t.tm_isdst= -1; + rtcstart = gmmktime(&t); + + FCEUI_SaveMovie(fname.c_str(), author, flag, sramfname, rtcstart); EndDialog(hwndDlg, 0); } return true; diff --git a/desmume/src/windows/resource.h b/desmume/src/windows/resource.h index 7eb12e8a5..e903a4459 100644 --- a/desmume/src/windows/resource.h +++ b/desmume/src/windows/resource.h @@ -353,8 +353,10 @@ #define IDC_CAP1_CURDAD 1026 #define IDC_CHECBOX_ADVANCEDTIMING 1026 #define IDC_DEFAULT 1027 +#define IDC_DTP_DATE 1027 #define IDC_3DCORE 1028 #define IDC_SNDCTRL_ENABLE 1028 +#define IDC_DTP_TIME 1028 #define IDC_TXT_COMPILED 1029 #define IDC_SNDCTRL_CH1NOMIX 1029 #define IDC_TXT_VERSION 1030 @@ -908,7 +910,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 121 #define _APS_NEXT_COMMAND_VALUE 40078 -#define _APS_NEXT_CONTROL_VALUE 1027 +#define _APS_NEXT_CONTROL_VALUE 1029 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/desmume/src/windows/resources.rc b/desmume/src/windows/resources.rc index ac4340afd..2b4c87b82 100644 Binary files a/desmume/src/windows/resources.rc and b/desmume/src/windows/resources.rc differ