FlashGBX 4.2__py3-none-any.whl → 4.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- FlashGBX/DataTransfer.py +1 -2
- FlashGBX/FlashGBX.py +2 -2
- FlashGBX/FlashGBX_CLI.py +40 -29
- FlashGBX/FlashGBX_GUI.py +484 -191
- FlashGBX/Flashcart.py +3 -1
- FlashGBX/GBMemory.py +3 -1
- FlashGBX/LK_Device.py +408 -199
- FlashGBX/Mapper.py +46 -7
- FlashGBX/PocketCamera.py +2 -2
- FlashGBX/PocketCameraWindow.py +35 -5
- FlashGBX/RomFileAGB.py +4 -1
- FlashGBX/RomFileDMG.py +13 -2
- FlashGBX/Util.py +86 -16
- FlashGBX/fw_GBFlash.py +0 -5
- FlashGBX/fw_GBxCartRW_v1_4.py +2 -5
- FlashGBX/fw_JoeyJr.py +23 -8
- FlashGBX/hw_GBFlash.py +16 -7
- FlashGBX/hw_GBxCartRW.py +18 -16
- FlashGBX/hw_JoeyJr.py +2 -2
- FlashGBX/res/Third Party Notices.md +21 -1
- FlashGBX/res/config.zip +0 -0
- FlashGBX/res/fw_GBFlash.zip +0 -0
- FlashGBX/res/fw_GBxCart_RW_v1_4.zip +0 -0
- FlashGBX/res/fw_GBxCart_RW_v1_4a.zip +0 -0
- FlashGBX/res/fw_JoeyJr.zip +0 -0
- {FlashGBX-4.2.dist-info → FlashGBX-4.4.dist-info}/METADATA +101 -52
- FlashGBX-4.4.dist-info/RECORD +43 -0
- {FlashGBX-4.2.dist-info → FlashGBX-4.4.dist-info}/WHEEL +1 -1
- FlashGBX-4.2.dist-info/RECORD +0 -43
- {FlashGBX-4.2.dist-info → FlashGBX-4.4.dist-info}/LICENSE +0 -0
- {FlashGBX-4.2.dist-info → FlashGBX-4.4.dist-info}/entry_points.txt +0 -0
- {FlashGBX-4.2.dist-info → FlashGBX-4.4.dist-info}/top_level.txt +0 -0
FlashGBX/FlashGBX_GUI.py
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
# FlashGBX
|
|
3
3
|
# Author: Lesserkuma (github.com/lesserkuma)
|
|
4
4
|
|
|
5
|
-
import sys, os, time, datetime, json, platform, subprocess, requests, webbrowser, pkg_resources, threading, calendar
|
|
5
|
+
import sys, os, time, datetime, json, platform, subprocess, requests, webbrowser, pkg_resources, threading, calendar, queue
|
|
6
6
|
from .pyside import QtCore, QtWidgets, QtGui, QApplication
|
|
7
7
|
from PIL.ImageQt import ImageQt
|
|
8
|
+
from PIL import Image
|
|
8
9
|
from serial import SerialException
|
|
9
10
|
from .RomFileDMG import RomFileDMG
|
|
10
11
|
from .RomFileAGB import RomFileAGB
|
|
@@ -28,8 +29,12 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
28
29
|
FWUPWIN = None
|
|
29
30
|
STATUS = {}
|
|
30
31
|
TEXT_COLOR = (0, 0, 0, 255)
|
|
32
|
+
MSGBOX_QUEUE = queue.Queue()
|
|
33
|
+
MSGBOX_DISPLAYING = False
|
|
31
34
|
|
|
32
35
|
def __init__(self, args):
|
|
36
|
+
sys.excepthook = Util.exception_hook
|
|
37
|
+
|
|
33
38
|
QtWidgets.QWidget.__init__(self)
|
|
34
39
|
Util.CONFIG_PATH = args['config_path']
|
|
35
40
|
Util.APP_PATH = args['app_path']
|
|
@@ -199,6 +204,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
199
204
|
self.mnuConfig.addAction("Use &No-Intro file names", lambda: self.SETTINGS.setValue("UseNoIntroFilenames", str(self.mnuConfig.actions()[7].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")))
|
|
200
205
|
self.mnuConfig.addAction("Automatic cartridge &power off", lambda: [ self.SETTINGS.setValue("AutoPowerOff", str(self.mnuConfig.actions()[8].isChecked()).lower().replace("true", "350").replace("false", "0")), self.SetAutoPowerOff() ])
|
|
201
206
|
self.mnuConfig.addAction("Skip writing matching ROM chunk&s", lambda: self.SETTINGS.setValue("CompareSectors", str(self.mnuConfig.actions()[9].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")))
|
|
207
|
+
self.mnuConfig.addAction("Alternative address set mode (can fix or cause write errors)", lambda: self.SETTINGS.setValue("ForceWrPullup", str(self.mnuConfig.actions()[10].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")))
|
|
202
208
|
self.mnuConfig.addSeparator()
|
|
203
209
|
self.mnuConfigReadModeAGB = QtWidgets.QMenu("&Read Method (Game Boy Advance)")
|
|
204
210
|
self.mnuConfigReadModeAGB.addAction("S&tream", lambda: [ self.SETTINGS.setValue("AGBReadMethod", str(self.mnuConfigReadModeAGB.actions()[1].isChecked()).lower().replace("true", "2")), self.SetAGBReadMethod() ])
|
|
@@ -228,6 +234,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
228
234
|
self.mnuConfig.actions()[7].setCheckable(True)
|
|
229
235
|
self.mnuConfig.actions()[8].setCheckable(True)
|
|
230
236
|
self.mnuConfig.actions()[9].setCheckable(True)
|
|
237
|
+
self.mnuConfig.actions()[10].setCheckable(True)
|
|
231
238
|
self.mnuConfig.actions()[0].setChecked(self.SETTINGS.value("UpdateCheck") == "enabled")
|
|
232
239
|
self.mnuConfig.actions()[1].setChecked(self.SETTINGS.value("SaveFileNameAddDateTime", default="disabled") == "enabled")
|
|
233
240
|
self.mnuConfig.actions()[2].setChecked(self.SETTINGS.value("PreferChipErase", default="disabled") == "enabled")
|
|
@@ -238,6 +245,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
238
245
|
self.mnuConfig.actions()[7].setChecked(self.SETTINGS.value("UseNoIntroFilenames", default="enabled") == "enabled")
|
|
239
246
|
self.mnuConfig.actions()[8].setChecked(self.SETTINGS.value("AutoPowerOff", default="350") != "0")
|
|
240
247
|
self.mnuConfig.actions()[9].setChecked(self.SETTINGS.value("CompareSectors", default="enabled") == "enabled")
|
|
248
|
+
self.mnuConfig.actions()[10].setChecked(self.SETTINGS.value("ForceWrPullup", default="disabled") == "enabled")
|
|
241
249
|
|
|
242
250
|
self.mnuThirdParty = QtWidgets.QMenu("Third Party &Notices")
|
|
243
251
|
self.mnuThirdParty.addAction("About &Qt", lambda: [ QtWidgets.QMessageBox.aboutQt(None) ])
|
|
@@ -299,8 +307,19 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
299
307
|
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), config_ret[i][1], QtWidgets.QMessageBox.Ok)
|
|
300
308
|
|
|
301
309
|
QtCore.QTimer.singleShot(1, lambda: [ self.UpdateCheck(), self.FindDevices(port=args["argparsed"].device_port, firstRun=True) ])
|
|
310
|
+
self.MSGBOX_TIMER = QtCore.QTimer()
|
|
311
|
+
self.MSGBOX_TIMER.timeout.connect(self.MsgBoxCheck)
|
|
312
|
+
self.MSGBOX_TIMER.start(200)
|
|
313
|
+
|
|
302
314
|
|
|
303
|
-
|
|
315
|
+
def MsgBoxCheck(self):
|
|
316
|
+
if not self.MSGBOX_DISPLAYING and not self.MSGBOX_QUEUE.empty():
|
|
317
|
+
self.MSGBOX_DISPLAYING = True
|
|
318
|
+
msgbox = self.MSGBOX_QUEUE.get()
|
|
319
|
+
Util.dprint(f"Processing Message Box: {msgbox}")
|
|
320
|
+
msgbox.exec()
|
|
321
|
+
self.MSGBOX_DISPLAYING = False
|
|
322
|
+
|
|
304
323
|
def GuiCreateGroupBoxDMGCartInfo(self):
|
|
305
324
|
self.grpDMGCartridgeInfo = QtWidgets.QGroupBox("Game Boy Cartridge Information")
|
|
306
325
|
self.grpDMGCartridgeInfo.setMinimumWidth(400)
|
|
@@ -314,7 +333,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
314
333
|
self.lblDMGGameNameResult = QtWidgets.QLabel("")
|
|
315
334
|
rowDMGGameName.addWidget(self.lblDMGGameNameResult)
|
|
316
335
|
rowDMGGameName.setStretch(0, 9)
|
|
317
|
-
rowDMGGameName.setStretch(1,
|
|
336
|
+
rowDMGGameName.setStretch(1, 12)
|
|
318
337
|
group_layout.addLayout(rowDMGGameName)
|
|
319
338
|
|
|
320
339
|
rowDMGRomTitle = QtWidgets.QHBoxLayout()
|
|
@@ -324,7 +343,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
324
343
|
self.lblDMGRomTitleResult = QtWidgets.QLabel("")
|
|
325
344
|
rowDMGRomTitle.addWidget(self.lblDMGRomTitleResult)
|
|
326
345
|
rowDMGRomTitle.setStretch(0, 9)
|
|
327
|
-
rowDMGRomTitle.setStretch(1,
|
|
346
|
+
rowDMGRomTitle.setStretch(1, 12)
|
|
328
347
|
group_layout.addLayout(rowDMGRomTitle)
|
|
329
348
|
|
|
330
349
|
rowDMGGameCodeRevision = QtWidgets.QHBoxLayout()
|
|
@@ -334,7 +353,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
334
353
|
self.lblDMGGameCodeRevisionResult = QtWidgets.QLabel("")
|
|
335
354
|
rowDMGGameCodeRevision.addWidget(self.lblDMGGameCodeRevisionResult)
|
|
336
355
|
rowDMGGameCodeRevision.setStretch(0, 9)
|
|
337
|
-
rowDMGGameCodeRevision.setStretch(1,
|
|
356
|
+
rowDMGGameCodeRevision.setStretch(1, 12)
|
|
338
357
|
group_layout.addLayout(rowDMGGameCodeRevision)
|
|
339
358
|
|
|
340
359
|
rowDMGHeaderRtc = QtWidgets.QHBoxLayout()
|
|
@@ -345,7 +364,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
345
364
|
self.lblDMGHeaderRtcResult.mousePressEvent = lambda event: [ self.EditRTC(event) ]
|
|
346
365
|
rowDMGHeaderRtc.addWidget(self.lblDMGHeaderRtcResult)
|
|
347
366
|
rowDMGHeaderRtc.setStretch(0, 9)
|
|
348
|
-
rowDMGHeaderRtc.setStretch(1,
|
|
367
|
+
rowDMGHeaderRtc.setStretch(1, 12)
|
|
349
368
|
group_layout.addLayout(rowDMGHeaderRtc)
|
|
350
369
|
|
|
351
370
|
rowDMGHeaderBootlogo = QtWidgets.QHBoxLayout()
|
|
@@ -355,7 +374,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
355
374
|
self.lblDMGHeaderBootlogoResult = QtWidgets.QLabel("")
|
|
356
375
|
rowDMGHeaderBootlogo.addWidget(self.lblDMGHeaderBootlogoResult)
|
|
357
376
|
rowDMGHeaderBootlogo.setStretch(0, 9)
|
|
358
|
-
rowDMGHeaderBootlogo.setStretch(1,
|
|
377
|
+
rowDMGHeaderBootlogo.setStretch(1, 12)
|
|
359
378
|
group_layout.addLayout(rowDMGHeaderBootlogo)
|
|
360
379
|
|
|
361
380
|
rowDMGHeaderROMChecksum = QtWidgets.QHBoxLayout()
|
|
@@ -365,7 +384,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
365
384
|
self.lblDMGHeaderROMChecksumResult = QtWidgets.QLabel("")
|
|
366
385
|
rowDMGHeaderROMChecksum.addWidget(self.lblDMGHeaderROMChecksumResult)
|
|
367
386
|
rowDMGHeaderROMChecksum.setStretch(0, 9)
|
|
368
|
-
rowDMGHeaderROMChecksum.setStretch(1,
|
|
387
|
+
rowDMGHeaderROMChecksum.setStretch(1, 12)
|
|
369
388
|
group_layout.addLayout(rowDMGHeaderROMChecksum)
|
|
370
389
|
|
|
371
390
|
rowDMGHeaderROMSize = QtWidgets.QHBoxLayout()
|
|
@@ -376,7 +395,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
376
395
|
self.cmbDMGHeaderROMSizeResult.view().setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
|
|
377
396
|
rowDMGHeaderROMSize.addWidget(self.cmbDMGHeaderROMSizeResult)
|
|
378
397
|
rowDMGHeaderROMSize.setStretch(0, 9)
|
|
379
|
-
rowDMGHeaderROMSize.setStretch(1,
|
|
398
|
+
rowDMGHeaderROMSize.setStretch(1, 12)
|
|
380
399
|
group_layout.addLayout(rowDMGHeaderROMSize)
|
|
381
400
|
|
|
382
401
|
rowDMGHeaderSaveType = QtWidgets.QHBoxLayout()
|
|
@@ -387,7 +406,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
387
406
|
self.cmbDMGHeaderSaveTypeResult.view().setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
|
|
388
407
|
rowDMGHeaderSaveType.addWidget(self.cmbDMGHeaderSaveTypeResult)
|
|
389
408
|
rowDMGHeaderSaveType.setStretch(0, 9)
|
|
390
|
-
rowDMGHeaderSaveType.setStretch(1,
|
|
409
|
+
rowDMGHeaderSaveType.setStretch(1, 12)
|
|
391
410
|
group_layout.addLayout(rowDMGHeaderSaveType)
|
|
392
411
|
|
|
393
412
|
rowDMGHeaderMapper = QtWidgets.QHBoxLayout()
|
|
@@ -398,7 +417,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
398
417
|
self.cmbDMGHeaderMapperResult.view().setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
|
|
399
418
|
rowDMGHeaderMapper.addWidget(self.cmbDMGHeaderMapperResult)
|
|
400
419
|
rowDMGHeaderMapper.setStretch(0, 9)
|
|
401
|
-
rowDMGHeaderMapper.setStretch(1,
|
|
420
|
+
rowDMGHeaderMapper.setStretch(1, 12)
|
|
402
421
|
group_layout.addLayout(rowDMGHeaderMapper)
|
|
403
422
|
|
|
404
423
|
rowDMGCartridgeType = QtWidgets.QHBoxLayout()
|
|
@@ -428,7 +447,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
428
447
|
self.lblAGBGameNameResult = QtWidgets.QLabel("")
|
|
429
448
|
rowAGBGameName.addWidget(self.lblAGBGameNameResult)
|
|
430
449
|
rowAGBGameName.setStretch(0, 9)
|
|
431
|
-
rowAGBGameName.setStretch(1,
|
|
450
|
+
rowAGBGameName.setStretch(1, 12)
|
|
432
451
|
group_layout.addLayout(rowAGBGameName)
|
|
433
452
|
|
|
434
453
|
rowAGBRomTitle = QtWidgets.QHBoxLayout()
|
|
@@ -438,7 +457,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
438
457
|
self.lblAGBRomTitleResult = QtWidgets.QLabel("")
|
|
439
458
|
rowAGBRomTitle.addWidget(self.lblAGBRomTitleResult)
|
|
440
459
|
rowAGBRomTitle.setStretch(0, 9)
|
|
441
|
-
rowAGBRomTitle.setStretch(1,
|
|
460
|
+
rowAGBRomTitle.setStretch(1, 12)
|
|
442
461
|
group_layout.addLayout(rowAGBRomTitle)
|
|
443
462
|
|
|
444
463
|
rowAGBHeaderGameCodeRevision = QtWidgets.QHBoxLayout()
|
|
@@ -448,7 +467,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
448
467
|
self.lblAGBHeaderGameCodeRevisionResult = QtWidgets.QLabel("")
|
|
449
468
|
rowAGBHeaderGameCodeRevision.addWidget(self.lblAGBHeaderGameCodeRevisionResult)
|
|
450
469
|
rowAGBHeaderGameCodeRevision.setStretch(0, 9)
|
|
451
|
-
rowAGBHeaderGameCodeRevision.setStretch(1,
|
|
470
|
+
rowAGBHeaderGameCodeRevision.setStretch(1, 12)
|
|
452
471
|
group_layout.addLayout(rowAGBHeaderGameCodeRevision)
|
|
453
472
|
|
|
454
473
|
rowAGBGpioRtc = QtWidgets.QHBoxLayout()
|
|
@@ -459,7 +478,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
459
478
|
self.lblAGBGpioRtcResult.mousePressEvent = lambda event: [ self.EditRTC(event) ]
|
|
460
479
|
rowAGBGpioRtc.addWidget(self.lblAGBGpioRtcResult)
|
|
461
480
|
rowAGBGpioRtc.setStretch(0, 9)
|
|
462
|
-
rowAGBGpioRtc.setStretch(1,
|
|
481
|
+
rowAGBGpioRtc.setStretch(1, 12)
|
|
463
482
|
group_layout.addLayout(rowAGBGpioRtc)
|
|
464
483
|
|
|
465
484
|
rowAGBHeaderBootlogo = QtWidgets.QHBoxLayout()
|
|
@@ -469,7 +488,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
469
488
|
self.lblAGBHeaderBootlogoResult = QtWidgets.QLabel("")
|
|
470
489
|
rowAGBHeaderBootlogo.addWidget(self.lblAGBHeaderBootlogoResult)
|
|
471
490
|
rowAGBHeaderBootlogo.setStretch(0, 9)
|
|
472
|
-
rowAGBHeaderBootlogo.setStretch(1,
|
|
491
|
+
rowAGBHeaderBootlogo.setStretch(1, 12)
|
|
473
492
|
group_layout.addLayout(rowAGBHeaderBootlogo)
|
|
474
493
|
|
|
475
494
|
rowAGBHeaderChecksum = QtWidgets.QHBoxLayout()
|
|
@@ -479,7 +498,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
479
498
|
self.lblAGBHeaderChecksumResult = QtWidgets.QLabel("")
|
|
480
499
|
rowAGBHeaderChecksum.addWidget(self.lblAGBHeaderChecksumResult)
|
|
481
500
|
rowAGBHeaderChecksum.setStretch(0, 9)
|
|
482
|
-
rowAGBHeaderChecksum.setStretch(1,
|
|
501
|
+
rowAGBHeaderChecksum.setStretch(1, 12)
|
|
483
502
|
group_layout.addLayout(rowAGBHeaderChecksum)
|
|
484
503
|
|
|
485
504
|
rowAGBHeaderROMChecksum = QtWidgets.QHBoxLayout()
|
|
@@ -489,7 +508,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
489
508
|
self.lblAGBHeaderROMChecksumResult = QtWidgets.QLabel("")
|
|
490
509
|
rowAGBHeaderROMChecksum.addWidget(self.lblAGBHeaderROMChecksumResult)
|
|
491
510
|
rowAGBHeaderROMChecksum.setStretch(0, 9)
|
|
492
|
-
rowAGBHeaderROMChecksum.setStretch(1,
|
|
511
|
+
rowAGBHeaderROMChecksum.setStretch(1, 12)
|
|
493
512
|
group_layout.addLayout(rowAGBHeaderROMChecksum)
|
|
494
513
|
|
|
495
514
|
rowAGBHeaderROMSize = QtWidgets.QHBoxLayout()
|
|
@@ -502,7 +521,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
502
521
|
self.cmbAGBHeaderROMSizeResult.setCurrentIndex(self.cmbAGBHeaderROMSizeResult.count() - 1)
|
|
503
522
|
rowAGBHeaderROMSize.addWidget(self.cmbAGBHeaderROMSizeResult)
|
|
504
523
|
rowAGBHeaderROMSize.setStretch(0, 9)
|
|
505
|
-
rowAGBHeaderROMSize.setStretch(1,
|
|
524
|
+
rowAGBHeaderROMSize.setStretch(1, 12)
|
|
506
525
|
group_layout.addLayout(rowAGBHeaderROMSize)
|
|
507
526
|
|
|
508
527
|
rowAGBHeaderSaveType = QtWidgets.QHBoxLayout()
|
|
@@ -515,7 +534,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
515
534
|
self.cmbAGBSaveTypeResult.setCurrentIndex(self.cmbAGBSaveTypeResult.count() - 1)
|
|
516
535
|
rowAGBHeaderSaveType.addWidget(self.cmbAGBSaveTypeResult)
|
|
517
536
|
rowAGBHeaderSaveType.setStretch(0, 9)
|
|
518
|
-
rowAGBHeaderSaveType.setStretch(1,
|
|
537
|
+
rowAGBHeaderSaveType.setStretch(1, 12)
|
|
519
538
|
group_layout.addLayout(rowAGBHeaderSaveType)
|
|
520
539
|
|
|
521
540
|
rowAGBCartridgeType = QtWidgets.QHBoxLayout()
|
|
@@ -655,23 +674,19 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
655
674
|
print("Error: Failed to check for updates (too many API requests). Try again later.")
|
|
656
675
|
else:
|
|
657
676
|
print("Error: Failed to check for updates (HTTP status {:d}).".format(ret.status_code))
|
|
658
|
-
else:
|
|
659
|
-
update_check = self.SETTINGS.value("UpdateCheck")
|
|
660
|
-
if update_check is None or (time.time() > (Util.VERSION_TIMESTAMP + (6*30*24*60*60))):
|
|
661
|
-
QtWidgets.QMessageBox.information(self, "{:s} {:s}".format(APPNAME, VERSION), "Welcome to {:s} {:s} by Lesserkuma!<br><br>".format(APPNAME, VERSION) + "The version update check has been disabled in the options menu and this version is now older than {:d} days. Please regularily check the <a href=\"https://github.com/lesserkuma/FlashGBX/releases/latest\">FlashGBX GitHub page</a> for the latest release notes and updates.".format(int((time.time() - Util.VERSION_TIMESTAMP)/60/60/24)), QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok)
|
|
662
677
|
|
|
663
678
|
def DisconnectDevice(self):
|
|
664
679
|
try:
|
|
665
680
|
devname = self.CONN.GetFullNameExtended()
|
|
666
681
|
self.CONN.Close(cartPowerOff=True)
|
|
667
|
-
self.CONN = None
|
|
668
|
-
self.DEVICES = {}
|
|
669
|
-
self.cmbDevice.clear()
|
|
670
682
|
print("Disconnected from {:s}".format(devname))
|
|
671
683
|
except:
|
|
672
684
|
pass
|
|
673
685
|
|
|
686
|
+
self.DEVICES = {}
|
|
687
|
+
self.cmbDevice.clear()
|
|
674
688
|
self.CONN = None
|
|
689
|
+
|
|
675
690
|
self.optAGB.setEnabled(False)
|
|
676
691
|
self.optDMG.setEnabled(False)
|
|
677
692
|
self.grpDMGCartridgeInfo.setEnabled(False)
|
|
@@ -696,6 +711,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
696
711
|
self.mnuConfig.actions()[5].setVisible(True)
|
|
697
712
|
self.mnuConfig.actions()[8].setVisible(True)
|
|
698
713
|
self.mnuConfig.actions()[9].setVisible(True)
|
|
714
|
+
self.mnuConfig.actions()[10].setVisible(False)
|
|
699
715
|
self.mnuTools.actions()[2].setEnabled(True)
|
|
700
716
|
self.mnuConfigReadModeAGB.setEnabled(True)
|
|
701
717
|
|
|
@@ -710,13 +726,13 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
710
726
|
msg = "This software is being developed by Lesserkuma as a hobby project. There is no affiliation with Nintendo or any other company. This software is provided as-is and the developer is not responsible for any damage that is caused by the use of it. Use at your own risk!<br><br>"
|
|
711
727
|
msg += f"© 2020–{datetime.datetime.now().year} Lesserkuma<br>"
|
|
712
728
|
msg += "• Website: <a href=\"https://github.com/lesserkuma/FlashGBX\">https://github.com/lesserkuma/FlashGBX</a><br><br>"
|
|
713
|
-
msg += "Acknowledgments and Contributors:<br>2358, 90sFlav, AcoVanConis, AdmirtheSableye, AlexiG, ALXCO-Hardware, AndehX, antPL, aronson, Ausar, bbsan, BennVenn, ccs21, chobby, ClassicOldSong, Cliffback, CodyWick13, Corborg, Cristóbal, crizzlycruz, Crystal, Därk, Davidish, DevDavisNunez, Diddy_Kong, djedditt, Dr-InSide, dyf2007, easthighNerd, EchelonPrime, edo999, Eldram, Ell, EmperorOfTigers, endrift, Erba Verde, ethanstrax, eveningmoose, Falknör, FerrantePescara, frarees, Frost Clock, gandalf1980, gboh, gekkio, Godan, Grender, HDR, Herax, Hiccup, hiks, howie0210, iamevn, Icesythe7, ide, inYourBackline, iyatemu, Jayro, Jenetrix, JFox, joyrider3774, jrharbort, JS7457, julgr, Kaede, kane159, KOOORAY, kscheel, kyokohunter, Leitplanke, litlemoran, LovelyA72, Lu, Luca DS, LucentW, manuelcm1, marv17, Merkin, metroid-maniac, Mr_V, olDirdey, orangeglo, paarongiroux, Paradoxical, Rairch, Raphaël BOICHOT, redalchemy, RetroGorek, RevZ, RibShark, s1cp, Satumox, Sgt.DoudouMiel, SH, Shinichi999, Sillyhatday, simonK, Sithdown, skite2001, Smelly-Ghost, Sonikks, Squiddy, Stitch, Super Maker, t5b6_de, Tauwasser, TheNFCookie, Timville, twitnic, velipso, Veund, voltagex, Voultar, Warez Waldo, wickawack, Winter1760, Wkr, x7l7j8cc, xactoes, xukkorz, yosoo, Zeii, Zelante, zipplet, Zoo, zvxr"
|
|
729
|
+
msg += "Acknowledgments and Contributors:<br>2358, 90sFlav, AcoVanConis, AdmirtheSableye, AlexiG, ALXCO-Hardware, AndehX, antPL, aronson, Ausar, bbsan, BennVenn, ccs21, chobby, ClassicOldSong, Cliffback, CodyWick13, Corborg, Cristóbal, crizzlycruz, Crystal, Därk, Davidish, delibird_deals, DevDavisNunez, Diddy_Kong, djedditt, Dr-InSide, dyf2007, easthighNerd, EchelonPrime, edo999, Eldram, Ell, EmperorOfTigers, endrift, Erba Verde, ethanstrax, eveningmoose, Falknör, FerrantePescara, frarees, Frost Clock, Gahr, gandalf1980, gboh, gekkio, Godan, Grender, HDR, Herax, Hiccup, hiks, howie0210, iamevn, Icesythe7, ide, infinest, inYourBackline, iyatemu, Jayro, Jenetrix, JFox, joyrider3774, jrharbort, JS7457, julgr, Kaede, kane159, KOOORAY, kscheel, kyokohunter, Leitplanke, litlemoran, LovelyA72, Lu, Luca DS, LucentW, luxkiller65, manuelcm1, marv17, Merkin, metroid-maniac, Mr_V, Mufsta, olDirdey, orangeglo, paarongiroux, Paradoxical, Rairch, Raphaël BOICHOT, redalchemy, RetroGorek, RevZ, RibShark, s1cp, Satumox, Sgt.DoudouMiel, SH, Shinichi999, Sillyhatday, simonK, Sithdown, skite2001, Smelly-Ghost, Sonikks, Squiddy, Stitch, Super Maker, t5b6_de, Tauwasser, TheNFCookie, Timville, twitnic, velipso, Veund, voltagex, Voultar, Warez Waldo, wickawack, Winter1760, Wkr, x7l7j8cc, xactoes, xukkorz, yosoo, Zeii, Zelante, zipplet, Zoo, zvxr"
|
|
714
730
|
QtWidgets.QMessageBox.information(self, "{:s} {:s}".format(APPNAME, VERSION), msg, QtWidgets.QMessageBox.Ok)
|
|
715
731
|
|
|
716
732
|
def AboutGameDB(self):
|
|
717
733
|
msg = f"{APPNAME} uses a game database that is based on the ongoing efforts of the No-Intro project. Visit <a href=\"https://no-intro.org/\">https://no-intro.org/</a> for more information.<br><br>"
|
|
718
734
|
msg += f"No-Intro databases referenced for this version of {APPNAME}:<br>"
|
|
719
|
-
msg += "• Nintendo - Game Boy (
|
|
735
|
+
msg += "• Nintendo - Game Boy (20250427-010043)<br>• Nintendo - Game Boy Advance (20250516-204815)<br>• Nintendo - Game Boy Advance (Video) (20241213-211743)<br>• Nintendo - Game Boy Color (20250516-032234)" # No-Intro DBs
|
|
720
736
|
QtWidgets.QMessageBox.information(self, "{:s} {:s}".format(APPNAME, VERSION), msg, QtWidgets.QMessageBox.Ok)
|
|
721
737
|
|
|
722
738
|
def OpenPath(self, path=None):
|
|
@@ -740,26 +756,19 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
740
756
|
if isinstance(event, QtGui.QMouseEvent):
|
|
741
757
|
if event.button() in (QtCore.Qt.MouseButton.MiddleButton, QtCore.Qt.MouseButton.RightButton): return
|
|
742
758
|
|
|
759
|
+
device = False
|
|
743
760
|
try:
|
|
744
|
-
|
|
745
|
-
Util.dprint("Platform: {:s}".format(platform.platform()))
|
|
746
|
-
if self.CONN is not None:
|
|
747
|
-
Util.dprint("Connected device: {:s}".format(self.CONN.GetFullNameExtended(more=True)))
|
|
748
|
-
else:
|
|
749
|
-
Util.dprint("No device connected")
|
|
750
|
-
Util.dprint("Now writing debug log file")
|
|
761
|
+
device = self.CONN.GetFullNameExtended(more=True)
|
|
751
762
|
except:
|
|
752
763
|
pass
|
|
764
|
+
|
|
765
|
+
Util.write_debug_log(device)
|
|
753
766
|
try:
|
|
754
|
-
fn = Util.CONFIG_PATH + "/debug.log"
|
|
755
|
-
with open(fn, "wb") as f:
|
|
756
|
-
f.write("\n".join(Util.DEBUG_LOG).encode("UTF-8-SIG"))
|
|
757
|
-
print("debug.log written")
|
|
758
767
|
if open_log is True:
|
|
768
|
+
fn = Util.CONFIG_PATH + "/debug.log"
|
|
759
769
|
self.OpenPath(fn)
|
|
760
|
-
return True
|
|
761
770
|
except:
|
|
762
|
-
|
|
771
|
+
pass
|
|
763
772
|
|
|
764
773
|
def ConnectDevice(self):
|
|
765
774
|
if self.CONN is not None:
|
|
@@ -820,6 +829,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
820
829
|
self.mnuConfig.actions()[5].setVisible(self.CONN.DEVICE_NAME == "GBxCart RW") # Limit Baud Rate
|
|
821
830
|
self.mnuConfig.actions()[8].setVisible(self.CONN.CanPowerCycleCart() and self.CONN.CanPowerCycleCart() and self.CONN.FW["fw_ver"] >= 12) # Auto Power Off
|
|
822
831
|
self.mnuConfig.actions()[9].setVisible(self.CONN.FW["fw_ver"] >= 12) # Skip writing matching ROM chunks
|
|
832
|
+
self.mnuConfig.actions()[10].setVisible(self.CONN.DEVICE_NAME == "Joey Jr") # Force WR Pullup
|
|
823
833
|
self.mnuConfigReadModeAGB.setEnabled(self.CONN.FW["fw_ver"] >= 12)
|
|
824
834
|
self.mnuConfigReadModeDMG.setEnabled(self.CONN.FW["fw_ver"] >= 12)
|
|
825
835
|
|
|
@@ -872,11 +882,12 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
872
882
|
if dev.FirmwareUpdateAvailable():
|
|
873
883
|
dontShowAgain = str(self.SETTINGS.value("SkipFirmwareUpdate", default="disabled")).lower() == "enabled"
|
|
874
884
|
if not dontShowAgain or dev.FW_UPDATE_REQ:
|
|
885
|
+
cb = None
|
|
875
886
|
if dev.FW_UPDATE_REQ is True:
|
|
876
887
|
text = "A firmware update for your {:s} device is required to use this software. Do you want to update now?".format(dev.GetFullName())
|
|
877
888
|
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Warning, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=text, standardButtons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, defaultButton=QtWidgets.QMessageBox.Yes)
|
|
878
889
|
elif dev.FW_UPDATE_REQ == 2:
|
|
879
|
-
text = "Your {:s} device is no longer supported
|
|
890
|
+
text = "Your {:s} device is no longer supported in this version of FlashGBX due to technical limitations. The last supported version is <a href=\"https://github.com/lesserkuma/FlashGBX/releases/tag/3.37\">FlashGBX v3.37</a>.\n\nYou can still use the Firmware Updater, however any other functions are no longer available.\n\nDo you want to run the Firmware Updater now?".format(dev.GetFullName()).replace("\n", "<br>")
|
|
880
891
|
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Warning, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=text, standardButtons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, defaultButton=QtWidgets.QMessageBox.Yes)
|
|
881
892
|
else:
|
|
882
893
|
text = "A firmware update for your {:s} device is available. Do you want to update now?".format(dev.GetFullName())
|
|
@@ -889,8 +900,9 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
889
900
|
if not Util.DEBUG:
|
|
890
901
|
self.DisconnectDevice()
|
|
891
902
|
else:
|
|
892
|
-
|
|
893
|
-
|
|
903
|
+
if cb is not None:
|
|
904
|
+
dontShowAgain = cb.isChecked()
|
|
905
|
+
if dontShowAgain: self.SETTINGS.setValue("SkipFirmwareUpdate", "enabled")
|
|
894
906
|
if answer == QtWidgets.QMessageBox.Yes:
|
|
895
907
|
self.ShowFirmwareUpdateWindow()
|
|
896
908
|
|
|
@@ -899,8 +911,16 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
899
911
|
if not Util.DEBUG:
|
|
900
912
|
self.DisconnectDevice()
|
|
901
913
|
QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), text, QtWidgets.QMessageBox.Ok)
|
|
914
|
+
|
|
915
|
+
if dev.IsUnregistered():
|
|
916
|
+
try:
|
|
917
|
+
text = dev.GetRegisterInformation()
|
|
918
|
+
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), text, QtWidgets.QMessageBox.Ok)
|
|
919
|
+
except:
|
|
920
|
+
pass
|
|
902
921
|
|
|
903
922
|
return True
|
|
923
|
+
|
|
904
924
|
return False
|
|
905
925
|
|
|
906
926
|
def FindDevices(self, connectToFirst=False, port=None, mode=None, firstRun=False):
|
|
@@ -911,7 +931,6 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
911
931
|
qt_app.processEvents()
|
|
912
932
|
|
|
913
933
|
messages = []
|
|
914
|
-
#last_msg = ""
|
|
915
934
|
|
|
916
935
|
# pylint: disable=global-variable-not-assigned
|
|
917
936
|
global hw_devices
|
|
@@ -933,8 +952,6 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
933
952
|
msg = ret[i][1]
|
|
934
953
|
if msg in messages: # don’t show the same message twice
|
|
935
954
|
continue
|
|
936
|
-
#else:
|
|
937
|
-
# last_msg = msg
|
|
938
955
|
if status == 3:
|
|
939
956
|
messages.append(msg)
|
|
940
957
|
self.CONN = None
|
|
@@ -959,7 +976,23 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
959
976
|
msg += message + "\n\n"
|
|
960
977
|
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), msg[:-2], QtWidgets.QMessageBox.Ok)
|
|
961
978
|
elif not firstRun:
|
|
962
|
-
|
|
979
|
+
msg = \
|
|
980
|
+
"No compatible devices found. Please ensure the device is connected properly.\n\n" \
|
|
981
|
+
"Compatible devices:\n" \
|
|
982
|
+
"- insideGadgets GBxCart RW\n" \
|
|
983
|
+
"- Geeksimon GBFlash\n" \
|
|
984
|
+
"- BennVenn Joey Jr (requires firmware update)\n\n" \
|
|
985
|
+
"Troubleshooting advice:\n" \
|
|
986
|
+
"- Reconnect the device, try different USB ports/cables, avoid passive USB hubs\n" \
|
|
987
|
+
"- Use a USB data cable (battery charging cables may not work)\n" \
|
|
988
|
+
"- Check if the operating system detects the device (if not, reboot your machine)\n" \
|
|
989
|
+
"- Update the firmware through Options → Tools → Firmware Updater"
|
|
990
|
+
if platform.system() == "Darwin":
|
|
991
|
+
msg += "\n - <b>For Joey Jr on macOS:</b> Use the dedicated <a href=\"https://github.com/lesserkuma/JoeyJr_FWUpdater\">Firmware Updater for Joey Jr</a>"
|
|
992
|
+
elif platform.system() == "Linux":
|
|
993
|
+
msg += "\n- <b>For Linux users:</b> Ensure your user account has permissions to use the device (try adding yourself to user groups “dialout” or “uucp”)"
|
|
994
|
+
|
|
995
|
+
QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Warning, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=msg.replace("\n", "<br>"), standardButtons=QtWidgets.QMessageBox.Ok).exec()
|
|
963
996
|
|
|
964
997
|
self.lblDevice.setText("No devices found.")
|
|
965
998
|
self.lblDevice.setStyleSheet("")
|
|
@@ -1080,7 +1113,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1080
1113
|
else:
|
|
1081
1114
|
msg += " This may indicate a bad dump, however this can be normal for some reproduction cartridges, unlicensed games, prototypes, patched games and intentional overdumps. You can also try to change the read mode in the options."
|
|
1082
1115
|
if self.CONN.GetMode() == "DMG" and self.cmbDMGHeaderMapperResult.currentText() == "MBC1":
|
|
1083
|
-
msg += "\n\nIf this is a NP GB-Memory Cartridge,
|
|
1116
|
+
msg += "\n\nIf this is a NP GB-Memory Cartridge, try the “Retry as G-MMC1” option."
|
|
1084
1117
|
button_gmmc1 = msgbox.addButton(" Retry as G-MMC1 ", QtWidgets.QMessageBox.ActionRole)
|
|
1085
1118
|
msgbox.setText(msg + msg_te)
|
|
1086
1119
|
msgbox.setIcon(QtWidgets.QMessageBox.Warning)
|
|
@@ -1151,22 +1184,24 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1151
1184
|
|
|
1152
1185
|
dontShowAgainCameraSavePopup = str(self.SETTINGS.value("SkipCameraSavePopup", default="disabled")).lower() == "enabled"
|
|
1153
1186
|
if not dontShowAgainCameraSavePopup:
|
|
1154
|
-
if self.CONN.GetMode() == "DMG" and self.CONN.INFO["mapper_raw"] == 252
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
self.
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1187
|
+
if self.CONN.GetMode() == "DMG" and self.CONN.INFO["mapper_raw"] == 252:
|
|
1188
|
+
# Pocket Camera
|
|
1189
|
+
if self.CONN.INFO["transferred"] == 0x20000 or (self.CONN.INFO["transferred"] == 0x100000 and "Unlicensed Photo!" in Util.DMG_Header_RAM_Sizes[self.cmbDMGHeaderSaveTypeResult.currentIndex()]):
|
|
1190
|
+
cbCameraSavePopup = QtWidgets.QCheckBox("Don’t show this message again", checked=dontShowAgain)
|
|
1191
|
+
msgboxCameraPopup = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Question, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text="Would you like to load your save data with the GB Camera Viewer now?")
|
|
1192
|
+
msgboxCameraPopup.setStandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
|
|
1193
|
+
msgboxCameraPopup.setDefaultButton(QtWidgets.QMessageBox.Yes)
|
|
1194
|
+
msgboxCameraPopup.setCheckBox(cbCameraSavePopup)
|
|
1195
|
+
answer = msgboxCameraPopup.exec()
|
|
1196
|
+
dontShowAgainCameraSavePopup = cbCameraSavePopup.isChecked()
|
|
1197
|
+
if dontShowAgainCameraSavePopup: self.SETTINGS.setValue("SkipCameraSavePopup", "enabled")
|
|
1198
|
+
if answer == QtWidgets.QMessageBox.Yes:
|
|
1199
|
+
self.CAMWIN = None
|
|
1200
|
+
self.CAMWIN = PocketCameraWindow(self, icon=self.windowIcon(), file=self.CONN.INFO["last_path"], config_path=Util.CONFIG_PATH, app_path=Util.APP_PATH)
|
|
1201
|
+
self.CAMWIN.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
|
|
1202
|
+
self.CAMWIN.setModal(True)
|
|
1203
|
+
self.CAMWIN.run()
|
|
1204
|
+
return
|
|
1170
1205
|
|
|
1171
1206
|
if "last_path" in self.CONN.INFO:
|
|
1172
1207
|
button_open_dir = msgbox.addButton(" Open Fol&der ", QtWidgets.QMessageBox.ActionRole)
|
|
@@ -1244,6 +1279,11 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1244
1279
|
self.CONN.INFO["dump_info"]["batteryless_sram"] = temp3
|
|
1245
1280
|
else:
|
|
1246
1281
|
self.ReadCartridge(resetStatus=False)
|
|
1282
|
+
|
|
1283
|
+
elif self.CONN.INFO["last_action"] == 6: # Detect Cartridge
|
|
1284
|
+
self.lblStatus4a.setText("Ready.")
|
|
1285
|
+
self.CONN.INFO["last_action"] = 0
|
|
1286
|
+
self.FinishDetectCartridge(self.CONN.INFO["detect_cart"])
|
|
1247
1287
|
|
|
1248
1288
|
else:
|
|
1249
1289
|
self.lblStatus4a.setText("Ready.")
|
|
@@ -1268,6 +1308,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1268
1308
|
def CartridgeTypeChanged(self, index):
|
|
1269
1309
|
self.STATUS["cart_type"] = {}
|
|
1270
1310
|
if index in (-1, 0): return
|
|
1311
|
+
if "detect_cartridge_args" in self.STATUS: return
|
|
1271
1312
|
if self.CONN.GetMode() == "DMG":
|
|
1272
1313
|
cart_types = self.CONN.GetSupportedCartridgesDMG()
|
|
1273
1314
|
if cart_types[1][index] == "RETAIL": # special keyword
|
|
@@ -1375,11 +1416,20 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1375
1416
|
return
|
|
1376
1417
|
|
|
1377
1418
|
if cart_type == 0:
|
|
1378
|
-
|
|
1419
|
+
if "detected_cart_type" not in self.STATUS: self.STATUS["detected_cart_type"] = ""
|
|
1420
|
+
if self.STATUS["detected_cart_type"] == "":
|
|
1421
|
+
self.STATUS["detected_cart_type"] = "WAITING_FLASH"
|
|
1422
|
+
self.STATUS["detect_cartridge_args"] = { "dpath":path }
|
|
1423
|
+
self.STATUS["can_skip_message"] = True
|
|
1424
|
+
self.DetectCartridge(checkSaveType=False)
|
|
1425
|
+
return
|
|
1426
|
+
cart_type = self.STATUS["detected_cart_type"]
|
|
1427
|
+
if "detected_cart_type" in self.STATUS: del(self.STATUS["detected_cart_type"])
|
|
1428
|
+
|
|
1379
1429
|
if cart_type is False: # clicked Cancel button
|
|
1380
1430
|
return
|
|
1381
|
-
elif cart_type is None or cart_type == 0:
|
|
1382
|
-
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "A compatible flash cartridge
|
|
1431
|
+
elif cart_type is None or cart_type == 0 or not isinstance(cart_type, int):
|
|
1432
|
+
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "A compatible flash cartridge profile could not be auto-detected.", QtWidgets.QMessageBox.Ok)
|
|
1383
1433
|
return
|
|
1384
1434
|
|
|
1385
1435
|
if self.CONN.GetMode() == "DMG":
|
|
@@ -1387,6 +1437,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1387
1437
|
elif self.CONN.GetMode() == "AGB":
|
|
1388
1438
|
self.cmbAGBCartridgeTypeResult.setCurrentIndex(cart_type)
|
|
1389
1439
|
|
|
1440
|
+
if "detected_cart_type" in self.STATUS: del(self.STATUS["detected_cart_type"])
|
|
1441
|
+
|
|
1390
1442
|
if self.CONN.GetMode() == "DMG":
|
|
1391
1443
|
self.SetDMGMapperResult(carts[cart_type])
|
|
1392
1444
|
mbc = Util.ConvertMapperTypeToMapper(self.cmbDMGHeaderMapperResult.currentIndex())
|
|
@@ -1430,8 +1482,6 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1430
1482
|
msg += " You can still give it a try, but it’s possible that it’s too large which may cause the ROM writing to fail."
|
|
1431
1483
|
answer = QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), msg, QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel)
|
|
1432
1484
|
if answer == QtWidgets.QMessageBox.Cancel: return
|
|
1433
|
-
#if "mbc" in carts[cart_type]:
|
|
1434
|
-
# mbc = carts[cart_type]["mbc"]
|
|
1435
1485
|
|
|
1436
1486
|
override_voltage = False
|
|
1437
1487
|
if 'voltage_variants' in carts[cart_type] and carts[cart_type]['voltage'] == 3.3:
|
|
@@ -1467,7 +1517,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1467
1517
|
if not Util.compare_mbc(hdr["mapper_raw"], mbc):
|
|
1468
1518
|
mbc1 = Util.get_mbc_name(mbc)
|
|
1469
1519
|
mbc2 = Util.get_mbc_name(hdr["mapper_raw"])
|
|
1470
|
-
compatible_mbc = [ "None", "MBC2", "MBC3", "MBC30", "MBC5", "MBC7", "MAC-GBD", "G-MMC1", "HuC-1", "HuC-3" ]
|
|
1520
|
+
compatible_mbc = [ "None", "MBC2", "MBC3", "MBC30", "MBC5", "MBC7", "MAC-GBD", "G-MMC1", "HuC-1", "HuC-3", "Unlicensed MBCX Mapper" ]
|
|
1471
1521
|
if (mbc2 == "None") or (mbc1 == "G-MMC1" and mbc2 == "MBC1") or (mbc2 == "G-MMC1" and mbc1 == "MBC1"):
|
|
1472
1522
|
pass
|
|
1473
1523
|
elif mbc2 != "None" and not (mbc1 in compatible_mbc and mbc2 in compatible_mbc):
|
|
@@ -1547,7 +1597,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1547
1597
|
pass
|
|
1548
1598
|
|
|
1549
1599
|
flash_offset = 0
|
|
1550
|
-
|
|
1600
|
+
force_wr_pullup = self.SETTINGS.value("ForceWrPullup", default="disabled").lower() == "enabled"
|
|
1601
|
+
|
|
1551
1602
|
self.grpDMGCartridgeInfo.setEnabled(False)
|
|
1552
1603
|
self.grpAGBCartridgeInfo.setEnabled(False)
|
|
1553
1604
|
self.grpActions.setEnabled(False)
|
|
@@ -1561,7 +1612,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1561
1612
|
verify_write = False
|
|
1562
1613
|
args = { "path":"", "buffer":buffer, "cart_type":cart_type, "override_voltage":override_voltage, "prefer_chip_erase":prefer_chip_erase, "fast_read_mode":True, "verify_write":verify_write, "fix_header":fix_header, "fix_bootlogo":fix_bootlogo, "mbc":mbc }
|
|
1563
1614
|
else:
|
|
1564
|
-
args = { "path":path, "cart_type":cart_type, "override_voltage":override_voltage, "prefer_chip_erase":prefer_chip_erase, "fast_read_mode":True, "verify_write":verify_write, "fix_header":fix_header, "fix_bootlogo":fix_bootlogo, "mbc":mbc, "flash_offset":flash_offset }
|
|
1615
|
+
args = { "path":path, "cart_type":cart_type, "override_voltage":override_voltage, "prefer_chip_erase":prefer_chip_erase, "fast_read_mode":True, "verify_write":verify_write, "fix_header":fix_header, "fix_bootlogo":fix_bootlogo, "mbc":mbc, "flash_offset":flash_offset, "force_wr_pullup":force_wr_pullup }
|
|
1565
1616
|
args["compare_sectors"] = self.SETTINGS.value("CompareSectors", default="disabled").lower() == "enabled"
|
|
1566
1617
|
self.CONN.FlashROM(fncSetProgress=self.PROGRESS.SetProgress, args=args)
|
|
1567
1618
|
#self.CONN._FlashROM(args=args)
|
|
@@ -1571,18 +1622,48 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1571
1622
|
self.STATUS["last_path"] = path
|
|
1572
1623
|
self.STATUS["args"] = args
|
|
1573
1624
|
|
|
1574
|
-
def BackupRAM(self):
|
|
1625
|
+
def BackupRAM(self, dpath=""):
|
|
1575
1626
|
if not self.CheckDeviceAlive(): return
|
|
1576
1627
|
|
|
1577
1628
|
rtc = False
|
|
1578
|
-
|
|
1579
|
-
path_datetime = ""
|
|
1580
|
-
if add_date_time and add_date_time.lower() == "enabled":
|
|
1581
|
-
path_datetime = "_{:s}".format(datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S"))
|
|
1629
|
+
path = ""
|
|
1582
1630
|
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1631
|
+
# Detect Cartridge needed?
|
|
1632
|
+
if \
|
|
1633
|
+
(self.CONN.GetMode() == "AGB" and self.cmbAGBSaveTypeResult.currentIndex() < len(Util.AGB_Header_Save_Types) and "Batteryless SRAM" in Util.AGB_Header_Save_Types[self.cmbAGBSaveTypeResult.currentIndex()]) or \
|
|
1634
|
+
(self.CONN.GetMode() == "DMG" and self.cmbDMGHeaderSaveTypeResult.currentIndex() < len(Util.DMG_Header_RAM_Sizes) and "Batteryless SRAM" in Util.DMG_Header_RAM_Sizes[self.cmbDMGHeaderSaveTypeResult.currentIndex()]) or \
|
|
1635
|
+
(self.CONN.GetMode() == "DMG" and "Unlicensed Photo!" in Util.DMG_Header_RAM_Sizes[self.cmbDMGHeaderSaveTypeResult.currentIndex()]) \
|
|
1636
|
+
:
|
|
1637
|
+
if self.CONN.GetFWBuildDate() == "": # Legacy Mode
|
|
1638
|
+
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text="This feature is not supported in Legacy Mode.", standardButtons=QtWidgets.QMessageBox.Ok)
|
|
1639
|
+
msgbox.exec()
|
|
1640
|
+
return
|
|
1641
|
+
|
|
1642
|
+
if self.CONN.GetMode() == "AGB":
|
|
1643
|
+
cart_type = self.cmbAGBCartridgeTypeResult.currentIndex()
|
|
1644
|
+
elif self.CONN.GetMode() == "DMG":
|
|
1645
|
+
cart_type = self.cmbDMGCartridgeTypeResult.currentIndex()
|
|
1646
|
+
if cart_type == 0 or ("dump_info" not in self.CONN.INFO or "batteryless_sram" not in self.CONN.INFO["dump_info"]):
|
|
1647
|
+
if "detected_cart_type" not in self.STATUS: self.STATUS["detected_cart_type"] = ""
|
|
1648
|
+
if self.STATUS["detected_cart_type"] == "":
|
|
1649
|
+
self.STATUS["detected_cart_type"] = "WAITING_SAVE_READ"
|
|
1650
|
+
self.STATUS["detect_cartridge_args"] = { "dpath":path }
|
|
1651
|
+
self.STATUS["can_skip_message"] = True
|
|
1652
|
+
self.DetectCartridge(checkSaveType=True)
|
|
1653
|
+
return
|
|
1654
|
+
cart_type = self.STATUS["detected_cart_type"]
|
|
1655
|
+
if "detected_cart_type" in self.STATUS: del(self.STATUS["detected_cart_type"])
|
|
1656
|
+
|
|
1657
|
+
if cart_type is False: # clicked Cancel button
|
|
1658
|
+
return
|
|
1659
|
+
elif cart_type is None or cart_type == 0 or not isinstance(cart_type, int):
|
|
1660
|
+
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "A compatible flash cartridge profile could not be auto-detected.", QtWidgets.QMessageBox.Ok)
|
|
1661
|
+
return
|
|
1662
|
+
if self.CONN.GetMode() == "AGB":
|
|
1663
|
+
self.cmbAGBCartridgeTypeResult.setCurrentIndex(cart_type)
|
|
1664
|
+
elif self.CONN.GetMode() == "DMG":
|
|
1665
|
+
self.cmbDMGCartridgeTypeResult.setCurrentIndex(cart_type)
|
|
1666
|
+
|
|
1586
1667
|
cart_type = 0
|
|
1587
1668
|
if self.CONN.GetMode() == "DMG":
|
|
1588
1669
|
setting_name = "LastDirSaveDataDMG"
|
|
@@ -1594,7 +1675,6 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1594
1675
|
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "No save type was selected.", QtWidgets.QMessageBox.Ok)
|
|
1595
1676
|
return
|
|
1596
1677
|
cart_type = self.cmbDMGCartridgeTypeResult.currentIndex()
|
|
1597
|
-
#save_size = Util.DMG_Header_RAM_Sizes_Flasher_Map[Util.DMG_Header_RAM_Sizes_Map.index(save_type)]
|
|
1598
1678
|
|
|
1599
1679
|
elif self.CONN.GetMode() == "AGB":
|
|
1600
1680
|
setting_name = "LastDirSaveDataAGB"
|
|
@@ -1606,13 +1686,23 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1606
1686
|
QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), "No save type was selected.", QtWidgets.QMessageBox.Ok)
|
|
1607
1687
|
return
|
|
1608
1688
|
cart_type = self.cmbAGBCartridgeTypeResult.currentIndex()
|
|
1609
|
-
#save_size = Util.AGB_Header_Save_Sizes[save_type]
|
|
1610
1689
|
else:
|
|
1611
1690
|
return
|
|
1612
1691
|
|
|
1613
1692
|
if not self.CheckHeader(): return
|
|
1614
|
-
|
|
1615
|
-
|
|
1693
|
+
if dpath == "":
|
|
1694
|
+
path = Util.GenerateFileName(mode=self.CONN.GetMode(), header=self.CONN.INFO, settings=self.SETTINGS)
|
|
1695
|
+
path = os.path.splitext(path)[0]
|
|
1696
|
+
|
|
1697
|
+
add_date_time = self.SETTINGS.value("SaveFileNameAddDateTime", default="disabled")
|
|
1698
|
+
if len(path) > 0 and add_date_time and add_date_time.lower() == "enabled":
|
|
1699
|
+
path += "_{:s}".format(datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S"))
|
|
1700
|
+
|
|
1701
|
+
path += ".sav"
|
|
1702
|
+
path = QtWidgets.QFileDialog.getSaveFileName(self, "Backup Save Data", last_dir + "/" + path, "Save Data File (*.sav *.srm *.fla *.eep);;All Files (*.*)")[0]
|
|
1703
|
+
if (path == ""): return
|
|
1704
|
+
else:
|
|
1705
|
+
path = dpath
|
|
1616
1706
|
|
|
1617
1707
|
verify_read = self.SETTINGS.value("VerifyData", default="enabled")
|
|
1618
1708
|
if verify_read and verify_read.lower() == "enabled":
|
|
@@ -1633,26 +1723,22 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1633
1723
|
rtc = (answer == QtWidgets.QMessageBox.Yes)
|
|
1634
1724
|
|
|
1635
1725
|
bl_args = {}
|
|
1636
|
-
if
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
cart_type = self.cmbAGBCartridgeTypeResult.currentIndex()
|
|
1642
|
-
if cart_type == 0 or ("dump_info" not in self.CONN.INFO or "batteryless_sram" not in self.CONN.INFO["dump_info"]):
|
|
1643
|
-
cart_type = self.DetectCartridge()
|
|
1644
|
-
if cart_type is False: # clicked Cancel button
|
|
1645
|
-
return
|
|
1646
|
-
elif cart_type is None or cart_type == 0:
|
|
1647
|
-
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "A compatible flash cartridge type could not be auto-detected.", QtWidgets.QMessageBox.Ok)
|
|
1648
|
-
return
|
|
1649
|
-
self.cmbAGBCartridgeTypeResult.setCurrentIndex(cart_type)
|
|
1726
|
+
if \
|
|
1727
|
+
(self.CONN.GetMode() == "AGB" and self.cmbAGBSaveTypeResult.currentIndex() < len(Util.AGB_Header_Save_Types) and "Batteryless SRAM" in Util.AGB_Header_Save_Types[self.cmbAGBSaveTypeResult.currentIndex()]) or \
|
|
1728
|
+
(self.CONN.GetMode() == "DMG" and self.cmbDMGHeaderSaveTypeResult.currentIndex() < len(Util.DMG_Header_RAM_Sizes) and "Batteryless SRAM" in Util.DMG_Header_RAM_Sizes[self.cmbDMGHeaderSaveTypeResult.currentIndex()]) \
|
|
1729
|
+
:
|
|
1730
|
+
if "detected_cart_type" in self.STATUS: del(self.STATUS["detected_cart_type"])
|
|
1650
1731
|
|
|
1651
1732
|
if "dump_info" in self.CONN.INFO and "batteryless_sram" in self.CONN.INFO["dump_info"]:
|
|
1652
1733
|
detected = self.CONN.INFO["dump_info"]["batteryless_sram"]
|
|
1653
1734
|
else:
|
|
1654
1735
|
detected = False
|
|
1655
|
-
|
|
1736
|
+
|
|
1737
|
+
if self.CONN.GetMode() == "AGB":
|
|
1738
|
+
rom_size = Util.AGB_Header_ROM_Sizes_Map[self.cmbAGBHeaderROMSizeResult.currentIndex()]
|
|
1739
|
+
elif self.CONN.GetMode() == "DMG":
|
|
1740
|
+
rom_size = Util.DMG_Header_ROM_Sizes_Map[self.cmbDMGHeaderROMSizeResult.currentIndex()]
|
|
1741
|
+
bl_args = self.GetBLArgs(rom_size=rom_size, detected=detected)
|
|
1656
1742
|
if bl_args is False: return
|
|
1657
1743
|
|
|
1658
1744
|
self.SETTINGS.setValue(setting_name, os.path.dirname(path))
|
|
@@ -1678,15 +1764,50 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1678
1764
|
self.STATUS["last_path"] = path
|
|
1679
1765
|
self.STATUS["args"] = args
|
|
1680
1766
|
|
|
1681
|
-
def WriteRAM(self, dpath="", erase=False, test=False):
|
|
1767
|
+
def WriteRAM(self, dpath="", erase=False, test=False, skip_warning=False):
|
|
1682
1768
|
if not self.CheckDeviceAlive(): return
|
|
1683
1769
|
mode = self.CONN.GetMode()
|
|
1684
1770
|
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1771
|
+
path = ""
|
|
1772
|
+
if erase is True:
|
|
1773
|
+
dpath = ""
|
|
1774
|
+
|
|
1775
|
+
# Detect Cartridge needed?
|
|
1776
|
+
if not test and ( \
|
|
1777
|
+
(mode == "AGB" and self.cmbAGBSaveTypeResult.currentIndex() < len(Util.AGB_Header_Save_Types) and "Batteryless SRAM" in Util.AGB_Header_Save_Types[self.cmbAGBSaveTypeResult.currentIndex()]) or \
|
|
1778
|
+
(mode == "DMG" and self.cmbDMGHeaderSaveTypeResult.currentIndex() < len(Util.DMG_Header_RAM_Sizes) and "Batteryless SRAM" in Util.DMG_Header_RAM_Sizes[self.cmbDMGHeaderSaveTypeResult.currentIndex()]) or \
|
|
1779
|
+
(mode == "DMG" and "Unlicensed Photo!" in Util.DMG_Header_RAM_Sizes[self.cmbDMGHeaderSaveTypeResult.currentIndex()]) \
|
|
1780
|
+
):
|
|
1781
|
+
if self.CONN.GetFWBuildDate() == "": # Legacy Mode
|
|
1782
|
+
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text="This feature is not supported in Legacy Mode.", standardButtons=QtWidgets.QMessageBox.Ok)
|
|
1783
|
+
msgbox.exec()
|
|
1784
|
+
return
|
|
1785
|
+
|
|
1786
|
+
if mode == "AGB":
|
|
1787
|
+
cart_type = self.cmbAGBCartridgeTypeResult.currentIndex()
|
|
1788
|
+
elif mode == "DMG":
|
|
1789
|
+
cart_type = self.cmbDMGCartridgeTypeResult.currentIndex()
|
|
1790
|
+
if cart_type == 0 or ("dump_info" not in self.CONN.INFO or "batteryless_sram" not in self.CONN.INFO["dump_info"]):
|
|
1791
|
+
if "detected_cart_type" not in self.STATUS: self.STATUS["detected_cart_type"] = ""
|
|
1792
|
+
if self.STATUS["detected_cart_type"] == "":
|
|
1793
|
+
self.STATUS["detected_cart_type"] = "WAITING_SAVE_WRITE"
|
|
1794
|
+
self.STATUS["detect_cartridge_args"] = { "dpath":dpath, "erase":erase }
|
|
1795
|
+
self.STATUS["can_skip_message"] = True
|
|
1796
|
+
self.DetectCartridge(checkSaveType=True)
|
|
1797
|
+
return
|
|
1798
|
+
cart_type = self.STATUS["detected_cart_type"]
|
|
1799
|
+
if "detected_cart_type" in self.STATUS: del(self.STATUS["detected_cart_type"])
|
|
1800
|
+
|
|
1801
|
+
if cart_type is False: # clicked Cancel button
|
|
1802
|
+
return
|
|
1803
|
+
elif cart_type is None or cart_type == 0 or not isinstance(cart_type, int):
|
|
1804
|
+
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "A compatible flash cartridge profile could not be auto-detected.", QtWidgets.QMessageBox.Ok)
|
|
1805
|
+
return
|
|
1806
|
+
if mode == "AGB":
|
|
1807
|
+
self.cmbAGBCartridgeTypeResult.setCurrentIndex(cart_type)
|
|
1808
|
+
elif mode == "DMG":
|
|
1809
|
+
self.cmbDMGCartridgeTypeResult.setCurrentIndex(cart_type)
|
|
1810
|
+
|
|
1690
1811
|
if mode == "DMG":
|
|
1691
1812
|
setting_name = "LastDirSaveDataDMG"
|
|
1692
1813
|
last_dir = self.SETTINGS.value(setting_name)
|
|
@@ -1697,7 +1818,6 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1697
1818
|
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "No save type was selected.", QtWidgets.QMessageBox.Ok)
|
|
1698
1819
|
return
|
|
1699
1820
|
cart_type = self.cmbDMGCartridgeTypeResult.currentIndex()
|
|
1700
|
-
#save_size = Util.DMG_Header_RAM_Sizes_Flasher_Map[Util.DMG_Header_RAM_Sizes_Map.index(save_type)]
|
|
1701
1821
|
|
|
1702
1822
|
elif mode == "AGB":
|
|
1703
1823
|
setting_name = "LastDirSaveDataAGB"
|
|
@@ -1708,7 +1828,6 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1708
1828
|
if save_type == 0:
|
|
1709
1829
|
QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), "No save type was selected.", QtWidgets.QMessageBox.Ok)
|
|
1710
1830
|
return
|
|
1711
|
-
#save_size = Util.AGB_Header_Save_Sizes[save_type]
|
|
1712
1831
|
cart_type = self.cmbAGBCartridgeTypeResult.currentIndex()
|
|
1713
1832
|
else:
|
|
1714
1833
|
return
|
|
@@ -1716,14 +1835,16 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1716
1835
|
|
|
1717
1836
|
filesize = 0
|
|
1718
1837
|
if dpath != "":
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1838
|
+
if not skip_warning:
|
|
1839
|
+
text = "The following save data file will now be written to the cartridge:\n" + dpath
|
|
1840
|
+
answer = QtWidgets.QMessageBox.question(self, "{:s} {:s}".format(APPNAME, VERSION), text, QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Ok)
|
|
1841
|
+
if answer == QtWidgets.QMessageBox.Cancel: return
|
|
1722
1842
|
path = dpath
|
|
1723
1843
|
self.SETTINGS.setValue(setting_name, os.path.dirname(path))
|
|
1724
1844
|
elif erase:
|
|
1725
|
-
|
|
1726
|
-
|
|
1845
|
+
if not skip_warning:
|
|
1846
|
+
answer = QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), "The save data on your cartridge will now be erased.", QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel)
|
|
1847
|
+
if answer == QtWidgets.QMessageBox.Cancel: return
|
|
1727
1848
|
elif test:
|
|
1728
1849
|
path = None
|
|
1729
1850
|
if self.CONN.GetFWBuildDate() == "": # Legacy Mode
|
|
@@ -1736,6 +1857,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1736
1857
|
msgbox.exec()
|
|
1737
1858
|
|
|
1738
1859
|
if (mode == "AGB" and self.cmbAGBSaveTypeResult.currentIndex() < len(Util.AGB_Header_Save_Types) and "Batteryless SRAM" in Util.AGB_Header_Save_Types[self.cmbAGBSaveTypeResult.currentIndex()]) or \
|
|
1860
|
+
(mode == "DMG" and self.cmbDMGHeaderSaveTypeResult.currentIndex() < len(Util.DMG_Header_RAM_Sizes) and "Batteryless SRAM" in Util.DMG_Header_RAM_Sizes[self.cmbDMGHeaderSaveTypeResult.currentIndex()]) or \
|
|
1861
|
+
(mode == "DMG" and self.cmbDMGHeaderSaveTypeResult.currentIndex() < len(Util.DMG_Header_RAM_Sizes) and "Unlicensed Photo!" in Util.DMG_Header_RAM_Sizes[self.cmbDMGHeaderSaveTypeResult.currentIndex()]) or \
|
|
1739
1862
|
("8M DACS" in Util.AGB_Header_Save_Types[self.cmbAGBSaveTypeResult.currentIndex()]) or \
|
|
1740
1863
|
(mode == "AGB" and "ereader" in self.CONN.INFO and self.CONN.INFO["ereader"] is True) or \
|
|
1741
1864
|
(mode == "DMG" and "256M Multi Cart" in self.cmbDMGHeaderMapperResult.currentText() and not self.CONN.CanPowerCycleCart()):
|
|
@@ -1744,11 +1867,15 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1744
1867
|
answer = QtWidgets.QMessageBox.question(self, "{:s} {:s}".format(APPNAME, VERSION), "The cartridge’s save chip will be tested for potential problems as follows:\n- Read the same data multiple times\n- Writing and reading different test patterns\n\nPlease ensure the cartridge pins are freshly cleaned and the save data is backed up before proceeding.", QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Ok)
|
|
1745
1868
|
if answer == QtWidgets.QMessageBox.Cancel: return
|
|
1746
1869
|
else:
|
|
1870
|
+
if path == "":
|
|
1871
|
+
path = Util.GenerateFileName(mode=mode, header=self.CONN.INFO, settings=self.SETTINGS)
|
|
1872
|
+
path = os.path.splitext(path)[0]
|
|
1873
|
+
path += ".sav"
|
|
1747
1874
|
path = QtWidgets.QFileDialog.getOpenFileName(self, "Restore Save Data", last_dir + "/" + path, "Save Data File (*.sav *.srm *.fla *.eep);;All Files (*.*)")[0]
|
|
1748
1875
|
if not path == "": self.SETTINGS.setValue(setting_name, os.path.dirname(path))
|
|
1749
1876
|
if (path == ""): return
|
|
1750
1877
|
|
|
1751
|
-
if not erase and not test:
|
|
1878
|
+
if not erase and not test and len(path) > 0:
|
|
1752
1879
|
filesize = os.path.getsize(path)
|
|
1753
1880
|
if filesize == 0 or filesize > 0x200000: # reject too large files to avoid exploding RAM
|
|
1754
1881
|
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "The size of this file is not supported.", QtWidgets.QMessageBox.Ok)
|
|
@@ -1771,7 +1898,6 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1771
1898
|
buffer = bytearray([0xFF] * 0x20000)
|
|
1772
1899
|
msg_text = "This {:s} cartridge currently has calibration data in place. It is strongly recommended to keep the existing calibration data.\n\nHow do you want to proceed?".format(cart_name)
|
|
1773
1900
|
button_overwrite = msgbox.addButton(" &Erase everything ", QtWidgets.QMessageBox.ActionRole)
|
|
1774
|
-
erase = False # Don’t just erase everything
|
|
1775
1901
|
else:
|
|
1776
1902
|
with open(path, "rb") as f: buffer = bytearray(f.read())
|
|
1777
1903
|
msg_text = "This {:s} cartridge currently has calibration data in place that is different from this save file’s data. It is strongly recommended to keep the existing calibration data unless you actually need to restore it from a previous backup.\n\nWould you like to keep the existing calibration data, or overwrite it with data from the file you selected?".format(cart_name)
|
|
@@ -1794,6 +1920,56 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1794
1920
|
answer = QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), msg_text, QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No)
|
|
1795
1921
|
if answer == QtWidgets.QMessageBox.No: return
|
|
1796
1922
|
|
|
1923
|
+
elif mode == "DMG" and self.CONN.INFO["dump_info"]["header"]["mapper_raw"] == 0xFC:
|
|
1924
|
+
if self.CONN.GetFWBuildDate() == "": # Legacy Mode
|
|
1925
|
+
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text="This cartridge is not supported in Legacy Mode.", standardButtons=QtWidgets.QMessageBox.Ok)
|
|
1926
|
+
msgbox.exec()
|
|
1927
|
+
return
|
|
1928
|
+
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Question, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text="")
|
|
1929
|
+
button_keep = msgbox.addButton(" &Keep existing calibration data ", QtWidgets.QMessageBox.ActionRole)
|
|
1930
|
+
if "Unlicensed Photo!" not in Util.DMG_Header_RAM_Sizes[self.cmbDMGHeaderSaveTypeResult.currentIndex()]:
|
|
1931
|
+
button_reset = msgbox.addButton(" &Force recalibration ", QtWidgets.QMessageBox.ActionRole)
|
|
1932
|
+
else:
|
|
1933
|
+
button_reset = None
|
|
1934
|
+
self.CONN.ReadInfo()
|
|
1935
|
+
cart_name = "Game Boy Camera"
|
|
1936
|
+
if self.CONN.INFO["db"] is not None:
|
|
1937
|
+
cart_name = self.CONN.INFO["db"]["gn"]
|
|
1938
|
+
if not test:
|
|
1939
|
+
if "gbcamera_calibration1" in self.CONN.INFO:
|
|
1940
|
+
if erase:
|
|
1941
|
+
buffer = bytearray([0x00] * 0x20000)
|
|
1942
|
+
if "Unlicensed Photo!" in Util.DMG_Header_RAM_Sizes[self.cmbDMGHeaderSaveTypeResult.currentIndex()]:
|
|
1943
|
+
buffer += bytearray([0xFF] * 0xE0000)
|
|
1944
|
+
msg_text = "This {:s} cartridge currently has calibration data in place.\n\nHow would you like to proceed?".format(cart_name)
|
|
1945
|
+
button_overwrite = msgbox.addButton(" &Erase everything ", QtWidgets.QMessageBox.ActionRole)
|
|
1946
|
+
else:
|
|
1947
|
+
with open(path, "rb") as f: buffer = bytearray(f.read())
|
|
1948
|
+
msg_text = "This {:s} cartridge currently has calibration data in place that is different from this save file’s data.\n\nHow would you like to proceed?".format(cart_name)
|
|
1949
|
+
button_overwrite = msgbox.addButton(" &Restore from save data ", QtWidgets.QMessageBox.ActionRole)
|
|
1950
|
+
button_cancel = msgbox.addButton("&Cancel", QtWidgets.QMessageBox.RejectRole)
|
|
1951
|
+
msgbox.setText(msg_text)
|
|
1952
|
+
msgbox.setDefaultButton(button_keep)
|
|
1953
|
+
msgbox.setEscapeButton(button_cancel)
|
|
1954
|
+
|
|
1955
|
+
if buffer[0x4FF2:0x5000] != self.CONN.INFO["gbcamera_calibration1"] or buffer[0x11FF2:0x12000] != self.CONN.INFO["gbcamera_calibration2"]:
|
|
1956
|
+
answer = msgbox.exec()
|
|
1957
|
+
if msgbox.clickedButton() == button_cancel:
|
|
1958
|
+
return
|
|
1959
|
+
elif msgbox.clickedButton() == button_keep:
|
|
1960
|
+
buffer[0x4FF2:0x5000] = self.CONN.INFO["gbcamera_calibration1"]
|
|
1961
|
+
buffer[0x11FF2:0x12000] = self.CONN.INFO["gbcamera_calibration2"]
|
|
1962
|
+
elif msgbox.clickedButton() == button_reset:
|
|
1963
|
+
buffer[0x4FF2:0x5000] = bytearray([0xAA] * 0xE)
|
|
1964
|
+
buffer[0x11FF2:0x12000] = bytearray([0xAA] * 0xE)
|
|
1965
|
+
elif msgbox.clickedButton() == button_overwrite:
|
|
1966
|
+
pass
|
|
1967
|
+
else:
|
|
1968
|
+
msg_text = "Warning: This {:s} cartridge may currently have calibration data in place. It is recommended to create a backup of the original save data first and store it in a safe place. That way the calibration data can be restored later.\n\nDo you still want to continue?".format(cart_name)
|
|
1969
|
+
answer = QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), msg_text, QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No)
|
|
1970
|
+
if answer == QtWidgets.QMessageBox.No: return
|
|
1971
|
+
|
|
1972
|
+
|
|
1797
1973
|
verify_write = self.SETTINGS.value("VerifyData", default="enabled")
|
|
1798
1974
|
if verify_write and verify_write.lower() == "enabled":
|
|
1799
1975
|
verify_write = True
|
|
@@ -2013,20 +2189,11 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2013
2189
|
|
|
2014
2190
|
else:
|
|
2015
2191
|
bl_args = {}
|
|
2016
|
-
if
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
cart_type = self.cmbAGBCartridgeTypeResult.currentIndex()
|
|
2022
|
-
if cart_type == 0 or ("dump_info" not in self.CONN.INFO or "batteryless_sram" not in self.CONN.INFO["dump_info"]):
|
|
2023
|
-
cart_type = self.DetectCartridge()
|
|
2024
|
-
if cart_type is False: # clicked Cancel button
|
|
2025
|
-
return
|
|
2026
|
-
elif cart_type is None or cart_type == 0:
|
|
2027
|
-
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "A compatible flash cartridge type could not be auto-detected.", QtWidgets.QMessageBox.Ok)
|
|
2028
|
-
return
|
|
2029
|
-
self.cmbAGBCartridgeTypeResult.setCurrentIndex(cart_type)
|
|
2192
|
+
if \
|
|
2193
|
+
(mode == "AGB" and self.cmbAGBSaveTypeResult.currentIndex() < len(Util.AGB_Header_Save_Types) and "Batteryless SRAM" in Util.AGB_Header_Save_Types[self.cmbAGBSaveTypeResult.currentIndex()]) or \
|
|
2194
|
+
(mode == "DMG" and self.cmbDMGHeaderSaveTypeResult.currentIndex() < len(Util.DMG_Header_RAM_Sizes) and "Batteryless SRAM" in Util.DMG_Header_RAM_Sizes[self.cmbDMGHeaderSaveTypeResult.currentIndex()]) \
|
|
2195
|
+
:
|
|
2196
|
+
if "detected_cart_type" in self.STATUS: del(self.STATUS["detected_cart_type"])
|
|
2030
2197
|
|
|
2031
2198
|
if "dump_info" in self.CONN.INFO and "batteryless_sram" in self.CONN.INFO["dump_info"]:
|
|
2032
2199
|
detected = self.CONN.INFO["dump_info"]["batteryless_sram"]
|
|
@@ -2036,6 +2203,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2036
2203
|
if bl_args is False: return
|
|
2037
2204
|
|
|
2038
2205
|
args = { "path":path, "cart_type":cart_type, "override_voltage":False, "prefer_chip_erase":False, "fast_read_mode":True, "verify_write":verify_write, "fix_header":False, "fix_bootlogo":False, "mbc":mbc }
|
|
2206
|
+
args.update(bl_args)
|
|
2039
2207
|
args.update({"bl_save":True, "flash_offset":bl_args["bl_offset"], "flash_size":bl_args["bl_size"]})
|
|
2040
2208
|
if erase:
|
|
2041
2209
|
args["path"] = ""
|
|
@@ -2043,12 +2211,13 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2043
2211
|
self.STATUS["args"] = args
|
|
2044
2212
|
self.CONN.FlashROM(fncSetProgress=self.PROGRESS.SetProgress, args=args)
|
|
2045
2213
|
#self.CONN._FlashROM(args=args)
|
|
2214
|
+
|
|
2046
2215
|
else:
|
|
2047
|
-
#cart_type = self.cmbAGBCartridgeTypeResult.currentIndex()
|
|
2048
2216
|
args = { "path":path, "mbc":mbc, "save_type":save_type, "rtc":rtc, "rtc_advance":rtc_advance, "erase":erase, "verify_write":verify_write, "cart_type":cart_type }
|
|
2049
2217
|
if buffer is not None:
|
|
2050
2218
|
args["buffer"] = buffer
|
|
2051
2219
|
args["path"] = None
|
|
2220
|
+
args["erase"] = False
|
|
2052
2221
|
self.STATUS["args"] = args
|
|
2053
2222
|
self.CONN.RestoreRAM(fncSetProgress=self.PROGRESS.SetProgress, args=args)
|
|
2054
2223
|
#args = { "mode":3, "path":path, "mbc":mbc, "save_type":save_type, "rtc":rtc, "rtc_advance":rtc_advance, "erase":erase, "verify_write":verify_write }
|
|
@@ -2071,11 +2240,18 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2071
2240
|
qt_app.processEvents()
|
|
2072
2241
|
|
|
2073
2242
|
def GetBLArgs(self, rom_size, detected=False):
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2243
|
+
mode = self.CONN.GetMode()
|
|
2244
|
+
if mode == "AGB":
|
|
2245
|
+
locs = [ 0x3C0000, 0x7C0000, 0xFC0000, 0x1FC0000 ]
|
|
2246
|
+
lens = [ 0x2000, 0x8000, 0x10000, 0x20000 ]
|
|
2247
|
+
elif mode == "DMG":
|
|
2248
|
+
locs = [ 0xD0000, 0x100000, 0x110000, 0x1D0000, 0x1E0000, 0x210000, 0x3D0000 ]
|
|
2249
|
+
lens = [ 0x2000, 0x8000, 0x10000, 0x20000 ]
|
|
2250
|
+
|
|
2251
|
+
temp = self.SETTINGS.value("BatterylessSramLocations{:s}".format(mode), "[]")
|
|
2077
2252
|
loc_index = None
|
|
2078
2253
|
len_index = None
|
|
2254
|
+
lay_index = None
|
|
2079
2255
|
|
|
2080
2256
|
try:
|
|
2081
2257
|
temp = json.loads(temp)
|
|
@@ -2087,19 +2263,46 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2087
2263
|
except:
|
|
2088
2264
|
pass
|
|
2089
2265
|
|
|
2266
|
+
intro_msg = ""
|
|
2090
2267
|
if detected is not False:
|
|
2091
2268
|
try:
|
|
2092
2269
|
loc_index = locs.index(detected["bl_offset"])
|
|
2093
2270
|
len_index = lens.index(detected["bl_size"])
|
|
2094
|
-
intro_msg = "In order to access Batteryless SRAM save data, its ROM location and size must
|
|
2271
|
+
intro_msg = "In order to access Batteryless SRAM save data, its ROM location and size must be specified.\n\nThe previously detected parameters have been pre-selected. Please adjust if necessary, then click “OK” to continue."
|
|
2095
2272
|
except:
|
|
2096
2273
|
detected = False
|
|
2097
2274
|
if detected is False:
|
|
2098
|
-
intro_msg = "In order to access Batteryless SRAM save data, its ROM location and size must
|
|
2275
|
+
intro_msg = "In order to access Batteryless SRAM save data, its ROM location and size must be specified.\n\n"
|
|
2276
|
+
if mode == "AGB":
|
|
2277
|
+
max_size = self.cmbAGBHeaderROMSizeResult.currentText().replace(" ", " ")
|
|
2278
|
+
elif mode == "DMG":
|
|
2279
|
+
max_size = self.cmbDMGHeaderROMSizeResult.currentText().replace(" ", " ")
|
|
2280
|
+
intro_msg2 = "⚠️ The required parameters could not be auto-detected. Please enter the ROM location and size manually below. Note that wrong values can corrupt your game upon writing, so having a full " + max_size + " ROM backup is recommended."
|
|
2281
|
+
|
|
2282
|
+
if mode == "DMG":
|
|
2283
|
+
# Load database of observed configurations from various bootlegs
|
|
2284
|
+
preselect = {}
|
|
2285
|
+
if os.path.exists(Util.CONFIG_PATH + "/db_DMG_bl.json"):
|
|
2286
|
+
with open(Util.CONFIG_PATH + "/db_DMG_bl.json", "r") as f:
|
|
2287
|
+
try:
|
|
2288
|
+
preselect = json.loads(f.read())
|
|
2289
|
+
except Exception as e:
|
|
2290
|
+
print("ERROR: Couldn’t load the database of batteryless SRAM configurations.", e, sep="\n")
|
|
2291
|
+
|
|
2292
|
+
try:
|
|
2293
|
+
if self.CONN.INFO["dump_info"]["header"]["game_title"] in list(preselect.keys()):
|
|
2294
|
+
loc_index = locs.index(preselect[self.CONN.INFO["dump_info"]["header"]["game_title"]][0])
|
|
2295
|
+
len_index = lens.index(preselect[self.CONN.INFO["dump_info"]["header"]["game_title"]][1])
|
|
2296
|
+
lay_index = preselect[self.CONN.INFO["dump_info"]["header"]["game_title"]][2]
|
|
2297
|
+
intro_msg2 = "The required parameters were pre-selected based on the ROM title “" + self.CONN.INFO["dump_info"]["header"]["game_title"] + "”. These may still be inaccurate, so you can adjust them below if necessary. Note that wrong values can corrupt your game when writing, so having a full " + max_size + " ROM backup is recommended."
|
|
2298
|
+
except:
|
|
2299
|
+
pass
|
|
2300
|
+
|
|
2301
|
+
intro_msg += intro_msg2
|
|
2099
2302
|
|
|
2100
2303
|
try:
|
|
2101
2304
|
if loc_index is None:
|
|
2102
|
-
loc_index = locs.index(int(self.SETTINGS.value("BatterylessSramLastLocation{:s}".format(
|
|
2305
|
+
loc_index = locs.index(int(self.SETTINGS.value("BatterylessSramLastLocation{:s}".format(mode))))
|
|
2103
2306
|
except:
|
|
2104
2307
|
pass
|
|
2105
2308
|
|
|
@@ -2110,7 +2313,13 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2110
2313
|
if l + 0x40000 >= rom_size: break
|
|
2111
2314
|
loc_index += 1
|
|
2112
2315
|
if loc_index >= len(locs): loc_index = len(locs) - 1
|
|
2113
|
-
if len_index is None:
|
|
2316
|
+
if len_index is None:
|
|
2317
|
+
if mode == "AGB":
|
|
2318
|
+
len_index = 2
|
|
2319
|
+
elif mode == "DMG":
|
|
2320
|
+
len_index = 1
|
|
2321
|
+
if lay_index is None:
|
|
2322
|
+
lay_index = 2
|
|
2114
2323
|
|
|
2115
2324
|
dlg_args = {
|
|
2116
2325
|
"title":"Batteryless SRAM Parameters",
|
|
@@ -2121,6 +2330,11 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2121
2330
|
[ "len", "cmb", "Size:", [ Util.formatFileSize(size=s, asInt=True) for s in lens ], len_index ],
|
|
2122
2331
|
]
|
|
2123
2332
|
}
|
|
2333
|
+
if mode == "DMG":
|
|
2334
|
+
dlg_args["params"].append(
|
|
2335
|
+
[ "layout", "cmb", "Layout:", [ "Continuous", "First half of ROM bank", "Second half of ROM bank" ], lay_index ]
|
|
2336
|
+
)
|
|
2337
|
+
|
|
2124
2338
|
dlg = UserInputDialog(self, icon=self.windowIcon(), args=dlg_args)
|
|
2125
2339
|
if dlg.exec_() == 1:
|
|
2126
2340
|
result = dlg.GetResult()
|
|
@@ -2135,10 +2349,12 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2135
2349
|
else:
|
|
2136
2350
|
bl_args["bl_offset"] = locs[result["loc"].currentIndex()]
|
|
2137
2351
|
bl_args["bl_size"] = lens[result["len"].currentIndex()]
|
|
2352
|
+
if mode == "DMG":
|
|
2353
|
+
bl_args["bl_layout"] = result["layout"].currentIndex()
|
|
2138
2354
|
|
|
2139
2355
|
locs.append(bl_args["bl_offset"])
|
|
2140
|
-
self.SETTINGS.setValue("BatterylessSramLocations{:s}".format(
|
|
2141
|
-
self.SETTINGS.setValue("BatterylessSramLastLocation{:s}".format(
|
|
2356
|
+
self.SETTINGS.setValue("BatterylessSramLocations{:s}".format(mode), json.dumps(locs))
|
|
2357
|
+
self.SETTINGS.setValue("BatterylessSramLastLocation{:s}".format(mode), json.dumps(bl_args["bl_offset"]))
|
|
2142
2358
|
ret = bl_args
|
|
2143
2359
|
else:
|
|
2144
2360
|
ret = False
|
|
@@ -2154,7 +2370,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2154
2370
|
|
|
2155
2371
|
if self.CONN.GetMode() == "DMG":
|
|
2156
2372
|
mbc = Util.get_mbc_name(Util.ConvertMapperTypeToMapper(self.cmbDMGHeaderMapperResult.currentIndex()))
|
|
2157
|
-
if mbc in ("MBC3", "MBC30"):
|
|
2373
|
+
if mbc in ("MBC3", "MBC30", "Unlicensed MBCX Mapper"):
|
|
2158
2374
|
dlg_args = {
|
|
2159
2375
|
"title":"MBC3/MBC30 Real Time Clock Editor",
|
|
2160
2376
|
"intro":"Enter the number of days, hours, minutes and seconds that passed since the RTC initially started.\n\nPlease note that all values are internal values. The game may use these only as a relative reference.",
|
|
@@ -2379,10 +2595,18 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2379
2595
|
|
|
2380
2596
|
if not self.CheckDeviceAlive(setMode=setTo): return
|
|
2381
2597
|
|
|
2382
|
-
|
|
2383
|
-
self.
|
|
2384
|
-
|
|
2385
|
-
self.
|
|
2598
|
+
try:
|
|
2599
|
+
if self.optDMG.isChecked() and (mode == "AGB" or mode == None):
|
|
2600
|
+
self.CONN.SetMode("DMG")
|
|
2601
|
+
elif self.optAGB.isChecked() and (mode == "DMG" or mode == None):
|
|
2602
|
+
self.CONN.SetMode("AGB")
|
|
2603
|
+
except BrokenPipeError:
|
|
2604
|
+
msg = "Failed to turn on the cartridge power.\n\nThe “Automatic cartridge power off” setting has therefore been disabled. Please re-connect the device and try again."
|
|
2605
|
+
self.mnuConfig.actions()[5].setChecked(False)
|
|
2606
|
+
self.SETTINGS.setValue("AutoPowerOff", "0")
|
|
2607
|
+
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), msg, QtWidgets.QMessageBox.Ok)
|
|
2608
|
+
self.DisconnectDevice()
|
|
2609
|
+
return False
|
|
2386
2610
|
|
|
2387
2611
|
ok = self.ReadCartridge()
|
|
2388
2612
|
qt_app.processEvents()
|
|
@@ -2412,17 +2636,23 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2412
2636
|
try:
|
|
2413
2637
|
data = self.CONN.ReadInfo(setPinsAsInputs=True)
|
|
2414
2638
|
except SerialException:
|
|
2639
|
+
self.LimitBaudRateGBxCartRW()
|
|
2415
2640
|
self.DisconnectDevice()
|
|
2416
2641
|
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "The connection to the device was lost while trying to read the ROM header. This may happen if the inserted cartridge issues a short circuit or its peak power draw is too high.\n\nAs a potential workaround for the latter, you can try hotswapping the cartridge:\n1. Remove the cartridge from the device.\n2. Reconnect the device and select mode.\n3. Then insert the cartridge and click “{:s}”.".format(self.btnHeaderRefresh.text().replace("&", "")), QtWidgets.QMessageBox.Ok)
|
|
2417
2642
|
return False
|
|
2418
2643
|
|
|
2419
2644
|
if data == False or len(data) == 0:
|
|
2645
|
+
self.LimitBaudRateGBxCartRW()
|
|
2420
2646
|
self.DisconnectDevice()
|
|
2421
|
-
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "Invalid response from the device.", QtWidgets.QMessageBox.Ok)
|
|
2647
|
+
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "Invalid response from the device. Please re-connect the USB cable.", QtWidgets.QMessageBox.Ok)
|
|
2422
2648
|
return False
|
|
2423
2649
|
|
|
2424
2650
|
if self.CONN.CheckROMStable() is False and resetStatus:
|
|
2425
|
-
|
|
2651
|
+
try:
|
|
2652
|
+
if data != bytearray(data[0] * len(data)):
|
|
2653
|
+
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "The cartridge connection is unstable!\nPlease clean the cartridge pins, carefully realign the cartridge and then try again.", QtWidgets.QMessageBox.Ok)
|
|
2654
|
+
except:
|
|
2655
|
+
pass
|
|
2426
2656
|
|
|
2427
2657
|
if self.CONN.GetMode() == "DMG":
|
|
2428
2658
|
self.cmbDMGHeaderMapperResult.clear()
|
|
@@ -2447,7 +2677,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2447
2677
|
self.lblDMGGameCodeRevisionResult.setText("{:s}-{:s}".format(data["db"]["gc"], str(data["version"])))
|
|
2448
2678
|
temp = data["db"]["gn"]
|
|
2449
2679
|
self.lblDMGGameNameResult.setText(temp)
|
|
2450
|
-
while self.lblDMGGameNameResult.fontMetrics().boundingRect(self.lblDMGGameNameResult.text()).width() >
|
|
2680
|
+
while self.lblDMGGameNameResult.fontMetrics().boundingRect(self.lblDMGGameNameResult.text()).width() > 240:
|
|
2451
2681
|
temp = temp[:-1]
|
|
2452
2682
|
self.lblDMGGameNameResult.setText(temp + "…")
|
|
2453
2683
|
if temp != data["db"]["gn"]:
|
|
@@ -2514,10 +2744,6 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2514
2744
|
self.lblDMGHeaderBootlogoResult.setStyleSheet(self.lblDMGRomTitleResult.styleSheet())
|
|
2515
2745
|
self.lblDMGHeaderROMChecksumResult.setText("")
|
|
2516
2746
|
self.lblDMGHeaderROMChecksumResult.setStyleSheet(self.lblDMGRomTitleResult.styleSheet())
|
|
2517
|
-
# cart_types = self.CONN.GetSupportedCartridgesDMG()
|
|
2518
|
-
# for i in range(0, len(cart_types[0])):
|
|
2519
|
-
# if "command_set" in cart_types[1][i] and cart_types[1][i]["command_set"] == "BLAZE_XPLODER":
|
|
2520
|
-
# self.cmbDMGCartridgeTypeResult.setCurrentIndex(i)
|
|
2521
2747
|
elif data["mapper_raw"] == 0x205: # Datel
|
|
2522
2748
|
self.lblDMGHeaderRtcResult.setText("")
|
|
2523
2749
|
self.lblDMGHeaderBootlogoResult.setText("")
|
|
@@ -2536,7 +2762,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2536
2762
|
if "logo_sachen" in data:
|
|
2537
2763
|
data["logo_sachen"].putpalette([ 255, 255, 255, 128, 128, 128 ])
|
|
2538
2764
|
try:
|
|
2539
|
-
self.lblDMGHeaderBootlogoResult.setPixmap(
|
|
2765
|
+
self.lblDMGHeaderBootlogoResult.setPixmap(Util.bitmap2pixmap(data["logo_sachen"]))
|
|
2540
2766
|
except:
|
|
2541
2767
|
pass
|
|
2542
2768
|
else:
|
|
@@ -2548,7 +2774,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2548
2774
|
else:
|
|
2549
2775
|
data["logo"].putpalette([ 255, 255, 255, 251, 0, 24 ])
|
|
2550
2776
|
try:
|
|
2551
|
-
self.lblDMGHeaderBootlogoResult.setPixmap(
|
|
2777
|
+
self.lblDMGHeaderBootlogoResult.setPixmap(Util.bitmap2pixmap(data["logo"]))
|
|
2552
2778
|
except:
|
|
2553
2779
|
pass
|
|
2554
2780
|
|
|
@@ -2569,7 +2795,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2569
2795
|
self.lblAGBHeaderGameCodeRevisionResult.setText("{:s}-{:s}".format(data["db"]["gc"], str(data["version"])))
|
|
2570
2796
|
temp = data["db"]["gn"]
|
|
2571
2797
|
self.lblAGBGameNameResult.setText(temp)
|
|
2572
|
-
while self.lblAGBGameNameResult.fontMetrics().boundingRect(self.lblAGBGameNameResult.text()).width() >
|
|
2798
|
+
while self.lblAGBGameNameResult.fontMetrics().boundingRect(self.lblAGBGameNameResult.text()).width() > 240:
|
|
2573
2799
|
temp = temp[:-1]
|
|
2574
2800
|
self.lblAGBGameNameResult.setText(temp + "…")
|
|
2575
2801
|
if temp != data["db"]["gn"]:
|
|
@@ -2661,7 +2887,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2661
2887
|
else:
|
|
2662
2888
|
data["logo"].putpalette([ 255, 255, 255, 251, 0, 24 ])
|
|
2663
2889
|
try:
|
|
2664
|
-
self.lblAGBHeaderBootlogoResult.setPixmap(
|
|
2890
|
+
self.lblAGBHeaderBootlogoResult.setPixmap(Util.bitmap2pixmap(data["logo"]))
|
|
2665
2891
|
except:
|
|
2666
2892
|
pass
|
|
2667
2893
|
|
|
@@ -2680,13 +2906,28 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2680
2906
|
self.btnRestoreRAM.setEnabled(True)
|
|
2681
2907
|
self.btnHeaderRefresh.setFocus()
|
|
2682
2908
|
self.SetProgressBars(min=0, max=100, value=0)
|
|
2683
|
-
self.lblStatus4a.setText("Ready.")
|
|
2684
2909
|
qt_app.processEvents()
|
|
2685
2910
|
|
|
2686
2911
|
if data['game_title'][:11] == "YJencrypted" and resetStatus:
|
|
2687
2912
|
QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), "This cartridge may be protected against reading or writing a ROM. If you don’t want to risk this cartridge to render itself unusable, please do not try to write a new ROM to it.", QtWidgets.QMessageBox.Ok)
|
|
2688
2913
|
|
|
2689
|
-
def
|
|
2914
|
+
def LimitBaudRateGBxCartRW(self):
|
|
2915
|
+
if self.CONN.GetName() == "GBxCart RW" and str(self.SETTINGS.value("AutoLimitBaudRate", default="enabled")).lower() == "enabled" and str(self.SETTINGS.value("LimitBaudRate", default="disabled")).lower() == "disabled":
|
|
2916
|
+
Util.dprint("Setting “" + self.mnuConfig.actions()[5].text().replace("&", "") + "” to “enabled”")
|
|
2917
|
+
self.mnuConfig.actions()[5].setChecked(True)
|
|
2918
|
+
self.SETTINGS.setValue("LimitBaudRate", "enabled")
|
|
2919
|
+
Util.dprint("Setting “" + self.mnuConfig.actions()[8].text().replace("&", "") + "” to “0”")
|
|
2920
|
+
self.mnuConfig.actions()[5].setChecked(False)
|
|
2921
|
+
self.SETTINGS.setValue("AutoPowerOff", "0")
|
|
2922
|
+
try:
|
|
2923
|
+
self.CONN.ChangeBaudRate(baudrate=1000000)
|
|
2924
|
+
except:
|
|
2925
|
+
try:
|
|
2926
|
+
self.DisconnectDevice()
|
|
2927
|
+
except:
|
|
2928
|
+
pass
|
|
2929
|
+
|
|
2930
|
+
def DetectCartridge(self, checkSaveType=True):
|
|
2690
2931
|
if not self.CheckDeviceAlive(): return
|
|
2691
2932
|
if not self.CONN.CheckROMStable():
|
|
2692
2933
|
answer = QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), "The cartridge connection is unstable!\nPlease clean the cartridge pins, carefully realign the cartridge for best results.\n\nContinue anyway?", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No)
|
|
@@ -2702,21 +2943,30 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2702
2943
|
self.lblStatus2aResult.setText("–")
|
|
2703
2944
|
self.lblStatus3aResult.setText("–")
|
|
2704
2945
|
self.lblStatus4aResult.setText("")
|
|
2705
|
-
self.lblStatus4a.setText("Analyzing Cartridge...")
|
|
2946
|
+
# self.lblStatus4a.setText("Analyzing Cartridge...")
|
|
2706
2947
|
self.SetProgressBars(min=0, max=0, value=1)
|
|
2707
2948
|
qt_app.processEvents()
|
|
2708
2949
|
|
|
2950
|
+
if "can_skip_message" not in self.STATUS: self.STATUS["can_skip_message"] = False
|
|
2951
|
+
limitVoltage = str(self.SETTINGS.value("AutoDetectLimitVoltage", default="disabled")).lower() == "enabled"
|
|
2952
|
+
self.CONN.DetectCartridge(fncSetProgress=self.PROGRESS.SetProgress, args={"limitVoltage":limitVoltage, "checkSaveType":checkSaveType})
|
|
2953
|
+
|
|
2954
|
+
def FinishDetectCartridge(self, ret):
|
|
2955
|
+
self.lblStatus1aResult.setText("–")
|
|
2956
|
+
self.lblStatus2aResult.setText("–")
|
|
2957
|
+
self.lblStatus3aResult.setText("–")
|
|
2958
|
+
|
|
2709
2959
|
limitVoltage = str(self.SETTINGS.value("AutoDetectLimitVoltage", default="disabled")).lower() == "enabled"
|
|
2710
|
-
ret = self.CONN.DetectCartridge(limitVoltage=limitVoltage, checkSaveType=not canSkipMessage)
|
|
2711
2960
|
if ret is False:
|
|
2712
2961
|
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "An error occured while trying to analyze the cartridge and you may need to physically reconnect the device.\n\nThis cartridge may not be auto-detectable, please select the cartridge type manually.", QtWidgets.QMessageBox.Ok)
|
|
2962
|
+
self.LimitBaudRateGBxCartRW()
|
|
2713
2963
|
self.DisconnectDevice()
|
|
2714
2964
|
cart_type = None
|
|
2715
2965
|
else:
|
|
2716
2966
|
(header, save_size, save_type, save_chip, sram_unstable, cart_types, cart_type_id, cfi_s, _, flash_id, detected_size) = ret
|
|
2717
|
-
|
|
2967
|
+
|
|
2718
2968
|
# Save Type
|
|
2719
|
-
if not
|
|
2969
|
+
if not self.STATUS["can_skip_message"]:
|
|
2720
2970
|
try:
|
|
2721
2971
|
if save_type is not None and save_type is not False:
|
|
2722
2972
|
if self.CONN.GetMode() == "DMG":
|
|
@@ -2735,9 +2985,12 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2735
2985
|
supp_cart_types = self.CONN.GetSupportedCartridgesDMG()
|
|
2736
2986
|
elif self.CONN.GetMode() == "AGB":
|
|
2737
2987
|
supp_cart_types = self.CONN.GetSupportedCartridgesAGB()
|
|
2988
|
+
else:
|
|
2989
|
+
raise NotImplementedError
|
|
2738
2990
|
except Exception as e:
|
|
2739
2991
|
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text="An unknown error occured. Please try again.\n\n" + str(e), standardButtons=QtWidgets.QMessageBox.Ok)
|
|
2740
2992
|
msgbox.exec()
|
|
2993
|
+
self.LimitBaudRateGBxCartRW()
|
|
2741
2994
|
return
|
|
2742
2995
|
|
|
2743
2996
|
try:
|
|
@@ -2768,9 +3021,12 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2768
3021
|
# Save Type
|
|
2769
3022
|
msg_save_type_s = ""
|
|
2770
3023
|
temp = ""
|
|
2771
|
-
if not
|
|
3024
|
+
if not self.STATUS["can_skip_message"] and save_type is not False and save_type is not None:
|
|
2772
3025
|
if save_chip is not None:
|
|
2773
|
-
|
|
3026
|
+
if save_type == 5 and "Unlicensed" in save_chip and "data" in self.CONN.INFO and self.CONN.INFO["data"] == bytearray([0xFF] * len(self.CONN.INFO["data"])):
|
|
3027
|
+
temp = "{:s} or {:s} ({:s})".format(Util.AGB_Header_Save_Types[4], Util.AGB_Header_Save_Types[5], save_chip)
|
|
3028
|
+
else:
|
|
3029
|
+
temp = "{:s} ({:s})".format(Util.AGB_Header_Save_Types[save_type], save_chip)
|
|
2774
3030
|
else:
|
|
2775
3031
|
if self.CONN.GetMode() == "DMG":
|
|
2776
3032
|
try:
|
|
@@ -2866,10 +3122,11 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2866
3122
|
else:
|
|
2867
3123
|
msg_flash_id_s_limit = ""
|
|
2868
3124
|
msg_flash_id_s = "<br><b>Flash ID Check{:s}:</b><pre style=\"font-size: 8pt; margin: 0;\">{:s}</pre>".format(msg_flash_id_s_limit, flash_id[:-1])
|
|
3125
|
+
if not is_generic:
|
|
2869
3126
|
if cfi_s != "":
|
|
2870
3127
|
msg_cfi_s = "<br><b>Common Flash Interface Data:</b><br>{:s}<br><br>".format(cfi_s.replace("\n", "<br>"))
|
|
2871
3128
|
else:
|
|
2872
|
-
msg_cfi_s = "<br><b>Common Flash Interface Data:</b>
|
|
3129
|
+
msg_cfi_s = "<br><b>Common Flash Interface Data:</b> Not available<br><br>"
|
|
2873
3130
|
|
|
2874
3131
|
if msg_cart_type_s_detail == "": msg_cart_type_s_detail = msg_cart_type_s
|
|
2875
3132
|
self.SetProgressBars(min=0, max=100, value=100)
|
|
@@ -2916,17 +3173,17 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2916
3173
|
msg = "The following cartridge configuration was detected:<br><br>"
|
|
2917
3174
|
if found_supported:
|
|
2918
3175
|
dontShowAgain = str(self.SETTINGS.value("SkipAutodetectMessage", default="disabled")).lower() == "enabled"
|
|
2919
|
-
if not dontShowAgain or not
|
|
3176
|
+
if not dontShowAgain or not self.STATUS["can_skip_message"]:
|
|
2920
3177
|
temp = "{:s}{:s}{:s}{:s}{:s}{:s}".format(msg, msg_flash_size_s, msg_save_type_s, msg_flash_mapper_s, msg_cart_type_s, msg_gbmem)
|
|
2921
3178
|
temp = temp[:-4]
|
|
2922
|
-
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Information, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=temp)
|
|
3179
|
+
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Information, windowTitle="{:s} {:s} | {:s}".format(APPNAME, VERSION, self.CONN.GetFullNameLabel()), text=temp)
|
|
2923
3180
|
msgbox.setTextFormat(QtCore.Qt.RichText)
|
|
2924
3181
|
button_ok = msgbox.addButton("&OK", QtWidgets.QMessageBox.ActionRole)
|
|
2925
3182
|
button_details = msgbox.addButton("&Details", QtWidgets.QMessageBox.ActionRole)
|
|
2926
3183
|
button_cancel = None
|
|
2927
3184
|
msgbox.setDefaultButton(button_ok)
|
|
2928
3185
|
cb = QtWidgets.QCheckBox("Always skip this message", checked=False)
|
|
2929
|
-
if
|
|
3186
|
+
if self.STATUS["can_skip_message"]:
|
|
2930
3187
|
button_cancel = msgbox.addButton("&Cancel", QtWidgets.QMessageBox.RejectRole)
|
|
2931
3188
|
msgbox.setEscapeButton(button_cancel)
|
|
2932
3189
|
msgbox.setCheckBox(cb)
|
|
@@ -2935,7 +3192,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2935
3192
|
|
|
2936
3193
|
msgbox.exec()
|
|
2937
3194
|
dontShowAgain = cb.isChecked()
|
|
2938
|
-
if dontShowAgain and
|
|
3195
|
+
if dontShowAgain and self.STATUS["can_skip_message"]: self.SETTINGS.setValue("SkipAutodetectMessage", "enabled")
|
|
2939
3196
|
|
|
2940
3197
|
if msgbox.clickedButton() == button_details:
|
|
2941
3198
|
show_details = True
|
|
@@ -2950,10 +3207,12 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2950
3207
|
self.btnHeaderRefresh.setFocus()
|
|
2951
3208
|
self.SetProgressBars(min=0, max=100, value=0)
|
|
2952
3209
|
self.lblStatus4a.setText("Ready.")
|
|
2953
|
-
|
|
3210
|
+
self.STATUS["can_skip_message"] = False
|
|
3211
|
+
if "detected_cart_type" in self.STATUS: del(self.STATUS["detected_cart_type"])
|
|
3212
|
+
return
|
|
2954
3213
|
|
|
2955
3214
|
if not found_supported or show_details is True:
|
|
2956
|
-
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Information, windowTitle="{:s} {:s}".format(APPNAME, VERSION))
|
|
3215
|
+
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Information, windowTitle="{:s} {:s} | {:s}".format(APPNAME, VERSION, self.CONN.GetFullNameLabel()))
|
|
2957
3216
|
button_ok = msgbox.addButton("&OK", QtWidgets.QMessageBox.ActionRole)
|
|
2958
3217
|
msgbox.setDefaultButton(button_ok)
|
|
2959
3218
|
msgbox.setEscapeButton(button_ok)
|
|
@@ -2976,7 +3235,9 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2976
3235
|
if answer == QtWidgets.QMessageBox.Yes:
|
|
2977
3236
|
self.SETTINGS.setValue("AutoDetectLimitVoltage", "disabled")
|
|
2978
3237
|
self.mnuConfig.actions()[4].setChecked(False)
|
|
2979
|
-
|
|
3238
|
+
self.STATUS["can_skip_message"] = False
|
|
3239
|
+
self.DetectCartridge()
|
|
3240
|
+
return
|
|
2980
3241
|
|
|
2981
3242
|
temp = "{:s}{:s}{:s}{:s}{:s}{:s}{:s}{:s}{:s}{:s}".format(msg, msg_header_s, msg_flash_size_s, msg_save_type_s, msg_flash_mapper_s, msg_flash_id_s, msg_cfi_s, msg_cart_type_s_detail, msg_gbmem, msg_fw)
|
|
2982
3243
|
temp = temp[:-4]
|
|
@@ -3006,7 +3267,31 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
3006
3267
|
self.btnHeaderRefresh.setFocus()
|
|
3007
3268
|
self.SetProgressBars(min=0, max=100, value=0)
|
|
3008
3269
|
self.lblStatus4a.setText("Ready.")
|
|
3009
|
-
|
|
3270
|
+
|
|
3271
|
+
waiting = None
|
|
3272
|
+
if "detected_cart_type" in self.STATUS and self.STATUS["detected_cart_type"] in ("WAITING_FLASH", "WAITING_SAVE_READ", "WAITING_SAVE_WRITE"):
|
|
3273
|
+
waiting = self.STATUS["detected_cart_type"]
|
|
3274
|
+
self.STATUS["detected_cart_type"] = cart_type
|
|
3275
|
+
self.STATUS["can_skip_message"] = False
|
|
3276
|
+
|
|
3277
|
+
if waiting == "WAITING_FLASH":
|
|
3278
|
+
if "detect_cartridge_args" in self.STATUS:
|
|
3279
|
+
self.FlashROM(dpath=self.STATUS["detect_cartridge_args"]["dpath"])
|
|
3280
|
+
del(self.STATUS["detect_cartridge_args"])
|
|
3281
|
+
else:
|
|
3282
|
+
self.FlashROM()
|
|
3283
|
+
elif waiting == "WAITING_SAVE_READ":
|
|
3284
|
+
if "detect_cartridge_args" in self.STATUS:
|
|
3285
|
+
self.BackupRAM(dpath=self.STATUS["detect_cartridge_args"]["dpath"])
|
|
3286
|
+
del(self.STATUS["detect_cartridge_args"])
|
|
3287
|
+
else:
|
|
3288
|
+
self.BackupRAM()
|
|
3289
|
+
elif waiting == "WAITING_SAVE_WRITE":
|
|
3290
|
+
if "detect_cartridge_args" in self.STATUS:
|
|
3291
|
+
self.WriteRAM(dpath=self.STATUS["detect_cartridge_args"]["dpath"], erase=self.STATUS["detect_cartridge_args"]["erase"], skip_warning=True)
|
|
3292
|
+
del(self.STATUS["detect_cartridge_args"])
|
|
3293
|
+
else:
|
|
3294
|
+
self.WriteRAM()
|
|
3010
3295
|
|
|
3011
3296
|
def WaitProgress(self, args):
|
|
3012
3297
|
if args["user_action"] == "REINSERT_CART":
|
|
@@ -3037,6 +3322,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
3037
3322
|
self.grpStatus.setTitle("Transfer Status (Write Save Data)")
|
|
3038
3323
|
elif args["method"] == "SAVE_WRITE_VERIFY":
|
|
3039
3324
|
self.grpStatus.setTitle("Transfer Status (Verify Save Data)")
|
|
3325
|
+
elif args["method"] == "DETECT_CART":
|
|
3326
|
+
self.grpStatus.setTitle("Transfer Status (Analyze Cartridge)")
|
|
3040
3327
|
|
|
3041
3328
|
if "error" in args:
|
|
3042
3329
|
self.lblStatus4a.setText("Failed!")
|
|
@@ -3049,6 +3336,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
3049
3336
|
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=str(args["error"]), standardButtons=QtWidgets.QMessageBox.Ok)
|
|
3050
3337
|
if not '\n' in str(args["error"]): msgbox.setTextFormat(QtCore.Qt.RichText)
|
|
3051
3338
|
msgbox.exec()
|
|
3339
|
+
self.LimitBaudRateGBxCartRW()
|
|
3052
3340
|
return
|
|
3053
3341
|
|
|
3054
3342
|
self.grpDMGCartridgeInfo.setEnabled(False)
|
|
@@ -3120,6 +3408,11 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
3120
3408
|
self.lblStatus4aResult.setText("")
|
|
3121
3409
|
self.btnCancel.setEnabled(args["abortable"])
|
|
3122
3410
|
self.SetProgressBars(min=0, max=size, value=pos)
|
|
3411
|
+
elif args["action"] == "UPDATE_INFO":
|
|
3412
|
+
self.lblStatus4a.setText(args["text"])
|
|
3413
|
+
self.lblStatus4aResult.setText("")
|
|
3414
|
+
self.btnCancel.setEnabled(args["abortable"])
|
|
3415
|
+
self.SetProgressBars(min=0, max=size, value=pos)
|
|
3123
3416
|
elif args["action"] == "FINISHED":
|
|
3124
3417
|
if pos > 0:
|
|
3125
3418
|
self.lblStatus1aResult.setText(Util.formatFileSize(size=pos))
|
|
@@ -3152,16 +3445,20 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
3152
3445
|
|
|
3153
3446
|
if "info_type" in args.keys() and "info_msg" in args.keys():
|
|
3154
3447
|
if args["info_type"] == "msgbox_critical":
|
|
3155
|
-
Util.dprint("Displaying Message Box:\n----\n{:s} {:s}\n----\n{:s}\n----".format(APPNAME, VERSION, args["info_msg"]))
|
|
3156
|
-
self.WriteDebugLog()
|
|
3157
3448
|
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=args["info_msg"], standardButtons=QtWidgets.QMessageBox.Ok)
|
|
3449
|
+
Util.dprint("Queueing Message Box {:s}:\n----\n{:s} {:s}\n----\n{:s}\n----".format(str(msgbox), APPNAME, VERSION, args["info_msg"]))
|
|
3158
3450
|
if not '\n' in args["info_msg"]: msgbox.setTextFormat(QtCore.Qt.RichText)
|
|
3159
|
-
|
|
3160
|
-
|
|
3451
|
+
self.MSGBOX_QUEUE.put(msgbox)
|
|
3452
|
+
self.WriteDebugLog()
|
|
3453
|
+
if "fatal" in args:
|
|
3454
|
+
self.LimitBaudRateGBxCartRW()
|
|
3455
|
+
self.DisconnectDevice()
|
|
3161
3456
|
elif args["info_type"] == "msgbox_information":
|
|
3162
3457
|
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Information, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=args["info_msg"], standardButtons=QtWidgets.QMessageBox.Ok)
|
|
3458
|
+
Util.dprint("Queueing Message Box {:s}:\n----\n{:s} {:s}\n----\n{:s}\n----".format(str(msgbox), APPNAME, VERSION, args["info_msg"]))
|
|
3163
3459
|
if not '\n' in args["info_msg"]: msgbox.setTextFormat(QtCore.Qt.RichText)
|
|
3164
|
-
msgbox.exec()
|
|
3460
|
+
#msgbox.exec()
|
|
3461
|
+
self.MSGBOX_QUEUE.put(msgbox)
|
|
3165
3462
|
elif args["info_type"] == "label":
|
|
3166
3463
|
self.lblStatus4a.setText(args["info_msg"])
|
|
3167
3464
|
|
|
@@ -3255,9 +3552,12 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
3255
3552
|
if self.CONN.GetMode() == "DMG":
|
|
3256
3553
|
header = self.CONN.ReadInfo(setPinsAsInputs=True)
|
|
3257
3554
|
if header["mapper_raw"] == 252: # GBD
|
|
3258
|
-
args = { "path":None, "mbc":252, "save_type":
|
|
3555
|
+
args = { "path":None, "mbc":252, "save_type":header["ram_size_raw"], "rtc":False }
|
|
3556
|
+
self.lblStatus4a.setText("Loading data, please wait...")
|
|
3557
|
+
qt_app.processEvents()
|
|
3259
3558
|
self.CONN.BackupRAM(fncSetProgress=False, args=args)
|
|
3260
3559
|
data = self.CONN.INFO["data"]
|
|
3560
|
+
self.lblStatus4a.setText("Ready.")
|
|
3261
3561
|
|
|
3262
3562
|
self.CAMWIN = None
|
|
3263
3563
|
self.CAMWIN = PocketCameraWindow(self, icon=self.windowIcon(), file=data, config_path=Util.CONFIG_PATH, app_path=Util.APP_PATH)
|
|
@@ -3318,6 +3618,11 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
3318
3618
|
|
|
3319
3619
|
def closeEvent(self, event):
|
|
3320
3620
|
self.DisconnectDevice()
|
|
3621
|
+
|
|
3622
|
+
self.MSGBOX_TIMER.stop()
|
|
3623
|
+
self.MSGBOX_DISPLAYING = True
|
|
3624
|
+
with self.MSGBOX_QUEUE.mutex:
|
|
3625
|
+
self.MSGBOX_QUEUE.queue.clear()
|
|
3321
3626
|
event.accept()
|
|
3322
3627
|
|
|
3323
3628
|
def run(self):
|
|
@@ -3338,18 +3643,6 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
3338
3643
|
except:
|
|
3339
3644
|
pass
|
|
3340
3645
|
qt_app.exec()
|
|
3341
|
-
# # Taskbar Progress on Windows only
|
|
3342
|
-
# try:
|
|
3343
|
-
# from PySide6.QtWin import QtWinTaskbarButton, QtWin
|
|
3344
|
-
# myappid = 'lesserkuma.flashgbx'
|
|
3345
|
-
# QtWin.setAppUserModelId(myappid)
|
|
3346
|
-
# taskbar_button = QtWinTaskbarButton()
|
|
3347
|
-
# self.TBPROG = taskbar_button.progress()
|
|
3348
|
-
# self.TBPROG.setRange(0, 100)
|
|
3349
|
-
# taskbar_button.setWindow(self.windowHandle())
|
|
3350
|
-
# self.TBPROG.setVisible(False)
|
|
3351
|
-
# except ImportError:
|
|
3352
|
-
# pass
|
|
3353
3646
|
|
|
3354
3647
|
else: # PySide2
|
|
3355
3648
|
qt_app.exec_()
|