FlashGBX 3.36__py3-none-any.whl → 4.0__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 +14 -7
- FlashGBX/FlashGBX_CLI.py +208 -28
- FlashGBX/FlashGBX_GUI.py +644 -209
- FlashGBX/Flashcart.py +195 -84
- FlashGBX/GBMemory.py +4 -5
- FlashGBX/LK_Device.py +4526 -0
- FlashGBX/Mapper.py +534 -356
- FlashGBX/RomFileAGB.py +92 -2
- FlashGBX/RomFileDMG.py +1 -1
- FlashGBX/UserInputDialog.py +20 -0
- FlashGBX/Util.py +116 -71
- FlashGBX/fw_GBFlash.py +426 -0
- FlashGBX/fw_GBxCartRW_v1_3.py +1 -1
- FlashGBX/fw_JoeyJr.py +472 -0
- FlashGBX/hw_GBFlash.py +244 -0
- FlashGBX/hw_GBxCartRW.py +200 -3715
- FlashGBX/hw_JoeyJr.py +309 -0
- FlashGBX/res/Third Party Notices.md +342 -0
- FlashGBX/res/config.zip +0 -0
- FlashGBX/res/fw_GBFlash.zip +0 -0
- FlashGBX/res/fw_GBxCart_RW_v1_3.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-3.36.dist-info → FlashGBX-4.0.dist-info}/METADATA +35 -14
- FlashGBX-4.0.dist-info/RECORD +43 -0
- {FlashGBX-3.36.dist-info → FlashGBX-4.0.dist-info}/WHEEL +1 -1
- FlashGBX/hw_GBxCartRW_ofw.py +0 -2599
- FlashGBX-3.36.dist-info/RECORD +0 -36
- {FlashGBX-3.36.dist-info → FlashGBX-4.0.dist-info}/LICENSE +0 -0
- {FlashGBX-3.36.dist-info → FlashGBX-4.0.dist-info}/entry_points.txt +0 -0
- {FlashGBX-3.36.dist-info → FlashGBX-4.0.dist-info}/top_level.txt +0 -0
FlashGBX/FlashGBX_GUI.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
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
|
|
5
|
+
import sys, os, time, datetime, json, platform, subprocess, requests, webbrowser, pkg_resources, threading, calendar
|
|
6
6
|
from .pyside import QtCore, QtWidgets, QtGui, QApplication
|
|
7
7
|
from PIL.ImageQt import ImageQt
|
|
8
8
|
from serial import SerialException
|
|
@@ -12,8 +12,8 @@ from .PocketCameraWindow import PocketCameraWindow
|
|
|
12
12
|
from .UserInputDialog import UserInputDialog
|
|
13
13
|
from .Util import APPNAME, VERSION, VERSION_PEP440
|
|
14
14
|
from . import Util
|
|
15
|
-
from . import hw_GBxCartRW,
|
|
16
|
-
hw_devices = [hw_GBxCartRW,
|
|
15
|
+
from . import hw_GBxCartRW, hw_GBFlash, hw_JoeyJr
|
|
16
|
+
hw_devices = [hw_GBxCartRW, hw_GBFlash, hw_JoeyJr]
|
|
17
17
|
|
|
18
18
|
class FlashGBX_GUI(QtWidgets.QWidget):
|
|
19
19
|
CONN = None
|
|
@@ -35,7 +35,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
35
35
|
Util.APP_PATH = args['app_path']
|
|
36
36
|
self.SETTINGS = Util.IniSettings(path=args["config_path"] + "/settings.ini")
|
|
37
37
|
self.FLASHCARTS = args["flashcarts"]
|
|
38
|
-
self.PROGRESS = Util.Progress(self.UpdateProgress)
|
|
38
|
+
self.PROGRESS = Util.Progress(self.UpdateProgress, self.WaitProgress)
|
|
39
39
|
|
|
40
40
|
self.setStyleSheet("QMessageBox { messagebox-text-interaction-flags: 5; }")
|
|
41
41
|
self.setWindowIcon(QtGui.QIcon(Util.APP_PATH + "/res/icon.ico"))
|
|
@@ -58,7 +58,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
58
58
|
self.layout_left.addWidget(self.grpAGBCartridgeInfo)
|
|
59
59
|
|
|
60
60
|
# Actions
|
|
61
|
-
self.grpActions = QtWidgets.QGroupBox("
|
|
61
|
+
self.grpActions = QtWidgets.QGroupBox("Functions")
|
|
62
62
|
self.grpActionsLayout = QtWidgets.QVBoxLayout()
|
|
63
63
|
self.grpActionsLayout.setContentsMargins(-1, 3, -1, -1)
|
|
64
64
|
|
|
@@ -174,43 +174,61 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
174
174
|
# List devices
|
|
175
175
|
self.layout_devices = QtWidgets.QHBoxLayout()
|
|
176
176
|
self.lblDevice = QtWidgets.QLabel()
|
|
177
|
-
self.lblDevice.mousePressEvent = self.WriteDebugLog
|
|
177
|
+
self.lblDevice.mousePressEvent = lambda event: [ self.WriteDebugLog(event, open_log=True) ]
|
|
178
|
+
self.lblDevice.setToolTip("Click here to generate a log file for debugging")
|
|
179
|
+
self.lblDevice.setCursor(QtCore.Qt.PointingHandCursor)
|
|
178
180
|
self.cmbDevice = QtWidgets.QComboBox()
|
|
179
181
|
self.cmbDevice.setStyleSheet("QComboBox { border: 0; margin: 0; padding: 0; max-width: 0px; }")
|
|
180
182
|
self.layout_devices.addWidget(self.lblDevice)
|
|
181
183
|
self.layout_devices.addWidget(self.cmbDevice)
|
|
182
184
|
self.layout_devices.addStretch()
|
|
183
185
|
|
|
184
|
-
btnText = "Too&ls"
|
|
185
|
-
self.btnTools = QtWidgets.QPushButton(btnText)
|
|
186
|
-
btnWidth = self.btnTools.fontMetrics().boundingRect(btnText).width() + 24
|
|
187
|
-
if platform.system() == "Darwin": btnWidth += 12
|
|
188
|
-
self.btnTools.setMaximumWidth(btnWidth)
|
|
189
|
-
self.mnuTools = QtWidgets.QMenu()
|
|
186
|
+
#btnText = "Too&ls"
|
|
187
|
+
#self.btnTools = QtWidgets.QPushButton(btnText)
|
|
188
|
+
#btnWidth = self.btnTools.fontMetrics().boundingRect(btnText).width() + 24
|
|
189
|
+
#if platform.system() == "Darwin": btnWidth += 12
|
|
190
|
+
#self.btnTools.setMaximumWidth(btnWidth)
|
|
191
|
+
self.mnuTools = QtWidgets.QMenu("&Tools")
|
|
190
192
|
self.mnuTools.addAction("Game Boy &Camera Album Viewer", self.ShowPocketCameraWindow)
|
|
191
193
|
self.mnuTools.addSeparator()
|
|
192
194
|
self.mnuTools.addAction("Firmware &Updater", self.ShowFirmwareUpdateWindow)
|
|
193
|
-
self.btnTools.setMenu(self.mnuTools)
|
|
194
|
-
|
|
195
|
-
btnText = "C&onfig"
|
|
196
|
-
self.btnConfig = QtWidgets.QPushButton(btnText)
|
|
197
|
-
btnWidth = self.btnConfig.fontMetrics().boundingRect(btnText).width() + 24
|
|
198
|
-
if platform.system() == "Darwin": btnWidth += 12
|
|
199
|
-
self.btnConfig.setMaximumWidth(btnWidth)
|
|
200
|
-
|
|
201
|
-
self.mnuConfig = QtWidgets.QMenu()
|
|
195
|
+
#self.btnTools.setMenu(self.mnuTools)
|
|
196
|
+
|
|
197
|
+
#btnText = "C&onfig"
|
|
198
|
+
#self.btnConfig = QtWidgets.QPushButton(btnText)
|
|
199
|
+
#btnWidth = self.btnConfig.fontMetrics().boundingRect(btnText).width() + 24
|
|
200
|
+
#if platform.system() == "Darwin": btnWidth += 12
|
|
201
|
+
#self.btnConfig.setMaximumWidth(btnWidth)
|
|
202
|
+
self.mnuConfig = QtWidgets.QMenu("&Settings")
|
|
202
203
|
self.mnuConfig.addAction("Check for &updates on application startup", lambda: [ self.EnableUpdateCheck() ])
|
|
203
204
|
self.mnuConfig.addAction("&Append date && time to filename of save data backups", lambda: self.SETTINGS.setValue("SaveFileNameAddDateTime", str(self.mnuConfig.actions()[1].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")))
|
|
204
205
|
self.mnuConfig.addAction("Prefer full &chip erase", lambda: self.SETTINGS.setValue("PreferChipErase", str(self.mnuConfig.actions()[2].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")))
|
|
205
206
|
self.mnuConfig.addAction("&Verify transferred data", lambda: self.SETTINGS.setValue("VerifyData", str(self.mnuConfig.actions()[3].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")))
|
|
206
|
-
self.mnuConfig.addAction("&Limit voltage
|
|
207
|
-
self.mnuConfig.addAction("Limit &baud rate to 1Mbps
|
|
207
|
+
self.mnuConfig.addAction("&Limit voltage when analyzing Game Boy carts", lambda: self.SETTINGS.setValue("AutoDetectLimitVoltage", str(self.mnuConfig.actions()[4].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")))
|
|
208
|
+
self.mnuConfig.addAction("Limit &baud rate to 1Mbps", lambda: [ self.SETTINGS.setValue("LimitBaudRate", str(self.mnuConfig.actions()[5].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")), self.SetLimitBaudRate() ])
|
|
208
209
|
self.mnuConfig.addAction("Always &generate ROM dump reports", lambda: self.SETTINGS.setValue("GenerateDumpReports", str(self.mnuConfig.actions()[6].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")))
|
|
209
210
|
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")))
|
|
211
|
+
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() ])
|
|
212
|
+
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")))
|
|
210
213
|
self.mnuConfig.addSeparator()
|
|
211
|
-
self.
|
|
214
|
+
self.mnuConfigReadModeAGB = QtWidgets.QMenu("&Read Method (Game Boy Advance)")
|
|
215
|
+
self.mnuConfigReadModeAGB.addAction("S&tream", lambda: [ self.SETTINGS.setValue("AGBReadMethod", str(self.mnuConfigReadModeAGB.actions()[1].isChecked()).lower().replace("true", "2")), self.SetAGBReadMethod() ])
|
|
216
|
+
self.mnuConfigReadModeAGB.addAction("&Single", lambda: [ self.SETTINGS.setValue("AGBReadMethod", str(self.mnuConfigReadModeAGB.actions()[0].isChecked()).lower().replace("true", "0")), self.SetAGBReadMethod() ])
|
|
217
|
+
self.mnuConfigReadModeAGB.actions()[0].setCheckable(True)
|
|
218
|
+
self.mnuConfigReadModeAGB.actions()[1].setCheckable(True)
|
|
219
|
+
self.mnuConfigReadModeAGB.actions()[0].setChecked(self.SETTINGS.value("AGBReadMethod", default="2") == "2")
|
|
220
|
+
self.mnuConfigReadModeAGB.actions()[1].setChecked(self.SETTINGS.value("AGBReadMethod", default="2") == "0")
|
|
221
|
+
self.mnuConfigReadModeDMG = QtWidgets.QMenu("&Read Method (Game Boy)")
|
|
222
|
+
self.mnuConfigReadModeDMG.addAction("&Normal", lambda: [ self.SETTINGS.setValue("DMGReadMethod", str(self.mnuConfigReadModeAGB.actions()[1].isChecked()).lower().replace("true", "1")), self.SetDMGReadMethod() ])
|
|
223
|
+
self.mnuConfigReadModeDMG.addAction("&Delayed", lambda: [ self.SETTINGS.setValue("DMGReadMethod", str(self.mnuConfigReadModeAGB.actions()[0].isChecked()).lower().replace("true", "2")), self.SetDMGReadMethod() ])
|
|
224
|
+
self.mnuConfigReadModeDMG.actions()[0].setCheckable(True)
|
|
225
|
+
self.mnuConfigReadModeDMG.actions()[1].setCheckable(True)
|
|
226
|
+
self.mnuConfigReadModeDMG.actions()[0].setChecked(self.SETTINGS.value("DMGReadMethod", default="1") == "1")
|
|
227
|
+
self.mnuConfigReadModeDMG.actions()[1].setChecked(self.SETTINGS.value("DMGReadMethod", default="1") == "2")
|
|
228
|
+
self.mnuConfig.addMenu(self.mnuConfigReadModeDMG)
|
|
229
|
+
self.mnuConfig.addMenu(self.mnuConfigReadModeAGB)
|
|
212
230
|
self.mnuConfig.addSeparator()
|
|
213
|
-
self.mnuConfig.addAction("
|
|
231
|
+
self.mnuConfig.addAction("Re-&enable suppressed messages", self.ReEnableMessages)
|
|
214
232
|
self.mnuConfig.actions()[0].setCheckable(True)
|
|
215
233
|
self.mnuConfig.actions()[1].setCheckable(True)
|
|
216
234
|
self.mnuConfig.actions()[2].setCheckable(True)
|
|
@@ -219,6 +237,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
219
237
|
self.mnuConfig.actions()[5].setCheckable(True)
|
|
220
238
|
self.mnuConfig.actions()[6].setCheckable(True)
|
|
221
239
|
self.mnuConfig.actions()[7].setCheckable(True)
|
|
240
|
+
self.mnuConfig.actions()[8].setCheckable(True)
|
|
241
|
+
self.mnuConfig.actions()[9].setCheckable(True)
|
|
222
242
|
self.mnuConfig.actions()[0].setChecked(self.SETTINGS.value("UpdateCheck") == "enabled")
|
|
223
243
|
self.mnuConfig.actions()[1].setChecked(self.SETTINGS.value("SaveFileNameAddDateTime", default="disabled") == "enabled")
|
|
224
244
|
self.mnuConfig.actions()[2].setChecked(self.SETTINGS.value("PreferChipErase", default="disabled") == "enabled")
|
|
@@ -227,15 +247,37 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
227
247
|
self.mnuConfig.actions()[5].setChecked(self.SETTINGS.value("LimitBaudRate", default="disabled") == "enabled")
|
|
228
248
|
self.mnuConfig.actions()[6].setChecked(self.SETTINGS.value("GenerateDumpReports", default="disabled") == "enabled")
|
|
229
249
|
self.mnuConfig.actions()[7].setChecked(self.SETTINGS.value("UseNoIntroFilenames", default="enabled") == "enabled")
|
|
230
|
-
|
|
231
|
-
self.
|
|
232
|
-
|
|
250
|
+
self.mnuConfig.actions()[8].setChecked(self.SETTINGS.value("AutoPowerOff", default="350") != "0")
|
|
251
|
+
self.mnuConfig.actions()[9].setChecked(self.SETTINGS.value("CompareSectors", default="enabled") == "enabled")
|
|
252
|
+
#self.btnConfig.setMenu(self.mnuConfig)
|
|
253
|
+
|
|
254
|
+
self.mnuThirdParty = QtWidgets.QMenu("Third Party &Notices")
|
|
255
|
+
self.mnuThirdParty.addAction("About &Qt", lambda: [ QtWidgets.QMessageBox.aboutQt(None) ])
|
|
256
|
+
self.mnuThirdParty.addAction("Licenses", lambda: [ self.OpenPath(Util.APP_PATH + "/res/Third Party Notices.md") ])
|
|
257
|
+
|
|
258
|
+
btnText = "&Options"
|
|
259
|
+
self.btnMainMenu = QtWidgets.QPushButton(btnText)
|
|
260
|
+
btnWidth = self.btnMainMenu.fontMetrics().boundingRect(btnText).width() + 24
|
|
261
|
+
if platform.system() == "Darwin": btnWidth += 12
|
|
262
|
+
self.btnMainMenu.setMaximumWidth(btnWidth)
|
|
263
|
+
self.mnuMainMenu = QtWidgets.QMenu()
|
|
264
|
+
self.mnuMainMenu.addMenu(self.mnuConfig)
|
|
265
|
+
self.mnuMainMenu.addMenu(self.mnuTools)
|
|
266
|
+
self.mnuMainMenu.addSeparator()
|
|
267
|
+
self.mnuMainMenu.addSeparator()
|
|
268
|
+
self.mnuMainMenu.addAction("Open &config folder", self.OpenPath)
|
|
269
|
+
self.mnuMainMenu.addSeparator()
|
|
270
|
+
self.mnuMainMenu.addMenu(self.mnuThirdParty)
|
|
271
|
+
self.mnuMainMenu.addAction("About &FlashGBX", self.AboutFlashGBX)
|
|
272
|
+
self.btnMainMenu.setMenu(self.mnuMainMenu)
|
|
273
|
+
|
|
233
274
|
self.btnConnect = QtWidgets.QPushButton("&Connect")
|
|
234
275
|
self.connect(self.btnConnect, QtCore.SIGNAL("clicked()"), self.ConnectDevice)
|
|
235
|
-
self.layout_devices.addWidget(self.
|
|
236
|
-
self.layout_devices.addWidget(self.
|
|
276
|
+
self.layout_devices.addWidget(self.btnMainMenu)
|
|
277
|
+
#self.layout_devices.addWidget(self.btnTools)
|
|
278
|
+
#self.layout_devices.addWidget(self.btnConfig)
|
|
237
279
|
self.layout_devices.addWidget(self.btnConnect)
|
|
238
|
-
|
|
280
|
+
|
|
239
281
|
self.layout.addLayout(self.layout_devices, 1, 0, 1, 0)
|
|
240
282
|
|
|
241
283
|
# Disable widgets
|
|
@@ -269,12 +311,12 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
269
311
|
elif config_ret[i][0] == 3:
|
|
270
312
|
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), config_ret[i][1], QtWidgets.QMessageBox.Ok)
|
|
271
313
|
|
|
272
|
-
QtCore.QTimer.singleShot(1, lambda: [ self.UpdateCheck(), self.FindDevices(port=args["argparsed"].device_port) ])
|
|
314
|
+
QtCore.QTimer.singleShot(1, lambda: [ self.UpdateCheck(), self.FindDevices(port=args["argparsed"].device_port, firstRun=True) ])
|
|
273
315
|
|
|
274
316
|
|
|
275
317
|
def GuiCreateGroupBoxDMGCartInfo(self):
|
|
276
318
|
self.grpDMGCartridgeInfo = QtWidgets.QGroupBox("Game Boy Cartridge Information")
|
|
277
|
-
self.grpDMGCartridgeInfo.setMinimumWidth(
|
|
319
|
+
self.grpDMGCartridgeInfo.setMinimumWidth(400)
|
|
278
320
|
group_layout = QtWidgets.QVBoxLayout()
|
|
279
321
|
group_layout.setContentsMargins(-1, 5, -1, -1)
|
|
280
322
|
|
|
@@ -284,6 +326,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
284
326
|
rowDMGGameName.addWidget(self.lblDMGGameName)
|
|
285
327
|
self.lblDMGGameNameResult = QtWidgets.QLabel("")
|
|
286
328
|
rowDMGGameName.addWidget(self.lblDMGGameNameResult)
|
|
329
|
+
rowDMGGameName.setStretch(0, 9)
|
|
330
|
+
rowDMGGameName.setStretch(1, 11)
|
|
287
331
|
group_layout.addLayout(rowDMGGameName)
|
|
288
332
|
|
|
289
333
|
rowDMGRomTitle = QtWidgets.QHBoxLayout()
|
|
@@ -292,6 +336,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
292
336
|
rowDMGRomTitle.addWidget(self.lblDMGRomTitle)
|
|
293
337
|
self.lblDMGRomTitleResult = QtWidgets.QLabel("")
|
|
294
338
|
rowDMGRomTitle.addWidget(self.lblDMGRomTitleResult)
|
|
339
|
+
rowDMGRomTitle.setStretch(0, 9)
|
|
340
|
+
rowDMGRomTitle.setStretch(1, 11)
|
|
295
341
|
group_layout.addLayout(rowDMGRomTitle)
|
|
296
342
|
|
|
297
343
|
rowDMGGameCodeRevision = QtWidgets.QHBoxLayout()
|
|
@@ -300,6 +346,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
300
346
|
rowDMGGameCodeRevision.addWidget(self.lblDMGGameCodeRevision)
|
|
301
347
|
self.lblDMGGameCodeRevisionResult = QtWidgets.QLabel("")
|
|
302
348
|
rowDMGGameCodeRevision.addWidget(self.lblDMGGameCodeRevisionResult)
|
|
349
|
+
rowDMGGameCodeRevision.setStretch(0, 9)
|
|
350
|
+
rowDMGGameCodeRevision.setStretch(1, 11)
|
|
303
351
|
group_layout.addLayout(rowDMGGameCodeRevision)
|
|
304
352
|
|
|
305
353
|
rowDMGHeaderRtc = QtWidgets.QHBoxLayout()
|
|
@@ -307,9 +355,16 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
307
355
|
lblDMGHeaderRtc.setContentsMargins(0, 1, 0, 1)
|
|
308
356
|
rowDMGHeaderRtc.addWidget(lblDMGHeaderRtc)
|
|
309
357
|
self.lblDMGHeaderRtcResult = QtWidgets.QLabel("")
|
|
310
|
-
self.lblDMGHeaderRtcResult.setCursor(QtGui.QCursor(QtCore.Qt.WhatsThisCursor))
|
|
311
|
-
self.lblDMGHeaderRtcResult.setToolTip("This shows the internal register values; in-game clock may use an offset")
|
|
358
|
+
#self.lblDMGHeaderRtcResult.setCursor(QtGui.QCursor(QtCore.Qt.WhatsThisCursor))
|
|
359
|
+
#self.lblDMGHeaderRtcResult.setToolTip("This shows the internal register values; in-game clock may use an offset")
|
|
360
|
+
#self.lblDMGHeaderRtcResult.setStyleSheet("QLabel {{ color: {:s}; text-decoration: underline; cursor: hand; }}".format(QApplication.palette().color(QtGui.QPalette.Link).name()))
|
|
361
|
+
#self.lblDMGHeaderRtcResult.setCursor(QtCore.Qt.PointingHandCursor)
|
|
362
|
+
#self.connect(self.lblDMGHeaderRtcResult, QtCore.SIGNAL("clicked()"), self.EditRTC)
|
|
363
|
+
#self.lblDMGHeaderRtcResult.clicked.connect(self.EditRTC)
|
|
364
|
+
self.lblDMGHeaderRtcResult.mousePressEvent = lambda event: [ self.EditRTC(event) ]
|
|
312
365
|
rowDMGHeaderRtc.addWidget(self.lblDMGHeaderRtcResult)
|
|
366
|
+
rowDMGHeaderRtc.setStretch(0, 9)
|
|
367
|
+
rowDMGHeaderRtc.setStretch(1, 11)
|
|
313
368
|
group_layout.addLayout(rowDMGHeaderRtc)
|
|
314
369
|
|
|
315
370
|
rowDMGHeaderBootlogo = QtWidgets.QHBoxLayout()
|
|
@@ -318,6 +373,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
318
373
|
rowDMGHeaderBootlogo.addWidget(lblDMGHeaderBootlogo)
|
|
319
374
|
self.lblDMGHeaderBootlogoResult = QtWidgets.QLabel("")
|
|
320
375
|
rowDMGHeaderBootlogo.addWidget(self.lblDMGHeaderBootlogoResult)
|
|
376
|
+
rowDMGHeaderBootlogo.setStretch(0, 9)
|
|
377
|
+
rowDMGHeaderBootlogo.setStretch(1, 11)
|
|
321
378
|
group_layout.addLayout(rowDMGHeaderBootlogo)
|
|
322
379
|
|
|
323
380
|
rowDMGHeaderROMChecksum = QtWidgets.QHBoxLayout()
|
|
@@ -326,6 +383,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
326
383
|
rowDMGHeaderROMChecksum.addWidget(lblDMGHeaderROMChecksum)
|
|
327
384
|
self.lblDMGHeaderROMChecksumResult = QtWidgets.QLabel("")
|
|
328
385
|
rowDMGHeaderROMChecksum.addWidget(self.lblDMGHeaderROMChecksumResult)
|
|
386
|
+
rowDMGHeaderROMChecksum.setStretch(0, 9)
|
|
387
|
+
rowDMGHeaderROMChecksum.setStretch(1, 11)
|
|
329
388
|
group_layout.addLayout(rowDMGHeaderROMChecksum)
|
|
330
389
|
|
|
331
390
|
rowDMGHeaderROMSize = QtWidgets.QHBoxLayout()
|
|
@@ -335,6 +394,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
335
394
|
self.cmbDMGHeaderROMSizeResult.setStyleSheet("combobox-popup: 0;")
|
|
336
395
|
self.cmbDMGHeaderROMSizeResult.view().setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
|
|
337
396
|
rowDMGHeaderROMSize.addWidget(self.cmbDMGHeaderROMSizeResult)
|
|
397
|
+
rowDMGHeaderROMSize.setStretch(0, 9)
|
|
398
|
+
rowDMGHeaderROMSize.setStretch(1, 11)
|
|
338
399
|
group_layout.addLayout(rowDMGHeaderROMSize)
|
|
339
400
|
|
|
340
401
|
rowDMGHeaderSaveType = QtWidgets.QHBoxLayout()
|
|
@@ -344,6 +405,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
344
405
|
self.cmbDMGHeaderSaveTypeResult.setStyleSheet("combobox-popup: 0;")
|
|
345
406
|
self.cmbDMGHeaderSaveTypeResult.view().setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
|
|
346
407
|
rowDMGHeaderSaveType.addWidget(self.cmbDMGHeaderSaveTypeResult)
|
|
408
|
+
rowDMGHeaderSaveType.setStretch(0, 9)
|
|
409
|
+
rowDMGHeaderSaveType.setStretch(1, 11)
|
|
347
410
|
group_layout.addLayout(rowDMGHeaderSaveType)
|
|
348
411
|
|
|
349
412
|
rowDMGHeaderMapper = QtWidgets.QHBoxLayout()
|
|
@@ -353,10 +416,12 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
353
416
|
self.cmbDMGHeaderMapperResult.setStyleSheet("combobox-popup: 0;")
|
|
354
417
|
self.cmbDMGHeaderMapperResult.view().setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
|
|
355
418
|
rowDMGHeaderMapper.addWidget(self.cmbDMGHeaderMapperResult)
|
|
419
|
+
rowDMGHeaderMapper.setStretch(0, 9)
|
|
420
|
+
rowDMGHeaderMapper.setStretch(1, 11)
|
|
356
421
|
group_layout.addLayout(rowDMGHeaderMapper)
|
|
357
422
|
|
|
358
423
|
rowDMGCartridgeType = QtWidgets.QHBoxLayout()
|
|
359
|
-
lblDMGCartridgeType = QtWidgets.QLabel("
|
|
424
|
+
lblDMGCartridgeType = QtWidgets.QLabel("Profile:")
|
|
360
425
|
rowDMGCartridgeType.addWidget(lblDMGCartridgeType)
|
|
361
426
|
self.cmbDMGCartridgeTypeResult = QtWidgets.QComboBox()
|
|
362
427
|
self.cmbDMGCartridgeTypeResult.setStyleSheet("max-width: 260px;")
|
|
@@ -371,7 +436,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
371
436
|
|
|
372
437
|
def GuiCreateGroupBoxAGBCartInfo(self):
|
|
373
438
|
self.grpAGBCartridgeInfo = QtWidgets.QGroupBox("Game Boy Advance Cartridge Information")
|
|
374
|
-
self.grpAGBCartridgeInfo.setMinimumWidth(
|
|
439
|
+
self.grpAGBCartridgeInfo.setMinimumWidth(400)
|
|
375
440
|
group_layout = QtWidgets.QVBoxLayout()
|
|
376
441
|
group_layout.setContentsMargins(-1, 5, -1, -1)
|
|
377
442
|
|
|
@@ -381,6 +446,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
381
446
|
rowAGBGameName.addWidget(lblAGBGameName)
|
|
382
447
|
self.lblAGBGameNameResult = QtWidgets.QLabel("")
|
|
383
448
|
rowAGBGameName.addWidget(self.lblAGBGameNameResult)
|
|
449
|
+
rowAGBGameName.setStretch(0, 9)
|
|
450
|
+
rowAGBGameName.setStretch(1, 11)
|
|
384
451
|
group_layout.addLayout(rowAGBGameName)
|
|
385
452
|
|
|
386
453
|
rowAGBRomTitle = QtWidgets.QHBoxLayout()
|
|
@@ -389,6 +456,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
389
456
|
rowAGBRomTitle.addWidget(lblAGBRomTitle)
|
|
390
457
|
self.lblAGBRomTitleResult = QtWidgets.QLabel("")
|
|
391
458
|
rowAGBRomTitle.addWidget(self.lblAGBRomTitleResult)
|
|
459
|
+
rowAGBRomTitle.setStretch(0, 9)
|
|
460
|
+
rowAGBRomTitle.setStretch(1, 11)
|
|
392
461
|
group_layout.addLayout(rowAGBRomTitle)
|
|
393
462
|
|
|
394
463
|
rowAGBHeaderGameCodeRevision = QtWidgets.QHBoxLayout()
|
|
@@ -397,6 +466,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
397
466
|
rowAGBHeaderGameCodeRevision.addWidget(lblAGBHeaderGameCodeRevision)
|
|
398
467
|
self.lblAGBHeaderGameCodeRevisionResult = QtWidgets.QLabel("")
|
|
399
468
|
rowAGBHeaderGameCodeRevision.addWidget(self.lblAGBHeaderGameCodeRevisionResult)
|
|
469
|
+
rowAGBHeaderGameCodeRevision.setStretch(0, 9)
|
|
470
|
+
rowAGBHeaderGameCodeRevision.setStretch(1, 11)
|
|
400
471
|
group_layout.addLayout(rowAGBHeaderGameCodeRevision)
|
|
401
472
|
|
|
402
473
|
rowAGBGpioRtc = QtWidgets.QHBoxLayout()
|
|
@@ -404,17 +475,22 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
404
475
|
lblAGBGpioRtc.setContentsMargins(0, 1, 0, 1)
|
|
405
476
|
rowAGBGpioRtc.addWidget(lblAGBGpioRtc)
|
|
406
477
|
self.lblAGBGpioRtcResult = QtWidgets.QLabel("")
|
|
407
|
-
self.lblAGBGpioRtcResult.setCursor(QtGui.QCursor(QtCore.Qt.WhatsThisCursor))
|
|
408
|
-
self.lblAGBGpioRtcResult.setToolTip(self.lblDMGHeaderRtcResult.toolTip())
|
|
478
|
+
#self.lblAGBGpioRtcResult.setCursor(QtGui.QCursor(QtCore.Qt.WhatsThisCursor))
|
|
479
|
+
#self.lblAGBGpioRtcResult.setToolTip(self.lblDMGHeaderRtcResult.toolTip())
|
|
480
|
+
self.lblAGBGpioRtcResult.mousePressEvent = lambda event: [ self.EditRTC(event) ]
|
|
409
481
|
rowAGBGpioRtc.addWidget(self.lblAGBGpioRtcResult)
|
|
482
|
+
rowAGBGpioRtc.setStretch(0, 9)
|
|
483
|
+
rowAGBGpioRtc.setStretch(1, 11)
|
|
410
484
|
group_layout.addLayout(rowAGBGpioRtc)
|
|
411
485
|
|
|
412
486
|
rowAGBHeaderBootlogo = QtWidgets.QHBoxLayout()
|
|
413
487
|
lblAGBHeaderBootlogo = QtWidgets.QLabel("Boot Logo:")
|
|
414
488
|
lblAGBHeaderBootlogo.setContentsMargins(0, 1, 0, 1)
|
|
415
489
|
rowAGBHeaderBootlogo.addWidget(lblAGBHeaderBootlogo)
|
|
416
|
-
self.
|
|
417
|
-
rowAGBHeaderBootlogo.addWidget(self.
|
|
490
|
+
self.lblAGBHeaderBootlogoResult = QtWidgets.QLabel("")
|
|
491
|
+
rowAGBHeaderBootlogo.addWidget(self.lblAGBHeaderBootlogoResult)
|
|
492
|
+
rowAGBHeaderBootlogo.setStretch(0, 9)
|
|
493
|
+
rowAGBHeaderBootlogo.setStretch(1, 11)
|
|
418
494
|
group_layout.addLayout(rowAGBHeaderBootlogo)
|
|
419
495
|
|
|
420
496
|
rowAGBHeaderChecksum = QtWidgets.QHBoxLayout()
|
|
@@ -423,6 +499,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
423
499
|
rowAGBHeaderChecksum.addWidget(lblAGBHeaderChecksum)
|
|
424
500
|
self.lblAGBHeaderChecksumResult = QtWidgets.QLabel("")
|
|
425
501
|
rowAGBHeaderChecksum.addWidget(self.lblAGBHeaderChecksumResult)
|
|
502
|
+
rowAGBHeaderChecksum.setStretch(0, 9)
|
|
503
|
+
rowAGBHeaderChecksum.setStretch(1, 11)
|
|
426
504
|
group_layout.addLayout(rowAGBHeaderChecksum)
|
|
427
505
|
|
|
428
506
|
rowAGBHeaderROMChecksum = QtWidgets.QHBoxLayout()
|
|
@@ -431,6 +509,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
431
509
|
rowAGBHeaderROMChecksum.addWidget(lblAGBHeaderROMChecksum)
|
|
432
510
|
self.lblAGBHeaderROMChecksumResult = QtWidgets.QLabel("")
|
|
433
511
|
rowAGBHeaderROMChecksum.addWidget(self.lblAGBHeaderROMChecksumResult)
|
|
512
|
+
rowAGBHeaderROMChecksum.setStretch(0, 9)
|
|
513
|
+
rowAGBHeaderROMChecksum.setStretch(1, 11)
|
|
434
514
|
group_layout.addLayout(rowAGBHeaderROMChecksum)
|
|
435
515
|
|
|
436
516
|
rowAGBHeaderROMSize = QtWidgets.QHBoxLayout()
|
|
@@ -442,6 +522,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
442
522
|
self.cmbAGBHeaderROMSizeResult.addItems(Util.AGB_Header_ROM_Sizes)
|
|
443
523
|
self.cmbAGBHeaderROMSizeResult.setCurrentIndex(self.cmbAGBHeaderROMSizeResult.count() - 1)
|
|
444
524
|
rowAGBHeaderROMSize.addWidget(self.cmbAGBHeaderROMSizeResult)
|
|
525
|
+
rowAGBHeaderROMSize.setStretch(0, 9)
|
|
526
|
+
rowAGBHeaderROMSize.setStretch(1, 11)
|
|
445
527
|
group_layout.addLayout(rowAGBHeaderROMSize)
|
|
446
528
|
|
|
447
529
|
rowAGBHeaderSaveType = QtWidgets.QHBoxLayout()
|
|
@@ -453,10 +535,12 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
453
535
|
self.cmbAGBSaveTypeResult.addItems(Util.AGB_Header_Save_Types)
|
|
454
536
|
self.cmbAGBSaveTypeResult.setCurrentIndex(self.cmbAGBSaveTypeResult.count() - 1)
|
|
455
537
|
rowAGBHeaderSaveType.addWidget(self.cmbAGBSaveTypeResult)
|
|
538
|
+
rowAGBHeaderSaveType.setStretch(0, 9)
|
|
539
|
+
rowAGBHeaderSaveType.setStretch(1, 11)
|
|
456
540
|
group_layout.addLayout(rowAGBHeaderSaveType)
|
|
457
541
|
|
|
458
542
|
rowAGBCartridgeType = QtWidgets.QHBoxLayout()
|
|
459
|
-
lblAGBCartridgeType = QtWidgets.QLabel("
|
|
543
|
+
lblAGBCartridgeType = QtWidgets.QLabel("Profile:")
|
|
460
544
|
rowAGBCartridgeType.addWidget(lblAGBCartridgeType)
|
|
461
545
|
self.cmbAGBCartridgeTypeResult = QtWidgets.QComboBox()
|
|
462
546
|
self.cmbAGBCartridgeTypeResult.setStyleSheet("max-width: 260px;")
|
|
@@ -468,6 +552,42 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
468
552
|
|
|
469
553
|
self.grpAGBCartridgeInfo.setLayout(group_layout)
|
|
470
554
|
return self.grpAGBCartridgeInfo
|
|
555
|
+
|
|
556
|
+
def SetAutoPowerOff(self):
|
|
557
|
+
if not self.CheckDeviceAlive(): return
|
|
558
|
+
try:
|
|
559
|
+
value = int(self.SETTINGS.value("AutoPowerOff", default="0"))
|
|
560
|
+
except ValueError:
|
|
561
|
+
value = 0
|
|
562
|
+
self.CONN.SetAutoPowerOff(value=value)
|
|
563
|
+
|
|
564
|
+
def SetDMGReadMethod(self):
|
|
565
|
+
if not self.CheckDeviceAlive(): return
|
|
566
|
+
try:
|
|
567
|
+
method = int(self.SETTINGS.value("DMGReadMethod", "1"))
|
|
568
|
+
except ValueError:
|
|
569
|
+
method = 1
|
|
570
|
+
self.CONN.SetDMGReadMethod(method)
|
|
571
|
+
self.mnuConfigReadModeDMG.actions()[0].setChecked(False)
|
|
572
|
+
self.mnuConfigReadModeDMG.actions()[1].setChecked(False)
|
|
573
|
+
if method == 1:
|
|
574
|
+
self.mnuConfigReadModeDMG.actions()[0].setChecked(True)
|
|
575
|
+
elif method == 2:
|
|
576
|
+
self.mnuConfigReadModeDMG.actions()[1].setChecked(True)
|
|
577
|
+
|
|
578
|
+
def SetAGBReadMethod(self):
|
|
579
|
+
if not self.CheckDeviceAlive(): return
|
|
580
|
+
try:
|
|
581
|
+
method = int(self.SETTINGS.value("AGBReadMethod", "2"))
|
|
582
|
+
except ValueError:
|
|
583
|
+
method = 2
|
|
584
|
+
self.CONN.SetAGBReadMethod(method)
|
|
585
|
+
self.mnuConfigReadModeAGB.actions()[0].setChecked(False)
|
|
586
|
+
self.mnuConfigReadModeAGB.actions()[1].setChecked(False)
|
|
587
|
+
if method == 2:
|
|
588
|
+
self.mnuConfigReadModeAGB.actions()[0].setChecked(True)
|
|
589
|
+
elif method == 0:
|
|
590
|
+
self.mnuConfigReadModeAGB.actions()[1].setChecked(True)
|
|
471
591
|
|
|
472
592
|
def SetLimitBaudRate(self):
|
|
473
593
|
if not self.CheckDeviceAlive(): return
|
|
@@ -476,7 +596,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
476
596
|
if limit_baudrate == "enabled":
|
|
477
597
|
self.CONN.ChangeBaudRate(baudrate=1000000)
|
|
478
598
|
else:
|
|
479
|
-
self.CONN.ChangeBaudRate(baudrate=
|
|
599
|
+
self.CONN.ChangeBaudRate(baudrate=2000000)
|
|
480
600
|
self.DisconnectDevice()
|
|
481
601
|
self.FindDevices(connectToFirst=True, mode=mode)
|
|
482
602
|
|
|
@@ -558,8 +678,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
558
678
|
print("Error: Failed to check for updates (HTTP status {:d}).".format(ret.status_code))
|
|
559
679
|
else:
|
|
560
680
|
update_check = self.SETTINGS.value("UpdateCheck")
|
|
561
|
-
if update_check is None or (time.time() > (Util.VERSION_TIMESTAMP + (
|
|
562
|
-
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
|
|
681
|
+
if update_check is None or (time.time() > (Util.VERSION_TIMESTAMP + (6*30*24*60*60))):
|
|
682
|
+
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)
|
|
563
683
|
|
|
564
684
|
def DisconnectDevice(self):
|
|
565
685
|
try:
|
|
@@ -567,6 +687,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
567
687
|
self.CONN.Close(cartPowerOff=True)
|
|
568
688
|
self.CONN = None
|
|
569
689
|
self.DEVICES = {}
|
|
690
|
+
self.cmbDevice.clear()
|
|
570
691
|
print("Disconnected from {:s}".format(devname))
|
|
571
692
|
except:
|
|
572
693
|
pass
|
|
@@ -593,6 +714,11 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
593
714
|
self.lblStatus4aResult.setText("")
|
|
594
715
|
self.lblStatus4a.setText("Disconnected.")
|
|
595
716
|
self.grpStatus.setTitle("Transfer Status")
|
|
717
|
+
self.mnuConfig.actions()[5].setVisible(True)
|
|
718
|
+
self.mnuConfig.actions()[8].setVisible(True)
|
|
719
|
+
self.mnuConfig.actions()[9].setVisible(True)
|
|
720
|
+
self.mnuTools.actions()[2].setEnabled(True)
|
|
721
|
+
self.mnuConfigReadModeAGB.setEnabled(True)
|
|
596
722
|
|
|
597
723
|
def ReEnableMessages(self):
|
|
598
724
|
self.SETTINGS.setValue("AutoReconnect", "disabled")
|
|
@@ -601,6 +727,13 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
601
727
|
self.SETTINGS.setValue("SkipFinishMessage", "disabled")
|
|
602
728
|
self.SETTINGS.setValue("SkipCameraSavePopup", "disabled")
|
|
603
729
|
|
|
730
|
+
def AboutFlashGBX(self):
|
|
731
|
+
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>"
|
|
732
|
+
msg += f"© 2020–{datetime.datetime.now().year} Lesserkuma<br>"
|
|
733
|
+
msg += "• Website: <a href=\"https://github.com/lesserkuma/FlashGBX\">https://github.com/lesserkuma/FlashGBX</a><br><br>"
|
|
734
|
+
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, Jayro, Jenetrix, JFox, joyrider3774, 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, 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"
|
|
735
|
+
QtWidgets.QMessageBox.information(self, "{:s} {:s}".format(APPNAME, VERSION), msg, QtWidgets.QMessageBox.Ok)
|
|
736
|
+
|
|
604
737
|
def OpenPath(self, path=None):
|
|
605
738
|
if path is None:
|
|
606
739
|
path = Util.CONFIG_PATH
|
|
@@ -616,24 +749,29 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
616
749
|
else:
|
|
617
750
|
subprocess.Popen(["xdg-open", path])
|
|
618
751
|
except:
|
|
619
|
-
QtWidgets.QMessageBox.
|
|
752
|
+
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "The file was not found.\n\n{:s}".format(path), QtWidgets.QMessageBox.Ok)
|
|
753
|
+
|
|
754
|
+
def WriteDebugLog(self, event=None, open_log=False):
|
|
755
|
+
if isinstance(event, QtGui.QMouseEvent):
|
|
756
|
+
if event.button() in (QtCore.Qt.MouseButton.MiddleButton, QtCore.Qt.MouseButton.RightButton): return
|
|
620
757
|
|
|
621
|
-
def WriteDebugLog(self, event=None):
|
|
622
758
|
try:
|
|
623
759
|
Util.dprint("{:s} version: {:s} ({:d})".format(Util.APPNAME, Util.VERSION_PEP440, Util.VERSION_TIMESTAMP))
|
|
624
760
|
Util.dprint("Platform: {:s}".format(platform.platform()))
|
|
625
761
|
if self.CONN is not None:
|
|
626
762
|
Util.dprint("Connected device: {:s}".format(self.CONN.GetFullNameExtended(more=True)))
|
|
627
763
|
else:
|
|
628
|
-
Util.dprint("No device connected
|
|
629
|
-
Util.dprint("Now writing debug log file
|
|
764
|
+
Util.dprint("No device connected")
|
|
765
|
+
Util.dprint("Now writing debug log file")
|
|
630
766
|
except:
|
|
631
767
|
pass
|
|
632
768
|
try:
|
|
633
769
|
fn = Util.CONFIG_PATH + "/debug.log"
|
|
634
770
|
with open(fn, "wb") as f:
|
|
635
771
|
f.write("\n".join(Util.DEBUG_LOG).encode("UTF-8-SIG"))
|
|
636
|
-
print("debug.log written
|
|
772
|
+
print("debug.log written")
|
|
773
|
+
if open_log is True:
|
|
774
|
+
self.OpenPath(fn)
|
|
637
775
|
return True
|
|
638
776
|
except:
|
|
639
777
|
return False
|
|
@@ -643,13 +781,14 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
643
781
|
self.DisconnectDevice()
|
|
644
782
|
return True
|
|
645
783
|
else:
|
|
784
|
+
self.CONN = None
|
|
646
785
|
if self.cmbDevice.count() > 0:
|
|
647
786
|
index = self.cmbDevice.currentText()
|
|
648
787
|
else:
|
|
649
788
|
index = self.lblDevice.text()
|
|
650
789
|
|
|
651
790
|
if index not in self.DEVICES:
|
|
652
|
-
self.FindDevices(
|
|
791
|
+
self.FindDevices()
|
|
653
792
|
return
|
|
654
793
|
|
|
655
794
|
dev = self.DEVICES[index]
|
|
@@ -657,7 +796,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
657
796
|
if str(self.SETTINGS.value("LimitBaudRate", default="disabled")).lower() == "enabled":
|
|
658
797
|
max_baud = 1000000
|
|
659
798
|
else:
|
|
660
|
-
max_baud =
|
|
799
|
+
max_baud = 2000000
|
|
661
800
|
ret = dev.Initialize(self.FLASHCARTS, port=port, max_baud=max_baud)
|
|
662
801
|
msg = ""
|
|
663
802
|
|
|
@@ -669,6 +808,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
669
808
|
for i in range(0, len(ret)):
|
|
670
809
|
status = ret[i][0]
|
|
671
810
|
text = ret[i][1]
|
|
811
|
+
if text in msg: continue
|
|
672
812
|
if status == 0:
|
|
673
813
|
msg += text + "\n"
|
|
674
814
|
elif status == 1:
|
|
@@ -687,10 +827,18 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
687
827
|
return False
|
|
688
828
|
|
|
689
829
|
if dev.IsConnected():
|
|
690
|
-
dev.SetWriteDelay(enable=str(self.SETTINGS.value("WriteDelay", default="disabled")).lower() == "enabled")
|
|
691
|
-
qt_app.processEvents()
|
|
692
830
|
self.CONN = dev
|
|
693
|
-
|
|
831
|
+
dev.SetWriteDelay(enable=str(self.SETTINGS.value("WriteDelay", default="disabled")).lower() == "enabled")
|
|
832
|
+
self.SetAutoPowerOff()
|
|
833
|
+
self.SetDMGReadMethod()
|
|
834
|
+
self.SetAGBReadMethod()
|
|
835
|
+
self.mnuConfig.actions()[5].setVisible(self.CONN.DEVICE_NAME == "GBxCart RW") # Limit Baud Rate
|
|
836
|
+
self.mnuConfig.actions()[8].setVisible(self.CONN.CanPowerCycleCart() and self.CONN.CanPowerCycleCart() and self.CONN.FW["fw_ver"] >= 12) # Auto Power Off
|
|
837
|
+
self.mnuConfig.actions()[9].setVisible(self.CONN.FW["fw_ver"] >= 12) # Skip writing matching ROM chunks
|
|
838
|
+
self.mnuConfigReadModeAGB.setEnabled(self.CONN.FW["fw_ver"] >= 12)
|
|
839
|
+
self.mnuConfigReadModeDMG.setEnabled(self.CONN.FW["fw_ver"] >= 12)
|
|
840
|
+
|
|
841
|
+
self.CONN.SetTimeout(float(self.SETTINGS.value("SerialTimeout", default="1")))
|
|
694
842
|
self.optDMG.setAutoExclusive(False)
|
|
695
843
|
self.optAGB.setAutoExclusive(False)
|
|
696
844
|
if "DMG" in self.CONN.GetSupprtedModes():
|
|
@@ -705,13 +853,13 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
705
853
|
self.btnConnect.setText("&Disconnect")
|
|
706
854
|
self.cmbDevice.setStyleSheet("QComboBox { border: 0; margin: 0; padding: 0; max-width: 0px; }")
|
|
707
855
|
if dev.GetFWBuildDate() == "":
|
|
708
|
-
self.lblDevice.setText(dev.
|
|
856
|
+
self.lblDevice.setText(dev.GetFullNameLabel() + " [Legacy Mode]")
|
|
709
857
|
else:
|
|
710
|
-
self.lblDevice.setText(dev.
|
|
858
|
+
self.lblDevice.setText(dev.GetFullNameLabel())
|
|
711
859
|
print("\nConnected to {:s}".format(dev.GetFullNameExtended(more=True)))
|
|
712
860
|
self.grpActions.setEnabled(True)
|
|
713
|
-
self.
|
|
714
|
-
self.
|
|
861
|
+
self.mnuTools.setEnabled(True)
|
|
862
|
+
self.mnuConfig.setEnabled(True)
|
|
715
863
|
self.btnCancel.setEnabled(False)
|
|
716
864
|
|
|
717
865
|
# Firmware Update Menu
|
|
@@ -739,9 +887,12 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
739
887
|
if dev.FirmwareUpdateAvailable():
|
|
740
888
|
dontShowAgain = str(self.SETTINGS.value("SkipFirmwareUpdate", default="disabled")).lower() == "enabled"
|
|
741
889
|
if not dontShowAgain or dev.FW_UPDATE_REQ:
|
|
742
|
-
if dev.FW_UPDATE_REQ:
|
|
890
|
+
if dev.FW_UPDATE_REQ is True:
|
|
743
891
|
text = "A firmware update for your {:s} device is required to use this software. Do you want to update now?".format(dev.GetFullName())
|
|
744
892
|
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)
|
|
893
|
+
elif dev.FW_UPDATE_REQ == 2:
|
|
894
|
+
text = "Your {:s} device is no longer supported as of FlashGBX v4.0+. You 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())
|
|
895
|
+
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)
|
|
745
896
|
else:
|
|
746
897
|
text = "A firmware update for your {:s} device is available. Do you want to update now?".format(dev.GetFullName())
|
|
747
898
|
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Information, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=text, standardButtons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, defaultButton=QtWidgets.QMessageBox.Yes)
|
|
@@ -757,8 +908,9 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
757
908
|
if dontShowAgain: self.SETTINGS.setValue("SkipFirmwareUpdate", "enabled")
|
|
758
909
|
if answer == QtWidgets.QMessageBox.Yes:
|
|
759
910
|
self.ShowFirmwareUpdateWindow()
|
|
911
|
+
|
|
760
912
|
elif dev.FW_UPDATE_REQ:
|
|
761
|
-
text = "A firmware update for your {:s} device is required to use this software
|
|
913
|
+
text = "A firmware update for your {:s} device is required to use this software.<br><br>Current firmware version: {:s}".format(dev.GetFullName(), dev.GetFirmwareVersion())
|
|
762
914
|
if not Util.DEBUG:
|
|
763
915
|
self.DisconnectDevice()
|
|
764
916
|
QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), text, QtWidgets.QMessageBox.Ok)
|
|
@@ -766,7 +918,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
766
918
|
return True
|
|
767
919
|
return False
|
|
768
920
|
|
|
769
|
-
def FindDevices(self, connectToFirst=False, port=None, mode=None):
|
|
921
|
+
def FindDevices(self, connectToFirst=False, port=None, mode=None, firstRun=False):
|
|
770
922
|
if self.CONN is not None:
|
|
771
923
|
self.DisconnectDevice()
|
|
772
924
|
self.lblDevice.setText("Searching...")
|
|
@@ -779,29 +931,39 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
779
931
|
# pylint: disable=global-variable-not-assigned
|
|
780
932
|
global hw_devices
|
|
781
933
|
for hw_device in hw_devices:
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
self.
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
934
|
+
ports = []
|
|
935
|
+
while True: # for finding other devices of the same type
|
|
936
|
+
dev = hw_device.GbxDevice()
|
|
937
|
+
if str(self.SETTINGS.value("LimitBaudRate", default="disabled")).lower() == "enabled":
|
|
938
|
+
max_baud = 1000000
|
|
939
|
+
else:
|
|
940
|
+
max_baud = 2000000
|
|
941
|
+
ret = dev.Initialize(self.FLASHCARTS, port=port, max_baud=max_baud)
|
|
942
|
+
if ret is False or dev.CheckActive() is False:
|
|
943
|
+
self.CONN = None
|
|
944
|
+
break
|
|
945
|
+
elif isinstance(ret, list):
|
|
946
|
+
for i in range(0, len(ret)):
|
|
947
|
+
status = ret[i][0]
|
|
948
|
+
msg = ret[i][1]
|
|
949
|
+
if msg in messages: # don’t show the same message twice
|
|
950
|
+
continue
|
|
951
|
+
else:
|
|
952
|
+
last_msg = msg
|
|
953
|
+
if status == 3:
|
|
954
|
+
messages.append(msg)
|
|
955
|
+
self.CONN = None
|
|
956
|
+
|
|
957
|
+
if dev.GetPort() in ports:
|
|
958
|
+
break
|
|
959
|
+
ports.append(dev.GetPort())
|
|
960
|
+
|
|
961
|
+
if dev.IsConnected():
|
|
962
|
+
self.DEVICES[dev.GetFullNameExtended()] = dev
|
|
963
|
+
if dev.GetPort() in ports: break
|
|
964
|
+
|
|
965
|
+
for dev in self.DEVICES.values():
|
|
966
|
+
dev.Close()
|
|
805
967
|
|
|
806
968
|
self.cmbDevice.setStyleSheet("QComboBox { border: 0; margin: 0; padding: 0; max-width: 0px; }")
|
|
807
969
|
|
|
@@ -811,7 +973,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
811
973
|
for message in messages:
|
|
812
974
|
msg += message + "\n\n"
|
|
813
975
|
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), msg[:-2], QtWidgets.QMessageBox.Ok)
|
|
814
|
-
|
|
976
|
+
elif not firstRun:
|
|
815
977
|
QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Warning, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text="No compatible devices found. Please ensure the device is connected properly.\n\nTroubleshooting advice:\n- Reconnect the device, try different USB ports/cables, avoid passive USB hubs\n- Use a USB data cable (battery charging cables may not work)\n- Check if the operating system detects the device (if not, reboot your machine)\n- Ensure your user account has permissions to use the device\n- Refer to the device compatibility list on the <a href=\"https://github.com/lesserkuma/FlashGBX/#compatible-cartridge-readerwriter-hardware\">GitHub page</a>".replace("\n", "<br>"), standardButtons=QtWidgets.QMessageBox.Ok).exec()
|
|
816
978
|
|
|
817
979
|
self.lblDevice.setText("No devices found.")
|
|
@@ -847,9 +1009,9 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
847
1009
|
return True
|
|
848
1010
|
|
|
849
1011
|
def AbortOperation(self):
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
self.CONN.
|
|
1012
|
+
if "stresstest_running" in self.STATUS:
|
|
1013
|
+
del(self.STATUS["stresstest_running"])
|
|
1014
|
+
self.CONN.AbortOperation()
|
|
853
1015
|
self.lblStatus4a.setText("Stopping... Please wait.")
|
|
854
1016
|
self.lblStatus4aResult.setText("")
|
|
855
1017
|
|
|
@@ -859,8 +1021,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
859
1021
|
self.grpDMGCartridgeInfo.setEnabled(True)
|
|
860
1022
|
self.grpAGBCartridgeInfo.setEnabled(True)
|
|
861
1023
|
self.grpActions.setEnabled(True)
|
|
862
|
-
self.
|
|
863
|
-
self.
|
|
1024
|
+
self.mnuTools.setEnabled(True)
|
|
1025
|
+
self.mnuConfig.setEnabled(True)
|
|
864
1026
|
self.btnCancel.setEnabled(False)
|
|
865
1027
|
|
|
866
1028
|
dontShowAgain = str(self.SETTINGS.value("SkipFinishMessage", default="disabled")).lower() == "enabled"
|
|
@@ -931,7 +1093,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
931
1093
|
if self.CONN.INFO["loop_detected"] is not False:
|
|
932
1094
|
msg += "\n\nA data loop was detected in the ROM backup at position 0x{:X} ({:s}). This may indicate a bad dump or overdump.".format(self.CONN.INFO["loop_detected"], Util.formatFileSize(size=self.CONN.INFO["loop_detected"], asInt=True))
|
|
933
1095
|
else:
|
|
934
|
-
msg += " This may indicate a bad dump, however this can be normal for some reproduction cartridges, unlicensed games, prototypes, patched games and intentional overdumps."
|
|
1096
|
+
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."
|
|
935
1097
|
if self.CONN.GetMode() == "DMG" and self.cmbDMGHeaderMapperResult.currentText() == "MBC1":
|
|
936
1098
|
msg += "\n\nIf this is a NP GB-Memory Cartridge, please use the “Retry as G-MMC1” button."
|
|
937
1099
|
button_gmmc1 = msgbox.addButton(" Retry as G-MMC1 ", QtWidgets.QMessageBox.ActionRole)
|
|
@@ -1044,7 +1206,13 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1044
1206
|
elif self.CONN.INFO["last_action"] == 4: # Flash ROM
|
|
1045
1207
|
if "broken_sectors" in self.CONN.INFO:
|
|
1046
1208
|
s = ""
|
|
1047
|
-
|
|
1209
|
+
sc = 0
|
|
1210
|
+
for sector in self.CONN.INFO["broken_sectors"]:
|
|
1211
|
+
sc += 1
|
|
1212
|
+
if sc > 10:
|
|
1213
|
+
s += "and others "
|
|
1214
|
+
break
|
|
1215
|
+
s += "0x{:X}~0x{:X}, ".format(sector[0], sector[0]+sector[1]-1)
|
|
1048
1216
|
msg_v = "The ROM was written completely, but verification of written data failed in the following sector(s): {:s}.".format(s[:-2])
|
|
1049
1217
|
if "verify_error_params" in self.CONN.INFO:
|
|
1050
1218
|
if self.CONN.GetMode() == "DMG":
|
|
@@ -1097,6 +1265,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1097
1265
|
self.CONN.INFO["last_action"] = 0
|
|
1098
1266
|
|
|
1099
1267
|
if dontShowAgain: self.SETTINGS.setValue("SkipFinishMessage", "enabled")
|
|
1268
|
+
# if self.CONN is not None and self.CONN.CanPowerCycleCart(): self.CONN.CartPowerOff()
|
|
1100
1269
|
self.SetProgressBars(min=0, max=1, value=1)
|
|
1101
1270
|
|
|
1102
1271
|
def DMGMapperTypeChanged(self, index):
|
|
@@ -1169,7 +1338,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1169
1338
|
rom_size = Util.AGB_Header_ROM_Sizes_Map[self.cmbAGBHeaderROMSizeResult.currentIndex()]
|
|
1170
1339
|
path = QtWidgets.QFileDialog.getSaveFileName(self, "Backup ROM", last_dir + "/" + path, "Game Boy Advance ROM File (*.gba *.srl);;All Files (*.*)")[0]
|
|
1171
1340
|
cart_type = self.cmbAGBCartridgeTypeResult.currentIndex()
|
|
1172
|
-
|
|
1341
|
+
|
|
1173
1342
|
if (path == ""): return
|
|
1174
1343
|
|
|
1175
1344
|
self.SETTINGS.setValue(setting_name, os.path.dirname(path))
|
|
@@ -1179,8 +1348,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1179
1348
|
self.grpDMGCartridgeInfo.setEnabled(False)
|
|
1180
1349
|
self.grpAGBCartridgeInfo.setEnabled(False)
|
|
1181
1350
|
self.grpActions.setEnabled(False)
|
|
1182
|
-
self.
|
|
1183
|
-
self.
|
|
1351
|
+
self.mnuTools.setEnabled(False)
|
|
1352
|
+
self.mnuConfig.setEnabled(False)
|
|
1184
1353
|
self.lblStatus4a.setText("Preparing...")
|
|
1185
1354
|
qt_app.processEvents()
|
|
1186
1355
|
args = { "path":path, "mbc":mbc, "rom_size":rom_size, "agb_rom_size":rom_size, "fast_read_mode":True, "cart_type":cart_type, "settings":self.SETTINGS }
|
|
@@ -1258,8 +1427,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1258
1427
|
if os.path.getsize(path) == 0:
|
|
1259
1428
|
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "The selected ROM file is empty.", QtWidgets.QMessageBox.Ok)
|
|
1260
1429
|
return
|
|
1261
|
-
if os.path.getsize(path) >
|
|
1262
|
-
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "ROM files bigger than
|
|
1430
|
+
if os.path.getsize(path) > 0x20000000: # reject too large files to avoid exploding RAM
|
|
1431
|
+
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "ROM files bigger than 512 MiB are not supported.", QtWidgets.QMessageBox.Ok)
|
|
1263
1432
|
return
|
|
1264
1433
|
|
|
1265
1434
|
with open(path, "rb") as file:
|
|
@@ -1365,7 +1534,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1365
1534
|
elif msgbox.clickedButton() == button_2:
|
|
1366
1535
|
pass
|
|
1367
1536
|
else:
|
|
1368
|
-
Util.dprint("Couldn’t find boot logo file in configuration folder
|
|
1537
|
+
Util.dprint("Couldn’t find boot logo file in configuration folder")
|
|
1369
1538
|
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Warning, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=msg_text)
|
|
1370
1539
|
msgbox.setStandardButtons(QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel)
|
|
1371
1540
|
msgbox.setDefaultButton(QtWidgets.QMessageBox.Cancel)
|
|
@@ -1397,8 +1566,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1397
1566
|
self.grpDMGCartridgeInfo.setEnabled(False)
|
|
1398
1567
|
self.grpAGBCartridgeInfo.setEnabled(False)
|
|
1399
1568
|
self.grpActions.setEnabled(False)
|
|
1400
|
-
self.
|
|
1401
|
-
self.
|
|
1569
|
+
self.mnuTools.setEnabled(False)
|
|
1570
|
+
self.mnuConfig.setEnabled(False)
|
|
1402
1571
|
self.lblStatus4a.setText("Preparing...")
|
|
1403
1572
|
qt_app.processEvents()
|
|
1404
1573
|
if len(buffer) > 0x1000 or just_erase:
|
|
@@ -1408,6 +1577,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1408
1577
|
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 }
|
|
1409
1578
|
else:
|
|
1410
1579
|
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 }
|
|
1580
|
+
args["compare_sectors"] = self.SETTINGS.value("CompareSectors", default="disabled").lower() == "enabled"
|
|
1411
1581
|
self.CONN.FlashROM(fncSetProgress=self.PROGRESS.SetProgress, args=args)
|
|
1412
1582
|
#self.CONN._FlashROM(args=args)
|
|
1413
1583
|
self.grpStatus.setTitle("Transfer Status")
|
|
@@ -1466,7 +1636,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1466
1636
|
verify_read = False
|
|
1467
1637
|
|
|
1468
1638
|
rtc = False
|
|
1469
|
-
if self.CONN.INFO["has_rtc"]:
|
|
1639
|
+
if self.CONN.INFO["has_rtc"] is True:
|
|
1470
1640
|
if self.CONN.GetMode() == "DMG" and mbc in (0x10, 0x110) and not self.CONN.IsClkConnected():
|
|
1471
1641
|
rtc = False
|
|
1472
1642
|
else:
|
|
@@ -1505,8 +1675,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1505
1675
|
self.grpDMGCartridgeInfo.setEnabled(False)
|
|
1506
1676
|
self.grpAGBCartridgeInfo.setEnabled(False)
|
|
1507
1677
|
self.grpActions.setEnabled(False)
|
|
1508
|
-
self.
|
|
1509
|
-
self.
|
|
1678
|
+
self.mnuTools.setEnabled(False)
|
|
1679
|
+
self.mnuConfig.setEnabled(False)
|
|
1510
1680
|
self.lblStatus4a.setText("Preparing...")
|
|
1511
1681
|
qt_app.processEvents()
|
|
1512
1682
|
|
|
@@ -1525,13 +1695,14 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1525
1695
|
|
|
1526
1696
|
def WriteRAM(self, dpath="", erase=False, test=False):
|
|
1527
1697
|
if not self.CheckDeviceAlive(): return
|
|
1528
|
-
|
|
1698
|
+
mode = self.CONN.GetMode()
|
|
1699
|
+
|
|
1529
1700
|
if dpath == "":
|
|
1530
|
-
path = Util.GenerateFileName(mode=
|
|
1701
|
+
path = Util.GenerateFileName(mode=mode, header=self.CONN.INFO, settings=self.SETTINGS)
|
|
1531
1702
|
path = os.path.splitext(path)[0]
|
|
1532
1703
|
path += ".sav"
|
|
1533
1704
|
|
|
1534
|
-
if
|
|
1705
|
+
if mode == "DMG":
|
|
1535
1706
|
setting_name = "LastDirSaveDataDMG"
|
|
1536
1707
|
last_dir = self.SETTINGS.value(setting_name)
|
|
1537
1708
|
if last_dir is None: last_dir = QtCore.QStandardPaths.writableLocation(QtCore.QStandardPaths.DocumentsLocation)
|
|
@@ -1540,9 +1711,10 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1540
1711
|
if save_type == 0:
|
|
1541
1712
|
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "No save type was selected.", QtWidgets.QMessageBox.Ok)
|
|
1542
1713
|
return
|
|
1714
|
+
cart_type = self.cmbDMGCartridgeTypeResult.currentIndex()
|
|
1543
1715
|
#save_size = Util.DMG_Header_RAM_Sizes_Flasher_Map[Util.DMG_Header_RAM_Sizes_Map.index(save_type)]
|
|
1544
1716
|
|
|
1545
|
-
elif
|
|
1717
|
+
elif mode == "AGB":
|
|
1546
1718
|
setting_name = "LastDirSaveDataAGB"
|
|
1547
1719
|
last_dir = self.SETTINGS.value(setting_name)
|
|
1548
1720
|
if last_dir is None: last_dir = QtCore.QStandardPaths.writableLocation(QtCore.QStandardPaths.DocumentsLocation)
|
|
@@ -1552,6 +1724,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1552
1724
|
QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), "No save type was selected.", QtWidgets.QMessageBox.Ok)
|
|
1553
1725
|
return
|
|
1554
1726
|
#save_size = Util.AGB_Header_Save_Sizes[save_type]
|
|
1727
|
+
cart_type = self.cmbAGBCartridgeTypeResult.currentIndex()
|
|
1555
1728
|
else:
|
|
1556
1729
|
return
|
|
1557
1730
|
if not self.CheckHeader(): return
|
|
@@ -1573,18 +1746,16 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1573
1746
|
msgbox.exec()
|
|
1574
1747
|
return
|
|
1575
1748
|
elif not self.CONN.CanPowerCycleCart():
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1749
|
+
if (mode == "AGB" and "SRAM" in self.cmbAGBSaveTypeResult.currentText()) or (mode == "DMG" and "SRAM" in self.cmbDMGHeaderSaveTypeResult.currentText()):
|
|
1750
|
+
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Warning, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text="Your device does not support automatic power cycling, so some tests may be skipped.", standardButtons=QtWidgets.QMessageBox.Ok)
|
|
1751
|
+
msgbox.exec()
|
|
1579
1752
|
|
|
1580
|
-
if
|
|
1581
|
-
("
|
|
1582
|
-
("
|
|
1753
|
+
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 \
|
|
1754
|
+
("8M DACS" in Util.AGB_Header_Save_Types[self.cmbAGBSaveTypeResult.currentIndex()]) or \
|
|
1755
|
+
(mode == "AGB" and "ereader" in self.CONN.INFO and self.CONN.INFO["ereader"] is True) or \
|
|
1756
|
+
(mode == "DMG" and "256M Multi Cart" in self.cmbDMGHeaderMapperResult.currentText() and not self.CONN.CanPowerCycleCart()):
|
|
1583
1757
|
QtWidgets.QMessageBox.information(self, "{:s} {:s}".format(APPNAME, VERSION), "Stress test is not supported for this save type.", QtWidgets.QMessageBox.Ok)
|
|
1584
1758
|
return
|
|
1585
|
-
if self.CONN.GetMode() == "AGB" and "ereader" in self.CONN.INFO and self.CONN.INFO["ereader"] is True:
|
|
1586
|
-
QtWidgets.QMessageBox.information(self, "{:s} {:s}".format(APPNAME, VERSION), "Stress test is not supported for this cartridge.", QtWidgets.QMessageBox.Ok)
|
|
1587
|
-
return
|
|
1588
1759
|
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)
|
|
1589
1760
|
if answer == QtWidgets.QMessageBox.Cancel: return
|
|
1590
1761
|
else:
|
|
@@ -1599,7 +1770,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1599
1770
|
return
|
|
1600
1771
|
|
|
1601
1772
|
buffer = None
|
|
1602
|
-
if
|
|
1773
|
+
if mode == "AGB" and "ereader" in self.CONN.INFO and self.CONN.INFO["ereader"] is True:
|
|
1603
1774
|
if self.CONN.GetFWBuildDate() == "": # Legacy Mode
|
|
1604
1775
|
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)
|
|
1605
1776
|
msgbox.exec()
|
|
@@ -1646,10 +1817,10 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1646
1817
|
|
|
1647
1818
|
rtc = False
|
|
1648
1819
|
rtc_advance = False
|
|
1649
|
-
if not test and self.CONN.INFO["has_rtc"]:
|
|
1650
|
-
if
|
|
1820
|
+
if not test and self.CONN.INFO["has_rtc"] is True:
|
|
1821
|
+
if mode == "DMG" and mbc in (0x10, 0x110) and not self.CONN.IsClkConnected():
|
|
1651
1822
|
rtc = False
|
|
1652
|
-
elif erase or Util.save_size_includes_rtc(mode=
|
|
1823
|
+
elif erase or Util.save_size_includes_rtc(mode=mode, mbc=mbc, save_size=filesize, save_type=save_type):
|
|
1653
1824
|
msg = "A Real Time Clock cartridge was detected. Do you want the Real Time Clock register values to be written as well?"
|
|
1654
1825
|
cb = QtWidgets.QCheckBox("&Adjust RTC", checked=True)
|
|
1655
1826
|
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Question, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=msg, standardButtons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Cancel)
|
|
@@ -1667,14 +1838,16 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1667
1838
|
self.grpDMGCartridgeInfo.setEnabled(False)
|
|
1668
1839
|
self.grpAGBCartridgeInfo.setEnabled(False)
|
|
1669
1840
|
self.grpActions.setEnabled(False)
|
|
1670
|
-
self.
|
|
1671
|
-
self.
|
|
1841
|
+
self.mnuTools.setEnabled(False)
|
|
1842
|
+
self.mnuConfig.setEnabled(False)
|
|
1672
1843
|
self.lblStatus4a.setText("Preparing...")
|
|
1673
1844
|
self.grpStatus.setTitle("Transfer Status")
|
|
1674
1845
|
self.lblStatus1aResult.setText("–")
|
|
1675
1846
|
self.lblStatus2aResult.setText("–")
|
|
1676
1847
|
self.lblStatus3aResult.setText("–")
|
|
1677
1848
|
self.lblStatus4aResult.setText("")
|
|
1849
|
+
self.btnCancel.setEnabled(True)
|
|
1850
|
+
self.STATUS["stresstest_running"] = True
|
|
1678
1851
|
qt_app.processEvents()
|
|
1679
1852
|
|
|
1680
1853
|
test_patterns = [
|
|
@@ -1719,7 +1892,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1719
1892
|
self.lblStatus4a.setText("Testing ({:s} 1/2)...".format(test_patterns_names[0]))
|
|
1720
1893
|
self.SetProgressBars(min=0, max=len(test_patterns)+3, value=0)
|
|
1721
1894
|
qt_app.processEvents()
|
|
1722
|
-
args = { "mode":2, "path":path, "mbc":mbc, "save_type":save_type, "rtc":False }
|
|
1895
|
+
args = { "mode":2, "path":path, "mbc":mbc, "save_type":save_type, "rtc":False, "cart_type":cart_type }
|
|
1723
1896
|
t = threading.Thread(target=lambda a: self.CONN.TransferData(args=a, signal=None), args=[args])
|
|
1724
1897
|
t.start()
|
|
1725
1898
|
while t.is_alive():
|
|
@@ -1734,6 +1907,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1734
1907
|
self.lblStatus4a.setText("Waiting for power cycle ({:d})...".format(i))
|
|
1735
1908
|
qt_app.processEvents()
|
|
1736
1909
|
time.sleep(1)
|
|
1910
|
+
if "stresstest_running" not in self.STATUS: break
|
|
1737
1911
|
self.CONN.CartPowerOn()
|
|
1738
1912
|
else:
|
|
1739
1913
|
time.sleep(1)
|
|
@@ -1746,27 +1920,32 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1746
1920
|
time.sleep(0.02)
|
|
1747
1921
|
t.join()
|
|
1748
1922
|
save2 = self.CONN.INFO["data"]
|
|
1749
|
-
except:
|
|
1923
|
+
except KeyError:
|
|
1924
|
+
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text="An error occured. Please ensure you selected the correct save type.", standardButtons=QtWidgets.QMessageBox.Ok)
|
|
1925
|
+
msgbox.exec()
|
|
1750
1926
|
save1 = None
|
|
1751
1927
|
|
|
1752
|
-
|
|
1928
|
+
stop = False
|
|
1929
|
+
if (save1 is not None and save1 != save2) and "stresstest_running" in self.STATUS:
|
|
1930
|
+
with open(Util.CONFIG_PATH + "/debug_stress_test_1.bin", "wb") as f: f.write(save1)
|
|
1931
|
+
with open(Util.CONFIG_PATH + "/debug_stress_test_2.bin", "wb") as f: f.write(save2)
|
|
1753
1932
|
msg = "Test {:d} ({:s}) failed!\nNote: SRAM requires a working battery to retain save data.\n\nContinue anyway?".format(test_ok+1, test_patterns_names[test_ok])
|
|
1754
1933
|
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Warning, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=msg, standardButtons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
|
|
1755
|
-
msgbox.setDefaultButton(QtWidgets.QMessageBox.
|
|
1934
|
+
msgbox.setDefaultButton(QtWidgets.QMessageBox.Yes)
|
|
1756
1935
|
answer = msgbox.exec()
|
|
1757
1936
|
if answer == QtWidgets.QMessageBox.No:
|
|
1758
|
-
|
|
1759
|
-
save2 = None
|
|
1937
|
+
stop = True
|
|
1760
1938
|
|
|
1761
|
-
if save1 is not None:
|
|
1939
|
+
if not stop and save1 is not None:
|
|
1762
1940
|
with open(backup_fn, "wb") as f: f.write(save1)
|
|
1763
1941
|
test_ok += 1
|
|
1764
1942
|
for i in range(0, len(test_patterns)):
|
|
1943
|
+
if "stresstest_running" not in self.STATUS: break
|
|
1765
1944
|
self.lblStatus4a.setText("Testing ({:s})...".format(test_patterns_names[i+1]))
|
|
1766
1945
|
self.SetProgressBars(min=0, max=len(test_patterns)+3, value=i+2)
|
|
1767
1946
|
qt_app.processEvents()
|
|
1768
1947
|
towrite = test_patterns[i]
|
|
1769
|
-
args = { "mode":3, "path":path, "mbc":mbc, "save_type":save_type, "rtc":False, "rtc_advance":rtc_advance, "erase":erase, "verify_write":False, "buffer":towrite }
|
|
1948
|
+
args = { "mode":3, "path":path, "mbc":mbc, "save_type":save_type, "rtc":False, "rtc_advance":rtc_advance, "erase":erase, "verify_write":False, "buffer":towrite, "cart_type":cart_type }
|
|
1770
1949
|
t = threading.Thread(target=lambda a: self.CONN.TransferData(args=a, signal=None), args=[args])
|
|
1771
1950
|
t.start()
|
|
1772
1951
|
while t.is_alive():
|
|
@@ -1778,7 +1957,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1778
1957
|
self.CONN.CartPowerOff()
|
|
1779
1958
|
time.sleep(0.5)
|
|
1780
1959
|
self.CONN.CartPowerOn()
|
|
1781
|
-
args = { "mode":2, "path":path, "mbc":mbc, "save_type":save_type, "rtc":False }
|
|
1960
|
+
args = { "mode":2, "path":path, "mbc":mbc, "save_type":save_type, "rtc":False, "cart_type":cart_type }
|
|
1782
1961
|
t = threading.Thread(target=lambda a: self.CONN.TransferData(args=a, signal=None), args=[args])
|
|
1783
1962
|
t.start()
|
|
1784
1963
|
while t.is_alive():
|
|
@@ -1790,17 +1969,18 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1790
1969
|
break
|
|
1791
1970
|
test_ok += 1
|
|
1792
1971
|
|
|
1972
|
+
self.btnCancel.setEnabled(False)
|
|
1793
1973
|
self.lblStatus4a.setText("Restoring original save data...")
|
|
1794
1974
|
self.SetProgressBars(min=0, max=len(test_patterns)+3, value=len(test_patterns)+2)
|
|
1795
1975
|
qt_app.processEvents()
|
|
1796
|
-
args = { "mode":3, "path":path, "mbc":mbc, "save_type":save_type, "rtc":False, "rtc_advance":rtc_advance, "erase":erase, "verify_write":False, "buffer":save1 }
|
|
1976
|
+
args = { "mode":3, "path":path, "mbc":mbc, "save_type":save_type, "rtc":False, "rtc_advance":rtc_advance, "erase":erase, "verify_write":False, "buffer":save1, "cart_type":cart_type }
|
|
1797
1977
|
t = threading.Thread(target=lambda a: self.CONN.TransferData(args=a, signal=None), args=[args])
|
|
1798
1978
|
t.start()
|
|
1799
1979
|
while t.is_alive():
|
|
1800
1980
|
qt_app.processEvents()
|
|
1801
1981
|
time.sleep(0.02)
|
|
1802
1982
|
t.join()
|
|
1803
|
-
args = { "mode":2, "path":path, "mbc":mbc, "save_type":save_type, "rtc":False }
|
|
1983
|
+
args = { "mode":2, "path":path, "mbc":mbc, "save_type":save_type, "rtc":False, "cart_type":cart_type }
|
|
1804
1984
|
t = threading.Thread(target=lambda a: self.CONN.TransferData(args=a, signal=None), args=[args])
|
|
1805
1985
|
t.start()
|
|
1806
1986
|
while t.is_alive():
|
|
@@ -1814,30 +1994,36 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1814
1994
|
self.SetProgressBars(min=0, max=100, value=100)
|
|
1815
1995
|
self.lblStatus4a.setText("Done.")
|
|
1816
1996
|
qt_app.processEvents()
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
try:
|
|
1822
|
-
if test_ok == 0:
|
|
1823
|
-
towrite = save1
|
|
1824
|
-
readback = save2
|
|
1825
|
-
with open(Util.CONFIG_PATH + "/debug_stress_test_1.bin", "wb") as f: f.write(towrite[:len(readback)])
|
|
1826
|
-
with open(Util.CONFIG_PATH + "/debug_stress_test_2.bin", "wb") as f: f.write(readback)
|
|
1827
|
-
except:
|
|
1828
|
-
pass
|
|
1829
|
-
if test_ok > 0:
|
|
1830
|
-
msg = "Test {:d} ({:s}) failed!".format(test_ok+1, test_patterns_names[test_ok])
|
|
1831
|
-
msg += msg_te
|
|
1832
|
-
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Warning, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=msg, standardButtons=QtWidgets.QMessageBox.Ok)
|
|
1997
|
+
|
|
1998
|
+
if "stresstest_running" in self.STATUS:
|
|
1999
|
+
if test_ok == len(test_patterns)+1:
|
|
2000
|
+
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Information, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text="All tests completed successfully!" + msg_te, standardButtons=QtWidgets.QMessageBox.Ok)
|
|
1833
2001
|
msgbox.exec()
|
|
1834
|
-
|
|
2002
|
+
else:
|
|
2003
|
+
try:
|
|
2004
|
+
if test_ok == 0:
|
|
2005
|
+
towrite = save1
|
|
2006
|
+
readback = save2
|
|
2007
|
+
with open(Util.CONFIG_PATH + "/debug_stress_test_1.bin", "wb") as f: f.write(towrite[:len(readback)])
|
|
2008
|
+
with open(Util.CONFIG_PATH + "/debug_stress_test_2.bin", "wb") as f: f.write(readback)
|
|
2009
|
+
except:
|
|
2010
|
+
pass
|
|
2011
|
+
if test_ok > 0:
|
|
2012
|
+
msg = "Test {:d} ({:s}) failed!".format(test_ok+1, test_patterns_names[test_ok])
|
|
2013
|
+
msg += msg_te
|
|
2014
|
+
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Warning, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=msg, standardButtons=QtWidgets.QMessageBox.Ok)
|
|
2015
|
+
msgbox.exec()
|
|
2016
|
+
else:
|
|
2017
|
+
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Information, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text="The stress test process was cancelled.", standardButtons=QtWidgets.QMessageBox.Ok)
|
|
2018
|
+
msgbox.exec()
|
|
2019
|
+
|
|
1835
2020
|
self.grpDMGCartridgeInfo.setEnabled(True)
|
|
1836
2021
|
self.grpAGBCartridgeInfo.setEnabled(True)
|
|
1837
2022
|
self.grpActions.setEnabled(True)
|
|
1838
|
-
self.
|
|
1839
|
-
self.
|
|
1840
|
-
|
|
2023
|
+
self.mnuTools.setEnabled(True)
|
|
2024
|
+
self.mnuConfig.setEnabled(True)
|
|
2025
|
+
self.btnCancel.setEnabled(False)
|
|
2026
|
+
|
|
1841
2027
|
if not self.CONN.IsConnected(): self.DisconnectDevice()
|
|
1842
2028
|
|
|
1843
2029
|
else:
|
|
@@ -1873,7 +2059,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1873
2059
|
self.CONN.FlashROM(fncSetProgress=self.PROGRESS.SetProgress, args=args)
|
|
1874
2060
|
#self.CONN._FlashROM(args=args)
|
|
1875
2061
|
else:
|
|
1876
|
-
|
|
2062
|
+
#cart_type = self.cmbAGBCartridgeTypeResult.currentIndex()
|
|
2063
|
+
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 }
|
|
1877
2064
|
if buffer is not None:
|
|
1878
2065
|
args["buffer"] = buffer
|
|
1879
2066
|
args["path"] = None
|
|
@@ -1881,14 +2068,15 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1881
2068
|
self.CONN.RestoreRAM(fncSetProgress=self.PROGRESS.SetProgress, args=args)
|
|
1882
2069
|
#args = { "mode":3, "path":path, "mbc":mbc, "save_type":save_type, "rtc":rtc, "rtc_advance":rtc_advance, "erase":erase, "verify_write":verify_write }
|
|
1883
2070
|
#self.CONN._BackupRestoreRAM(args=args)
|
|
2071
|
+
|
|
1884
2072
|
self.STATUS["time_start"] = time.time()
|
|
1885
2073
|
self.STATUS["last_path"] = path
|
|
1886
2074
|
self.STATUS["args"] = args
|
|
1887
2075
|
self.grpDMGCartridgeInfo.setEnabled(False)
|
|
1888
2076
|
self.grpAGBCartridgeInfo.setEnabled(False)
|
|
1889
2077
|
self.grpActions.setEnabled(False)
|
|
1890
|
-
self.
|
|
1891
|
-
self.
|
|
2078
|
+
self.mnuTools.setEnabled(False)
|
|
2079
|
+
self.mnuConfig.setEnabled(False)
|
|
1892
2080
|
self.lblStatus4a.setText("Preparing...")
|
|
1893
2081
|
self.grpStatus.setTitle("Transfer Status")
|
|
1894
2082
|
self.lblStatus1aResult.setText("–")
|
|
@@ -1972,6 +2160,178 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
1972
2160
|
del(dlg)
|
|
1973
2161
|
return ret
|
|
1974
2162
|
|
|
2163
|
+
def EditRTC(self, _):
|
|
2164
|
+
data = self.CONN.INFO
|
|
2165
|
+
if "dump_info" not in data: return
|
|
2166
|
+
if "has_rtc" not in data or data["has_rtc"] is not True: return
|
|
2167
|
+
if "rtc_dict" not in data or len(data["rtc_dict"]) == 0: return
|
|
2168
|
+
rtc_data = data["rtc_dict"]
|
|
2169
|
+
|
|
2170
|
+
if self.CONN.GetMode() == "DMG":
|
|
2171
|
+
mbc = Util.get_mbc_name(Util.ConvertMapperTypeToMapper(self.cmbDMGHeaderMapperResult.currentIndex()))
|
|
2172
|
+
if mbc in ("MBC3", "MBC30"):
|
|
2173
|
+
dlg_args = {
|
|
2174
|
+
"title":"MBC3/MBC30 Real Time Clock Editor",
|
|
2175
|
+
"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.",
|
|
2176
|
+
"params": [
|
|
2177
|
+
# ID, Type, Value(s), Default Index
|
|
2178
|
+
[ "rtc_d", "spb", "Days:", (0, 511), rtc_data["rtc_d"] ],
|
|
2179
|
+
[ "rtc_h", "spb", "Hours:", (0, 23), rtc_data["rtc_h"] ],
|
|
2180
|
+
[ "rtc_m", "spb", "Minutes:", (0, 59), rtc_data["rtc_m"] ],
|
|
2181
|
+
[ "rtc_s", "spb", "Seconds:", (0, 59), rtc_data["rtc_s"] ],
|
|
2182
|
+
[ "current", "chk", "Ignore above time values and use the current time instead", None, False ],
|
|
2183
|
+
]
|
|
2184
|
+
}
|
|
2185
|
+
dlg = UserInputDialog(self, icon=self.windowIcon(), args=dlg_args)
|
|
2186
|
+
if dlg.exec_() == 1:
|
|
2187
|
+
result = dlg.GetResult()
|
|
2188
|
+
rtc_dict = {}
|
|
2189
|
+
for key, value in result.items():
|
|
2190
|
+
if isinstance(value, QtWidgets.QSpinBox):
|
|
2191
|
+
rtc_dict[key] = value.value()
|
|
2192
|
+
elif isinstance(value, QtWidgets.QCheckBox):
|
|
2193
|
+
rtc_dict[key] = value.isChecked()
|
|
2194
|
+
if result["current"].isChecked():
|
|
2195
|
+
dt = datetime.datetime.now() + datetime.timedelta(seconds=1)
|
|
2196
|
+
rtc_dict.update({
|
|
2197
|
+
"rtc_h":dt.hour,
|
|
2198
|
+
"rtc_m":dt.minute,
|
|
2199
|
+
"rtc_s":dt.second,
|
|
2200
|
+
})
|
|
2201
|
+
mbc = Util.ConvertMapperTypeToMapper(self.cmbDMGHeaderMapperResult.currentIndex())
|
|
2202
|
+
args = { "mbc":mbc, "rtc_dict":rtc_dict }
|
|
2203
|
+
else:
|
|
2204
|
+
return False
|
|
2205
|
+
|
|
2206
|
+
elif mbc in ("HuC-3"):
|
|
2207
|
+
dlg_args = {
|
|
2208
|
+
"title":"HuC-3 Real Time Clock Editor",
|
|
2209
|
+
"intro":"Enter the number of days since your last play, and the current time.\n\nPlease note that the day value is an internal value. The game may use it only as a relative reference.",
|
|
2210
|
+
"params": [
|
|
2211
|
+
# ID, Type, Value(s), Default Index
|
|
2212
|
+
[ "rtc_d", "spb", "Days:", (0, 4095), rtc_data["rtc_d"] ],
|
|
2213
|
+
[ "rtc_h", "spb", "Hours:", (0, 23), rtc_data["rtc_h"] ],
|
|
2214
|
+
[ "rtc_m", "spb", "Minutes:", (0, 59), rtc_data["rtc_m"] ],
|
|
2215
|
+
[ "current", "chk", "Ignore above time values and use the current time instead", None, False ],
|
|
2216
|
+
]
|
|
2217
|
+
}
|
|
2218
|
+
dlg = UserInputDialog(self, icon=self.windowIcon(), args=dlg_args)
|
|
2219
|
+
if dlg.exec_() == 1:
|
|
2220
|
+
result = dlg.GetResult()
|
|
2221
|
+
rtc_dict = {}
|
|
2222
|
+
for key, value in result.items():
|
|
2223
|
+
if isinstance(value, QtWidgets.QSpinBox):
|
|
2224
|
+
rtc_dict[key] = value.value()
|
|
2225
|
+
elif isinstance(value, QtWidgets.QCheckBox):
|
|
2226
|
+
rtc_dict[key] = value.isChecked()
|
|
2227
|
+
if result["current"].isChecked():
|
|
2228
|
+
dt = datetime.datetime.now()
|
|
2229
|
+
rtc_dict.update({
|
|
2230
|
+
"rtc_h":dt.hour,
|
|
2231
|
+
"rtc_m":dt.minute
|
|
2232
|
+
})
|
|
2233
|
+
mbc = Util.ConvertMapperTypeToMapper(self.cmbDMGHeaderMapperResult.currentIndex())
|
|
2234
|
+
args = { "mbc":mbc, "rtc_dict":rtc_dict }
|
|
2235
|
+
else:
|
|
2236
|
+
return False
|
|
2237
|
+
|
|
2238
|
+
elif mbc in ("TAMA5"):
|
|
2239
|
+
dlg_args = {
|
|
2240
|
+
"title":"TAMA5 Real Time Clock Editor",
|
|
2241
|
+
"intro":"Enter the date and time used in the game.\n\nPlease note that the day value is an internal value. The game may use it only as a relative reference.",
|
|
2242
|
+
"params": [
|
|
2243
|
+
# ID, Type, Value(s), Default Index
|
|
2244
|
+
[ "rtc_y", "spb", "Years passed:", (0, 80), rtc_data["rtc_y"] - 19 ], # 19–99
|
|
2245
|
+
[ "rtc_leap_year_state", "spb", "Years since last leap year:", (0, 3), rtc_data["rtc_leap_year_state"] ],
|
|
2246
|
+
[ "rtc_m", "spb", "Month:", (1, 12), rtc_data["rtc_m"] ],
|
|
2247
|
+
[ "rtc_d", "spb", "Day:", (1, 31), rtc_data["rtc_d"] ],
|
|
2248
|
+
[ "rtc_h", "spb", "Hours:", (0, 23), rtc_data["rtc_h"] ],
|
|
2249
|
+
[ "rtc_i", "spb", "Minutes:", (0, 59), rtc_data["rtc_i"] ],
|
|
2250
|
+
[ "rtc_s", "spb", "Seconds:", (0, 59), rtc_data["rtc_s"] ],
|
|
2251
|
+
[ "current", "chk", "Ignore above values and use the current date and time instead", None, False ],
|
|
2252
|
+
]
|
|
2253
|
+
}
|
|
2254
|
+
dlg = UserInputDialog(self, icon=self.windowIcon(), args=dlg_args)
|
|
2255
|
+
if dlg.exec_() == 1:
|
|
2256
|
+
result = dlg.GetResult()
|
|
2257
|
+
rtc_dict = {}
|
|
2258
|
+
for key, value in result.items():
|
|
2259
|
+
if isinstance(value, QtWidgets.QSpinBox):
|
|
2260
|
+
rtc_dict[key] = value.value()
|
|
2261
|
+
elif isinstance(value, QtWidgets.QCheckBox):
|
|
2262
|
+
rtc_dict[key] = value.isChecked()
|
|
2263
|
+
if result["current"].isChecked():
|
|
2264
|
+
dt = datetime.datetime.now() + datetime.timedelta(seconds=2)
|
|
2265
|
+
rtc_dict.update({
|
|
2266
|
+
"rtc_m":dt.month,
|
|
2267
|
+
"rtc_d":dt.day,
|
|
2268
|
+
"rtc_h":dt.hour,
|
|
2269
|
+
"rtc_i":dt.minute,
|
|
2270
|
+
"rtc_s":dt.second,
|
|
2271
|
+
})
|
|
2272
|
+
for y in range(dt.year, 0, -1):
|
|
2273
|
+
if (y % 4 == 0 and y % 100 != 0) or (y % 400 == 0):
|
|
2274
|
+
rtc_dict["rtc_leap_year_state"] = dt.year - y
|
|
2275
|
+
break
|
|
2276
|
+
mbc = Util.ConvertMapperTypeToMapper(self.cmbDMGHeaderMapperResult.currentIndex())
|
|
2277
|
+
rtc_dict["rtc_y"] += 19
|
|
2278
|
+
rtc_dict["rtc_buffer"] = rtc_data["rtc_buffer"]
|
|
2279
|
+
args = { "mbc":mbc, "rtc_dict":rtc_dict }
|
|
2280
|
+
else:
|
|
2281
|
+
return False
|
|
2282
|
+
|
|
2283
|
+
elif self.CONN.GetMode() == "AGB":
|
|
2284
|
+
dlg_args = {
|
|
2285
|
+
"title":"GBA Real Time Clock Editor",
|
|
2286
|
+
"intro":"Enter the date and time for the Real Time Clock.\n\nPlease note that all values are internal values. The game may use these only as a relative reference.",
|
|
2287
|
+
"params": [
|
|
2288
|
+
# ID, Type, Value(s), Default Index
|
|
2289
|
+
[ "rtc_y", "spb", "Year:", (2000, 2099), rtc_data["rtc_y"] + 2000 ],
|
|
2290
|
+
[ "rtc_m", "spb", "Month:", (1, 12), rtc_data["rtc_m"] ],
|
|
2291
|
+
[ "rtc_d", "spb", "Day:", (1, 31), rtc_data["rtc_d"] ],
|
|
2292
|
+
[ "rtc_h", "spb", "Hours:", (0, 23), rtc_data["rtc_h"] ],
|
|
2293
|
+
[ "rtc_i", "spb", "Minutes:", (0, 59), rtc_data["rtc_i"] ],
|
|
2294
|
+
[ "rtc_s", "spb", "Seconds:", (0, 59), rtc_data["rtc_s"] ],
|
|
2295
|
+
[ "rtc_w", "cmb", "Weekday:", list(calendar.day_name), rtc_data["rtc_w"] ],
|
|
2296
|
+
[ "current", "chk", "Ignore above values and use the current date and time instead", None, False ],
|
|
2297
|
+
]
|
|
2298
|
+
}
|
|
2299
|
+
dlg = UserInputDialog(self, icon=self.windowIcon(), args=dlg_args)
|
|
2300
|
+
if dlg.exec_() == 1:
|
|
2301
|
+
result = dlg.GetResult()
|
|
2302
|
+
rtc_dict = {}
|
|
2303
|
+
for key, value in result.items():
|
|
2304
|
+
if isinstance(value, QtWidgets.QSpinBox):
|
|
2305
|
+
rtc_dict[key] = value.value()
|
|
2306
|
+
elif isinstance(value, QtWidgets.QComboBox):
|
|
2307
|
+
rtc_dict[key] = value.currentIndex()
|
|
2308
|
+
if result["current"].isChecked():
|
|
2309
|
+
dt = datetime.datetime.now() + datetime.timedelta(seconds=1)
|
|
2310
|
+
rtc_dict.update({
|
|
2311
|
+
"rtc_y":dt.year,
|
|
2312
|
+
"rtc_m":dt.month,
|
|
2313
|
+
"rtc_d":dt.day,
|
|
2314
|
+
"rtc_w":dt.weekday(),
|
|
2315
|
+
"rtc_h":dt.hour,
|
|
2316
|
+
"rtc_i":dt.minute,
|
|
2317
|
+
"rtc_s":dt.second,
|
|
2318
|
+
})
|
|
2319
|
+
rtc_dict["rtc_y"] -= 2000
|
|
2320
|
+
mbc = Util.ConvertMapperTypeToMapper(self.cmbDMGHeaderMapperResult.currentIndex())
|
|
2321
|
+
args = { "rtc_dict":rtc_dict }
|
|
2322
|
+
else:
|
|
2323
|
+
return False
|
|
2324
|
+
|
|
2325
|
+
self.STATUS["args"] = args
|
|
2326
|
+
ret = self.CONN.WriteRTC(args=args)
|
|
2327
|
+
self.ReadCartridge(resetStatus=False)
|
|
2328
|
+
if ret:
|
|
2329
|
+
QtWidgets.QMessageBox.information(self, "{:s} {:s}".format(APPNAME, VERSION), "The Real Time Clock register values have been updated.", QtWidgets.QMessageBox.Ok)
|
|
2330
|
+
return True
|
|
2331
|
+
else:
|
|
2332
|
+
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "An error occured while updating the Real Time Clock register values.", QtWidgets.QMessageBox.Ok)
|
|
2333
|
+
return False
|
|
2334
|
+
|
|
1975
2335
|
def CheckDeviceAlive(self, setMode=False):
|
|
1976
2336
|
if self.CONN is not None:
|
|
1977
2337
|
mode = self.CONN.GetMode()
|
|
@@ -2068,21 +2428,9 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2068
2428
|
data = self.CONN.ReadInfo(setPinsAsInputs=True)
|
|
2069
2429
|
except SerialException:
|
|
2070
2430
|
self.DisconnectDevice()
|
|
2071
|
-
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
|
|
2431
|
+
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)
|
|
2072
2432
|
return False
|
|
2073
2433
|
|
|
2074
|
-
if resetStatus:
|
|
2075
|
-
self.btnHeaderRefresh.setEnabled(True)
|
|
2076
|
-
self.btnDetectCartridge.setEnabled(True)
|
|
2077
|
-
self.btnBackupROM.setEnabled(True)
|
|
2078
|
-
self.btnFlashROM.setEnabled(True)
|
|
2079
|
-
self.btnBackupRAM.setEnabled(True)
|
|
2080
|
-
self.btnRestoreRAM.setEnabled(True)
|
|
2081
|
-
self.btnHeaderRefresh.setFocus()
|
|
2082
|
-
self.SetProgressBars(min=0, max=100, value=0)
|
|
2083
|
-
self.lblStatus4a.setText("Ready.")
|
|
2084
|
-
qt_app.processEvents()
|
|
2085
|
-
|
|
2086
2434
|
if data == False or len(data) == 0:
|
|
2087
2435
|
self.DisconnectDevice()
|
|
2088
2436
|
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "Invalid response from the device.", QtWidgets.QMessageBox.Ok)
|
|
@@ -2114,7 +2462,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2114
2462
|
self.lblDMGGameCodeRevisionResult.setText("{:s}-{:s}".format(data["db"]["gc"], str(data["version"])))
|
|
2115
2463
|
temp = data["db"]["gn"]
|
|
2116
2464
|
self.lblDMGGameNameResult.setText(temp)
|
|
2117
|
-
while self.lblDMGGameNameResult.fontMetrics().boundingRect(self.lblDMGGameNameResult.text()).width() >
|
|
2465
|
+
while self.lblDMGGameNameResult.fontMetrics().boundingRect(self.lblDMGGameNameResult.text()).width() > 200:
|
|
2118
2466
|
temp = temp[:-1]
|
|
2119
2467
|
self.lblDMGGameNameResult.setText(temp + "…")
|
|
2120
2468
|
if temp != data["db"]["gn"]:
|
|
@@ -2128,6 +2476,12 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2128
2476
|
self.lblDMGGameCodeRevisionResult.setText(str(data['version']))
|
|
2129
2477
|
|
|
2130
2478
|
self.lblDMGHeaderRtcResult.setText(data["rtc_string"])
|
|
2479
|
+
if data["has_rtc"] is True and len(data["rtc_dict"]) > 0 and "rtc_valid" in data["rtc_dict"] and data["rtc_dict"]["rtc_valid"] is True:
|
|
2480
|
+
self.lblDMGHeaderRtcResult.setCursor(QtCore.Qt.PointingHandCursor)
|
|
2481
|
+
self.lblDMGHeaderRtcResult.setToolTip("Click here to edit the Real Time Clock register values")
|
|
2482
|
+
else:
|
|
2483
|
+
self.lblDMGHeaderRtcResult.setCursor(QtCore.Qt.ArrowCursor)
|
|
2484
|
+
self.lblDMGHeaderRtcResult.setToolTip("")
|
|
2131
2485
|
|
|
2132
2486
|
if data['logo_correct'] and data['header_checksum_correct']:
|
|
2133
2487
|
self.lblDMGHeaderBootlogoResult.setText("OK")
|
|
@@ -2162,7 +2516,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2162
2516
|
self.lblDMGGameNameResult.setStyleSheet(self.lblDMGRomTitleResult.styleSheet())
|
|
2163
2517
|
|
|
2164
2518
|
if data['logo_correct'] and not self.CONN.IsSupportedMbc(data["mapper_raw"]) and resetStatus:
|
|
2165
|
-
QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), "This cartridge uses a mapper that may not be completely supported by {:s} using
|
|
2519
|
+
QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), "This cartridge uses a mapper that may not be completely supported by {:s} using your {:s} device.".format(APPNAME, self.CONN.GetFullName()), QtWidgets.QMessageBox.Ok)
|
|
2166
2520
|
if data['logo_correct'] and data['game_title'] in ("NP M-MENU MENU", "DMG MULTI MENU "):
|
|
2167
2521
|
cart_types = self.CONN.GetSupportedCartridgesDMG()
|
|
2168
2522
|
for i in range(0, len(cart_types[0])):
|
|
@@ -2175,6 +2529,10 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2175
2529
|
self.lblDMGHeaderBootlogoResult.setStyleSheet(self.lblDMGRomTitleResult.styleSheet())
|
|
2176
2530
|
self.lblDMGHeaderROMChecksumResult.setText("")
|
|
2177
2531
|
self.lblDMGHeaderROMChecksumResult.setStyleSheet(self.lblDMGRomTitleResult.styleSheet())
|
|
2532
|
+
# cart_types = self.CONN.GetSupportedCartridgesDMG()
|
|
2533
|
+
# for i in range(0, len(cart_types[0])):
|
|
2534
|
+
# if "command_set" in cart_types[1][i] and cart_types[1][i]["command_set"] == "BLAZE_XPLODER":
|
|
2535
|
+
# self.cmbDMGCartridgeTypeResult.setCurrentIndex(i)
|
|
2178
2536
|
elif data["mapper_raw"] == 0x205: # Datel
|
|
2179
2537
|
self.lblDMGHeaderRtcResult.setText("")
|
|
2180
2538
|
self.lblDMGHeaderBootlogoResult.setText("")
|
|
@@ -2199,7 +2557,9 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2199
2557
|
else:
|
|
2200
2558
|
if "logo" in data:
|
|
2201
2559
|
if data['logo_correct']:
|
|
2202
|
-
|
|
2560
|
+
rgb = ( self.TEXT_COLOR[0], self.TEXT_COLOR[1], self.TEXT_COLOR[2] ) # GUI font color
|
|
2561
|
+
rgb = tuple(min(255, int(c + (127.5 - c) * 0.25)) if c < 127.5 else max(0, int(c - (c - 127.5) * 0.25)) for c in rgb)
|
|
2562
|
+
data["logo"].putpalette([ 255, 255, 255, rgb[0], rgb[1], rgb[2] ])
|
|
2203
2563
|
else:
|
|
2204
2564
|
data["logo"].putpalette([ 255, 255, 255, 251, 0, 24 ])
|
|
2205
2565
|
try:
|
|
@@ -2224,7 +2584,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2224
2584
|
self.lblAGBHeaderGameCodeRevisionResult.setText("{:s}-{:s}".format(data["db"]["gc"], str(data["version"])))
|
|
2225
2585
|
temp = data["db"]["gn"]
|
|
2226
2586
|
self.lblAGBGameNameResult.setText(temp)
|
|
2227
|
-
while self.lblAGBGameNameResult.fontMetrics().boundingRect(self.lblAGBGameNameResult.text()).width() >
|
|
2587
|
+
while self.lblAGBGameNameResult.fontMetrics().boundingRect(self.lblAGBGameNameResult.text()).width() > 200:
|
|
2228
2588
|
temp = temp[:-1]
|
|
2229
2589
|
self.lblAGBGameNameResult.setText(temp + "…")
|
|
2230
2590
|
if temp != data["db"]["gn"]:
|
|
@@ -2237,16 +2597,22 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2237
2597
|
self.lblAGBGameNameResult.setText("(Not in database)")
|
|
2238
2598
|
|
|
2239
2599
|
if data['logo_correct']:
|
|
2240
|
-
self.
|
|
2241
|
-
self.
|
|
2600
|
+
self.lblAGBHeaderBootlogoResult.setText("OK")
|
|
2601
|
+
self.lblAGBHeaderBootlogoResult.setStyleSheet(self.lblAGBRomTitleResult.styleSheet())
|
|
2242
2602
|
if not os.path.exists(Util.CONFIG_PATH + "/bootlogo_agb.bin"):
|
|
2243
2603
|
with open(Util.CONFIG_PATH + "/bootlogo_agb.bin", "wb") as f:
|
|
2244
2604
|
f.write(data['raw'][0x04:0xA0])
|
|
2245
2605
|
else:
|
|
2246
|
-
self.
|
|
2247
|
-
self.
|
|
2606
|
+
self.lblAGBHeaderBootlogoResult.setText("Invalid")
|
|
2607
|
+
self.lblAGBHeaderBootlogoResult.setStyleSheet("QLabel { color: red; }")
|
|
2248
2608
|
|
|
2249
2609
|
self.lblAGBGpioRtcResult.setText(data["rtc_string"])
|
|
2610
|
+
if data["has_rtc"] is True and len(data["rtc_dict"]) > 0 and "rtc_valid" in data["rtc_dict"] and data["rtc_dict"]["rtc_valid"] is True:
|
|
2611
|
+
self.lblAGBGpioRtcResult.setCursor(QtCore.Qt.PointingHandCursor)
|
|
2612
|
+
self.lblAGBGpioRtcResult.setToolTip("Click here to edit the Real Time Clock register values")
|
|
2613
|
+
else:
|
|
2614
|
+
self.lblAGBGpioRtcResult.setCursor(QtCore.Qt.ArrowCursor)
|
|
2615
|
+
self.lblAGBGpioRtcResult.setToolTip("")
|
|
2250
2616
|
|
|
2251
2617
|
if data['header_checksum_correct']:
|
|
2252
2618
|
self.lblAGBHeaderChecksumResult.setText("Valid (0x{:02X})".format(data['header_checksum']))
|
|
@@ -2286,10 +2652,11 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2286
2652
|
self.cmbAGBSaveTypeResult.setCurrentIndex(0)
|
|
2287
2653
|
else:
|
|
2288
2654
|
self.lblAGBGameNameResult.setStyleSheet(self.lblDMGRomTitleResult.styleSheet())
|
|
2289
|
-
if data['logo_correct']
|
|
2655
|
+
if data['logo_correct']:
|
|
2290
2656
|
cart_types = self.CONN.GetSupportedCartridgesAGB()
|
|
2291
2657
|
for i in range(0, len(cart_types[0])):
|
|
2292
|
-
if "3d_memory" in cart_types[1][i]
|
|
2658
|
+
if ((data['3d_memory'] is True and "3d_memory" in cart_types[1][i]) or
|
|
2659
|
+
(data['vast_fame'] is True and "vast_fame" in cart_types[1][i])):
|
|
2293
2660
|
self.cmbAGBCartridgeTypeResult.setCurrentIndex(i)
|
|
2294
2661
|
|
|
2295
2662
|
if data["dacs_8m"] is True:
|
|
@@ -2300,7 +2667,19 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2300
2667
|
|
|
2301
2668
|
if data['logo_correct'] and isinstance(data["db"], dict) and "rs" in data["db"] and data["db"]['rs'] == 0x4000000 and not self.CONN.IsSupported3dMemory() and resetStatus:
|
|
2302
2669
|
QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), "This cartridge uses a Memory Bank Controller that may not be completely supported by the firmware of the {:s} device. Please check for firmware updates in the Tools menu or the maker’s website.".format(self.CONN.GetFullName()), QtWidgets.QMessageBox.Ok)
|
|
2303
|
-
|
|
2670
|
+
|
|
2671
|
+
if "logo" in data:
|
|
2672
|
+
if data['logo_correct']:
|
|
2673
|
+
rgb = ( self.TEXT_COLOR[0], self.TEXT_COLOR[1], self.TEXT_COLOR[2] ) # GUI font color
|
|
2674
|
+
rgb = tuple(min(255, int(c + (127.5 - c) * 0.25)) if c < 127.5 else max(0, int(c - (c - 127.5) * 0.25)) for c in rgb)
|
|
2675
|
+
data["logo"].putpalette([ 255, 255, 255, rgb[0], rgb[1], rgb[2] ])
|
|
2676
|
+
else:
|
|
2677
|
+
data["logo"].putpalette([ 255, 255, 255, 251, 0, 24 ])
|
|
2678
|
+
try:
|
|
2679
|
+
self.lblAGBHeaderBootlogoResult.setPixmap(QtGui.QPixmap.fromImage(ImageQt(data["logo"].convert("RGBA"))))
|
|
2680
|
+
except:
|
|
2681
|
+
pass
|
|
2682
|
+
|
|
2304
2683
|
if resetStatus:
|
|
2305
2684
|
self.lblStatus1aResult.setText("–")
|
|
2306
2685
|
self.lblStatus2aResult.setText("–")
|
|
@@ -2308,6 +2687,16 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2308
2687
|
self.lblStatus4a.setText("Ready.")
|
|
2309
2688
|
self.grpStatus.setTitle("Transfer Status")
|
|
2310
2689
|
self.FinishOperation()
|
|
2690
|
+
self.btnHeaderRefresh.setEnabled(True)
|
|
2691
|
+
self.btnDetectCartridge.setEnabled(True)
|
|
2692
|
+
self.btnBackupROM.setEnabled(True)
|
|
2693
|
+
self.btnFlashROM.setEnabled(True)
|
|
2694
|
+
self.btnBackupRAM.setEnabled(True)
|
|
2695
|
+
self.btnRestoreRAM.setEnabled(True)
|
|
2696
|
+
self.btnHeaderRefresh.setFocus()
|
|
2697
|
+
self.SetProgressBars(min=0, max=100, value=0)
|
|
2698
|
+
self.lblStatus4a.setText("Ready.")
|
|
2699
|
+
qt_app.processEvents()
|
|
2311
2700
|
|
|
2312
2701
|
if data['game_title'][:11] == "YJencrypted" and resetStatus:
|
|
2313
2702
|
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)
|
|
@@ -2339,7 +2728,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2339
2728
|
self.DisconnectDevice()
|
|
2340
2729
|
cart_type = None
|
|
2341
2730
|
else:
|
|
2342
|
-
(header, save_size, save_type, save_chip, sram_unstable, cart_types, cart_type_id, cfi_s, _, flash_id) = ret
|
|
2731
|
+
(header, save_size, save_type, save_chip, sram_unstable, cart_types, cart_type_id, cfi_s, _, flash_id, detected_size) = ret
|
|
2343
2732
|
|
|
2344
2733
|
# Save Type
|
|
2345
2734
|
if not canSkipMessage:
|
|
@@ -2361,7 +2750,12 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2361
2750
|
supp_cart_types = self.CONN.GetSupportedCartridgesDMG()
|
|
2362
2751
|
elif self.CONN.GetMode() == "AGB":
|
|
2363
2752
|
supp_cart_types = self.CONN.GetSupportedCartridgesAGB()
|
|
2364
|
-
|
|
2753
|
+
except Exception as e:
|
|
2754
|
+
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)
|
|
2755
|
+
msgbox.exec()
|
|
2756
|
+
return
|
|
2757
|
+
|
|
2758
|
+
try:
|
|
2365
2759
|
if len(cart_types) > 0:
|
|
2366
2760
|
cart_type = cart_type_id
|
|
2367
2761
|
if self.CONN.GetMode() == "DMG":
|
|
@@ -2388,6 +2782,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2388
2782
|
|
|
2389
2783
|
# Save Type
|
|
2390
2784
|
msg_save_type_s = ""
|
|
2785
|
+
temp = ""
|
|
2391
2786
|
if not canSkipMessage and save_type is not False and save_type is not None:
|
|
2392
2787
|
if save_chip is not None:
|
|
2393
2788
|
temp = "{:s} ({:s})".format(Util.AGB_Header_Save_Types[save_type], save_chip)
|
|
@@ -2436,7 +2831,10 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2436
2831
|
msg_cart_type_s_detail = "<b>Compatible Cartridge Types:</b><br>{:s}<br>".format(msg_cart_type)
|
|
2437
2832
|
found_supported = True
|
|
2438
2833
|
|
|
2439
|
-
if
|
|
2834
|
+
if detected_size > 0:
|
|
2835
|
+
size = detected_size
|
|
2836
|
+
msg_flash_size_s = "<b>ROM Size:</b> {:s}<br>".format(Util.formatFileSize(size=size, asInt=True))
|
|
2837
|
+
elif "flash_size" in supp_cart_types[1][cart_type_id]:
|
|
2440
2838
|
size = supp_cart_types[1][cart_type_id]["flash_size"]
|
|
2441
2839
|
msg_flash_size_s = "<b>ROM Size:</b> {:s}<br>".format(Util.formatFileSize(size=size, asInt=True))
|
|
2442
2840
|
|
|
@@ -2451,7 +2849,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2451
2849
|
|
|
2452
2850
|
else:
|
|
2453
2851
|
if (len(flash_id.split("\n")) > 2) and ((self.CONN.GetMode() == "DMG") or ("dacs_8m" in header and header["dacs_8m"] is not True)):
|
|
2454
|
-
msg_cart_type_s = "<b>Cartridge Type:</b> Unknown flash cartridge
|
|
2852
|
+
msg_cart_type_s = "<b>Cartridge Type:</b> Unknown flash cartridge"
|
|
2455
2853
|
if ("[ 0/90]" in flash_id):
|
|
2456
2854
|
try_this = "Generic Flash Cartridge (0/90)"
|
|
2457
2855
|
elif ("[ AAA/AA]" in flash_id):
|
|
@@ -2493,7 +2891,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2493
2891
|
show_details = False
|
|
2494
2892
|
|
|
2495
2893
|
msg_gbmem = ""
|
|
2496
|
-
if "gbmem_parsed" in header:
|
|
2894
|
+
if "gbmem_parsed" in header and header["gbmem_parsed"] is not None:
|
|
2497
2895
|
msg_gbmem = "<br><b>NP GB-Memory Cartridge Data:</b><br>"
|
|
2498
2896
|
if isinstance(header["gbmem_parsed"], list):
|
|
2499
2897
|
msg_gbmem += "" \
|
|
@@ -2625,6 +3023,18 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2625
3023
|
self.lblStatus4a.setText("Ready.")
|
|
2626
3024
|
return cart_type
|
|
2627
3025
|
|
|
3026
|
+
def WaitProgress(self, args):
|
|
3027
|
+
if args["user_action"] == "REINSERT_CART":
|
|
3028
|
+
title = "{:s} {:s}".format(APPNAME, VERSION)
|
|
3029
|
+
if "title" in args:
|
|
3030
|
+
title += " – " + args["title"]
|
|
3031
|
+
msg = args["msg"]
|
|
3032
|
+
answer = QtWidgets.QMessageBox.warning(self, title, msg, QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Ok)
|
|
3033
|
+
if answer == QtWidgets.QMessageBox.Ok:
|
|
3034
|
+
self.CONN.USER_ANSWER = True
|
|
3035
|
+
else:
|
|
3036
|
+
self.CONN.USER_ANSWER = False
|
|
3037
|
+
|
|
2628
3038
|
def UpdateProgress(self, args):
|
|
2629
3039
|
if args is None: return
|
|
2630
3040
|
if self.CONN is None: return
|
|
@@ -2648,8 +3058,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2648
3058
|
self.grpDMGCartridgeInfo.setEnabled(True)
|
|
2649
3059
|
self.grpAGBCartridgeInfo.setEnabled(True)
|
|
2650
3060
|
self.grpActions.setEnabled(True)
|
|
2651
|
-
self.
|
|
2652
|
-
self.
|
|
3061
|
+
self.mnuTools.setEnabled(True)
|
|
3062
|
+
self.mnuConfig.setEnabled(True)
|
|
2653
3063
|
self.btnCancel.setEnabled(False)
|
|
2654
3064
|
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=str(args["error"]), standardButtons=QtWidgets.QMessageBox.Ok)
|
|
2655
3065
|
if not '\n' in str(args["error"]): msgbox.setTextFormat(QtCore.Qt.RichText)
|
|
@@ -2659,8 +3069,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2659
3069
|
self.grpDMGCartridgeInfo.setEnabled(False)
|
|
2660
3070
|
self.grpAGBCartridgeInfo.setEnabled(False)
|
|
2661
3071
|
self.grpActions.setEnabled(False)
|
|
2662
|
-
self.
|
|
2663
|
-
self.
|
|
3072
|
+
self.mnuTools.setEnabled(False)
|
|
3073
|
+
self.mnuConfig.setEnabled(False)
|
|
2664
3074
|
|
|
2665
3075
|
pos = 0
|
|
2666
3076
|
size = 0
|
|
@@ -2743,8 +3153,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2743
3153
|
self.grpDMGCartridgeInfo.setEnabled(True)
|
|
2744
3154
|
self.grpAGBCartridgeInfo.setEnabled(True)
|
|
2745
3155
|
self.grpActions.setEnabled(True)
|
|
2746
|
-
self.
|
|
2747
|
-
self.
|
|
3156
|
+
self.mnuTools.setEnabled(True)
|
|
3157
|
+
self.mnuConfig.setEnabled(True)
|
|
2748
3158
|
self.grpStatus.setTitle("Transfer Status")
|
|
2749
3159
|
self.lblStatus1aResult.setText("–")
|
|
2750
3160
|
self.lblStatus2aResult.setText("–")
|
|
@@ -2815,8 +3225,25 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2815
3225
|
def ShowFirmwareUpdateWindow(self):
|
|
2816
3226
|
if self.CONN is None:
|
|
2817
3227
|
try:
|
|
2818
|
-
|
|
2819
|
-
|
|
3228
|
+
dev_types = {
|
|
3229
|
+
"GBxCart RW v1.4 or v1.4a/b/c":hw_GBxCartRW.GbxDevice.GetFirmwareUpdaterClass(None),
|
|
3230
|
+
"GBFlash":hw_GBFlash.GbxDevice.GetFirmwareUpdaterClass(None),
|
|
3231
|
+
"Joey Jr":hw_JoeyJr.GbxDevice.GetFirmwareUpdaterClass(None),
|
|
3232
|
+
}
|
|
3233
|
+
dlg_args = {
|
|
3234
|
+
"title":"Select Device Type",
|
|
3235
|
+
"intro":"Please select the device that you are using below.",
|
|
3236
|
+
"params": [
|
|
3237
|
+
# ID, Type, Value(s), Default Index
|
|
3238
|
+
[ "dev_type", "cmb", "Device Type:", dev_types.keys(), 0 ]
|
|
3239
|
+
]
|
|
3240
|
+
}
|
|
3241
|
+
dlg = UserInputDialog(self, icon=self.windowIcon(), args=dlg_args)
|
|
3242
|
+
if dlg.exec_() == 1:
|
|
3243
|
+
result = dlg.GetResult()
|
|
3244
|
+
FirmwareUpdater = list(dev_types.values())[result["dev_type"].currentIndex()][1]
|
|
3245
|
+
else:
|
|
3246
|
+
return False
|
|
2820
3247
|
except:
|
|
2821
3248
|
return False
|
|
2822
3249
|
else:
|
|
@@ -2825,6 +3252,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2825
3252
|
return False
|
|
2826
3253
|
else:
|
|
2827
3254
|
FirmwareUpdater = self.CONN.GetFirmwareUpdaterClass()[1]
|
|
3255
|
+
|
|
2828
3256
|
self.FWUPWIN = None
|
|
2829
3257
|
self.FWUPWIN = FirmwareUpdater(self, app_path=Util.APP_PATH, icon=self.windowIcon(), device=self.CONN)
|
|
2830
3258
|
self.FWUPWIN.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
|
|
@@ -2834,9 +3262,11 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2834
3262
|
def ShowPocketCameraWindow(self):
|
|
2835
3263
|
data = None
|
|
2836
3264
|
if self.CONN is not None:
|
|
2837
|
-
if self.CONN.GetMode() is None:
|
|
2838
|
-
|
|
2839
|
-
|
|
3265
|
+
if self.CONN.GetMode() is None and "DMG" in self.CONN.GetSupprtedModes():
|
|
3266
|
+
answer = QtWidgets.QMessageBox.question(self, "{:s} {:s}".format(APPNAME, VERSION), "Is a Game Boy Camera cartridge currently inserted?", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No)
|
|
3267
|
+
if answer == QtWidgets.QMessageBox.Yes:
|
|
3268
|
+
self.optDMG.setChecked(True)
|
|
3269
|
+
self.SetMode()
|
|
2840
3270
|
if self.CONN.GetMode() == "DMG":
|
|
2841
3271
|
header = self.CONN.ReadInfo(setPinsAsInputs=True)
|
|
2842
3272
|
if header["mapper_raw"] == 252: # GBD
|
|
@@ -2917,25 +3347,30 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|
|
2917
3347
|
self.show()
|
|
2918
3348
|
|
|
2919
3349
|
if callable(getattr(qt_app, "exec", None)): # PySide6
|
|
2920
|
-
qt_app.exec()
|
|
2921
|
-
# Taskbar Progress on Windows only
|
|
2922
3350
|
try:
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
taskbar_button = QtWinTaskbarButton()
|
|
2927
|
-
self.TBPROG = taskbar_button.progress()
|
|
2928
|
-
self.TBPROG.setRange(0, 100)
|
|
2929
|
-
taskbar_button.setWindow(self.windowHandle())
|
|
2930
|
-
self.TBPROG.setVisible(False)
|
|
2931
|
-
except ImportError:
|
|
3351
|
+
if platform.system() == "Windows":
|
|
3352
|
+
qt_app.setStyle("windowsvista")
|
|
3353
|
+
except:
|
|
2932
3354
|
pass
|
|
3355
|
+
qt_app.exec()
|
|
3356
|
+
# # Taskbar Progress on Windows only
|
|
3357
|
+
# try:
|
|
3358
|
+
# from PySide6.QtWin import QtWinTaskbarButton, QtWin
|
|
3359
|
+
# myappid = 'lesserkuma.flashgbx'
|
|
3360
|
+
# QtWin.setAppUserModelId(myappid)
|
|
3361
|
+
# taskbar_button = QtWinTaskbarButton()
|
|
3362
|
+
# self.TBPROG = taskbar_button.progress()
|
|
3363
|
+
# self.TBPROG.setRange(0, 100)
|
|
3364
|
+
# taskbar_button.setWindow(self.windowHandle())
|
|
3365
|
+
# self.TBPROG.setVisible(False)
|
|
3366
|
+
# except ImportError:
|
|
3367
|
+
# pass
|
|
2933
3368
|
|
|
2934
3369
|
else: # PySide2
|
|
2935
3370
|
qt_app.exec_()
|
|
2936
3371
|
# Taskbar Progress on Windows only
|
|
2937
3372
|
try:
|
|
2938
|
-
from PySide2.QtWinExtras import QWinTaskbarButton, QtWin
|
|
3373
|
+
from PySide2.QtWinExtras import QWinTaskbarButton, QtWin # type: ignore
|
|
2939
3374
|
myappid = 'lesserkuma.flashgbx'
|
|
2940
3375
|
QtWin.setCurrentProcessExplicitAppUserModelID(myappid)
|
|
2941
3376
|
taskbar_button = QWinTaskbarButton()
|