mirror of
https://github.com/lesserkuma/FlashGBX.git
synced 2026-08-25 02:05:14 -05:00
1.2
This commit is contained in:
@@ -11,7 +11,7 @@ from . import hw_GBxCartRW
|
||||
hw_devices = [hw_GBxCartRW]
|
||||
|
||||
APPNAME = "FlashGBX"
|
||||
VERSION_PEP440 = "1.1"
|
||||
VERSION_PEP440 = "1.2"
|
||||
VERSION = "v{:s}".format(VERSION_PEP440)
|
||||
|
||||
class FlashGBX(QtWidgets.QWidget):
|
||||
@@ -258,7 +258,7 @@ class FlashGBX(QtWidgets.QWidget):
|
||||
if os.path.exists(self.CONFIG_PATH + "/" + zfile):
|
||||
zfile_crc = zip.getinfo(zfile).CRC
|
||||
with open(self.CONFIG_PATH + "/" + zfile, "rb") as ofile: buffer = ofile.read()
|
||||
ofile_crc = zlib.crc32(buffer) & 0xffffffff
|
||||
ofile_crc = zlib.crc32(buffer) & 0xFFFFFFFF
|
||||
if zfile_crc == ofile_crc: continue
|
||||
os.rename(self.CONFIG_PATH + "/" + zfile, self.CONFIG_PATH + "/" + zfile + "_" + datetime.now().strftime("%Y%m%d%H%M%S") + ".bak")
|
||||
rf_list += zfile + "\n"
|
||||
@@ -795,7 +795,7 @@ class FlashGBX(QtWidgets.QWidget):
|
||||
self.lblHeaderROMChecksumResult.setStyleSheet("QLabel { color: green; }");
|
||||
self.lblStatus4a.setText("Done!")
|
||||
#msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Information, windowTitle=APPNAME, text="The ROM was dumped successfully!", standardButtons=QtWidgets.QMessageBox.Ok)
|
||||
msgbox.setText("The ROM was dumped successfully!")
|
||||
msgbox.setText("The ROM backup is complete and the checksum was verified successfully!")
|
||||
if not dontShowAgain:
|
||||
msgbox.exec()
|
||||
dontShowAgain = cb.isChecked()
|
||||
@@ -809,7 +809,7 @@ class FlashGBX(QtWidgets.QWidget):
|
||||
self.lblAGBHeaderROMChecksumResult.setText("Valid (0x{:06X})".format(self.AGB_Global_CRC32))
|
||||
self.lblAGBHeaderROMChecksumResult.setStyleSheet("QLabel { color: green; }");
|
||||
self.lblStatus4a.setText("Done!")
|
||||
msgbox.setText("The ROM was dumped successfully!")
|
||||
msgbox.setText("The ROM backup is complete and the checksum was verified successfully!")
|
||||
if not dontShowAgain:
|
||||
msgbox.exec()
|
||||
dontShowAgain = cb.isChecked()
|
||||
@@ -818,12 +818,12 @@ class FlashGBX(QtWidgets.QWidget):
|
||||
self.lblAGBHeaderROMChecksumResult.setText("0x{:06X}".format(self.CONN.INFO["rom_checksum_calc"]))
|
||||
self.lblAGBHeaderROMChecksumResult.setStyleSheet(self.lblHeaderCGBResult.styleSheet())
|
||||
self.lblStatus4a.setText("Done!")
|
||||
QtWidgets.QMessageBox.information(self, APPNAME, "The ROM was dumped successfully, but its integrity could not be verified as this ROM is not in the database.", QtWidgets.QMessageBox.Ok)
|
||||
QtWidgets.QMessageBox.information(self, APPNAME, "The ROM backup is complete!", QtWidgets.QMessageBox.Ok)
|
||||
else:
|
||||
self.lblAGBHeaderROMChecksumResult.setText("Invalid (0x{:06X}≠0x{:06X})".format(self.CONN.INFO["rom_checksum_calc"], self.AGB_Global_CRC32))
|
||||
self.lblAGBHeaderROMChecksumResult.setStyleSheet("QLabel { color: red; }");
|
||||
self.lblStatus4a.setText("Done.")
|
||||
QtWidgets.QMessageBox.warning(self, APPNAME, "The ROM was dumped, but the checksum doesn’t match the known database entry. This may indicate a bad dump, however this can be normal for some reproduction cartridges, prototypes and patched games.", QtWidgets.QMessageBox.Ok)
|
||||
QtWidgets.QMessageBox.warning(self, APPNAME, "The ROM backup is complete, but the checksum doesn’t match the known database entry. This may indicate a bad dump, however this can be normal for some reproduction cartridges, prototypes and patched games.", QtWidgets.QMessageBox.Ok)
|
||||
|
||||
elif self.CONN.INFO["last_action"] == 2: # Backup RAM
|
||||
self.lblStatus4a.setText("Done!")
|
||||
@@ -877,7 +877,7 @@ class FlashGBX(QtWidgets.QWidget):
|
||||
QtWidgets.QMessageBox.critical(self, APPNAME, "No flash cartridge type configuration files found. Try to restart the application with the “--reset” switch to reset the configuration.", QtWidgets.QMessageBox.Ok)
|
||||
return 0
|
||||
|
||||
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Question, windowTitle=APPNAME, text="Would you like " + APPNAME + " to try and auto-detect the flash cartridge type?\n(Original game cartridges can not be re-written.)", standardButtons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, defaultButton=QtWidgets.QMessageBox.Yes)
|
||||
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Question, windowTitle=APPNAME, text="Would you like " + APPNAME + " to try and auto-detect the flash cartridge type?\n(Official game cartridges can not be re-written.)", standardButtons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, defaultButton=QtWidgets.QMessageBox.Yes)
|
||||
cb = QtWidgets.QCheckBox("Limit voltage to 3.3V", checked=True)
|
||||
if self.CONN.GetMode() == "DMG":
|
||||
msgbox.setCheckBox(cb)
|
||||
@@ -898,11 +898,11 @@ class FlashGBX(QtWidgets.QWidget):
|
||||
limitVoltage = False
|
||||
|
||||
if answer == QtWidgets.QMessageBox.Yes:
|
||||
(flashid, cfi_s, cfi) = self.CONN.CheckFlashChip(limitVoltage)
|
||||
(flash_id, cfi_s, cfi) = self.CONN.CheckFlashChip(limitVoltage)
|
||||
if cfi_s == "":
|
||||
QtWidgets.QMessageBox.information(self, APPNAME, "There was no Common Flash Interface (CFI) response from the cartridge. If a flash chip exists on the cartridge PCB, it may be too old or require unique unlocking and handling.", QtWidgets.QMessageBox.Ok)
|
||||
QtWidgets.QMessageBox.information(self, APPNAME, "Flash chip query result: <pre>" + flash_id + "</pre>There was no Common Flash Interface (CFI) response from the cartridge. If a flash chip exists on the cartridge PCB, it may be too old or require unique unlocking and handling.", QtWidgets.QMessageBox.Ok)
|
||||
else:
|
||||
QtWidgets.QMessageBox.information(self, APPNAME, "Flash chip query result: <pre>" + flashid + "</pre><pre>" + str(cfi_s) + "</pre>", QtWidgets.QMessageBox.Ok)
|
||||
QtWidgets.QMessageBox.information(self, APPNAME, "Flash chip query result: <pre>" + flash_id + "</pre><pre>" + str(cfi_s) + "</pre>", QtWidgets.QMessageBox.Ok)
|
||||
with open(self.CONFIG_PATH + "/cfi.bin", "wb") as f: f.write(cfi['raw'])
|
||||
return 0
|
||||
else:
|
||||
@@ -948,11 +948,11 @@ class FlashGBX(QtWidgets.QWidget):
|
||||
msgbox.setEscapeButton(button_cancel)
|
||||
answer = msgbox.exec()
|
||||
if msgbox.clickedButton() == button_cfi:
|
||||
(flashid, cfi_s, cfi) = self.CONN.CheckFlashChip(limitVoltage=limitVoltage, cart_type=cart_types[1][cart_type])
|
||||
(flash_id, cfi_s, cfi) = self.CONN.CheckFlashChip(limitVoltage=limitVoltage, cart_type=cart_types[1][cart_type])
|
||||
if cfi_s == "":
|
||||
QtWidgets.QMessageBox.information(self, APPNAME, "There was no Common Flash Interface (CFI) response from the cartridge. If a flash chip exists on the cartridge PCB, it may be too old or require unique unlocking and handling.", QtWidgets.QMessageBox.Ok)
|
||||
QtWidgets.QMessageBox.information(self, APPNAME, "Flash chip query result: <pre>" + flash_id + "</pre>There was no Common Flash Interface (CFI) response from the cartridge. If a flash chip exists on the cartridge PCB, it may be too old or require unique unlocking and handling.", QtWidgets.QMessageBox.Ok)
|
||||
else:
|
||||
QtWidgets.QMessageBox.information(self, APPNAME, "Flash chip query result: <pre>" + flashid + "</pre><pre>" + str(cfi_s) + "</pre>", QtWidgets.QMessageBox.Ok)
|
||||
QtWidgets.QMessageBox.information(self, APPNAME, "Flash chip query result: <pre>" + flash_id + "</pre><pre>" + str(cfi_s) + "</pre>", QtWidgets.QMessageBox.Ok)
|
||||
with open(self.CONFIG_PATH + "/cfi.bin", "wb") as f: f.write(cfi['raw'])
|
||||
elif msgbox.clickedButton() == button_cancel: return 0
|
||||
|
||||
@@ -1319,9 +1319,6 @@ class FlashGBX(QtWidgets.QWidget):
|
||||
|
||||
def ReadCartridge(self, resetStatus=True):
|
||||
if not self.CheckDeviceAlive(): return
|
||||
if self.CONN.CheckROMStable() is False:
|
||||
QtWidgets.QMessageBox.warning(self, APPNAME, "Unstable ROM reading detected. Please reconnect the device, make sure you selected the correct mode and that the cartridge contacts are clean.", QtWidgets.QMessageBox.Ok)
|
||||
|
||||
data = self.CONN.ReadInfo()
|
||||
|
||||
if data == False or len(data) == 0:
|
||||
@@ -1334,10 +1331,7 @@ class FlashGBX(QtWidgets.QWidget):
|
||||
self.cmbDMGCartridgeTypeResult.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents)
|
||||
if "flash_type" in data:
|
||||
self.cmbDMGCartridgeTypeResult.setCurrentIndex(data["flash_type"])
|
||||
|
||||
if "manufacturer" in data:
|
||||
self.lblChipManufacturerResult.setText(data['manufacturer'])
|
||||
self.lblChipIDResult.setText("0x{:02X}".format(data['chip_id']))
|
||||
|
||||
self.lblHeaderTitleResult.setText(data['game_title'])
|
||||
if data['sgb'] in self.DMG_Header_SGB:
|
||||
self.lblHeaderSGBResult.setText(self.DMG_Header_SGB[data['sgb']])
|
||||
@@ -1374,6 +1368,20 @@ class FlashGBX(QtWidgets.QWidget):
|
||||
if k == 0x05 or k == 0x06: self.cmbHeaderRAMSizeResult.setCurrentIndex(1) # MBC2 Save
|
||||
i += 1
|
||||
|
||||
if data['empty'] == True: # defaults
|
||||
self.lblHeaderTitleResult.setText("(No ROM data detected)")
|
||||
self.lblHeaderTitleResult.setStyleSheet("QLabel { color: red; }");
|
||||
#self.lblHeaderSGBResult.setText("")
|
||||
#self.lblHeaderCGBResult.setText("")
|
||||
#self.lblHeaderLogoValidResult.setText("")
|
||||
#self.lblHeaderChecksumResult.setText("")
|
||||
#self.lblHeaderROMChecksumResult.setText("")
|
||||
self.cmbHeaderROMSizeResult.setCurrentIndex(11)
|
||||
self.cmbHeaderRAMSizeResult.setCurrentIndex(0)
|
||||
self.cmbHeaderFeaturesResult.setCurrentIndex(0)
|
||||
else:
|
||||
self.lblHeaderTitleResult.setStyleSheet(self.lblHeaderCGBResult.styleSheet())
|
||||
|
||||
self.grpAGBCartridgeInfo.setVisible(False)
|
||||
self.grpDMGCartridgeInfo.setVisible(True)
|
||||
|
||||
@@ -1425,10 +1433,10 @@ class FlashGBX(QtWidgets.QWidget):
|
||||
print("FAIL: Database for Game Boy Advance titles not found in " + "{0:s}/db_AGB.json".format(self.CONFIG_PATH))
|
||||
|
||||
if db_agb_entry != None:
|
||||
self.cmbAGBHeaderROMSizeResult.setCurrentIndex(self.AGB_Header_ROM_Sizes_Map.index(db_agb_entry['rom_size']))
|
||||
self.cmbAGBHeaderROMSizeResult.setCurrentIndex(self.AGB_Header_ROM_Sizes_Map.index(db_agb_entry['rs']))
|
||||
if data["rom_size_calc"] < 0x400000:
|
||||
self.lblAGBHeaderROMChecksumResult.setText("In database (0x{:06X})".format(db_agb_entry['rom_crc32']))
|
||||
self.AGB_Global_CRC32 = db_agb_entry['rom_crc32']
|
||||
self.lblAGBHeaderROMChecksumResult.setText("In database (0x{:06X})".format(db_agb_entry['rc']))
|
||||
self.AGB_Global_CRC32 = db_agb_entry['rc']
|
||||
|
||||
elif data["rom_size"] != 0:
|
||||
if not data["rom_size"] in self.AGB_Header_ROM_Sizes_Map:
|
||||
@@ -1440,8 +1448,22 @@ class FlashGBX(QtWidgets.QWidget):
|
||||
if data["save_type"] == None:
|
||||
self.cmbAGBSaveTypeResult.setCurrentIndex(0)
|
||||
if db_agb_entry != None:
|
||||
if db_agb_entry['savetype'] < len(self.AGB_Header_Save_Types):
|
||||
self.cmbAGBSaveTypeResult.setCurrentIndex(db_agb_entry['savetype'])
|
||||
if db_agb_entry['st'] < len(self.AGB_Header_Save_Types):
|
||||
self.cmbAGBSaveTypeResult.setCurrentIndex(db_agb_entry['st'])
|
||||
|
||||
if data['empty'] == True: # defaults
|
||||
self.lblAGBHeaderTitleResult.setText("(No ROM data detected)")
|
||||
self.lblAGBHeaderTitleResult.setStyleSheet("QLabel { color: red; }");
|
||||
#self.lblAGBHeaderCodeResult.setText("")
|
||||
#self.lblAGBHeaderVersionResult.setText("")
|
||||
#self.lblAGBHeaderLogoValidResult.setText("")
|
||||
#self.lblAGBHeader96hResult.setText("")
|
||||
#self.lblAGBHeaderChecksumResult.setText("")
|
||||
#self.lblAGBHeaderROMChecksumResult.setText("")
|
||||
self.cmbAGBHeaderROMSizeResult.setCurrentIndex(3)
|
||||
self.cmbAGBSaveTypeResult.setCurrentIndex(0)
|
||||
else:
|
||||
self.lblHeaderTitleResult.setStyleSheet(self.lblHeaderCGBResult.styleSheet())
|
||||
|
||||
self.grpDMGCartridgeInfo.setVisible(False)
|
||||
self.grpAGBCartridgeInfo.setVisible(True)
|
||||
@@ -1455,8 +1477,12 @@ class FlashGBX(QtWidgets.QWidget):
|
||||
self.FinishOperation()
|
||||
|
||||
if self.CONN.CheckROMStable() is False:
|
||||
QtWidgets.QMessageBox.warning(self, APPNAME, "Unstable ROM reading detected. Please reconnect the device, make sure you selected the correct mode and that the cartridge contacts are clean.", QtWidgets.QMessageBox.Ok)
|
||||
|
||||
QtWidgets.QMessageBox.warning(self, APPNAME, "Unstable ROM reading detected. Please make sure that the cartridge contacts are very clean and that you selected the correct mode.", QtWidgets.QMessageBox.Ok)
|
||||
return
|
||||
|
||||
if not data['logo_correct'] and data['empty'] == False:
|
||||
QtWidgets.QMessageBox.warning(self, APPNAME, "The Nintendo Logo check failed which usually means that the cartridge couldn’t be read correctly. Please make sure that the cartridge contacts are very clean and that you selected the correct mode.", QtWidgets.QMessageBox.Ok)
|
||||
|
||||
if data['game_title'][:11] == "YJencrypted":
|
||||
QtWidgets.QMessageBox.warning(self, APPNAME, "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)
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ class RomFileAGB:
|
||||
def GetHeader(self):
|
||||
buffer = self.ROMFILE
|
||||
data = {}
|
||||
data["empty"] = (self.ROMFILE == bytearray([buffer[0]] * len(buffer)))
|
||||
data["logo_correct"] = hashlib.sha1(buffer[0x04:0xA0]).digest() == bytearray([ 0x17, 0xDA, 0xA0, 0xFE, 0xC0, 0x2F, 0xC3, 0x3C, 0x0F, 0x6A, 0xBB, 0x54, 0x9A, 0x8B, 0x80, 0xB6, 0x61, 0x3B, 0x48, 0xEE ])
|
||||
game_title = bytearray(buffer[0xA0:0xAC]).decode("ascii", "replace")
|
||||
game_title = re.sub(r"(\x00+)$", "", game_title).replace("\x00", "_")
|
||||
|
||||
@@ -57,6 +57,7 @@ class RomFileDMG:
|
||||
def GetHeader(self):
|
||||
buffer = self.ROMFILE
|
||||
data = {}
|
||||
data["empty"] = (self.ROMFILE == bytearray([buffer[0]] * len(buffer)))
|
||||
data["logo_correct"] = hashlib.sha1(buffer[0x104:0x134]).digest() == bytearray([ 0x07, 0x45, 0xFD, 0xEF, 0x34, 0x13, 0x2D, 0x1B, 0x3D, 0x48, 0x8C, 0xFB, 0xDF, 0x03, 0x79, 0xA3, 0x9F, 0xD5, 0x4B, 0x4C ])
|
||||
game_title = bytearray(buffer[0x134:0x143]).decode("ascii", "replace")
|
||||
game_title = re.sub(r"(\x00+)$", "", game_title).replace("\x00", "_")
|
||||
|
||||
@@ -103,5 +103,5 @@ def ParseCFI(buffer):
|
||||
|
||||
def dprint(*args, **kwargs):
|
||||
# uncomment for some debug prints
|
||||
#print(" ".join(map(str, args)), **kwargs)
|
||||
#print(datetime.datetime.now().strftime("[%Y-%m-%d %H:%M:%S]"), " ".join(map(str, args)), **kwargs)
|
||||
pass
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
53
FlashGBX/config/fc_DMG_AT49F040_AUDIO.txt
Normal file
53
FlashGBX/config/fc_DMG_AT49F040_AUDIO.txt
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"type":"DMG",
|
||||
"names":[
|
||||
"DIY cart with AT49F040 @ AUDIO"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0x1F, 0x13, 0xFE, 0xFF ]
|
||||
],
|
||||
"voltage":5,
|
||||
"flash_size":0x8000,
|
||||
"start_addr":0,
|
||||
"first_bank":1,
|
||||
"write_pin":"AUDIO",
|
||||
"chip_erase_timeout":60,
|
||||
"commands":{
|
||||
"reset":[
|
||||
[ 0, 0xF0 ]
|
||||
],
|
||||
"read_identifier":[
|
||||
[ 0x5555, 0xAA ],
|
||||
[ 0x2AAA, 0x55 ],
|
||||
[ 0x5555, 0x90 ]
|
||||
],
|
||||
"chip_erase":[
|
||||
[ 0x5555, 0xAA ],
|
||||
[ 0x2AAA, 0x55 ],
|
||||
[ 0x5555, 0x80 ],
|
||||
[ 0x5555, 0xAA ],
|
||||
[ 0x2AAA, 0x55 ],
|
||||
[ 0x5555, 0x10 ]
|
||||
],
|
||||
"chip_erase_wait_for":[
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ 0, 0xFF, 0xFF ]
|
||||
],
|
||||
"single_write":[
|
||||
[ 0x5555, 0xAA ],
|
||||
[ 0x2AAA, 0x55 ],
|
||||
[ 0x5555, 0xA0 ],
|
||||
[ "PA", "PD" ]
|
||||
],
|
||||
"single_write_wait_for":[
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ]
|
||||
]
|
||||
}
|
||||
}
|
||||
53
FlashGBX/config/fc_DMG_AT49F040_WR.txt
Normal file
53
FlashGBX/config/fc_DMG_AT49F040_WR.txt
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"type":"DMG",
|
||||
"names":[
|
||||
"DIY cart with AT49F040 @ WR"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0x1F, 0x13, 0xFE, 0xFF ]
|
||||
],
|
||||
"voltage":5,
|
||||
"flash_size":0x8000,
|
||||
"start_addr":0,
|
||||
"first_bank":1,
|
||||
"write_pin":"WR",
|
||||
"chip_erase_timeout":60,
|
||||
"commands":{
|
||||
"reset":[
|
||||
[ 0, 0xF0 ]
|
||||
],
|
||||
"read_identifier":[
|
||||
[ 0x5555, 0xAA ],
|
||||
[ 0x2AAA, 0x55 ],
|
||||
[ 0x5555, 0x90 ]
|
||||
],
|
||||
"chip_erase":[
|
||||
[ 0x5555, 0xAA ],
|
||||
[ 0x2AAA, 0x55 ],
|
||||
[ 0x5555, 0x80 ],
|
||||
[ 0x5555, 0xAA ],
|
||||
[ 0x2AAA, 0x55 ],
|
||||
[ 0x5555, 0x10 ]
|
||||
],
|
||||
"chip_erase_wait_for":[
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ 0, 0xFF, 0xFF ]
|
||||
],
|
||||
"single_write":[
|
||||
[ 0x5555, 0xAA ],
|
||||
[ 0x2AAA, 0x55 ],
|
||||
[ 0x5555, 0xA0 ],
|
||||
[ "PA", "PD" ]
|
||||
],
|
||||
"single_write_wait_for":[
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ]
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -203,7 +203,7 @@ class GbxDevice:
|
||||
def Close(self):
|
||||
if self.IsConnected():
|
||||
try:
|
||||
self.set_mode(self.DEVICE_CMD['VOLTAGE_3_3V']) # set to lower voltage when closing for safety
|
||||
self.set_mode(self.DEVICE_CMD["VOLTAGE_3_3V"]) # set to lower voltage when closing for safety
|
||||
self.DEVICE.close()
|
||||
except:
|
||||
self.DEVICE = None
|
||||
@@ -225,9 +225,9 @@ class GbxDevice:
|
||||
return self.PORT
|
||||
|
||||
def LoadFirmwareVersion(self):
|
||||
self.write(self.DEVICE_CMD['READ_FIRMWARE_VERSION'])
|
||||
self.write(self.DEVICE_CMD["READ_FIRMWARE_VERSION"])
|
||||
fw = bytearray(self.read(1))[0]
|
||||
self.write(self.DEVICE_CMD['READ_PCB_VERSION'])
|
||||
self.write(self.DEVICE_CMD["READ_PCB_VERSION"])
|
||||
pcb = bytearray(self.read(1))[0]
|
||||
self.FW = [fw, pcb]
|
||||
|
||||
@@ -375,22 +375,22 @@ class GbxDevice:
|
||||
if self.MODE == "DMG":
|
||||
if self.FAST_READ and length == 0x4000:
|
||||
if set_address:
|
||||
self.set_number(offset, self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_mode(self.DEVICE_CMD['READ_ROM_4000H'])
|
||||
self.set_number(offset, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
self.set_mode(self.DEVICE_CMD["READ_ROM_4000H"])
|
||||
else:
|
||||
if set_address:
|
||||
self.set_number(offset, self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_mode(self.DEVICE_CMD['READ_ROM_RAM'])
|
||||
self.set_number(offset, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
self.set_mode(self.DEVICE_CMD["READ_ROM_RAM"])
|
||||
buffer = self.read(length, last=True)
|
||||
elif self.MODE == "AGB":
|
||||
if self.FAST_READ and length == 0x10000:
|
||||
if set_address:
|
||||
self.set_number(math.floor(offset / 2), self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_mode(self.DEVICE_CMD['GBA_READ_ROM_8000H'])
|
||||
self.set_number(math.floor(offset / 2), self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
self.set_mode(self.DEVICE_CMD["GBA_READ_ROM_8000H"])
|
||||
else:
|
||||
if set_address:
|
||||
self.set_number(math.floor(offset / 2), self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_mode(self.DEVICE_CMD['GBA_READ_ROM'])
|
||||
self.set_number(math.floor(offset / 2), self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
self.set_mode(self.DEVICE_CMD["GBA_READ_ROM"])
|
||||
buffer = self.read(length, last=True)
|
||||
|
||||
'''
|
||||
@@ -430,11 +430,11 @@ class GbxDevice:
|
||||
def gba_flash_write_address_byte(self, address, data):
|
||||
address = int(address / 2)
|
||||
address = format(address, 'x')
|
||||
buffer = self.DEVICE_CMD['GBA_FLASH_CART_WRITE_BYTE'] + address + '\x00'
|
||||
buffer = self.DEVICE_CMD["GBA_FLASH_CART_WRITE_BYTE"] + address + '\x00'
|
||||
self.write(buffer)
|
||||
time.sleep(0.001)
|
||||
data = format(data, 'x')
|
||||
buffer = self.DEVICE_CMD['GBA_FLASH_CART_WRITE_BYTE'] + data + '\x00'
|
||||
buffer = self.DEVICE_CMD["GBA_FLASH_CART_WRITE_BYTE"] + data + '\x00'
|
||||
self.write(buffer)
|
||||
time.sleep(0.001)
|
||||
ack = self.wait_for_ack()
|
||||
@@ -445,7 +445,7 @@ class GbxDevice:
|
||||
|
||||
def gb_flash_write_address_byte(self, address, data):
|
||||
address = format(address, 'x')
|
||||
buffer = self.DEVICE_CMD['GB_FLASH_WRITE_BYTE'] + address + '\x00'
|
||||
buffer = self.DEVICE_CMD["GB_FLASH_WRITE_BYTE"] + address + '\x00'
|
||||
self.write(buffer)
|
||||
buffer = format(data, 'x') + '\x00'
|
||||
self.write(buffer)
|
||||
@@ -456,17 +456,17 @@ class GbxDevice:
|
||||
return False
|
||||
|
||||
def gbx_flash_write_data_bytes(self, command, data):
|
||||
buffer = bytearray(self.DEVICE_CMD[command], "ascii") + bytearray(data)
|
||||
buffer = bytearray(command, "ascii") + bytearray(data)
|
||||
self.write(buffer)
|
||||
|
||||
def set_bank(self, address, bank):
|
||||
address = format(address, 'x')
|
||||
buffer = self.DEVICE_CMD['SET_BANK'] + address + '\x00'
|
||||
buffer = self.DEVICE_CMD["SET_BANK"] + address + '\x00'
|
||||
self.write(buffer)
|
||||
time.sleep(0.005)
|
||||
|
||||
bank = format(bank, 'd')
|
||||
buffer = self.DEVICE_CMD['SET_BANK'] + bank + '\x00'
|
||||
buffer = self.DEVICE_CMD["SET_BANK"] + bank + '\x00'
|
||||
self.write(buffer)
|
||||
time.sleep(0.005)
|
||||
|
||||
@@ -474,14 +474,16 @@ class GbxDevice:
|
||||
dprint("set_mode(command={:s})".format(str(command)))
|
||||
buffer = format(command, 's')
|
||||
self.write(buffer)
|
||||
if command in (self.DEVICE_CMD["VOLTAGE_3_3V"], self.DEVICE_CMD["VOLTAGE_5V"]):
|
||||
#time.sleep(0.01)
|
||||
pass
|
||||
|
||||
def set_number(self, number, command):
|
||||
buffer = format(command, 's') + format(int(number), 'x') + '\x00'
|
||||
self.write(buffer)
|
||||
if command in ("SET_START_ADDRESS"):
|
||||
time.sleep(0.005)
|
||||
elif command in ("VOLTAGE_3_3V", "VOLTAGE_5V"):
|
||||
time.sleep(0.3)
|
||||
if command in (self.DEVICE_CMD["SET_START_ADDRESS"]):
|
||||
#time.sleep(0.005)
|
||||
pass
|
||||
|
||||
def EnableRAM(self, mbc=1, enable=True):
|
||||
if enable:
|
||||
@@ -492,28 +494,36 @@ class GbxDevice:
|
||||
if mbc <= 4: self.set_bank(0x6000, 0)
|
||||
time.sleep(0.2)
|
||||
|
||||
def SetBankROM(self, bank, mbc=5):
|
||||
dprint("SetBankROM(", bank, ",", mbc, ")", bank & 0xFF, ((bank >> 8) & 0xFF))
|
||||
def SetBankROM(self, bank, mbc=0, bank_count=0):
|
||||
dprint("SetBankROM(bank={:d}, mbc={:d}, bank_count={:d})".format(bank, mbc, bank_count))
|
||||
if mbc == 0 and bank_count == 0: mbc = 5
|
||||
if mbc == 1: # MBC1
|
||||
dprint("0x6000=0x00, 0x4000=0x{:X}, 0x2000=0x{:X}".format(bank >> 5, bank & 0x1F))
|
||||
self.set_bank(0x6000, 0)
|
||||
self.set_bank(0x4000, bank >> 5)
|
||||
self.set_bank(0x2000, bank & 0x1F)
|
||||
elif mbc == 1.1: # Hudson MBC1
|
||||
self.set_bank(0x4000, bank >> 4)
|
||||
if (bank < 10):
|
||||
dprint("0x4000=0x{:X}, 0x2000=0x{:X}".format(bank >> 4, bank & 0x1F))
|
||||
self.set_bank(0x2000, bank & 0x1F)
|
||||
else:
|
||||
dprint("0x4000=0x{:X}, 0x2000=0x{:X}".format(bank >> 4, 0x10 | (bank & 0x1F)))
|
||||
self.set_bank(0x2000, 0x10 | (bank & 0x1F))
|
||||
else:
|
||||
elif (mbc == 0 and bank_count > 256) or mbc == 5: # MBC5
|
||||
dprint("0x2100=0x{:X}, 0x3000=0x{:X}".format(bank & 0xFF, ((bank >> 8) & 0xFF)))
|
||||
self.set_bank(0x2100, (bank & 0xFF))
|
||||
self.set_bank(0x3000, ((bank >> 8) & 0xFF))
|
||||
else: # MBC2, MBC3 and others
|
||||
dprint("0x2100=0x{:X}".format(bank & 0xFF))
|
||||
self.set_bank(0x2100, (bank & 0xFF))
|
||||
|
||||
def SetBankRAM(self, bank):
|
||||
self.set_bank(0x4000, (bank & 0xFF))
|
||||
|
||||
def ReadFlashSaveMakerID(self):
|
||||
makers = { 0x1F:"ATMEL", 0xBF:"SST/SANYO", 0xC2:"MACRONIX", 0x32:"PANASONIC", 0x62:"SANYO" }
|
||||
self.set_mode(self.DEVICE_CMD['GBA_FLASH_READ_ID'])
|
||||
self.set_mode(self.DEVICE_CMD["GBA_FLASH_READ_ID"])
|
||||
time.sleep(0.02)
|
||||
buffer = self.DEVICE.read(2)
|
||||
if buffer[0] in makers.keys():
|
||||
@@ -523,21 +533,24 @@ class GbxDevice:
|
||||
|
||||
def SetMode(self, mode):
|
||||
if mode == "DMG":
|
||||
self.set_mode(self.DEVICE_CMD['VOLTAGE_5V'])
|
||||
self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
|
||||
self.MODE = "DMG"
|
||||
elif mode == "AGB":
|
||||
self.set_mode(self.DEVICE_CMD['VOLTAGE_3_3V'])
|
||||
self.set_mode(self.DEVICE_CMD["VOLTAGE_3_3V"])
|
||||
self.MODE = "AGB"
|
||||
self.set_number(0, self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_number(0, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
|
||||
def AutoDetectFlash(self, limitVoltage=False):
|
||||
flash_types = []
|
||||
flash_type = 0
|
||||
flash_id = None
|
||||
if limitVoltage:
|
||||
self.set_mode(self.DEVICE_CMD['VOLTAGE_3_3V'])
|
||||
|
||||
if self.MODE == "DMG":
|
||||
if limitVoltage:
|
||||
self.set_mode(self.DEVICE_CMD["VOLTAGE_3_3V"])
|
||||
else:
|
||||
self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
|
||||
|
||||
supported_carts = list(self.SUPPORTED_CARTS['DMG'].values())
|
||||
for f in range(2, len(supported_carts)):
|
||||
flashcart_meta = supported_carts[f]
|
||||
@@ -545,16 +558,16 @@ class GbxDevice:
|
||||
if flash_id not in flashcart_meta["flash_ids"]:
|
||||
continue
|
||||
|
||||
self.set_mode(self.DEVICE_CMD['GB_CART_MODE'])
|
||||
self.set_mode(self.DEVICE_CMD["GB_CART_MODE"])
|
||||
if "flash_commands_on_bank_1" in flashcart_meta:
|
||||
self.set_mode(self.DEVICE_CMD['GB_FLASH_BANK_1_COMMAND_WRITES'])
|
||||
self.set_mode(self.DEVICE_CMD["GB_FLASH_BANK_1_COMMAND_WRITES"])
|
||||
|
||||
if flashcart_meta["write_pin"] == "WR":
|
||||
self.set_mode(self.DEVICE_CMD['GB_FLASH_WE_PIN'])
|
||||
self.set_mode(self.DEVICE_CMD['WE_AS_WR_PIN'])
|
||||
self.set_mode(self.DEVICE_CMD["GB_FLASH_WE_PIN"])
|
||||
self.set_mode(self.DEVICE_CMD["WE_AS_WR_PIN"])
|
||||
elif flashcart_meta["write_pin"] in ("AUDIO", "VIN"):
|
||||
self.set_mode(self.DEVICE_CMD['GB_FLASH_WE_PIN'])
|
||||
self.set_mode(self.DEVICE_CMD['WE_AS_AUDIO_PIN'])
|
||||
self.set_mode(self.DEVICE_CMD["GB_FLASH_WE_PIN"])
|
||||
self.set_mode(self.DEVICE_CMD["WE_AS_AUDIO_PIN"])
|
||||
|
||||
# Unlock Flash
|
||||
if "unlock" in flashcart_meta["commands"]:
|
||||
@@ -594,7 +607,7 @@ class GbxDevice:
|
||||
flash_types.append(flash_type)
|
||||
|
||||
if not flash_id_found:
|
||||
self.set_mode(self.DEVICE_CMD['VOLTAGE_5V'])
|
||||
self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
|
||||
|
||||
elif self.MODE == "AGB":
|
||||
supported_carts = list(self.SUPPORTED_CARTS['AGB'].values())
|
||||
@@ -644,9 +657,6 @@ class GbxDevice:
|
||||
return flash_types
|
||||
|
||||
def CheckFlashChip(self, limitVoltage=False, cart_type=None):
|
||||
if limitVoltage:
|
||||
self.set_mode(self.DEVICE_CMD['VOLTAGE_3_3V'])
|
||||
|
||||
flash_id_lines = []
|
||||
flash_commands = [
|
||||
{ 'read_cfi':[[0x555, 0x98]], 'read_identifier':[[ 0x555, 0xAA ], [ 0x2AA, 0x55 ], [ 0x555, 0x90 ]], 'reset':[[ 0x0, 0xF0 ]] },
|
||||
@@ -671,6 +681,10 @@ class GbxDevice:
|
||||
cfi = {'raw':b''}
|
||||
|
||||
if self.MODE == "DMG":
|
||||
if limitVoltage:
|
||||
self.set_mode(self.DEVICE_CMD["VOLTAGE_3_3V"])
|
||||
else:
|
||||
self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
|
||||
rom_string = "[ ROM ] " + rom_string
|
||||
we_pins = [ "WR", "AUDIO" ]
|
||||
else:
|
||||
@@ -681,8 +695,8 @@ class GbxDevice:
|
||||
if "method" in cfi: break
|
||||
for method in flash_commands:
|
||||
if self.MODE == "DMG":
|
||||
self.set_mode(self.DEVICE_CMD['GB_FLASH_WE_PIN'])
|
||||
self.set_mode(self.DEVICE_CMD['WE_AS_' + we + '_PIN'])
|
||||
self.set_mode(self.DEVICE_CMD["GB_FLASH_WE_PIN"])
|
||||
self.set_mode(self.DEVICE_CMD["WE_AS_" + we + "_PIN"])
|
||||
|
||||
for i in range(0, len(method['reset'])):
|
||||
self.gbx_flash_write_address_byte(method['reset'][i][0], method['reset'][i][1])
|
||||
@@ -770,6 +784,32 @@ class GbxDevice:
|
||||
#s += "\nSHA-1: {:s}".format(cfi["sha1"])
|
||||
cfi_info = s
|
||||
|
||||
if cfi['raw'] == b'':
|
||||
for we in we_pins:
|
||||
for method in flash_commands:
|
||||
for i in range(0, len(method['reset'])):
|
||||
self.gbx_flash_write_address_byte(method['reset'][i][0], method["reset"][i][1])
|
||||
for i in range(0, len(method['read_identifier'])):
|
||||
self.gbx_flash_write_address_byte(method['read_identifier'][i][0], method["read_identifier"][i][1])
|
||||
flash_id = self.ReadROM(0, 64)[0:8]
|
||||
for i in range(0, len(method['reset'])):
|
||||
self.gbx_flash_write_address_byte(method['reset'][i][0], method["reset"][i][1])
|
||||
|
||||
if flash_id != check_buffer[0:8]:
|
||||
if self.MODE == "DMG":
|
||||
method_string = "[" + we.ljust(5) + "/{:4X}/{:2X}]".format(method['read_identifier'][0][0], method['read_identifier'][0][1])
|
||||
else:
|
||||
method_string = "[{:6X}/{:2X}]".format(method['read_identifier'][0][0], method['read_identifier'][0][1])
|
||||
line_exists = False
|
||||
for i in range(0, len(flash_id_lines)):
|
||||
if method_string == flash_id_lines[i][0]: line_exists = True
|
||||
if not line_exists: flash_id_lines.append([method_string, flash_id])
|
||||
for i in range(0, len(method['reset'])):
|
||||
self.gbx_flash_write_address_byte(method['reset'][i][0], method['reset'][i][1])
|
||||
|
||||
if self.MODE == "DMG":
|
||||
self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
|
||||
|
||||
flash_id = ""
|
||||
for i in range(0, len(flash_id_lines)):
|
||||
flash_id += flash_id_lines[i][0] + " "
|
||||
@@ -777,8 +817,7 @@ class GbxDevice:
|
||||
flash_id += "{:02X} ".format(flash_id_lines[i][1][j])
|
||||
flash_id += "\n"
|
||||
|
||||
if flash_id != "":
|
||||
flash_id = rom_string + flash_id
|
||||
flash_id = rom_string + flash_id
|
||||
|
||||
return (flash_id, cfi_info, cfi)
|
||||
|
||||
@@ -794,6 +833,9 @@ class GbxDevice:
|
||||
if not self.IsConnected(): raise Exception("Couldn’t access the the device.")
|
||||
data = {}
|
||||
self.POS = 0
|
||||
if self.MODE == "DMG":
|
||||
self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
|
||||
|
||||
header = self.ReadROM(0, 0x180)
|
||||
|
||||
if self.MODE == "DMG":
|
||||
@@ -813,7 +855,7 @@ class GbxDevice:
|
||||
self.INFO["flash_type"] = 0
|
||||
self.INFO["last_action"] = 0
|
||||
|
||||
self.set_mode(self.DEVICE_CMD['SET_PINS_AS_INPUTS'])
|
||||
self.set_mode(self.DEVICE_CMD["SET_PINS_AS_INPUTS"])
|
||||
return data
|
||||
|
||||
def BackupROM(self, fncSetProgress=None, path="ROM.gb", mbc=0x00, rom_banks=512, agb_rom_size=0, start_addr=0, fast_read_mode=False):
|
||||
@@ -1067,13 +1109,13 @@ class GbxDevice:
|
||||
endAddr = startAddr + min(save_size, bank_size)
|
||||
if endAddr > (startAddr + save_size): endAddr = startAddr + save_size
|
||||
if save_type == 1 or save_type == 2: # EEPROM
|
||||
self.set_number(eeprom_size, self.DEVICE_CMD['GBA_SET_EEPROM_SIZE'])
|
||||
self.set_number(eeprom_size, self.DEVICE_CMD["GBA_SET_EEPROM_SIZE"])
|
||||
elif (save_type == 5) and bank > 0: # 1M SRAM
|
||||
self.gbx_flash_write_address_byte(0x1000000, bank)
|
||||
elif (save_type == 6 or save_type == 7) and bank > 0: # FLASH
|
||||
self.set_number(bank, self.DEVICE_CMD['GBA_FLASH_SET_BANK'])
|
||||
self.set_number(bank, self.DEVICE_CMD["GBA_FLASH_SET_BANK"])
|
||||
|
||||
self.set_number(startAddr, self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_number(startAddr, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
|
||||
buffer_len = transfer_size
|
||||
sector = 0
|
||||
@@ -1082,8 +1124,8 @@ class GbxDevice:
|
||||
if self.MODE == "DMG":
|
||||
self.EnableRAM(mbc=mbc, enable=False)
|
||||
elif self.MODE == "AGB":
|
||||
if bank > 0: self.set_number(0, self.DEVICE_CMD['GBA_FLASH_SET_BANK'])
|
||||
self.set_mode(self.DEVICE_CMD['READ_ROM_RAM'])
|
||||
if bank > 0: self.set_number(0, self.DEVICE_CMD["GBA_FLASH_SET_BANK"])
|
||||
self.set_mode(self.DEVICE_CMD["READ_ROM_RAM"])
|
||||
self.ReadInfo()
|
||||
cancel_args = {"action":"ABORT", "abortable":False}
|
||||
cancel_args.update(self.CANCEL_ARGS)
|
||||
@@ -1111,20 +1153,21 @@ class GbxDevice:
|
||||
elif mode == 3: # Restore
|
||||
data = data_import[pos:pos+buffer_len]
|
||||
if self.MODE == "DMG":
|
||||
self.gbx_flash_write_data_bytes("WRITE_RAM", data)
|
||||
|
||||
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["WRITE_RAM"], data)
|
||||
|
||||
elif self.MODE == "AGB":
|
||||
if save_type == 6 or save_type == 7: # FLASH
|
||||
if maker_id == "ATMEL":
|
||||
self.gbx_flash_write_data_bytes("GBA_FLASH_WRITE_ATMEL", data)
|
||||
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_ATMEL"], data)
|
||||
else:
|
||||
if (currAddr % 4096 == 0):
|
||||
self.set_number(sector, self.DEVICE_CMD['GBA_FLASH_4K_SECTOR_ERASE'])
|
||||
self.set_number(sector, self.DEVICE_CMD["GBA_FLASH_4K_SECTOR_ERASE"])
|
||||
self.wait_for_ack()
|
||||
sector += 1
|
||||
lives = 50
|
||||
while True: # wait for 0xFF (= erase done)
|
||||
self.set_number(currAddr, self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_number(currAddr, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
self.set_mode(self.DEVICE_CMD[read_command])
|
||||
buffer = self.read(buffer_len, last=True)
|
||||
if buffer[0] == 0xFF: break
|
||||
@@ -1133,9 +1176,9 @@ class GbxDevice:
|
||||
if lives == 0:
|
||||
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Writing the flash save data failed. Please make sure you selected the correct save type.", "abortable":False})
|
||||
return False
|
||||
self.set_number(currAddr, self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_number(currAddr, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
|
||||
self.gbx_flash_write_data_bytes("GBA_FLASH_WRITE_BYTE", data)
|
||||
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_BYTE"], data)
|
||||
|
||||
else: # EEPROM / SRAM
|
||||
self.gbx_flash_write_data_bytes(write_command, data)
|
||||
@@ -1156,7 +1199,7 @@ class GbxDevice:
|
||||
if (save_type == 5) and bank > 0: # 1M SRAM
|
||||
self.gbx_flash_write_address_byte(0x1000000, 0)
|
||||
elif (save_type == 6 or save_type == 7) and bank > 0: # FLASH
|
||||
self.set_number(0, self.DEVICE_CMD['GBA_FLASH_SET_BANK'])
|
||||
self.set_number(0, self.DEVICE_CMD["GBA_FLASH_SET_BANK"])
|
||||
|
||||
if mode == 2: file.close()
|
||||
|
||||
@@ -1195,7 +1238,7 @@ class GbxDevice:
|
||||
self._FlashROM(buffer=data_import, cart_type=cart_type, voltage=args["override_voltage"], start_addr=args["start_addr"], signal=signal, prefer_sector_erase=args["prefer_sector_erase"], reverse_sectors=args["reverse_sectors"], fast_read_mode=args["fast_read_mode"], verify_flash=args["verify_flash"])
|
||||
|
||||
# Reset pins to avoid save data loss
|
||||
self.set_mode(self.DEVICE_CMD['SET_PINS_AS_INPUTS'])
|
||||
self.set_mode(self.DEVICE_CMD["SET_PINS_AS_INPUTS"])
|
||||
|
||||
#######################################################################################################################################
|
||||
|
||||
@@ -1204,6 +1247,7 @@ class GbxDevice:
|
||||
if self.INFO == None: self.ReadInfo()
|
||||
self.INFO["last_action"] = 4
|
||||
bank_size = 0x4000
|
||||
mbc = 0
|
||||
time_start = time.time()
|
||||
|
||||
data_import = copy.copy(buffer)
|
||||
@@ -1239,32 +1283,36 @@ class GbxDevice:
|
||||
|
||||
# Set Voltage
|
||||
if voltage == 3.3:
|
||||
self.set_mode(self.DEVICE_CMD['VOLTAGE_3_3V'])
|
||||
self.set_mode(self.DEVICE_CMD["VOLTAGE_3_3V"])
|
||||
elif voltage == 5:
|
||||
self.set_mode(self.DEVICE_CMD['VOLTAGE_5V'])
|
||||
self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
|
||||
elif flashcart_meta["voltage"] == 3.3:
|
||||
self.set_mode(self.DEVICE_CMD['VOLTAGE_3_3V'])
|
||||
self.set_mode(self.DEVICE_CMD["VOLTAGE_3_3V"])
|
||||
elif flashcart_meta["voltage"] == 5:
|
||||
self.set_mode(self.DEVICE_CMD['VOLTAGE_5V'])
|
||||
self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
|
||||
|
||||
if "mbc" in flashcart_meta:
|
||||
mbc = flashcart_meta['mbc']
|
||||
dprint("Set MBC to {:d}".format(mbc))
|
||||
|
||||
if self.MODE == "DMG":
|
||||
self.set_mode(self.DEVICE_CMD['GB_CART_MODE'])
|
||||
self.set_mode(self.DEVICE_CMD["GB_CART_MODE"])
|
||||
if "flash_commands_on_bank_1" in flashcart_meta and flashcart_meta["flash_commands_on_bank_1"]:
|
||||
self.set_mode(self.DEVICE_CMD['GB_FLASH_BANK_1_COMMAND_WRITES'])
|
||||
self.set_mode(self.DEVICE_CMD["GB_FLASH_BANK_1_COMMAND_WRITES"])
|
||||
dprint("Setting GB_FLASH_BANK_1_COMMAND_WRITES...")
|
||||
|
||||
self.set_mode(self.DEVICE_CMD['GB_FLASH_WE_PIN'])
|
||||
self.set_mode(self.DEVICE_CMD["GB_FLASH_WE_PIN"])
|
||||
if flashcart_meta["write_pin"] == "WR":
|
||||
self.set_mode(self.DEVICE_CMD['WE_AS_WR_PIN'])
|
||||
self.set_mode(self.DEVICE_CMD["WE_AS_WR_PIN"])
|
||||
dprint("Setting WE_AS_WR_PIN...")
|
||||
elif flashcart_meta["write_pin"] in ("AUDIO", "VIN"):
|
||||
self.set_mode(self.DEVICE_CMD['WE_AS_AUDIO_PIN'])
|
||||
self.set_mode(self.DEVICE_CMD["WE_AS_AUDIO_PIN"])
|
||||
dprint("Setting WE_AS_AUDIO_PIN...")
|
||||
|
||||
if "single_write" in flashcart_meta["commands"] and len(flashcart_meta["commands"]["single_write"]) == 4:
|
||||
# Submit flash program commands to firmware
|
||||
dprint("Setting GB_FLASH_PROGRAM_METHOD...")
|
||||
self.set_mode(self.DEVICE_CMD['GB_FLASH_PROGRAM_METHOD'])
|
||||
self.set_mode(self.DEVICE_CMD["GB_FLASH_PROGRAM_METHOD"])
|
||||
for i in range(0, 3):
|
||||
dprint("single_write_command(",i,"):", hex(flashcart_meta["commands"]["single_write"][i][0]), "=", hex(flashcart_meta["commands"]["single_write"][i][1]))
|
||||
self.write(bytearray(format(flashcart_meta["commands"]["single_write"][i][0], "x"), "ascii") + b'\x00', True)
|
||||
@@ -1331,7 +1379,7 @@ class GbxDevice:
|
||||
|
||||
dprint("Chip erase took {:d} seconds".format(math.ceil(time.time() - time_start)))
|
||||
|
||||
self.set_number(0, self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_number(0, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
|
||||
# Write Flash
|
||||
pos = 0
|
||||
@@ -1342,7 +1390,7 @@ class GbxDevice:
|
||||
if "start_addr" in flashcart_meta: currAddr = flashcart_meta["start_addr"]
|
||||
endAddr = 0x7FFF
|
||||
bank_count = math.ceil(len(data_import) / bank_size)
|
||||
if start_addr == 0: self.SetBankROM(0)
|
||||
if start_addr == 0: self.SetBankROM(0, mbc=mbc, bank_count=bank_count)
|
||||
elif self.MODE == "AGB":
|
||||
currAddr = 0
|
||||
endAddr = len(data_import)
|
||||
@@ -1356,7 +1404,7 @@ class GbxDevice:
|
||||
# Fast Forward
|
||||
if start_addr > 0:
|
||||
first_bank = math.floor(start_addr / bank_size)
|
||||
self.SetBankROM(first_bank)
|
||||
self.SetBankROM(first_bank, mbc=mbc, bank_count=bank_count)
|
||||
offset = start_addr % bank_size
|
||||
currAddr = bank_size + offset
|
||||
if "sector_erase" in flashcart_meta["commands"]:
|
||||
@@ -1391,7 +1439,7 @@ class GbxDevice:
|
||||
dprint("BANK {:d}".format(bank))
|
||||
if self.MODE == "DMG":
|
||||
if bank > first_bank: currAddr = bank_size
|
||||
self.set_number(currAddr, self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_number(currAddr, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
|
||||
while (currAddr < endAddr):
|
||||
if pos >= len(data_import): break
|
||||
@@ -1413,7 +1461,7 @@ class GbxDevice:
|
||||
if "reset" in flashcart_meta["commands"]:
|
||||
for i in range(0, len(flashcart_meta["commands"]["reset"])):
|
||||
self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
|
||||
self.SetBankROM(bank)
|
||||
self.SetBankROM(bank, mbc=mbc, bank_count=bank_count)
|
||||
time.sleep(0.05)
|
||||
|
||||
# Sector Erase (if supported)
|
||||
@@ -1480,9 +1528,9 @@ class GbxDevice:
|
||||
self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
|
||||
|
||||
if self.MODE == "DMG":
|
||||
self.set_number(currAddr, self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_number(currAddr, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
elif self.MODE == "AGB":
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
|
||||
if sector_count is not None:
|
||||
sector_count -= 1
|
||||
@@ -1499,9 +1547,9 @@ class GbxDevice:
|
||||
skipping = True
|
||||
else:
|
||||
if skipping:
|
||||
self.set_number(currAddr, self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_number(currAddr, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
skipping = False
|
||||
self.gbx_flash_write_data_bytes("GB_FLASH_WRITE_INTEL_BUFFERED_32BYTE", data)
|
||||
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GB_FLASH_WRITE_INTEL_BUFFERED_32BYTE"], data)
|
||||
ack = self.wait_for_ack()
|
||||
currAddr += 32
|
||||
pos += 32
|
||||
@@ -1518,9 +1566,9 @@ class GbxDevice:
|
||||
skipping = True
|
||||
else:
|
||||
if skipping:
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
skipping = False
|
||||
self.gbx_flash_write_data_bytes("GBA_FLASH_WRITE_INTEL_INTERLEAVED_256BYTE", data)
|
||||
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_INTEL_INTERLEAVED_256BYTE"], data)
|
||||
ack = self.wait_for_ack()
|
||||
currAddr += 256
|
||||
pos += 256
|
||||
@@ -1539,7 +1587,7 @@ class GbxDevice:
|
||||
data = data_import[pos:pos+2]
|
||||
|
||||
if int(currAddr % 0x8000) == 0:
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
|
||||
# R24+
|
||||
elif (int(self.FW[0]) >= 24) and "single_write_7FC0_to_7FFF" not in flashcart_meta:
|
||||
@@ -1548,9 +1596,9 @@ class GbxDevice:
|
||||
skipping = True
|
||||
else:
|
||||
if skipping:
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
skipping = False
|
||||
self.gbx_flash_write_data_bytes("GBA_FLASH_WRITE_INTEL_256BYTE", data)
|
||||
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_INTEL_256BYTE"], data)
|
||||
ack = self.wait_for_ack()
|
||||
|
||||
currAddr += 256
|
||||
@@ -1562,9 +1610,9 @@ class GbxDevice:
|
||||
skipping = True
|
||||
else:
|
||||
if skipping:
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
skipping = False
|
||||
self.gbx_flash_write_data_bytes("GBA_FLASH_WRITE_INTEL_64BYTE", data)
|
||||
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_INTEL_64BYTE"], data)
|
||||
ack = self.wait_for_ack()
|
||||
|
||||
currAddr += 64
|
||||
@@ -1577,9 +1625,9 @@ class GbxDevice:
|
||||
skipping = True
|
||||
else:
|
||||
if skipping:
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
skipping = False
|
||||
self.gbx_flash_write_data_bytes("GBA_FLASH_WRITE_BUFFERED_256BYTE_SWAPPED_D0D1", data)
|
||||
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_BUFFERED_256BYTE_SWAPPED_D0D1"], data)
|
||||
ack = self.wait_for_ack()
|
||||
currAddr += 256
|
||||
pos += 256
|
||||
@@ -1598,7 +1646,7 @@ class GbxDevice:
|
||||
data = data_import[pos:pos+2]
|
||||
|
||||
if currAddr == 256:
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
|
||||
else:
|
||||
data = data_import[pos:pos+256]
|
||||
@@ -1606,9 +1654,9 @@ class GbxDevice:
|
||||
skipping = True
|
||||
else:
|
||||
if skipping:
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
skipping = False
|
||||
self.gbx_flash_write_data_bytes("GBA_FLASH_WRITE_BUFFERED_256BYTE", data)
|
||||
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_BUFFERED_256BYTE"], data)
|
||||
ack = self.wait_for_ack()
|
||||
currAddr += 256
|
||||
pos += 256
|
||||
@@ -1629,14 +1677,14 @@ class GbxDevice:
|
||||
skipping = True
|
||||
else:
|
||||
if skipping:
|
||||
self.set_number(currAddr, self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_number(currAddr, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
skipping = False
|
||||
if "pulse_reset_after_write" in flashcart_meta and flashcart_meta["pulse_reset_after_write"]:
|
||||
self.gbx_flash_write_data_bytes("GB_FLASH_WRITE_64BYTE_PULSE_RESET", data)
|
||||
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GB_FLASH_WRITE_64BYTE_PULSE_RESET"], data)
|
||||
elif len(data) == 64:
|
||||
self.gbx_flash_write_data_bytes("GB_FLASH_WRITE_64BYTE", data)
|
||||
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GB_FLASH_WRITE_64BYTE"], data)
|
||||
elif len(data) == 256:
|
||||
self.gbx_flash_write_data_bytes("GB_FLASH_WRITE_UNBUFFERED_256BYTE", data)
|
||||
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GB_FLASH_WRITE_UNBUFFERED_256BYTE"], data)
|
||||
ack = self.wait_for_ack()
|
||||
|
||||
currAddr += len(data)
|
||||
@@ -1650,9 +1698,9 @@ class GbxDevice:
|
||||
skipping = True
|
||||
else:
|
||||
if skipping:
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
skipping = False
|
||||
self.gbx_flash_write_data_bytes("GBA_FLASH_WRITE_256BYTE_SWAPPED_D0D1", data)
|
||||
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_256BYTE_SWAPPED_D0D1"], data)
|
||||
ack = self.wait_for_ack()
|
||||
currAddr += 256
|
||||
pos += 256
|
||||
@@ -1664,9 +1712,9 @@ class GbxDevice:
|
||||
skipping = True
|
||||
else:
|
||||
if skipping:
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
skipping = False
|
||||
self.gbx_flash_write_data_bytes("GBA_FLASH_WRITE_INTEL_64BYTE_WORD", data)
|
||||
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_INTEL_64BYTE_WORD"], data)
|
||||
ack = self.wait_for_ack()
|
||||
currAddr += 64
|
||||
pos += 64
|
||||
@@ -1678,9 +1726,9 @@ class GbxDevice:
|
||||
skipping = True
|
||||
else:
|
||||
if skipping:
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD['SET_START_ADDRESS'])
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
skipping = False
|
||||
self.gbx_flash_write_data_bytes("GBA_FLASH_WRITE_SHARP_64BYTE", data)
|
||||
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_SHARP_64BYTE"], data)
|
||||
ack = self.wait_for_ack()
|
||||
currAddr += 64
|
||||
pos += 64
|
||||
@@ -1697,7 +1745,7 @@ class GbxDevice:
|
||||
data = data_import[pos:pos+2]
|
||||
|
||||
if ack == False:
|
||||
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Couldn’t write {:d} bytes to flash at position 0x{:X}. Please make sure that the cartridge contacts are clean, and that the selected cartridge type and settings are correct.".format(len(data), pos), "abortable":False})
|
||||
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Couldn’t write {:d} bytes to flash at position 0x{:X}. Please make sure that the cartridge contacts are clean, and that the selected cartridge type and settings are correct.".format(len(data), pos-len(data)), "abortable":False})
|
||||
return False
|
||||
else:
|
||||
self.SetProgress({"action":"WRITE", "bytes_added":len(data), "skipping":skipping})
|
||||
@@ -1717,7 +1765,6 @@ class GbxDevice:
|
||||
rom_size = len(data_import)
|
||||
buffer_len = 0x1000
|
||||
if self.MODE == "DMG":
|
||||
mbc = 5
|
||||
if fast_read_mode:
|
||||
buffer_len = 0x4000
|
||||
self.FAST_READ = True
|
||||
@@ -1748,7 +1795,7 @@ class GbxDevice:
|
||||
if bank > 0:
|
||||
startAddr = bank_size
|
||||
endAddr = startAddr + bank_size
|
||||
self.SetBankROM(bank, mbc)
|
||||
self.SetBankROM(bank, mbc=mbc, bank_count=bank_count)
|
||||
|
||||
for currAddr in range(startAddr, endAddr, buffer_len):
|
||||
if self.CANCEL:
|
||||
@@ -1786,4 +1833,7 @@ class GbxDevice:
|
||||
verified = True
|
||||
|
||||
self.POS = 0
|
||||
if self.MODE == "DMG":
|
||||
self.SetBankROM(0, mbc=mbc, bank_count=bank_count)
|
||||
|
||||
self.SetProgress({"action":"FINISHED", "verified":verified})
|
||||
|
||||
Binary file not shown.
@@ -29,6 +29,7 @@ by Lesserkuma
|
||||
|
||||
- BUNG Doctor GB Card 64M
|
||||
- DIY cart with AM29F016/AM29F016B
|
||||
- DIY cart with AT49F040
|
||||
- GB Smart 32M
|
||||
- insideGadgets 32 KB
|
||||
- insideGadgets 512 KB
|
||||
@@ -149,13 +150,14 @@ The author would like to thank the following very kind people for their help and
|
||||
- djedditt (testing)
|
||||
- easthighNerd (feature suggestions)
|
||||
- Frost Clock (flash chip info)
|
||||
- howie0210 (flash chip info)
|
||||
- Icesythe7 (feature suggestions)
|
||||
- JFox (help with properly packaging the app for pip)
|
||||
- julgr (macOS help, testing)
|
||||
- litlemoran (flash chip info)
|
||||
- LovelyA72 (flash chip info)
|
||||
- LucentW (flash chip info, testing)
|
||||
- marv17 (flash chip info, testing, feature suggestions)
|
||||
- marv17 (flash chip info, testing, bug reports, feature suggestions)
|
||||
- Paradoxical (flash chip info)
|
||||
- RevZ (Linux help, testing, bug reports, flash chip info)
|
||||
- Super Maker (flash chip info, testing)
|
||||
@@ -264,3 +266,8 @@ The author would like to thank the following very kind people for their help and
|
||||
- Added a warning for very old reproduction cartridges with DRM that show “YJencrypted” as their game title *(thanks Super Maker)*
|
||||
- Added a firmware check when writing to cartridges with flash chips manufactured by Sharp (unsupported by GBxCart RW firmware R25)
|
||||
- Added optional verification of written data after ROM flashing *(thanks marv17 for the suggestion)*
|
||||
|
||||
### v1.2 (released 2021-01-16)
|
||||
- Fixed a bug introduced in v1.1 that broke MBC3 handling *(thanks marv17 for reporting)*
|
||||
- Will now default back to 5V for Game Boy cartridges after unsuccessful flash chip auto-detection
|
||||
- Added support for DIY carts with the AT49F040 flash chip *(thanks howie0210)*
|
||||
|
||||
2
setup.py
2
setup.py
@@ -4,7 +4,7 @@ with open("README.md", "r", encoding="utf-8") as fh: long_description = fh.read(
|
||||
|
||||
setuptools.setup(
|
||||
name="FlashGBX",
|
||||
version="1.1",
|
||||
version="1.2",
|
||||
author="Lesserkuma",
|
||||
description="A GUI application that can read and write Game Boy and Game Boy Advance cartridge data. Currently supports the GBxCart RW hardware device by insideGadgets.",
|
||||
url="https://github.com/lesserkuma/FlashGBX",
|
||||
|
||||
Reference in New Issue
Block a user