Add new field 'rtcStart' to the movie. It specifies the time of RTC at the beginning of the movie. (needs more test!)

TODO: record firmware settings as well.
This commit is contained in:
gocha 2010-04-03 07:11:29 +00:00
parent 196170a5c0
commit 1d0743861b
10 changed files with 168 additions and 107 deletions

View File

@ -34,6 +34,7 @@
#include "aggdraw.h"
#include "movie.h"
#include "rtc.h"
#include "NDSSystem.h"
#include "mic.h"
#include "saves.h"

View File

@ -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());
}
}

View File

@ -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:

View File

@ -22,6 +22,8 @@
#define WIN32_LEAN_AND_MEAN
#include <assert.h>
#include <limits.h>
#include <ctype.h>
#include <time.h>
#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;i<comments.size();i++)
fp->fprintf("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<u8>* 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)

View File

@ -5,6 +5,7 @@
#include <map>
#include <string>
#include <stdlib.h>
#include <time.h>
#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

View File

@ -28,7 +28,6 @@
#include "common.h"
#include "debug.h"
#include "armcpu.h"
#include <time.h>
#include <string.h>
#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

View File

@ -25,11 +25,14 @@
#ifndef _RTC_H_
#define _RTC_H_
#include <stdlib.h>
#include <time.h>
#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

View File

@ -20,11 +20,13 @@
#include <io.h>
#include <fstream>
#include <time.h>
#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<MAX_PATH>(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;

View File

@ -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

Binary file not shown.