FlashGBX 4.3__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/FlashGBX.py +1 -1
- FlashGBX/FlashGBX_CLI.py +24 -17
- FlashGBX/FlashGBX_GUI.py +346 -139
- FlashGBX/Flashcart.py +2 -1
- FlashGBX/GBMemory.py +3 -1
- FlashGBX/LK_Device.py +301 -216
- FlashGBX/Mapper.py +4 -4
- FlashGBX/PocketCameraWindow.py +31 -1
- FlashGBX/RomFileAGB.py +4 -1
- FlashGBX/RomFileDMG.py +7 -2
- FlashGBX/Util.py +30 -8
- FlashGBX/fw_JoeyJr.py +8 -1
- FlashGBX/hw_GBFlash.py +2 -2
- FlashGBX/hw_GBxCartRW.py +15 -15
- FlashGBX/hw_JoeyJr.py +2 -2
- 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.3.dist-info → FlashGBX-4.4.dist-info}/METADATA +91 -52
- FlashGBX-4.4.dist-info/RECORD +43 -0
- {FlashGBX-4.3.dist-info → FlashGBX-4.4.dist-info}/WHEEL +1 -1
- FlashGBX-4.3.dist-info/RECORD +0 -43
- {FlashGBX-4.3.dist-info → FlashGBX-4.4.dist-info}/LICENSE +0 -0
- {FlashGBX-4.3.dist-info → FlashGBX-4.4.dist-info}/entry_points.txt +0 -0
- {FlashGBX-4.3.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,6 +29,8 @@ 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):
|
|
33
36
|
sys.excepthook = Util.exception_hook
|
|
@@ -201,6 +204,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
201
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")))
|
|
202
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() ])
|
|
203
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")))
|
|
204
208
|
self.mnuConfig.addSeparator()
|
|
205
209
|
self.mnuConfigReadModeAGB = QtWidgets.QMenu("&Read Method (Game Boy Advance)")
|
|
206
210
|
self.mnuConfigReadModeAGB.addAction("S&tream", lambda: [ self.SETTINGS.setValue("AGBReadMethod", str(self.mnuConfigReadModeAGB.actions()[1].isChecked()).lower().replace("true", "2")), self.SetAGBReadMethod() ])
|
|
@@ -230,6 +234,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
230
234
|
self.mnuConfig.actions()[7].setCheckable(True)
|
|
231
235
|
self.mnuConfig.actions()[8].setCheckable(True)
|
|
232
236
|
self.mnuConfig.actions()[9].setCheckable(True)
|
|
237
|
+
self.mnuConfig.actions()[10].setCheckable(True)
|
|
233
238
|
self.mnuConfig.actions()[0].setChecked(self.SETTINGS.value("UpdateCheck") == "enabled")
|
|
234
239
|
self.mnuConfig.actions()[1].setChecked(self.SETTINGS.value("SaveFileNameAddDateTime", default="disabled") == "enabled")
|
|
235
240
|
self.mnuConfig.actions()[2].setChecked(self.SETTINGS.value("PreferChipErase", default="disabled") == "enabled")
|
|
@@ -240,6 +245,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
240
245
|
self.mnuConfig.actions()[7].setChecked(self.SETTINGS.value("UseNoIntroFilenames", default="enabled") == "enabled")
|
|
241
246
|
self.mnuConfig.actions()[8].setChecked(self.SETTINGS.value("AutoPowerOff", default="350") != "0")
|
|
242
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")
|
|
243
249
|
|
|
244
250
|
self.mnuThirdParty = QtWidgets.QMenu("Third Party &Notices")
|
|
245
251
|
self.mnuThirdParty.addAction("About &Qt", lambda: [ QtWidgets.QMessageBox.aboutQt(None) ])
|
|
@@ -301,8 +307,19 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
301
307
|
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), config_ret[i][1], QtWidgets.QMessageBox.Ok)
|
|
302
308
|
|
|
303
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
|
+
|
|
304
314
|
|
|
305
|
-
|
|
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
|
+
|
|
306
323
|
def GuiCreateGroupBoxDMGCartInfo(self):
|
|
307
324
|
self.grpDMGCartridgeInfo = QtWidgets.QGroupBox("Game Boy Cartridge Information")
|
|
308
325
|
self.grpDMGCartridgeInfo.setMinimumWidth(400)
|
|
@@ -657,23 +674,19 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
657
674
|
print("Error: Failed to check for updates (too many API requests). Try again later.")
|
|
658
675
|
else:
|
|
659
676
|
print("Error: Failed to check for updates (HTTP status {:d}).".format(ret.status_code))
|
|
660
|
-
else:
|
|
661
|
-
update_check = self.SETTINGS.value("UpdateCheck")
|
|
662
|
-
if update_check is None or (time.time() > (Util.VERSION_TIMESTAMP + (6*30*24*60*60))):
|
|
663
|
-
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)
|
|
664
677
|
|
|
665
678
|
def DisconnectDevice(self):
|
|
666
679
|
try:
|
|
667
680
|
devname = self.CONN.GetFullNameExtended()
|
|
668
681
|
self.CONN.Close(cartPowerOff=True)
|
|
669
|
-
self.CONN = None
|
|
670
|
-
self.DEVICES = {}
|
|
671
|
-
self.cmbDevice.clear()
|
|
672
682
|
print("Disconnected from {:s}".format(devname))
|
|
673
683
|
except:
|
|
674
684
|
pass
|
|
675
685
|
|
|
686
|
+
self.DEVICES = {}
|
|
687
|
+
self.cmbDevice.clear()
|
|
676
688
|
self.CONN = None
|
|
689
|
+
|
|
677
690
|
self.optAGB.setEnabled(False)
|
|
678
691
|
self.optDMG.setEnabled(False)
|
|
679
692
|
self.grpDMGCartridgeInfo.setEnabled(False)
|
|
@@ -698,6 +711,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
698
711
|
self.mnuConfig.actions()[5].setVisible(True)
|
|
699
712
|
self.mnuConfig.actions()[8].setVisible(True)
|
|
700
713
|
self.mnuConfig.actions()[9].setVisible(True)
|
|
714
|
+
self.mnuConfig.actions()[10].setVisible(False)
|
|
701
715
|
self.mnuTools.actions()[2].setEnabled(True)
|
|
702
716
|
self.mnuConfigReadModeAGB.setEnabled(True)
|
|
703
717
|
|
|
@@ -712,13 +726,13 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
712
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>"
|
|
713
727
|
msg += f"© 2020–{datetime.datetime.now().year} Lesserkuma<br>"
|
|
714
728
|
msg += "• Website: <a href=\"https://github.com/lesserkuma/FlashGBX\">https://github.com/lesserkuma/FlashGBX</a><br><br>"
|
|
715
|
-
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"
|
|
716
730
|
QtWidgets.QMessageBox.information(self, "{:s} {:s}".format(APPNAME, VERSION), msg, QtWidgets.QMessageBox.Ok)
|
|
717
731
|
|
|
718
732
|
def AboutGameDB(self):
|
|
719
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>"
|
|
720
734
|
msg += f"No-Intro databases referenced for this version of {APPNAME}:<br>"
|
|
721
|
-
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
|
|
722
736
|
QtWidgets.QMessageBox.information(self, "{:s} {:s}".format(APPNAME, VERSION), msg, QtWidgets.QMessageBox.Ok)
|
|
723
737
|
|
|
724
738
|
def OpenPath(self, path=None):
|
|
@@ -815,6 +829,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
815
829
|
self.mnuConfig.actions()[5].setVisible(self.CONN.DEVICE_NAME == "GBxCart RW") # Limit Baud Rate
|
|
816
830
|
self.mnuConfig.actions()[8].setVisible(self.CONN.CanPowerCycleCart() and self.CONN.CanPowerCycleCart() and self.CONN.FW["fw_ver"] >= 12) # Auto Power Off
|
|
817
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
|
|
818
833
|
self.mnuConfigReadModeAGB.setEnabled(self.CONN.FW["fw_ver"] >= 12)
|
|
819
834
|
self.mnuConfigReadModeDMG.setEnabled(self.CONN.FW["fw_ver"] >= 12)
|
|
820
835
|
|
|
@@ -872,7 +887,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
872
887
|
text = "A firmware update for your {:s} device is required to use this software. Do you want to update now?".format(dev.GetFullName())
|
|
873
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)
|
|
874
889
|
elif dev.FW_UPDATE_REQ == 2:
|
|
875
|
-
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>")
|
|
876
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)
|
|
877
892
|
else:
|
|
878
893
|
text = "A firmware update for your {:s} device is available. Do you want to update now?".format(dev.GetFullName())
|
|
@@ -916,7 +931,6 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
916
931
|
qt_app.processEvents()
|
|
917
932
|
|
|
918
933
|
messages = []
|
|
919
|
-
#last_msg = ""
|
|
920
934
|
|
|
921
935
|
# pylint: disable=global-variable-not-assigned
|
|
922
936
|
global hw_devices
|
|
@@ -938,8 +952,6 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
938
952
|
msg = ret[i][1]
|
|
939
953
|
if msg in messages: # don’t show the same message twice
|
|
940
954
|
continue
|
|
941
|
-
#else:
|
|
942
|
-
# last_msg = msg
|
|
943
955
|
if status == 3:
|
|
944
956
|
messages.append(msg)
|
|
945
957
|
self.CONN = None
|
|
@@ -964,7 +976,23 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
964
976
|
msg += message + "\n\n"
|
|
965
977
|
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), msg[:-2], QtWidgets.QMessageBox.Ok)
|
|
966
978
|
elif not firstRun:
|
|
967
|
-
|
|
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()
|
|
968
996
|
|
|
969
997
|
self.lblDevice.setText("No devices found.")
|
|
970
998
|
self.lblDevice.setStyleSheet("")
|
|
@@ -1156,22 +1184,24 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1156
1184
|
|
|
1157
1185
|
dontShowAgainCameraSavePopup = str(self.SETTINGS.value("SkipCameraSavePopup", default="disabled")).lower() == "enabled"
|
|
1158
1186
|
if not dontShowAgainCameraSavePopup:
|
|
1159
|
-
if self.CONN.GetMode() == "DMG" and self.CONN.INFO["mapper_raw"] == 252
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
self.
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
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
|
|
1175
1205
|
|
|
1176
1206
|
if "last_path" in self.CONN.INFO:
|
|
1177
1207
|
button_open_dir = msgbox.addButton(" Open Fol&der ", QtWidgets.QMessageBox.ActionRole)
|
|
@@ -1278,6 +1308,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1278
1308
|
def CartridgeTypeChanged(self, index):
|
|
1279
1309
|
self.STATUS["cart_type"] = {}
|
|
1280
1310
|
if index in (-1, 0): return
|
|
1311
|
+
if "detect_cartridge_args" in self.STATUS: return
|
|
1281
1312
|
if self.CONN.GetMode() == "DMG":
|
|
1282
1313
|
cart_types = self.CONN.GetSupportedCartridgesDMG()
|
|
1283
1314
|
if cart_types[1][index] == "RETAIL": # special keyword
|
|
@@ -1397,7 +1428,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1397
1428
|
|
|
1398
1429
|
if cart_type is False: # clicked Cancel button
|
|
1399
1430
|
return
|
|
1400
|
-
elif cart_type is None or cart_type == 0:
|
|
1431
|
+
elif cart_type is None or cart_type == 0 or not isinstance(cart_type, int):
|
|
1401
1432
|
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "A compatible flash cartridge profile could not be auto-detected.", QtWidgets.QMessageBox.Ok)
|
|
1402
1433
|
return
|
|
1403
1434
|
|
|
@@ -1451,8 +1482,6 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1451
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."
|
|
1452
1483
|
answer = QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), msg, QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel)
|
|
1453
1484
|
if answer == QtWidgets.QMessageBox.Cancel: return
|
|
1454
|
-
#if "mbc" in carts[cart_type]:
|
|
1455
|
-
# mbc = carts[cart_type]["mbc"]
|
|
1456
1485
|
|
|
1457
1486
|
override_voltage = False
|
|
1458
1487
|
if 'voltage_variants' in carts[cart_type] and carts[cart_type]['voltage'] == 3.3:
|
|
@@ -1568,7 +1597,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1568
1597
|
pass
|
|
1569
1598
|
|
|
1570
1599
|
flash_offset = 0
|
|
1571
|
-
|
|
1600
|
+
force_wr_pullup = self.SETTINGS.value("ForceWrPullup", default="disabled").lower() == "enabled"
|
|
1601
|
+
|
|
1572
1602
|
self.grpDMGCartridgeInfo.setEnabled(False)
|
|
1573
1603
|
self.grpAGBCartridgeInfo.setEnabled(False)
|
|
1574
1604
|
self.grpActions.setEnabled(False)
|
|
@@ -1582,7 +1612,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1582
1612
|
verify_write = False
|
|
1583
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 }
|
|
1584
1614
|
else:
|
|
1585
|
-
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 }
|
|
1586
1616
|
args["compare_sectors"] = self.SETTINGS.value("CompareSectors", default="disabled").lower() == "enabled"
|
|
1587
1617
|
self.CONN.FlashROM(fncSetProgress=self.PROGRESS.SetProgress, args=args)
|
|
1588
1618
|
#self.CONN._FlashROM(args=args)
|
|
@@ -1592,18 +1622,48 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1592
1622
|
self.STATUS["last_path"] = path
|
|
1593
1623
|
self.STATUS["args"] = args
|
|
1594
1624
|
|
|
1595
|
-
def BackupRAM(self):
|
|
1625
|
+
def BackupRAM(self, dpath=""):
|
|
1596
1626
|
if not self.CheckDeviceAlive(): return
|
|
1597
1627
|
|
|
1598
1628
|
rtc = False
|
|
1599
|
-
|
|
1600
|
-
path_datetime = ""
|
|
1601
|
-
if add_date_time and add_date_time.lower() == "enabled":
|
|
1602
|
-
path_datetime = "_{:s}".format(datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S"))
|
|
1629
|
+
path = ""
|
|
1603
1630
|
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
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
|
+
|
|
1607
1667
|
cart_type = 0
|
|
1608
1668
|
if self.CONN.GetMode() == "DMG":
|
|
1609
1669
|
setting_name = "LastDirSaveDataDMG"
|
|
@@ -1615,7 +1675,6 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1615
1675
|
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "No save type was selected.", QtWidgets.QMessageBox.Ok)
|
|
1616
1676
|
return
|
|
1617
1677
|
cart_type = self.cmbDMGCartridgeTypeResult.currentIndex()
|
|
1618
|
-
#save_size = Util.DMG_Header_RAM_Sizes_Flasher_Map[Util.DMG_Header_RAM_Sizes_Map.index(save_type)]
|
|
1619
1678
|
|
|
1620
1679
|
elif self.CONN.GetMode() == "AGB":
|
|
1621
1680
|
setting_name = "LastDirSaveDataAGB"
|
|
@@ -1627,13 +1686,23 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1627
1686
|
QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), "No save type was selected.", QtWidgets.QMessageBox.Ok)
|
|
1628
1687
|
return
|
|
1629
1688
|
cart_type = self.cmbAGBCartridgeTypeResult.currentIndex()
|
|
1630
|
-
#save_size = Util.AGB_Header_Save_Sizes[save_type]
|
|
1631
1689
|
else:
|
|
1632
1690
|
return
|
|
1633
1691
|
|
|
1634
1692
|
if not self.CheckHeader(): return
|
|
1635
|
-
|
|
1636
|
-
|
|
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
|
|
1637
1706
|
|
|
1638
1707
|
verify_read = self.SETTINGS.value("VerifyData", default="enabled")
|
|
1639
1708
|
if verify_read and verify_read.lower() == "enabled":
|
|
@@ -1654,37 +1723,22 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1654
1723
|
rtc = (answer == QtWidgets.QMessageBox.Yes)
|
|
1655
1724
|
|
|
1656
1725
|
bl_args = {}
|
|
1657
|
-
if
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
return
|
|
1662
|
-
cart_type = self.cmbAGBCartridgeTypeResult.currentIndex()
|
|
1663
|
-
if cart_type == 0 or ("dump_info" not in self.CONN.INFO or "batteryless_sram" not in self.CONN.INFO["dump_info"]):
|
|
1664
|
-
if "detected_cart_type" not in self.STATUS: self.STATUS["detected_cart_type"] = ""
|
|
1665
|
-
if self.STATUS["detected_cart_type"] == "":
|
|
1666
|
-
self.STATUS["detected_cart_type"] = "WAITING_SAVE_READ"
|
|
1667
|
-
self.STATUS["detect_cartridge_args"] = { "dpath":path }
|
|
1668
|
-
self.STATUS["can_skip_message"] = True
|
|
1669
|
-
self.DetectCartridge(checkSaveType=True)
|
|
1670
|
-
return
|
|
1671
|
-
cart_type = self.STATUS["detected_cart_type"]
|
|
1672
|
-
if "detected_cart_type" in self.STATUS: del(self.STATUS["detected_cart_type"])
|
|
1673
|
-
|
|
1674
|
-
if cart_type is False: # clicked Cancel button
|
|
1675
|
-
return
|
|
1676
|
-
elif cart_type is None or cart_type == 0:
|
|
1677
|
-
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "A compatible flash cartridge profile could not be auto-detected.", QtWidgets.QMessageBox.Ok)
|
|
1678
|
-
return
|
|
1679
|
-
self.cmbAGBCartridgeTypeResult.setCurrentIndex(cart_type)
|
|
1680
|
-
|
|
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
|
+
:
|
|
1681
1730
|
if "detected_cart_type" in self.STATUS: del(self.STATUS["detected_cart_type"])
|
|
1682
1731
|
|
|
1683
1732
|
if "dump_info" in self.CONN.INFO and "batteryless_sram" in self.CONN.INFO["dump_info"]:
|
|
1684
1733
|
detected = self.CONN.INFO["dump_info"]["batteryless_sram"]
|
|
1685
1734
|
else:
|
|
1686
1735
|
detected = False
|
|
1687
|
-
|
|
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)
|
|
1688
1742
|
if bl_args is False: return
|
|
1689
1743
|
|
|
1690
1744
|
self.SETTINGS.setValue(setting_name, os.path.dirname(path))
|
|
@@ -1714,13 +1768,46 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1714
1768
|
if not self.CheckDeviceAlive(): return
|
|
1715
1769
|
mode = self.CONN.GetMode()
|
|
1716
1770
|
|
|
1717
|
-
|
|
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)
|
|
1718
1810
|
|
|
1719
|
-
if dpath == "":
|
|
1720
|
-
path = Util.GenerateFileName(mode=mode, header=self.CONN.INFO, settings=self.SETTINGS)
|
|
1721
|
-
path = os.path.splitext(path)[0]
|
|
1722
|
-
path += ".sav"
|
|
1723
|
-
|
|
1724
1811
|
if mode == "DMG":
|
|
1725
1812
|
setting_name = "LastDirSaveDataDMG"
|
|
1726
1813
|
last_dir = self.SETTINGS.value(setting_name)
|
|
@@ -1731,7 +1818,6 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1731
1818
|
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "No save type was selected.", QtWidgets.QMessageBox.Ok)
|
|
1732
1819
|
return
|
|
1733
1820
|
cart_type = self.cmbDMGCartridgeTypeResult.currentIndex()
|
|
1734
|
-
#save_size = Util.DMG_Header_RAM_Sizes_Flasher_Map[Util.DMG_Header_RAM_Sizes_Map.index(save_type)]
|
|
1735
1821
|
|
|
1736
1822
|
elif mode == "AGB":
|
|
1737
1823
|
setting_name = "LastDirSaveDataAGB"
|
|
@@ -1742,7 +1828,6 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1742
1828
|
if save_type == 0:
|
|
1743
1829
|
QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), "No save type was selected.", QtWidgets.QMessageBox.Ok)
|
|
1744
1830
|
return
|
|
1745
|
-
#save_size = Util.AGB_Header_Save_Sizes[save_type]
|
|
1746
1831
|
cart_type = self.cmbAGBCartridgeTypeResult.currentIndex()
|
|
1747
1832
|
else:
|
|
1748
1833
|
return
|
|
@@ -1772,6 +1857,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1772
1857
|
msgbox.exec()
|
|
1773
1858
|
|
|
1774
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 \
|
|
1775
1862
|
("8M DACS" in Util.AGB_Header_Save_Types[self.cmbAGBSaveTypeResult.currentIndex()]) or \
|
|
1776
1863
|
(mode == "AGB" and "ereader" in self.CONN.INFO and self.CONN.INFO["ereader"] is True) or \
|
|
1777
1864
|
(mode == "DMG" and "256M Multi Cart" in self.cmbDMGHeaderMapperResult.currentText() and not self.CONN.CanPowerCycleCart()):
|
|
@@ -1780,11 +1867,15 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1780
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)
|
|
1781
1868
|
if answer == QtWidgets.QMessageBox.Cancel: return
|
|
1782
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"
|
|
1783
1874
|
path = QtWidgets.QFileDialog.getOpenFileName(self, "Restore Save Data", last_dir + "/" + path, "Save Data File (*.sav *.srm *.fla *.eep);;All Files (*.*)")[0]
|
|
1784
1875
|
if not path == "": self.SETTINGS.setValue(setting_name, os.path.dirname(path))
|
|
1785
1876
|
if (path == ""): return
|
|
1786
1877
|
|
|
1787
|
-
if not erase and not test:
|
|
1878
|
+
if not erase and not test and len(path) > 0:
|
|
1788
1879
|
filesize = os.path.getsize(path)
|
|
1789
1880
|
if filesize == 0 or filesize > 0x200000: # reject too large files to avoid exploding RAM
|
|
1790
1881
|
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "The size of this file is not supported.", QtWidgets.QMessageBox.Ok)
|
|
@@ -1807,7 +1898,6 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1807
1898
|
buffer = bytearray([0xFF] * 0x20000)
|
|
1808
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)
|
|
1809
1900
|
button_overwrite = msgbox.addButton(" &Erase everything ", QtWidgets.QMessageBox.ActionRole)
|
|
1810
|
-
erase = False # Don’t just erase everything
|
|
1811
1901
|
else:
|
|
1812
1902
|
with open(path, "rb") as f: buffer = bytearray(f.read())
|
|
1813
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)
|
|
@@ -1830,6 +1920,56 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1830
1920
|
answer = QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), msg_text, QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No)
|
|
1831
1921
|
if answer == QtWidgets.QMessageBox.No: return
|
|
1832
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
|
+
|
|
1833
1973
|
verify_write = self.SETTINGS.value("VerifyData", default="enabled")
|
|
1834
1974
|
if verify_write and verify_write.lower() == "enabled":
|
|
1835
1975
|
verify_write = True
|
|
@@ -2049,30 +2189,10 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2049
2189
|
|
|
2050
2190
|
else:
|
|
2051
2191
|
bl_args = {}
|
|
2052
|
-
if
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
return
|
|
2057
|
-
cart_type = self.cmbAGBCartridgeTypeResult.currentIndex()
|
|
2058
|
-
if cart_type == 0 or ("dump_info" not in self.CONN.INFO or "batteryless_sram" not in self.CONN.INFO["dump_info"]):
|
|
2059
|
-
if "detected_cart_type" not in self.STATUS: self.STATUS["detected_cart_type"] = ""
|
|
2060
|
-
if self.STATUS["detected_cart_type"] == "":
|
|
2061
|
-
self.STATUS["detected_cart_type"] = "WAITING_SAVE_WRITE"
|
|
2062
|
-
self.STATUS["detect_cartridge_args"] = { "dpath":path, "erase":erase }
|
|
2063
|
-
self.STATUS["can_skip_message"] = True
|
|
2064
|
-
self.DetectCartridge(checkSaveType=True)
|
|
2065
|
-
return
|
|
2066
|
-
cart_type = self.STATUS["detected_cart_type"]
|
|
2067
|
-
if "detected_cart_type" in self.STATUS: del(self.STATUS["detected_cart_type"])
|
|
2068
|
-
|
|
2069
|
-
if cart_type is False: # clicked Cancel button
|
|
2070
|
-
return
|
|
2071
|
-
elif cart_type is None or cart_type == 0:
|
|
2072
|
-
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "A compatible flash cartridge profile could not be auto-detected.", QtWidgets.QMessageBox.Ok)
|
|
2073
|
-
return
|
|
2074
|
-
self.cmbAGBCartridgeTypeResult.setCurrentIndex(cart_type)
|
|
2075
|
-
|
|
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
|
+
:
|
|
2076
2196
|
if "detected_cart_type" in self.STATUS: del(self.STATUS["detected_cart_type"])
|
|
2077
2197
|
|
|
2078
2198
|
if "dump_info" in self.CONN.INFO and "batteryless_sram" in self.CONN.INFO["dump_info"]:
|
|
@@ -2083,6 +2203,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2083
2203
|
if bl_args is False: return
|
|
2084
2204
|
|
|
2085
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)
|
|
2086
2207
|
args.update({"bl_save":True, "flash_offset":bl_args["bl_offset"], "flash_size":bl_args["bl_size"]})
|
|
2087
2208
|
if erase:
|
|
2088
2209
|
args["path"] = ""
|
|
@@ -2090,12 +2211,13 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2090
2211
|
self.STATUS["args"] = args
|
|
2091
2212
|
self.CONN.FlashROM(fncSetProgress=self.PROGRESS.SetProgress, args=args)
|
|
2092
2213
|
#self.CONN._FlashROM(args=args)
|
|
2214
|
+
|
|
2093
2215
|
else:
|
|
2094
|
-
#cart_type = self.cmbAGBCartridgeTypeResult.currentIndex()
|
|
2095
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 }
|
|
2096
2217
|
if buffer is not None:
|
|
2097
2218
|
args["buffer"] = buffer
|
|
2098
2219
|
args["path"] = None
|
|
2220
|
+
args["erase"] = False
|
|
2099
2221
|
self.STATUS["args"] = args
|
|
2100
2222
|
self.CONN.RestoreRAM(fncSetProgress=self.PROGRESS.SetProgress, args=args)
|
|
2101
2223
|
#args = { "mode":3, "path":path, "mbc":mbc, "save_type":save_type, "rtc":rtc, "rtc_advance":rtc_advance, "erase":erase, "verify_write":verify_write }
|
|
@@ -2118,11 +2240,18 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2118
2240
|
qt_app.processEvents()
|
|
2119
2241
|
|
|
2120
2242
|
def GetBLArgs(self, rom_size, detected=False):
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
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), "[]")
|
|
2124
2252
|
loc_index = None
|
|
2125
2253
|
len_index = None
|
|
2254
|
+
lay_index = None
|
|
2126
2255
|
|
|
2127
2256
|
try:
|
|
2128
2257
|
temp = json.loads(temp)
|
|
@@ -2139,15 +2268,41 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2139
2268
|
try:
|
|
2140
2269
|
loc_index = locs.index(detected["bl_offset"])
|
|
2141
2270
|
len_index = lens.index(detected["bl_size"])
|
|
2142
|
-
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."
|
|
2143
2272
|
except:
|
|
2144
2273
|
detected = False
|
|
2145
2274
|
if detected is False:
|
|
2146
|
-
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
|
|
2147
2302
|
|
|
2148
2303
|
try:
|
|
2149
2304
|
if loc_index is None:
|
|
2150
|
-
loc_index = locs.index(int(self.SETTINGS.value("BatterylessSramLastLocation{:s}".format(
|
|
2305
|
+
loc_index = locs.index(int(self.SETTINGS.value("BatterylessSramLastLocation{:s}".format(mode))))
|
|
2151
2306
|
except:
|
|
2152
2307
|
pass
|
|
2153
2308
|
|
|
@@ -2158,7 +2313,13 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2158
2313
|
if l + 0x40000 >= rom_size: break
|
|
2159
2314
|
loc_index += 1
|
|
2160
2315
|
if loc_index >= len(locs): loc_index = len(locs) - 1
|
|
2161
|
-
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
|
|
2162
2323
|
|
|
2163
2324
|
dlg_args = {
|
|
2164
2325
|
"title":"Batteryless SRAM Parameters",
|
|
@@ -2169,6 +2330,11 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2169
2330
|
[ "len", "cmb", "Size:", [ Util.formatFileSize(size=s, asInt=True) for s in lens ], len_index ],
|
|
2170
2331
|
]
|
|
2171
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
|
+
|
|
2172
2338
|
dlg = UserInputDialog(self, icon=self.windowIcon(), args=dlg_args)
|
|
2173
2339
|
if dlg.exec_() == 1:
|
|
2174
2340
|
result = dlg.GetResult()
|
|
@@ -2183,10 +2349,12 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2183
2349
|
else:
|
|
2184
2350
|
bl_args["bl_offset"] = locs[result["loc"].currentIndex()]
|
|
2185
2351
|
bl_args["bl_size"] = lens[result["len"].currentIndex()]
|
|
2352
|
+
if mode == "DMG":
|
|
2353
|
+
bl_args["bl_layout"] = result["layout"].currentIndex()
|
|
2186
2354
|
|
|
2187
2355
|
locs.append(bl_args["bl_offset"])
|
|
2188
|
-
self.SETTINGS.setValue("BatterylessSramLocations{:s}".format(
|
|
2189
|
-
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"]))
|
|
2190
2358
|
ret = bl_args
|
|
2191
2359
|
else:
|
|
2192
2360
|
ret = False
|
|
@@ -2433,7 +2601,9 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2433
2601
|
elif self.optAGB.isChecked() and (mode == "DMG" or mode == None):
|
|
2434
2602
|
self.CONN.SetMode("AGB")
|
|
2435
2603
|
except BrokenPipeError:
|
|
2436
|
-
msg = "Failed to turn on the cartridge power.\n\
|
|
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")
|
|
2437
2607
|
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), msg, QtWidgets.QMessageBox.Ok)
|
|
2438
2608
|
self.DisconnectDevice()
|
|
2439
2609
|
return False
|
|
@@ -2466,13 +2636,15 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2466
2636
|
try:
|
|
2467
2637
|
data = self.CONN.ReadInfo(setPinsAsInputs=True)
|
|
2468
2638
|
except SerialException:
|
|
2639
|
+
self.LimitBaudRateGBxCartRW()
|
|
2469
2640
|
self.DisconnectDevice()
|
|
2470
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)
|
|
2471
2642
|
return False
|
|
2472
2643
|
|
|
2473
2644
|
if data == False or len(data) == 0:
|
|
2645
|
+
self.LimitBaudRateGBxCartRW()
|
|
2474
2646
|
self.DisconnectDevice()
|
|
2475
|
-
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)
|
|
2476
2648
|
return False
|
|
2477
2649
|
|
|
2478
2650
|
if self.CONN.CheckROMStable() is False and resetStatus:
|
|
@@ -2572,10 +2744,6 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2572
2744
|
self.lblDMGHeaderBootlogoResult.setStyleSheet(self.lblDMGRomTitleResult.styleSheet())
|
|
2573
2745
|
self.lblDMGHeaderROMChecksumResult.setText("")
|
|
2574
2746
|
self.lblDMGHeaderROMChecksumResult.setStyleSheet(self.lblDMGRomTitleResult.styleSheet())
|
|
2575
|
-
# cart_types = self.CONN.GetSupportedCartridgesDMG()
|
|
2576
|
-
# for i in range(0, len(cart_types[0])):
|
|
2577
|
-
# if "command_set" in cart_types[1][i] and cart_types[1][i]["command_set"] == "BLAZE_XPLODER":
|
|
2578
|
-
# self.cmbDMGCartridgeTypeResult.setCurrentIndex(i)
|
|
2579
2747
|
elif data["mapper_raw"] == 0x205: # Datel
|
|
2580
2748
|
self.lblDMGHeaderRtcResult.setText("")
|
|
2581
2749
|
self.lblDMGHeaderBootlogoResult.setText("")
|
|
@@ -2594,7 +2762,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2594
2762
|
if "logo_sachen" in data:
|
|
2595
2763
|
data["logo_sachen"].putpalette([ 255, 255, 255, 128, 128, 128 ])
|
|
2596
2764
|
try:
|
|
2597
|
-
self.lblDMGHeaderBootlogoResult.setPixmap(
|
|
2765
|
+
self.lblDMGHeaderBootlogoResult.setPixmap(Util.bitmap2pixmap(data["logo_sachen"]))
|
|
2598
2766
|
except:
|
|
2599
2767
|
pass
|
|
2600
2768
|
else:
|
|
@@ -2606,7 +2774,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2606
2774
|
else:
|
|
2607
2775
|
data["logo"].putpalette([ 255, 255, 255, 251, 0, 24 ])
|
|
2608
2776
|
try:
|
|
2609
|
-
self.lblDMGHeaderBootlogoResult.setPixmap(
|
|
2777
|
+
self.lblDMGHeaderBootlogoResult.setPixmap(Util.bitmap2pixmap(data["logo"]))
|
|
2610
2778
|
except:
|
|
2611
2779
|
pass
|
|
2612
2780
|
|
|
@@ -2719,7 +2887,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2719
2887
|
else:
|
|
2720
2888
|
data["logo"].putpalette([ 255, 255, 255, 251, 0, 24 ])
|
|
2721
2889
|
try:
|
|
2722
|
-
self.lblAGBHeaderBootlogoResult.setPixmap(
|
|
2890
|
+
self.lblAGBHeaderBootlogoResult.setPixmap(Util.bitmap2pixmap(data["logo"]))
|
|
2723
2891
|
except:
|
|
2724
2892
|
pass
|
|
2725
2893
|
|
|
@@ -2743,6 +2911,22 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2743
2911
|
if data['game_title'][:11] == "YJencrypted" and resetStatus:
|
|
2744
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)
|
|
2745
2913
|
|
|
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
|
+
|
|
2746
2930
|
def DetectCartridge(self, checkSaveType=True):
|
|
2747
2931
|
if not self.CheckDeviceAlive(): return
|
|
2748
2932
|
if not self.CONN.CheckROMStable():
|
|
@@ -2775,11 +2959,12 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2775
2959
|
limitVoltage = str(self.SETTINGS.value("AutoDetectLimitVoltage", default="disabled")).lower() == "enabled"
|
|
2776
2960
|
if ret is False:
|
|
2777
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()
|
|
2778
2963
|
self.DisconnectDevice()
|
|
2779
2964
|
cart_type = None
|
|
2780
2965
|
else:
|
|
2781
2966
|
(header, save_size, save_type, save_chip, sram_unstable, cart_types, cart_type_id, cfi_s, _, flash_id, detected_size) = ret
|
|
2782
|
-
|
|
2967
|
+
|
|
2783
2968
|
# Save Type
|
|
2784
2969
|
if not self.STATUS["can_skip_message"]:
|
|
2785
2970
|
try:
|
|
@@ -2805,6 +2990,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2805
2990
|
except Exception as e:
|
|
2806
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)
|
|
2807
2992
|
msgbox.exec()
|
|
2993
|
+
self.LimitBaudRateGBxCartRW()
|
|
2808
2994
|
return
|
|
2809
2995
|
|
|
2810
2996
|
try:
|
|
@@ -2837,7 +3023,10 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2837
3023
|
temp = ""
|
|
2838
3024
|
if not self.STATUS["can_skip_message"] and save_type is not False and save_type is not None:
|
|
2839
3025
|
if save_chip is not None:
|
|
2840
|
-
|
|
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)
|
|
2841
3030
|
else:
|
|
2842
3031
|
if self.CONN.GetMode() == "DMG":
|
|
2843
3032
|
try:
|
|
@@ -2933,10 +3122,11 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2933
3122
|
else:
|
|
2934
3123
|
msg_flash_id_s_limit = ""
|
|
2935
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:
|
|
2936
3126
|
if cfi_s != "":
|
|
2937
3127
|
msg_cfi_s = "<br><b>Common Flash Interface Data:</b><br>{:s}<br><br>".format(cfi_s.replace("\n", "<br>"))
|
|
2938
3128
|
else:
|
|
2939
|
-
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>"
|
|
2940
3130
|
|
|
2941
3131
|
if msg_cart_type_s_detail == "": msg_cart_type_s_detail = msg_cart_type_s
|
|
2942
3132
|
self.SetProgressBars(min=0, max=100, value=100)
|
|
@@ -2986,7 +3176,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2986
3176
|
if not dontShowAgain or not self.STATUS["can_skip_message"]:
|
|
2987
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)
|
|
2988
3178
|
temp = temp[:-4]
|
|
2989
|
-
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)
|
|
2990
3180
|
msgbox.setTextFormat(QtCore.Qt.RichText)
|
|
2991
3181
|
button_ok = msgbox.addButton("&OK", QtWidgets.QMessageBox.ActionRole)
|
|
2992
3182
|
button_details = msgbox.addButton("&Details", QtWidgets.QMessageBox.ActionRole)
|
|
@@ -3022,7 +3212,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
3022
3212
|
return
|
|
3023
3213
|
|
|
3024
3214
|
if not found_supported or show_details is True:
|
|
3025
|
-
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()))
|
|
3026
3216
|
button_ok = msgbox.addButton("&OK", QtWidgets.QMessageBox.ActionRole)
|
|
3027
3217
|
msgbox.setDefaultButton(button_ok)
|
|
3028
3218
|
msgbox.setEscapeButton(button_ok)
|
|
@@ -3091,7 +3281,11 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
3091
3281
|
else:
|
|
3092
3282
|
self.FlashROM()
|
|
3093
3283
|
elif waiting == "WAITING_SAVE_READ":
|
|
3094
|
-
self.
|
|
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()
|
|
3095
3289
|
elif waiting == "WAITING_SAVE_WRITE":
|
|
3096
3290
|
if "detect_cartridge_args" in self.STATUS:
|
|
3097
3291
|
self.WriteRAM(dpath=self.STATUS["detect_cartridge_args"]["dpath"], erase=self.STATUS["detect_cartridge_args"]["erase"], skip_warning=True)
|
|
@@ -3142,6 +3336,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
3142
3336
|
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=str(args["error"]), standardButtons=QtWidgets.QMessageBox.Ok)
|
|
3143
3337
|
if not '\n' in str(args["error"]): msgbox.setTextFormat(QtCore.Qt.RichText)
|
|
3144
3338
|
msgbox.exec()
|
|
3339
|
+
self.LimitBaudRateGBxCartRW()
|
|
3145
3340
|
return
|
|
3146
3341
|
|
|
3147
3342
|
self.grpDMGCartridgeInfo.setEnabled(False)
|
|
@@ -3250,16 +3445,20 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
3250
3445
|
|
|
3251
3446
|
if "info_type" in args.keys() and "info_msg" in args.keys():
|
|
3252
3447
|
if args["info_type"] == "msgbox_critical":
|
|
3253
|
-
Util.dprint("Displaying Message Box:\n----\n{:s} {:s}\n----\n{:s}\n----".format(APPNAME, VERSION, args["info_msg"]))
|
|
3254
|
-
self.WriteDebugLog()
|
|
3255
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"]))
|
|
3256
3450
|
if not '\n' in args["info_msg"]: msgbox.setTextFormat(QtCore.Qt.RichText)
|
|
3257
|
-
|
|
3258
|
-
|
|
3451
|
+
self.MSGBOX_QUEUE.put(msgbox)
|
|
3452
|
+
self.WriteDebugLog()
|
|
3453
|
+
if "fatal" in args:
|
|
3454
|
+
self.LimitBaudRateGBxCartRW()
|
|
3455
|
+
self.DisconnectDevice()
|
|
3259
3456
|
elif args["info_type"] == "msgbox_information":
|
|
3260
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"]))
|
|
3261
3459
|
if not '\n' in args["info_msg"]: msgbox.setTextFormat(QtCore.Qt.RichText)
|
|
3262
|
-
msgbox.exec()
|
|
3460
|
+
#msgbox.exec()
|
|
3461
|
+
self.MSGBOX_QUEUE.put(msgbox)
|
|
3263
3462
|
elif args["info_type"] == "label":
|
|
3264
3463
|
self.lblStatus4a.setText(args["info_msg"])
|
|
3265
3464
|
|
|
@@ -3353,9 +3552,12 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
3353
3552
|
if self.CONN.GetMode() == "DMG":
|
|
3354
3553
|
header = self.CONN.ReadInfo(setPinsAsInputs=True)
|
|
3355
3554
|
if header["mapper_raw"] == 252: # GBD
|
|
3356
|
-
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()
|
|
3357
3558
|
self.CONN.BackupRAM(fncSetProgress=False, args=args)
|
|
3358
3559
|
data = self.CONN.INFO["data"]
|
|
3560
|
+
self.lblStatus4a.setText("Ready.")
|
|
3359
3561
|
|
|
3360
3562
|
self.CAMWIN = None
|
|
3361
3563
|
self.CAMWIN = PocketCameraWindow(self, icon=self.windowIcon(), file=data, config_path=Util.CONFIG_PATH, app_path=Util.APP_PATH)
|
|
@@ -3416,6 +3618,11 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
3416
3618
|
|
|
3417
3619
|
def closeEvent(self, event):
|
|
3418
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()
|
|
3419
3626
|
event.accept()
|
|
3420
3627
|
|
|
3421
3628
|
def run(self):
|