1 /*  Copyright 2005 Guillaume Duhamel
2 	Copyright 2005-2006, 2013 Theo Berkau
3 	Copyright 2008 Filipe Azevedo <pasnox@gmail.com>
4 
5 	This file is part of Yabause.
6 
7 	Yabause is free software; you can redistribute it and/or modify
8 	it under the terms of the GNU General Public License as published by
9 	the Free Software Foundation; either version 2 of the License, or
10 	(at your option) any later version.
11 
12 	Yabause is distributed in the hope that it will be useful,
13 	but WITHOUT ANY WARRANTY; without even the implied warranty of
14 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 	GNU General Public License for more details.
16 
17 	You should have received a copy of the GNU General Public License
18 	along with Yabause; if not, write to the Free Software
19 	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
20 */
21 #include "YabauseThread.h"
22 #include "Settings.h"
23 #include "VolatileSettings.h"
24 #include "ui/UIPortManager.h"
25 #include "ui/UIYabause.h"
26 
27 #include "../peripheral.h"
28 
29 #include <QDateTime>
30 #include <QStringList>
31 #include <QDebug>
32 #include <QFile>
33 
YabauseThread(QObject * o)34 YabauseThread::YabauseThread( QObject* o )
35 	: QObject( o )
36 {
37 	mPause = true;
38 	mTimerId = -1;
39 	mInit = -1;
40 	memset(&mYabauseConf, 0, sizeof(mYabauseConf));
41 	showFPS = false;
42 }
43 
~YabauseThread()44 YabauseThread::~YabauseThread()
45 {
46 	deInitEmulation();
47 }
48 
yabauseConf()49 yabauseinit_struct* YabauseThread::yabauseConf()
50 {
51 	return &mYabauseConf;
52 }
53 
initEmulation()54 void YabauseThread::initEmulation()
55 {
56 	reloadSettings();
57 	mInit = YabauseInit( &mYabauseConf );
58 #ifdef HAVE_LIBGL
59 	if (mInit == -1)
60 	{
61 		VideoDisableGL();
62 		emit disableGL();
63 		mInit = YabauseInit( &mYabauseConf );
64 	}
65 #endif
66 	SetOSDToggle(showFPS);
67 }
68 
deInitEmulation()69 void YabauseThread::deInitEmulation()
70 {
71 	YabauseDeInit();
72 	mInit = -1;
73 }
74 
pauseEmulation(bool pause,bool reset)75 bool YabauseThread::pauseEmulation( bool pause, bool reset )
76 {
77 	if ( mPause == pause && !reset ) {
78 		return true;
79 	}
80 
81 	if ( mInit == 0 && reset ) {
82 		deInitEmulation();
83 	}
84 
85 	if ( mInit < 0 ) {
86 		initEmulation();
87 	}
88 
89 	if ( mInit < 0 )
90 	{
91 		emit error( QtYabause::translate( "Can't initialize Yabause" ), false );
92 		return false;
93 	}
94 
95 	mPause = pause;
96 
97 	if ( mPause ) {
98 		ScspMuteAudio(SCSP_MUTE_SYSTEM);
99 		killTimer( mTimerId );
100 		mTimerId = -1;
101 	}
102 	else {
103 		ScspUnMuteAudio(SCSP_MUTE_SYSTEM);
104 		mTimerId = startTimer( 0 );
105 	}
106 
107 	VolatileSettings * vs = QtYabause::volatileSettings();
108 
109 	if (vs->value("autostart").toBool())
110 	{
111 		if (vs->value("autostart/binary").toBool()) {
112 			MappedMemoryLoadExec(
113 				vs->value("autostart/binary/filename").toString().toLocal8Bit().constData(),
114 				vs->value("autostart/binary/address").toUInt());
115 		}
116 		else if (vs->value("autostart/load").toBool()) {
117 			YabLoadStateSlot( QFile::encodeName( QtYabause::volatileSettings()->value( "General/SaveStates", getDataDirPath() ).toString() ).constData(), vs->value("autostart/load/slot").toInt() );
118 		}
119 		vs->setValue("autostart", false);
120 	}
121 
122 	emit this->pause( mPause );
123 
124 	return true;
125 }
126 
resetEmulation()127 bool YabauseThread::resetEmulation()
128 {
129 	if ( mInit < 0 ) {
130 		return false;
131 	}
132 
133 	YabauseReset();
134 
135 	emit reset();
136 
137 	return true;
138 }
139 
reloadControllers()140 void YabauseThread::reloadControllers()
141 {
142 	PerPortReset();
143 	QtYabause::clearPadsBits();
144 
145 	Settings* settings = QtYabause::settings();
146 
147 	emit toggleEmulateMouse( false );
148 
149 	for ( uint port = 1; port < 3; port++ )
150 	{
151 		settings->beginGroup( QString( "Input/Port/%1/Id" ).arg( port ) );
152 		QStringList ids = settings->childGroups();
153 		settings->endGroup();
154 
155 		ids.sort();
156 		foreach ( const QString& id, ids )
157 		{
158 			uint type = settings->value( QString( UIPortManager::mSettingsType ).arg( port ).arg( id ) ).toUInt();
159 
160 			switch ( type )
161 			{
162             case PERVIRTUALON:
163 				case PERPAD:
164 				{
165 					PerPad_struct* padbits = PerPadAdd( port == 1 ? &PORTDATA1 : &PORTDATA2 );
166 
167 					settings->beginGroup( QString( "Input/Port/%1/Id/%2/Controller/%3/Key" ).arg( port ).arg( id ).arg( type ) );
168 					QStringList padKeys = settings->childKeys();
169 					settings->endGroup();
170 
171 					padKeys.sort();
172 					foreach ( const QString& padKey, padKeys )
173 					{
174 						const QString key = settings->value( QString( UIPortManager::mSettingsKey ).arg( port ).arg( id ).arg( type ).arg( padKey ) ).toString();
175 
176 						PerSetKey( key.toUInt(), padKey.toUInt(), padbits );
177 					}
178 					break;
179 				}
180 				case PERWHEEL:
181             {
182                PerAnalog_struct* analogbits = PerWheelAdd(port == 1 ? &PORTDATA1 : &PORTDATA2);
183 
184                settings->beginGroup(QString("Input/Port/%1/Id/%2/Controller/%3/Key").arg(port).arg(id).arg(type));
185                QStringList analogKeys = settings->childKeys();
186                settings->endGroup();
187 
188                analogKeys.sort();
189                foreach(const QString& analogKey, analogKeys)
190                {
191                   const QString key = settings->value(QString(UIPortManager::mSettingsKey).arg(port).arg(id).arg(type).arg(analogKey)).toString();
192 
193                   PerSetKey(key.toUInt(), analogKey.toUInt(), analogbits);
194                }
195                break;
196             }
197             case PERMISSIONSTICK:
198             {
199                PerAnalog_struct* analogbits = PerMissionStickAdd(port == 1 ? &PORTDATA1 : &PORTDATA2);
200 
201                settings->beginGroup(QString("Input/Port/%1/Id/%2/Controller/%3/Key").arg(port).arg(id).arg(type));
202                QStringList analogKeys = settings->childKeys();
203                settings->endGroup();
204 
205                analogKeys.sort();
206                foreach(const QString& analogKey, analogKeys)
207                {
208                   const QString key = settings->value(QString(UIPortManager::mSettingsKey).arg(port).arg(id).arg(type).arg(analogKey)).toString();
209 
210                   PerSetKey(key.toUInt(), analogKey.toUInt(), analogbits);
211                }
212                break;
213             }
214             case PERTWINSTICKS:
215             {
216                PerAnalog_struct* analogbits = PerTwinSticksAdd(port == 1 ? &PORTDATA1 : &PORTDATA2);
217 
218                settings->beginGroup(QString("Input/Port/%1/Id/%2/Controller/%3/Key").arg(port).arg(id).arg(type));
219                QStringList analogKeys = settings->childKeys();
220                settings->endGroup();
221 
222                analogKeys.sort();
223                foreach(const QString& analogKey, analogKeys)
224                {
225                   const QString key = settings->value(QString(UIPortManager::mSettingsKey).arg(port).arg(id).arg(type).arg(analogKey)).toString();
226 
227                   PerSetKey(key.toUInt(), analogKey.toUInt(), analogbits);
228                }
229                break;
230             }
231 				case PER3DPAD:
232 				{
233 					PerAnalog_struct* analogbits = Per3DPadAdd( port == 1 ? &PORTDATA1 : &PORTDATA2 );
234 
235 					settings->beginGroup( QString( "Input/Port/%1/Id/%2/Controller/%3/Key" ).arg( port ).arg( id ).arg( type ) );
236 					QStringList analogKeys = settings->childKeys();
237 					settings->endGroup();
238 
239 					analogKeys.sort();
240 					foreach ( const QString& analogKey, analogKeys )
241 					{
242 						const QString key = settings->value( QString( UIPortManager::mSettingsKey ).arg( port ).arg( id ).arg( type ).arg( analogKey ) ).toString();
243 
244 						PerSetKey( key.toUInt(), analogKey.toUInt(), analogbits );
245 					}
246 					break;
247 				}
248 				case PERGUN:
249 				{
250 					PerGun_struct* gunbits = PerGunAdd( port == 1 ? &PORTDATA1 : &PORTDATA2 );
251 					settings->beginGroup( QString( "Input/Port/%1/Id/%2/Controller/%3/Key" ).arg( port ).arg( id ).arg( type ) );
252 					QStringList gunKeys = settings->childKeys();
253 					settings->endGroup();
254 
255 					gunKeys.sort();
256 					foreach ( const QString& gunKey, gunKeys )
257 					{
258 						const QString key = settings->value( QString( UIPortManager::mSettingsKey ).arg( port ).arg( id ).arg( type ).arg( gunKey ) ).toString();
259 
260 						PerSetKey( key.toUInt(), gunKey.toUInt(), gunbits );
261 					}
262 					break;
263 				}
264 				case PERKEYBOARD:
265 					QtYabause::mainWindow()->appendLog( "Keyboard controller type is not yet supported" );
266 					break;
267 				case PERMOUSE:
268 				{
269 					PerMouse_struct* mousebits = PerMouseAdd( port == 1 ? &PORTDATA1 : &PORTDATA2 );
270 
271 					settings->beginGroup( QString( "Input/Port/%1/Id/%2/Controller/%3/Key" ).arg( port ).arg( id ).arg( type ) );
272 					QStringList mouseKeys = settings->childKeys();
273 					settings->endGroup();
274 
275 					mouseKeys.sort();
276 					foreach ( const QString& mouseKey, mouseKeys )
277 					{
278 						const QString key = settings->value( QString( UIPortManager::mSettingsKey ).arg( port ).arg( id ).arg( type ).arg( mouseKey ) ).toString();
279 
280 						PerSetKey( key.toUInt(), mouseKey.toUInt(), mousebits );
281 					}
282 
283 					emit toggleEmulateMouse( true );
284 					break;
285 				}
286 				case 0:
287 					// Unconnected
288 					break;
289 				default:
290 					QtYabause::mainWindow()->appendLog( "Invalid controller type" );
291 					break;
292 			}
293 		}
294 	}
295 }
296 
localtime_qt(const QDateTime & input,struct tm * result)297 static struct tm *localtime_qt(const QDateTime &input, struct tm *result)
298 {
299 	QDate date(input.date());
300 	result->tm_year = date.year() - 1900;
301 	result->tm_mon = date.month();
302 	result->tm_mday = date.day();
303 	result->tm_wday = date.dayOfWeek();
304 	result->tm_yday = date.dayOfYear();
305 
306 	QTime time(input.time());
307 	result->tm_sec = time.second();
308 	result->tm_min = time.minute();
309 	result->tm_hour = time.hour();
310 
311 	return result;
312 }
313 
reloadClock()314 void YabauseThread::reloadClock()
315 {
316 	QString tmp;
317 	Settings* s = QtYabause::settings();
318 
319 	if (mYabauseConf.basetime == 0)
320 		tmp = "";
321 	else
322 		tmp = QDateTime::fromTime_t(mYabauseConf.basetime).toString();
323 
324 	// Clock sync
325 	mYabauseConf.clocksync = (int)s->value( "General/ClockSync", mYabauseConf.clocksync ).toBool();
326 	tmp = s->value( "General/FixedBaseTime", tmp ).toString();
327 	if (!tmp.isEmpty() && mYabauseConf.clocksync)
328 	{
329 		QDateTime date = QDateTime::fromString(tmp, Qt::ISODate);
330 		mYabauseConf.basetime = (long)date.toTime_t();
331 	}
332 	else {
333 		mYabauseConf.basetime = 0;
334 	}
335 }
336 
reloadSettings()337 void YabauseThread::reloadSettings()
338 {
339 	//QMutexLocker l( &mMutex );
340 	// get settings pointer
341 	VolatileSettings* vs = QtYabause::volatileSettings();
342 
343 	// reset yabause conf
344 	resetYabauseConf();
345 
346 	// read & apply settings
347    mYabauseConf.m68kcoretype = vs->value("Advanced/68kCore", mYabauseConf.m68kcoretype).toInt();
348 	mYabauseConf.percoretype = vs->value( "Input/PerCore", mYabauseConf.percoretype ).toInt();
349 	mYabauseConf.sh1coretype = vs->value( "Advanced/SH1Interpreter", mYabauseConf.sh1coretype ).toInt();
350 	mYabauseConf.use_cd_block_lle = vs->value( "Advanced/EnableCDBlockLLE", mYabauseConf.use_cd_block_lle ).toBool();
351    mYabauseConf.use_sh2_dma_timing = vs->value("Advanced/EnableSh2DmaTiming", mYabauseConf.use_sh2_dma_timing).toBool();
352    mYabauseConf.use_scu_dma_timing = vs->value("Advanced/EnableScuDmaTiming", mYabauseConf.use_scu_dma_timing).toBool();
353    mYabauseConf.sh2_cache_enabled = vs->value("Advanced/EnableSh2Cache", mYabauseConf.sh2_cache_enabled).toBool();
354 	mYabauseConf.sh2coretype = vs->value( "Advanced/SH2Interpreter", mYabauseConf.sh2coretype ).toInt();
355 	mYabauseConf.vidcoretype = vs->value( "Video/VideoCore", mYabauseConf.vidcoretype ).toInt();
356 	mYabauseConf.osdcoretype = vs->value( "Video/OSDCore", mYabauseConf.osdcoretype ).toInt();
357 	mYabauseConf.sndcoretype = vs->value( "Sound/SoundCore", mYabauseConf.sndcoretype ).toInt();
358 	mYabauseConf.cdcoretype = vs->value( "General/CdRom", mYabauseConf.cdcoretype ).toInt();
359 	mYabauseConf.carttype = vs->value( "Cartridge/Type", mYabauseConf.carttype ).toInt();
360 	const QString r = vs->value( "Advanced/Region", mYabauseConf.regionid ).toString();
361 	if ( r.isEmpty() || r == "Auto" )
362 		mYabauseConf.regionid = 0;
363 	else
364 	{
365 		switch ( r[0].toLatin1() )
366 		{
367 			case 'J': mYabauseConf.regionid = 1; break;
368 			case 'T': mYabauseConf.regionid = 2; break;
369 			case 'U': mYabauseConf.regionid = 4; break;
370 			case 'B': mYabauseConf.regionid = 5; break;
371 			case 'K': mYabauseConf.regionid = 6; break;
372 			case 'A': mYabauseConf.regionid = 0xA; break;
373 			case 'E': mYabauseConf.regionid = 0xC; break;
374 			case 'L': mYabauseConf.regionid = 0xD; break;
375 		}
376 	}
377 	if (vs->value("General/EnableEmulatedBios", false).toBool())
378 		mYabauseConf.biospath = strdup( "" );
379 	else
380 		mYabauseConf.biospath = strdup( QFile::encodeName( vs->value( "General/Bios", mYabauseConf.biospath ).toString()).constData() );
381 
382 	mYabauseConf.cdpath = strdup( QFile::encodeName( vs->value( "General/CdRomISO", mYabauseConf.cdpath ).toString()).constData());
383 	mYabauseConf.ssfpath = strdup( QFile::encodeName( vs->value("General/SSFPath", mYabauseConf.ssfpath).toString()).constData());
384 	mYabauseConf.play_ssf = vs->value("General/PlaySSF", false).toBool();
385 	showFPS = vs->value( "General/ShowFPS", false ).toBool();
386 	mYabauseConf.usethreads = (int)vs->value( "General/EnableMultiThreading", mYabauseConf.usethreads ).toBool();
387 	mYabauseConf.numthreads = vs->value( "General/NumThreads", mYabauseConf.numthreads ).toInt();
388 	mYabauseConf.buppath = strdup( QFile::encodeName( vs->value( "Memory/Path", mYabauseConf.buppath ).toString()).constData() );
389 	mYabauseConf.sh1rompath = strdup( QFile::encodeName( vs->value( "SH1ROM/Path", mYabauseConf.mpegpath ).toString()).constData() );
390 	mYabauseConf.mpegpath = strdup( QFile::encodeName( vs->value( "MpegROM/Path", mYabauseConf.mpegpath ).toString()).constData() );
391 	mYabauseConf.cartpath = strdup( QFile::encodeName( vs->value( "Cartridge/Path", mYabauseConf.cartpath ).toString()).constData() );
392 	mYabauseConf.modemip = strdup( vs->value( "Cartridge/ModemIP", mYabauseConf.modemip ).toString().toLatin1().constData() );
393 	mYabauseConf.modemport = strdup( vs->value( "Cartridge/ModemPort", mYabauseConf.modemport ).toString().toLatin1().constData() );
394 	mYabauseConf.videoformattype = vs->value( "Video/VideoFormat", mYabauseConf.videoformattype ).toInt();
395    mYabauseConf.use_new_scsp = (int)vs->value("Sound/NewScsp", mYabauseConf.use_new_scsp).toBool();
396    mYabauseConf.use_scsp_dsp_dynarec = (int)vs->value("Sound/EnableScspDspDynarec", mYabauseConf.use_scsp_dsp_dynarec).toBool();
397    mYabauseConf.use_scu_dsp_jit = (int)vs->value("Advanced/EnableScuDspDynarec", mYabauseConf.use_scu_dsp_jit).toBool();
398 
399 	emit requestSize( QSize( vs->value( "Video/WinWidth", 0 ).toInt(), vs->value( "Video/WinHeight", 0 ).toInt() ) );
400 	emit requestFullscreen( vs->value( "Video/Fullscreen", false ).toBool() );
401 	emit requestVolumeChange( vs->value( "Sound/Volume", 100 ).toInt() );
402 
403 	reloadClock();
404 	reloadControllers();
405 }
406 
emulationRunning()407 bool YabauseThread::emulationRunning()
408 {
409 	//QMutexLocker l( &mMutex );
410 	return mTimerId != -1 && !mPause;
411 }
412 
emulationPaused()413 bool YabauseThread::emulationPaused()
414 {
415 	//QMutexLocker l( &mMutex );
416 	return mPause;
417 }
418 
resetYabauseConf()419 void YabauseThread::resetYabauseConf()
420 {
421 	// free structure
422 	memset( &mYabauseConf, 0, sizeof( yabauseinit_struct ) );
423 	// fill default structure
424 	mYabauseConf.m68kcoretype = M68KCORE_MUSASHI;
425 	mYabauseConf.percoretype = QtYabause::defaultPERCore().id;
426 	mYabauseConf.sh1coretype = SH2CORE_DEFAULT;
427 	mYabauseConf.use_cd_block_lle = 0;
428 	mYabauseConf.sh2coretype = SH2CORE_DEFAULT;
429 	mYabauseConf.vidcoretype = QtYabause::defaultVIDCore().id;
430 	mYabauseConf.sndcoretype = QtYabause::defaultSNDCore().id;
431 	mYabauseConf.cdcoretype = QtYabause::defaultCDCore().id;
432 	mYabauseConf.carttype = CART_NONE;
433 	mYabauseConf.regionid = 0;
434 	mYabauseConf.biospath = 0;
435 	mYabauseConf.cdpath = 0;
436 	mYabauseConf.buppath = 0;
437 	mYabauseConf.mpegpath = 0;
438 	mYabauseConf.cartpath = 0;
439 	mYabauseConf.videoformattype = VIDEOFORMATTYPE_NTSC;
440 	mYabauseConf.skip_load = 0;
441 	int numThreads = QThread::idealThreadCount();
442 	mYabauseConf.usethreads = numThreads <= 1 ? 0 : 1;
443 	mYabauseConf.numthreads = numThreads < 0 ? 1 : numThreads;
444 }
445 
timerEvent(QTimerEvent *)446 void YabauseThread::timerEvent( QTimerEvent* )
447 {
448 	//mPause = true;
449 	//mRunning = true;
450 	//while ( mRunning )
451 	{
452 		if ( !mPause )
453 			PERCore->HandleEvents();
454 		//else
455 			//msleep( 25 );
456 		//sleep( 0 );
457 	}
458 }
459