mirror of
https://github.com/lesserkuma/FlashGBX.git
synced 2026-04-24 23:37:34 -05:00
1.4.1
This commit is contained in:
parent
53dcb072d7
commit
1473474a91
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
ko_fi: lesserkuma
|
||||
|
|
@ -161,6 +161,8 @@ def main(portableMode=False):
|
|||
try:
|
||||
from . import FlashGBX_GUI
|
||||
app = FlashGBX_GUI.FlashGBX_GUI(args)
|
||||
except ModuleNotFoundError:
|
||||
app = None
|
||||
except:
|
||||
exc = traceback.format_exc()
|
||||
app = None
|
||||
|
|
@ -168,9 +170,9 @@ def main(portableMode=False):
|
|||
if app is None:
|
||||
from . import FlashGBX_CLI
|
||||
if args["argparsed"].action is None:
|
||||
parser.print_help()
|
||||
print("\n\n{:s}ERROR: GUI mode couldn’t be launched, but the application can be run in CLI mode.\n Command line switches are explained above.{:s}\n".format(Util.ANSI.RED, Util.ANSI.RESET))
|
||||
if exc is not None: print("{:s}{:s}{:s}".format(Util.ANSI.YELLOW, exc, Util.ANSI.RESET))
|
||||
parser.print_help()
|
||||
print("\n\n{:s}NOTE: GUI mode couldn’t be launched, but the application can be run in CLI mode.\n Optional command line switches are explained above.{:s}\n".format(Util.ANSI.RED, Util.ANSI.RESET))
|
||||
|
||||
print("Now running in CLI mode.\n")
|
||||
app = FlashGBX_CLI.FlashGBX_CLI(args)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
CONFIG_PATH = ""
|
||||
TBPROG = None # Windows 7+ Taskbar Progress Bar
|
||||
PROGRESS = None
|
||||
STATUS = {}
|
||||
|
||||
def __init__(self, args):
|
||||
QtWidgets.QWidget.__init__(self)
|
||||
|
|
@ -697,7 +698,10 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
if not dontShowAgain:
|
||||
msgbox.exec()
|
||||
dontShowAgain = cb.isChecked()
|
||||
elif "DMG-MMSA-JPN" in self.cmbDMGCartridgeTypeResult.currentText():
|
||||
elif "dmg-mmsa-jpn" in self.STATUS["cart_type"] and "operation" in self.STATUS and self.STATUS["operation"] == "GBMEMORY_INITIAL_DUMP":
|
||||
# todo
|
||||
self.STATUS["operation"] = None
|
||||
elif "dmg-mmsa-jpn" in self.STATUS["cart_type"]:
|
||||
self.lblHeaderROMChecksumResult.setText("0x{:04X}".format(self.CONN.INFO["rom_checksum_calc"]))
|
||||
self.lblStatus4a.setText("Done!")
|
||||
msgbox.setText("The ROM backup is complete!")
|
||||
|
|
@ -875,15 +879,14 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
cart_type = self.CartridgeTypeAutoDetect()
|
||||
if (cart_type == 1): cart_type = 0
|
||||
self.cmbDMGCartridgeTypeResult.setCurrentIndex(cart_type)
|
||||
self.STATUS["cart_type"] = cart_types[1][index]
|
||||
elif cart_types[1][index] == "RETAIL": # special keyword
|
||||
pass
|
||||
else:
|
||||
for i in range(0, len(Util.DMG_Header_ROM_Sizes_Flasher_Map)):
|
||||
if cart_types[1][index]["flash_size"] == (Util.DMG_Header_ROM_Sizes_Flasher_Map[i] * 0x4000):
|
||||
self.cmbHeaderROMSizeResult.setCurrentIndex(i)
|
||||
|
||||
#if "DMG-MMSA-JPN" in cart_types[0][index]:
|
||||
# self.cmbHeaderFeaturesResult.setCurrentIndex(list(Util.DMG_Header_Features.keys()).index(0x105))
|
||||
self.STATUS["cart_type"] = cart_types[1][index]
|
||||
|
||||
elif self.CONN.GetMode() == "AGB":
|
||||
cart_types = self.CONN.GetSupportedCartridgesAGB()
|
||||
|
|
@ -895,6 +898,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
pass
|
||||
else:
|
||||
self.cmbAGBHeaderROMSizeResult.setCurrentIndex(Util.AGB_Header_ROM_Sizes_Map.index(cart_types[1][index]["flash_size"]))
|
||||
self.STATUS["cart_type"] = cart_types[1][index]
|
||||
|
||||
def BackupROM(self):
|
||||
if not self.CheckDeviceAlive(): return
|
||||
|
|
@ -931,7 +935,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
if last_dir is None: last_dir = QtCore.QStandardPaths.writableLocation(QtCore.QStandardPaths.DocumentsLocation)
|
||||
path = self.lblAGBHeaderTitleResult.text().strip().encode('ascii', 'ignore').decode('ascii') + "_" + self.lblAGBHeaderCodeResult.text().strip().encode('ascii', 'ignore').decode('ascii')
|
||||
if path == "_": path = self.lblAGBHeaderCodeResult.text().strip().encode('ascii', 'ignore').decode('ascii')
|
||||
if path == "" or path == "(No ROM data detected)": path = "ROM"
|
||||
if path == "" or path.startswith("(No ROM data detected)"): path = "ROM"
|
||||
path = re.sub(r"[<>:\"/\\|\?\*]", "_", path)
|
||||
rom_size = Util.AGB_Header_ROM_Sizes_Map[self.cmbAGBHeaderROMSizeResult.currentIndex()]
|
||||
path = path + ".gba"
|
||||
|
|
@ -945,7 +949,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
self.lblAGBHeaderROMChecksumResult.setStyleSheet(self.lblHeaderCGBResult.styleSheet())
|
||||
|
||||
self.CONN.BackupROM(fncSetProgress=self.PROGRESS.SetProgress, path=path, mbc=mbc, rom_banks=rom_banks, agb_rom_size=rom_size, fast_read_mode=fast_read_mode, cart_type=cart_type)
|
||||
|
||||
|
||||
def FlashROM(self, dpath=""):
|
||||
if not self.CheckDeviceAlive(): return
|
||||
path = ""
|
||||
|
|
@ -1092,7 +1096,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
if last_dir is None: last_dir = QtCore.QStandardPaths.writableLocation(QtCore.QStandardPaths.DocumentsLocation)
|
||||
path = self.lblAGBHeaderTitleResult.text().strip().encode('ascii', 'ignore').decode('ascii') + "_" + self.lblAGBHeaderCodeResult.text().strip().encode('ascii', 'ignore').decode('ascii')
|
||||
if path == "_": path = self.lblAGBHeaderCodeResult.text().strip().encode('ascii', 'ignore').decode('ascii')
|
||||
if path == "" or path == "(No ROM data detected)": path = "ROM"
|
||||
if path == "" or path.startswith("(No ROM data detected)"): path = "ROM"
|
||||
mbc = 0
|
||||
save_type = self.cmbAGBSaveTypeResult.currentIndex()
|
||||
if save_type == 0:
|
||||
|
|
@ -1176,8 +1180,9 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
|
||||
rtc = False
|
||||
# RTC of TAMA5, HuC-3
|
||||
if (features == 0xFD and (filesize == save_type + 0x18 or erase)) or \
|
||||
(features == 0xFE and (filesize == save_type + 0xC or erase)): #or (features == 0x10 and filesize == save_type + 0x30 or erase):
|
||||
if self.CONN.GetMode() == "DMG" and \
|
||||
((features == 0xFD and (filesize == save_type + 0x18 or erase)) or \
|
||||
(features == 0xFE and (filesize == save_type + 0xC or erase))): #or (features == 0x10 and filesize == save_type + 0x30 or erase):
|
||||
answer = QtWidgets.QMessageBox.question(self, "{:s} {:s}".format(APPNAME, VERSION), "Do you want the Real Time Clock register values to be also written?", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Yes)
|
||||
if answer == QtWidgets.QMessageBox.Cancel: return
|
||||
rtc = (answer == QtWidgets.QMessageBox.Yes)
|
||||
|
|
@ -1276,6 +1281,10 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
self.DisconnectDevice()
|
||||
return False
|
||||
|
||||
if self.CONN.CheckROMStable() is False:
|
||||
QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), "Unstable ROM reading detected. Please make sure you selected the correct mode and that the cartridge contacts are clean.", QtWidgets.QMessageBox.Ok)
|
||||
return
|
||||
|
||||
if self.CONN.GetMode() == "DMG":
|
||||
self.cmbHeaderFeaturesResult.clear()
|
||||
self.cmbHeaderFeaturesResult.addItems(list(Util.DMG_Header_Features.values()))
|
||||
|
|
@ -1343,11 +1352,11 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
else:
|
||||
self.lblHeaderTitleResult.setStyleSheet(self.lblHeaderCGBResult.styleSheet())
|
||||
if data['logo_correct'] and not self.CONN.IsSupportedMbc(data["features_raw"]):
|
||||
QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), "This cartridge uses a Memory Bank Controller that may not be completely supported yet. A future version of {:s} may add support for it.".format(APPNAME), QtWidgets.QMessageBox.Ok)
|
||||
QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), "This cartridge uses a Memory Bank Controller that may not be completely supported yet. A future version of {:s} or the {:s} device firmware may add support for it.".format(APPNAME, self.CONN.GetName()), QtWidgets.QMessageBox.Ok)
|
||||
if data['logo_correct'] and data['game_title'] == "NP M-MENU MENU":
|
||||
cart_types = self.CONN.GetSupportedCartridgesDMG()
|
||||
for i in range(0, len(cart_types[0])):
|
||||
if "DMG-MMSA-JPN" in cart_types[0][i]:
|
||||
if "dmg-mmsa-jpn" in cart_types[1][i]:
|
||||
self.cmbDMGCartridgeTypeResult.setCurrentIndex(i)
|
||||
|
||||
self.grpAGBCartridgeInfo.setVisible(False)
|
||||
|
|
@ -1441,10 +1450,6 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
self.grpStatus.setTitle("Transfer Status")
|
||||
self.FinishOperation()
|
||||
|
||||
if self.CONN.CheckROMStable() is False:
|
||||
QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), "Unstable ROM reading detected. Please make sure you selected the correct mode and that the cartridge contacts are clean.", QtWidgets.QMessageBox.Ok)
|
||||
return
|
||||
|
||||
if not data['logo_correct'] and data['empty'] == False:
|
||||
QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), "The Nintendo Logo check failed which usually means that the cartridge couldn’t be read correctly. Please make sure you selected the correct mode and that the cartridge contacts are clean.", QtWidgets.QMessageBox.Ok)
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@ class RomFileDMG:
|
|||
|
||||
def __init__(self, file=None):
|
||||
if isinstance(file, str):
|
||||
self.ROMFILE_PATH = file
|
||||
if self.ROMFILE_PATH != None: self.Load()
|
||||
self.Open(file)
|
||||
elif isinstance(file, bytearray):
|
||||
self.ROMFILE = file
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ from enum import Enum
|
|||
|
||||
# Common constants
|
||||
APPNAME = "FlashGBX"
|
||||
VERSION_PEP440 = "1.4"
|
||||
VERSION_PEP440 = "1.4.1"
|
||||
VERSION = "v{:s}".format(VERSION_PEP440)
|
||||
DEBUG = False
|
||||
|
||||
|
|
@ -14,7 +14,7 @@ AGB_Header_ROM_Sizes_Map = [ 0x400000, 0x800000, 0x1000000, 0x2000000, 0x4000000
|
|||
AGB_Header_Save_Types = [ "None", "4K EEPROM (512 Bytes)", "64K EEPROM (8 KB)", "256K SRAM (32 KB)", "512K SRAM (64 KB)", "1M SRAM (128 KB)", "512K FLASH (64 KB)", "1M FLASH (128 KB)" ]
|
||||
AGB_Global_CRC32 = 0
|
||||
|
||||
DMG_Header_Features = { 0x00:'None', 0x01:'MBC1', 0x02:'MBC1+SRAM', 0x03:'MBC1+SRAM+BATTERY', 0x06:'MBC2+BATTERY', 0x10:'MBC3+RTC+SRAM+BATTERY', 0x13:'MBC3+SRAM+BATTERY', 0x19:'MBC5', 0x1B:'MBC5+SRAM+BATTERY', 0x1C:'MBC5+RUMBLE', 0x1E:'MBC5+RUMBLE+SRAM+BATTERY', 0x20:'MBC6+FLASH+SRAM+BATTERY', 0x22:'MBC7+ACCELEROMETER+EEPROM', 0x101:'MBC1M', 0x103:'MBC1M+SRAM+BATTERY', 0x0B:'MMM01', 0x0D:'MMM01+SRAM+BATTERY', 0xFC:'CAMERA+SRAM+BATTERY', 0x105:'G-MMC1', 0x104:'M161', 0xFF:'HuC-1+IR+SRAM+BATTERY', 0xFE:'HuC-3+RTC+SRAM+BATTERY', 0xFD:'TAMA5+RTC+EEPROM' }
|
||||
DMG_Header_Features = { 0x00:'None', 0x01:'MBC1', 0x02:'MBC1+SRAM', 0x03:'MBC1+SRAM+BATTERY', 0x06:'MBC2+SRAM+BATTERY', 0x10:'MBC3+RTC+SRAM+BATTERY', 0x13:'MBC3+SRAM+BATTERY', 0x19:'MBC5', 0x1B:'MBC5+SRAM+BATTERY', 0x1C:'MBC5+RUMBLE', 0x1E:'MBC5+RUMBLE+SRAM+BATTERY', 0x20:'MBC6+FLASH+SRAM+BATTERY', 0x22:'MBC7+ACCELEROMETER+EEPROM', 0x101:'MBC1M', 0x103:'MBC1M+SRAM+BATTERY', 0x0B:'MMM01', 0x0D:'MMM01+SRAM+BATTERY', 0xFC:'CAMERA+SRAM+BATTERY', 0x105:'G-MMC1+SRAM+BATTERY', 0x104:'M161', 0xFF:'HuC-1+IR+SRAM+BATTERY', 0xFE:'HuC-3+RTC+SRAM+BATTERY', 0xFD:'TAMA5+RTC+EEPROM' }
|
||||
DMG_Header_ROM_Sizes = [ "32 KB", "64 KB", "128 KB", "256 KB", "512 KB", "1 MB", "2 MB", "4 MB", "8 MB" ]
|
||||
DMG_Header_ROM_Sizes_Map = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 ]
|
||||
DMG_Header_ROM_Sizes_Flasher_Map = [ 2, 4, 8, 16, 32, 64, 128, 256, 512 ] # Number of ROM banks
|
||||
|
|
@ -342,11 +342,11 @@ def ParseCFI(buffer):
|
|||
if "{:s}{:s}{:s}".format(chr(buffer[pri_address]), chr(buffer[pri_address+2]), chr(buffer[pri_address+4])) == "PRI":
|
||||
if buffer[pri_address + 0x1E] not in (0, 0xFF):
|
||||
temp = { 0x02: 'As shown', 0x03: 'Reversed' }
|
||||
info["tb_boot_sector_raw"] = buffer[0x9E]
|
||||
info["tb_boot_sector_raw"] = buffer[pri_address + 0x1E]
|
||||
try:
|
||||
info["tb_boot_sector"] = "{:s} (0x{:02X})".format(temp[buffer[0x9E]], buffer[0x9E])
|
||||
info["tb_boot_sector"] = "{:s} (0x{:02X})".format(temp[buffer[pri_address + 0x1E]], buffer[pri_address + 0x1E])
|
||||
except:
|
||||
info["tb_boot_sector"] = "0x{:02X}".format(buffer[0x9E])
|
||||
info["tb_boot_sector"] = "0x{:02X}".format(buffer[pri_address + 0x1E])
|
||||
elif "{:s}{:s}{:s}".format(chr(buffer[0x214]), chr(buffer[0x216]), chr(buffer[0x218])) == "PRI":
|
||||
pass # todo
|
||||
|
||||
|
|
|
|||
53
FlashGBX/config/fc_AGB_4050M0Y0Q0.txt
Normal file
53
FlashGBX/config/fc_AGB_4050M0Y0Q0.txt
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
{
|
||||
"type":"AGB",
|
||||
"names":[
|
||||
"4050M0Y0Q0-39VF512 with 4050M0Y0Q0"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0x8A, 0x00, 0x02, 0x89 ]
|
||||
],
|
||||
"voltage":3.3,
|
||||
"flash_size":0x2000000,
|
||||
"sector_size":[
|
||||
[0x40000, 128]
|
||||
],
|
||||
"reset_every":0x400000,
|
||||
"commands":{
|
||||
"reset":[
|
||||
[ 0, 0xFF ]
|
||||
],
|
||||
"read_identifier":[
|
||||
[ 0, 0x90 ]
|
||||
],
|
||||
"sector_erase":[
|
||||
[ "SA", 0x60 ],
|
||||
[ "SA", 0xD0 ],
|
||||
[ "SA", 0x20 ],
|
||||
[ "SA", 0xD0 ]
|
||||
],
|
||||
"sector_erase_wait_for":[
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ "SA", 0x80, 0x80 ]
|
||||
],
|
||||
"buffer_write":[
|
||||
[ "SA", 0x60 ],
|
||||
[ "SA", 0xD0 ],
|
||||
[ "SA", 0xEA ],
|
||||
[ "SA", "BS" ],
|
||||
[ "PA", "PD" ],
|
||||
[ "SA", 0xD0 ],
|
||||
[ "SA", 0xFF ]
|
||||
],
|
||||
"buffer_write_wait_for":[
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ "SA", 0x80, 0x80 ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ "SA", 0x80, 0x80 ],
|
||||
[ null, null, null ]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
],
|
||||
"voltage":3.3,
|
||||
"flash_size":0x1000000,
|
||||
"chip_erase_timeout":80,
|
||||
"chip_erase_timeout":100,
|
||||
"wait_read_status_register":true,
|
||||
"reset_every":0x400000,
|
||||
"commands":{
|
||||
|
|
|
|||
66
FlashGBX/config/fc_AGB_MSP55LV128_2.txt
Normal file
66
FlashGBX/config/fc_AGB_MSP55LV128_2.txt
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
{
|
||||
"type":"AGB",
|
||||
"names":[
|
||||
"B104 with MSP55LV128"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0x04, 0x00, 0x7E, 0x22 ]
|
||||
],
|
||||
"voltage":3.3,
|
||||
"flash_size":0x1000000,
|
||||
"sector_size":0x10000,
|
||||
"commands":{
|
||||
"reset":[
|
||||
[ 0, 0xF0 ]
|
||||
],
|
||||
"read_identifier":[
|
||||
[ 0xAAA, 0xAA ],
|
||||
[ 0x555, 0x55 ],
|
||||
[ 0xAAA, 0x90 ]
|
||||
],
|
||||
"sector_erase":[
|
||||
[ 0xAAA, 0xAA ],
|
||||
[ 0x555, 0x55 ],
|
||||
[ 0xAAA, 0x80 ],
|
||||
[ 0xAAA, 0xAA ],
|
||||
[ 0x555, 0x55 ],
|
||||
[ "SA", 0x30 ]
|
||||
],
|
||||
"sector_erase_wait_for":[
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ "SA", 0xFFFF, 0xFFFF ]
|
||||
],
|
||||
"buffer_write":[
|
||||
[ 0xAAA, 0xAA ],
|
||||
[ 0x555, 0x55 ],
|
||||
[ "SA", 0x25 ],
|
||||
[ "SA", "BS" ],
|
||||
[ "PA", "PD" ],
|
||||
[ "SA", 0x29 ]
|
||||
],
|
||||
"buffer_write_wait_for":[
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ "SA", "PD", 0xFFFF ]
|
||||
],
|
||||
"single_write":[
|
||||
[ 0xAAA, 0xAA ],
|
||||
[ 0x555, 0x55 ],
|
||||
[ 0xAAA, 0xA0 ],
|
||||
[ "PA", "PD" ]
|
||||
],
|
||||
"single_write_wait_for":[
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
"flash_ids":[
|
||||
[ 0xC2, 0x89, 0xC2, 0xFF ]
|
||||
],
|
||||
"dmg-mmsa-jpn":true,
|
||||
"voltage":5,
|
||||
"flash_size":0x100000,
|
||||
"start_addr":0,
|
||||
|
|
@ -15,6 +16,8 @@
|
|||
"hidden_sector_size":128,
|
||||
"commands":{
|
||||
"reset":[
|
||||
[ 0x2100, 0x01 ],
|
||||
|
||||
[ 0x120, 0x02 ],
|
||||
|
||||
[ 0x120, 0x0F ],
|
||||
|
|
@ -25,6 +28,7 @@
|
|||
|
||||
[ 0x120, 0x04 ],
|
||||
[ 0x13F, 0xA5 ],
|
||||
|
||||
[ 0x120, 0x08 ],
|
||||
[ 0x13F, 0xA5 ]
|
||||
],
|
||||
|
|
@ -35,9 +39,13 @@
|
|||
[ 0x13F, 0xA5, 1 ],
|
||||
|
||||
[ 0x120, 0x11, 1 ],
|
||||
[ 0x13F, 0xA5, 1 ]
|
||||
[ 0x13F, 0xA5, 1 ],
|
||||
|
||||
[ 0x2100, 0x01, 1 ]
|
||||
],
|
||||
"read_identifier":[
|
||||
[ 0x2100, 0x01 ],
|
||||
|
||||
[ 0x120, 0x0F ],
|
||||
[ 0x125, 0x55 ],
|
||||
[ 0x126, 0x55 ],
|
||||
|
|
@ -57,6 +65,8 @@
|
|||
[ 0x13F, 0xA5 ]
|
||||
],
|
||||
"read_hidden_sector":[
|
||||
[ 0x2100, 0x01 ],
|
||||
|
||||
[ 0x120, 0x0F ],
|
||||
[ 0x125, 0x55 ],
|
||||
[ 0x126, 0x55 ],
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ from . import Util
|
|||
class GbxDevice:
|
||||
DEVICE_NAME = "GBxCart RW"
|
||||
DEVICE_MIN_FW = 19
|
||||
DEVICE_MAX_FW = 26
|
||||
DEVICE_MAX_FW = 27
|
||||
|
||||
DEVICE_CMD = {
|
||||
"CART_MODE":'C',
|
||||
|
|
@ -26,6 +26,8 @@ class GbxDevice:
|
|||
"SET_BANK_WITH_CS":'H',
|
||||
"RESET_MBC":'-',
|
||||
"GB_CART_MODE":'G',
|
||||
"READ_EEPROM_MBC7":'~',
|
||||
"WRITE_EEPROM_MBC7":'#',
|
||||
# GBA defines/commands
|
||||
"EEPROM_NONE":0,
|
||||
"EEPROM_4KBIT":1,
|
||||
|
|
@ -81,6 +83,7 @@ class GbxDevice:
|
|||
"GBA_FLASH_WRITE_BUFFERED_256BYTE":'c',
|
||||
"GBA_FLASH_WRITE_BUFFERED_256BYTE_SWAPPED_D0D1":'d',
|
||||
"GBA_FLASH_WRITE_INTEL_64BYTE":'l',
|
||||
"GBA_FLASH_WRITE_INTEL_1024BYTE_4050":'K',
|
||||
"GBA_FLASH_WRITE_INTEL_256BYTE":';',
|
||||
"GBA_FLASH_WRITE_INTEL_64BYTE_WORD":'u',
|
||||
"GBA_FLASH_WRITE_INTEL_INTERLEAVED_256BYTE":'v',
|
||||
|
|
@ -261,10 +264,13 @@ class GbxDevice:
|
|||
return ["DMG", "AGB"]
|
||||
|
||||
def IsSupportedMbc(self, mbc):
|
||||
return mbc in ( 0x00, 0x01, 0x02, 0x03, 0x06, 0x0B, 0x0D, 0x10, 0x13, 0x19, 0x1B, 0x1C, 0x1E, 0xFC, 0xFD, 0xFE, 0xFF, 0x101, 0x103, 0x105 )
|
||||
if (int(self.FW[0]) >= 26):
|
||||
return mbc in ( 0x00, 0x01, 0x02, 0x03, 0x06, 0x0B, 0x0D, 0x10, 0x13, 0x19, 0x1B, 0x1C, 0x1E, 0xFC, 0xFD, 0xFE, 0xFF, 0x101, 0x103, 0x104, 0x105 )
|
||||
else:
|
||||
return mbc in ( 0x00, 0x01, 0x02, 0x03, 0x06, 0x10, 0x13, 0x19, 0x1B, 0x1C, 0x1E, 0xFC, 0xFE, 0xFF, 0x101, 0x103, 0x105 )
|
||||
|
||||
def IsSupported3dMemory(self):
|
||||
return False #int(self.FW[0]) >= 27
|
||||
return False
|
||||
|
||||
def IsClkConnected(self):
|
||||
return False
|
||||
|
|
@ -510,6 +516,7 @@ class GbxDevice:
|
|||
buffer = self.DEVICE_CMD["GBA_FLASH_CART_WRITE_BYTE"] + data + '\x00'
|
||||
self.write(buffer)
|
||||
time.sleep(0.001)
|
||||
|
||||
ack = self.wait_for_ack()
|
||||
if ack == False:
|
||||
self.CANCEL = True
|
||||
|
|
@ -522,6 +529,7 @@ class GbxDevice:
|
|||
self.write(buffer)
|
||||
buffer = format(data, 'x') + '\x00'
|
||||
self.write(buffer)
|
||||
|
||||
ack = self.wait_for_ack()
|
||||
if ack == False:
|
||||
self.CANCEL = True
|
||||
|
|
@ -539,11 +547,11 @@ class GbxDevice:
|
|||
cmd = self.DEVICE_CMD["SET_BANK_WITH_CS"]
|
||||
else:
|
||||
cmd = self.DEVICE_CMD["SET_BANK"]
|
||||
|
||||
address = format(address, 'x')
|
||||
buffer = cmd + address + '\x00'
|
||||
self.write(buffer)
|
||||
time.sleep(0.005)
|
||||
|
||||
bank = format(bank, 'd')
|
||||
buffer = cmd + bank + '\x00'
|
||||
self.write(buffer)
|
||||
|
|
@ -555,7 +563,8 @@ class GbxDevice:
|
|||
self.write(buffer)
|
||||
|
||||
def set_number(self, number, command):
|
||||
buffer = format(command, 's') + format(int(number), 'x') + '\x00'
|
||||
number = int(number)
|
||||
buffer = format(command, 's') + format(number, 'x') + '\x00'
|
||||
self.write(buffer)
|
||||
time.sleep(0.005)
|
||||
|
||||
|
|
@ -573,8 +582,10 @@ class GbxDevice:
|
|||
time.sleep(0.2)
|
||||
|
||||
def SetBankROM(self, bank, mbc=0, bank_count=0):
|
||||
dprint("SetBankROM(bank={:d}, mbc={:X}, bank_count={:d})".format(bank, int(mbc), bank_count))
|
||||
if mbc == 0 and bank_count == 0: mbc = 0x19 # MBC5
|
||||
dprint("SetBankROM(bank={:d}, mbc=0x{:X}, bank_count={:d})".format(bank, int(mbc), bank_count))
|
||||
if mbc == 0 and bank_count == 0:
|
||||
mbc = 0x19 # MBC5
|
||||
|
||||
if mbc in (0x01, 0x02, 0x03): # MBC1
|
||||
dprint("└[MBC1] 0x6000=0x00, 0x4000=0x{:X}, 0x2000=0x{:X}".format(bank >> 5, bank & 0x1F))
|
||||
self.cart_write(0x6000, 0)
|
||||
|
|
@ -613,8 +624,13 @@ class GbxDevice:
|
|||
self.cart_write(0xA001, Util.TAMA5_REG.ROM_BANK_H.value, cs=True) # ROM bank (high)
|
||||
self.cart_write(0xA000, (bank >> 4) & 0x0F, cs=True)
|
||||
elif mbc == 0xFF: # HuC-1
|
||||
dprint("└[HuC-1] 0x2000=0x{:X}".format(bank & 0xFF))
|
||||
dprint("└[HuC-1] 0x2000=0x{:X}".format(bank & 0x3F))
|
||||
self.cart_write(0x2000, (bank & 0x3F))
|
||||
elif mbc == 0x104: # M161
|
||||
dprint("└[M161] RESET_MBC, 0x4000=0x{:X}".format(bank & 0x7))
|
||||
self.set_mode(self.DEVICE_CMD['RESET_MBC'])
|
||||
self.wait_for_ack()
|
||||
self.cart_write(0x4000, (bank & 0x7))
|
||||
else: # MBC2, MBC3 and others
|
||||
dprint("└[MBCx] 0x2100=0x{:X}".format(bank & 0xFF))
|
||||
self.cart_write(0x2100, (bank & 0xFF))
|
||||
|
|
@ -949,8 +965,11 @@ class GbxDevice:
|
|||
if self.MODE == "DMG":
|
||||
self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
|
||||
time.sleep(0.1)
|
||||
self.set_mode(self.DEVICE_CMD['RESET_MBC'])
|
||||
self.wait_for_ack()
|
||||
# Firmware check R26+
|
||||
if (int(self.FW[0]) >= 26):
|
||||
self.set_mode(self.DEVICE_CMD['RESET_MBC'])
|
||||
self.wait_for_ack()
|
||||
# Firmware check R26+
|
||||
|
||||
header = self.ReadROM(0, 0x180)
|
||||
|
||||
|
|
@ -1032,12 +1051,11 @@ class GbxDevice:
|
|||
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"A firmware update is required to access this cartridge. Please update the firmware of your GBxCart RW device to version R26 or higher.", "abortable":False})
|
||||
return False
|
||||
# Firmware check R26+
|
||||
# Firmware check R27+
|
||||
# Firmware check
|
||||
if "agb_rom_size" in args and args["agb_rom_size"] == 64 * 1024 * 1024: # 3D Memory
|
||||
if (int(self.FW[0]) < 27):
|
||||
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"A future firmware update is required to access this cartridge. Please look for updates of FlashGBX and GBxCart RW firmware.", "abortable":False})
|
||||
return False
|
||||
# Firmware check R27+
|
||||
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"A future firmware update is required to access this cartridge. Please look out for updates of FlashGBX and GBxCart RW firmware.", "abortable":False})
|
||||
return False
|
||||
# Firmware check
|
||||
|
||||
# Enable TAMA5
|
||||
if self.MODE == "DMG" and "mbc" in args and args["mbc"] == 0xFD:
|
||||
|
|
@ -1054,7 +1072,7 @@ class GbxDevice:
|
|||
if lives < 0:
|
||||
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"The TAMA5 cartridge doesn’t seem to respond. Please try again.", "abortable":False})
|
||||
return False
|
||||
|
||||
|
||||
# main work starts here
|
||||
self.INFO["last_action"] = mode
|
||||
self.FAST_READ = False
|
||||
|
|
@ -1065,6 +1083,11 @@ class GbxDevice:
|
|||
supported_carts = list(self.SUPPORTED_CARTS['DMG'].values())
|
||||
mbc = args["mbc"]
|
||||
bank_count = args["rom_banks"]
|
||||
|
||||
if mbc == 0x104: # M161
|
||||
bank_count = 8
|
||||
bank_size = 0x8000
|
||||
|
||||
if fast_read_mode:
|
||||
buffer_len = 0x4000
|
||||
self.FAST_READ = True
|
||||
|
|
@ -1101,7 +1124,7 @@ class GbxDevice:
|
|||
if flashcart_meta in ("RETAIL", "AUTODETECT"): flashcart_meta = False
|
||||
else:
|
||||
flashcart_meta = args["cart_type"]
|
||||
|
||||
|
||||
if flashcart_meta is not False and "unlock_before_rom_dump" in flashcart_meta and flashcart_meta["unlock_before_rom_dump"] is True:
|
||||
# Unlock Flash
|
||||
if "unlock" in flashcart_meta["commands"]:
|
||||
|
|
@ -1145,6 +1168,9 @@ class GbxDevice:
|
|||
if mbc in (0x0B, 0x0D) and bank % 0x20 == 0: # MMM01
|
||||
startAddr = 0
|
||||
endAddr = bank_size
|
||||
elif mbc == 0x104: # M161
|
||||
startAddr = 0
|
||||
endAddr = 0x8000
|
||||
|
||||
self.SetBankROM(bank, mbc)
|
||||
|
||||
|
|
@ -1255,8 +1281,28 @@ class GbxDevice:
|
|||
if mbc == 0xFD: # TAMA5
|
||||
if args["rtc"]: save_size += 0x10
|
||||
elif mbc == 0x22: # MBC7 EEPROM
|
||||
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Save data handling is not supported yet for this cartridge type.", "abortable":False})
|
||||
return False
|
||||
transfer_size = 32
|
||||
self.cart_write(0x4000, 0x40)
|
||||
if mode == 3: # Restore
|
||||
self.cart_write(0xA080, 0x00) # init eeprom
|
||||
self.cart_write(0xA080, 0x80)
|
||||
|
||||
self.cart_write(0xA080, 0x80) # init command
|
||||
self.cart_write(0xA080, 0xC0)
|
||||
self.cart_write(0xA080, 0x82)
|
||||
self.cart_write(0xA080, 0xC2)
|
||||
|
||||
self.cart_write(0xA080, 0x80) # write enable command
|
||||
self.cart_write(0xA080, 0xC0)
|
||||
self.cart_write(0xA080, 0x80)
|
||||
self.cart_write(0xA080, 0xC0)
|
||||
self.cart_write(0xA080, 0x82)
|
||||
self.cart_write(0xA080, 0xC2)
|
||||
self.cart_write(0xA080, 0x82)
|
||||
self.cart_write(0xA080, 0xC2)
|
||||
for _ in range(0, 6):
|
||||
self.cart_write(0xA080, 0x80)
|
||||
self.cart_write(0xA080, 0xC0)
|
||||
|
||||
if transfer_size >= save_size:
|
||||
transfer_size = save_size
|
||||
|
|
@ -1305,19 +1351,18 @@ class GbxDevice:
|
|||
bank_count = 2
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
# Get Save Flash Manufacturer
|
||||
maker_id = None
|
||||
if save_type == 6 or save_type == 7:
|
||||
maker_id = self.ReadFlashSaveMakerID()
|
||||
if maker_id == "ATMEL":
|
||||
print("NOTE: For save data, this cartridge uses an ATMEL chip which is untested.")
|
||||
if maker_id == "ATMEL" and mode == 3:
|
||||
transfer_size = 128
|
||||
elif maker_id == "SANYO":
|
||||
if int(self.FW[0]) < 24:
|
||||
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"A firmware update is required to access this cartridge. Please update the firmware of your GBxCart RW device to version R24 or higher.", "abortable":False})
|
||||
return False
|
||||
|
||||
|
||||
# Prepare some stuff
|
||||
if mode == 2: # Backup
|
||||
try:
|
||||
|
|
@ -1349,7 +1394,8 @@ class GbxDevice:
|
|||
if self.MODE == "DMG":
|
||||
endAddr = startAddr + bank_size
|
||||
if endAddr > (startAddr + save_size): endAddr = startAddr + save_size
|
||||
self.SetBankRAM(bank, mbc)
|
||||
if mbc != 0x22: # exclude MBC7
|
||||
self.SetBankRAM(bank, mbc)
|
||||
|
||||
elif self.MODE == "AGB":
|
||||
endAddr = startAddr + min(save_size, bank_size)
|
||||
|
|
@ -1382,6 +1428,12 @@ class GbxDevice:
|
|||
if self.MODE == "DMG":
|
||||
if mbc == 0xFD: # TAMA5
|
||||
buffer = self.ReadRAM_TAMA5(rtc=args["rtc"])
|
||||
elif mbc == 0x22: # MBC7 EEPROM
|
||||
self.set_mode(self.DEVICE_CMD["READ_EEPROM_MBC7"])
|
||||
buffer = self.read(length=buffer_len, last=True, ask_next_bytes=False)
|
||||
if buffer == False:
|
||||
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Backup failed, please try again.", "abortable":False})
|
||||
return False
|
||||
else:
|
||||
buffer = self.ReadROM(currAddr, buffer_len)
|
||||
elif self.MODE == "AGB":
|
||||
|
|
@ -1399,6 +1451,9 @@ class GbxDevice:
|
|||
if self.MODE == "DMG":
|
||||
if mbc == 0xFD: # TAMA5
|
||||
self.WriteRAM_TAMA5(data, rtc=args["rtc"])
|
||||
elif mbc == 0x22: # MBC7 EEPROM
|
||||
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["WRITE_EEPROM_MBC7"], data)
|
||||
self.wait_for_ack()
|
||||
else:
|
||||
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["WRITE_RAM"], data)
|
||||
self.wait_for_ack()
|
||||
|
|
@ -1422,7 +1477,7 @@ class GbxDevice:
|
|||
time.sleep(0.01)
|
||||
lives -= 1
|
||||
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})
|
||||
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Accessing the save data flash chip failed. Please make sure you selected the correct save type. If you are using a reproduction cartridge, check if it really is equipped with a flash chip for save data, or if it uses SRAM for save data instead.", "abortable":False})
|
||||
return False
|
||||
self.set_number(currAddr, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
|
||||
|
|
@ -1441,8 +1496,30 @@ class GbxDevice:
|
|||
self.INFO["transferred"] = pos
|
||||
|
||||
if self.MODE == "DMG":
|
||||
# MBC7 EEPROM write end
|
||||
if mode == 3 and mbc == 0x22:
|
||||
self.cart_write(0xA080, 0x00) # init eeprom
|
||||
self.cart_write(0xA080, 0x80)
|
||||
|
||||
self.cart_write(0xA080, 0x80) # init command
|
||||
self.cart_write(0xA080, 0xC0)
|
||||
self.cart_write(0xA080, 0x82)
|
||||
self.cart_write(0xA080, 0xC2)
|
||||
|
||||
self.cart_write(0xA080, 0x80) # disable write command
|
||||
self.cart_write(0xA080, 0xC0)
|
||||
self.cart_write(0xA080, 0x80)
|
||||
self.cart_write(0xA080, 0xC0)
|
||||
self.cart_write(0xA080, 0x80)
|
||||
self.cart_write(0xA080, 0xC0)
|
||||
self.cart_write(0xA080, 0x80)
|
||||
self.cart_write(0xA080, 0xC0)
|
||||
for _ in range(0, 6):
|
||||
self.cart_write(0xA080, 0x80)
|
||||
self.cart_write(0xA080, 0xC0)
|
||||
|
||||
# RTC for MBC3+RTC+SRAM+BATTERY
|
||||
if mbc == 0x10 and args["rtc"]:
|
||||
elif mbc == 0x10 and args["rtc"]:
|
||||
buffer = bytearray()
|
||||
self.cart_write(0x6000, 0)
|
||||
self.cart_write(0x6000, 1)
|
||||
|
|
@ -1622,6 +1699,11 @@ class GbxDevice:
|
|||
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Support for this flash cartridge type has been temporarily dropped with GBxCart RW firmware version R25. You can either downgrade to firmware version R24, or look for a newer firmware and FlashGBX version.", "abortable":False})
|
||||
return False
|
||||
# Firmware check R25+
|
||||
# Firmware check
|
||||
if self.MODE == "AGB" and "buffer_write" in flashcart_meta["commands"] and flashcart_meta["commands"]["buffer_write"] == [['SA', 0x60], ['SA', 0xD0], ['SA', 0xEA], ['SA', 'BS'], ['PA', 'PD'], ['SA', 0xD0], ['SA', 0xFF]]:
|
||||
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"A future firmware update is required to access this cartridge. Please look out for updates of FlashGBX and GBxCart RW firmware.", "abortable":False})
|
||||
return False
|
||||
# Firmware check
|
||||
|
||||
# Set Voltage
|
||||
if voltage == 3.3:
|
||||
|
|
@ -1937,7 +2019,7 @@ class GbxDevice:
|
|||
currAddr += 256
|
||||
pos += 256
|
||||
|
||||
# 256L30B etc.
|
||||
# 256L30B, M36L0R etc.
|
||||
elif flashcart_meta["commands"]["buffer_write"] == [['SA', 0x60], ['SA', 0xD0], ['SA', 0xE8], ['SA', 'BS'], ['PA', 'PD'], ['SA', 0xD0], ['SA', 0xFF]]:
|
||||
if "single_write_7FC0_to_7FFF" in flashcart_meta and flashcart_meta["single_write_7FC0_to_7FFF"] and int(currAddr % 0x8000) in range(0x7FC0, 0x7FFF):
|
||||
for i in range(0, len(flashcart_meta["commands"]["single_write"])):
|
||||
|
|
@ -2025,6 +2107,24 @@ class GbxDevice:
|
|||
currAddr += 256
|
||||
pos += 256
|
||||
|
||||
# 4050M0Y0Q0 etc.
|
||||
elif flashcart_meta["commands"]["buffer_write"] == [['SA', 0x60], ['SA', 0xD0], ['SA', 0xEA], ['SA', 'BS'], ['PA', 'PD'], ['SA', 0xD0], ['SA', 0xFF]]:
|
||||
data = data_import[pos:pos+1024]
|
||||
if data == bytearray([0xFF] * len(data)):
|
||||
skipping = True
|
||||
else:
|
||||
if skipping:
|
||||
self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
|
||||
skipping = False
|
||||
|
||||
for i in range(0, 4):
|
||||
buffer = data[256*i:256*i+256]
|
||||
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_INTEL_1024BYTE_4050"], buffer)
|
||||
ack = self.wait_for_ack()
|
||||
self.write('0')
|
||||
currAddr += 1024
|
||||
pos += 1024
|
||||
|
||||
else: # TODO
|
||||
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Buffer writing for this flash chip is not implemented yet.\n\n{:s}".format(str(flashcart_meta["commands"]["buffer_write"])), "abortable":False})
|
||||
return False
|
||||
|
|
@ -2096,7 +2196,7 @@ class GbxDevice:
|
|||
ack = self.wait_for_ack()
|
||||
currAddr += 64
|
||||
pos += 64
|
||||
|
||||
|
||||
else: # super slow -- for testing purposes only!
|
||||
for i in range(0, len(flashcart_meta["commands"]["single_write"])):
|
||||
addr = flashcart_meta["commands"]["single_write"][i][0]
|
||||
|
|
@ -2104,6 +2204,24 @@ class GbxDevice:
|
|||
if addr == "PA": addr = int(currAddr)
|
||||
if data == "PD": data = struct.unpack('H', data_import[pos:pos+2])[0]
|
||||
self.gbx_flash_write_address_byte(addr, data)
|
||||
|
||||
if flashcart_meta["commands"]["single_write_wait_for"][i][0] != None:
|
||||
addr = flashcart_meta["commands"]["single_write_wait_for"][i][0]
|
||||
data = flashcart_meta["commands"]["single_write_wait_for"][i][1]
|
||||
if addr == "SA": addr = currAddr
|
||||
time.sleep(0.05)
|
||||
timeout = 100
|
||||
while True:
|
||||
wait_for = self.ReadROM(currAddr, 64)
|
||||
wait_for = ((wait_for[1] << 8 | wait_for[0]) & flashcart_meta["commands"]["single_write_wait_for"][i][2])
|
||||
print("SW_SR {:X}=={:X}?".format(wait_for, data))
|
||||
time.sleep(0.1)
|
||||
timeout -= 1
|
||||
if timeout < 1:
|
||||
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Writing a single word timed out. Please make sure that the cartridge contacts are clean, and that the selected cartridge type and settings are correct.", "abortable":False})
|
||||
return False
|
||||
if wait_for == data: break
|
||||
|
||||
currAddr += 2
|
||||
pos += 2
|
||||
data = data_import[pos:pos+2]
|
||||
|
|
@ -2112,7 +2230,11 @@ class GbxDevice:
|
|||
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})
|
||||
if isinstance(data, int) or data is None or data == b'':
|
||||
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"No flash commands available for this cartridge type. Please make sure that the selected cartridge type and settings are correct. ({:s})".format(str(data)), "abortable":False})
|
||||
return False
|
||||
else:
|
||||
self.SetProgress({"action":"WRITE", "bytes_added":len(data), "skipping":skipping})
|
||||
|
||||
self.SetProgress({"action":"UPDATE_POS", "pos":pos})
|
||||
time.sleep(0.5)
|
||||
|
|
|
|||
Binary file not shown.
45
README.md
45
README.md
|
|
@ -31,20 +31,19 @@ by Lesserkuma
|
|||
- MBC2
|
||||
- MBC3/MBC30
|
||||
- MBC5
|
||||
- MBC7 (ROM backup only)
|
||||
- MBC7
|
||||
- MBC1M
|
||||
- MMM01
|
||||
- Game Boy Camera
|
||||
- G-MMC1 (ROM and map backup only)
|
||||
- M161
|
||||
- HuC-1
|
||||
- HuC-3
|
||||
- TAMA5
|
||||
|
||||
- Game Boy Advance
|
||||
- All cartridges without memory mapping
|
||||
- 3D Memory (GBA Video)¹
|
||||
|
||||
¹ Preliminary support; will not work until the GBxCart RW device is updated to a future firmware version
|
||||
- 3D Memory (GBA Video)
|
||||
|
||||
### Currently supported flash cartridges
|
||||
|
||||
|
|
@ -112,6 +111,7 @@ by Lesserkuma
|
|||
- 28F256L03B-DRV with 256L30B
|
||||
- 36L0R8-39VF512 with M36L0R8060B
|
||||
- 36L0R8-39VF512 with M36L0R8060T
|
||||
- 4050M0Y0Q0-39VF512 with 4050M0Y0Q0
|
||||
- 4050_4400_4000_4350_36L0R_V5 with 4050L0YTQ2
|
||||
- 4050_4400_4000_4350_36L0R_V5 with M36L0R7050T
|
||||
- 4050_4400_4000_4350_36L0R_V5 with M36L0T8060T
|
||||
|
|
@ -125,6 +125,7 @@ by Lesserkuma
|
|||
- AGB-E05-02 with M29W128GH
|
||||
- AGB-E08-09 with 29LV128DTMC-90Q
|
||||
- AGB-SD-E05 with MSP55LV128
|
||||
- B104 with MSP55LV128
|
||||
- BX2006_0106_NEW with S29GL128N10TFI01
|
||||
- BX2006_TSOP_64BALL with GL128S
|
||||
- BX2006_TSOP_64BALL with GL256S
|
||||
|
|
@ -141,9 +142,9 @@ If you have Python and pip installed, you can use `pip install FlashGBX` to down
|
|||
|
||||
To run FlashGBX in portable mode, you can also download the source code archive and call `python run.py` after installing the prerequisites yourself.
|
||||
|
||||
*On some platforms you may have to use `pip3`/`python3` instead of `pip`/`python`.*
|
||||
The application should work on pretty much every operating system that supports Qt-GUI applications built using [Python 3.7+](https://www.python.org/downloads/) with [PySide2](https://pypi.org/project/PySide2/), [pyserial](https://pypi.org/project/pyserial/), [Pillow](https://pypi.org/project/Pillow/), [setuptools](https://pypi.org/project/setuptools/) and [requests](https://pypi.org/project/requests/) packages.
|
||||
|
||||
The application should work on pretty much every operating system that supports Qt-GUI applications built using [Python 3](https://www.python.org/downloads/) with [PySide2](https://pypi.org/project/PySide2/), [pyserial](https://pypi.org/project/pyserial/), [Pillow](https://pypi.org/project/Pillow/), [requests](https://pypi.org/project/requests/) and [setuptools](https://pypi.org/project/setuptools/) packages.
|
||||
*On some platforms you may have to use `pip3`/`python3` instead of `pip`/`python`.*
|
||||
|
||||
### Windows binaries
|
||||
|
||||
|
|
@ -162,6 +163,8 @@ These executables have been created using *PyInstaller* and *Inno Setup*.
|
|||
|
||||
* On some Linux systems, you may need the *XCB Xinerama package* if you see an error regarding failed Qt platform plugin initialization. You can install it with `sudo apt install libxcb-xinerama0` etc.
|
||||
|
||||
* If the `PySide2` package is not available for your system, you can install FlashGBX like so instead: `pip install pyserial Pillow setuptools requests` followed by `pip install --no-deps FlashGBX`.
|
||||
|
||||
* On older systems such as MacOS X El Capitan 10.11, you may run into an error that says `TypeError: 'Shiboken.ObjectType' object is not iterable`. Installing [Python 3.7.9](https://www.python.org/downloads/release/python-379/) instead of the latest available version may resolve this issue. If that still doesn’t work, you can try to uninstall PySide2 (`pip uninstall PySide2`) and then run FlashGBX again in command line interface mode.
|
||||
|
||||
* For save data backup/restore on Game Boy Advance reproduction cartridges, depending on how it was built, you may have to manually select the save type for it to work properly. However, the save data backup/restore feature may not work on certain reproduction cartridges with batteryless-patched ROMs. As those cartridges use the same flash chip for both ROM and save data storage, a full ROM backup will usually include the save data. Also, when flashing a new unpatched ROM to a cartridge like this, the game may not be able to save progress without soldering in a battery. See the [Flash Cart DB website](https://flashcartdb.com/index.php/Clone_and_Repo_Cart_Problems) for more information.
|
||||
|
|
@ -196,11 +199,11 @@ The author would like to thank the following very kind people for their help and
|
|||
- Super Maker (flash chip info, testing)
|
||||
- Veund (flash chip info)
|
||||
- Zeii (flash chip info)
|
||||
- Zelante (flash chip info)
|
||||
|
||||
## Changes
|
||||
|
||||
### v0.7β (released 2020-09-25)
|
||||
|
||||
- First started tracking changes
|
||||
- Added a way to launch the flash cartridge type auto-detection process from the type list
|
||||
- Added support for SD007_48BALL_64M_V6 with 29DL163BD-90 *(thanks LovelyA72)*
|
||||
|
|
@ -218,7 +221,6 @@ The author would like to thank the following very kind people for their help and
|
|||
- First public beta release
|
||||
|
||||
### v0.8β (released 2020-10-03)
|
||||
|
||||
- Added support for the DIY cart with AM29F016/AM29F016B with AUDIO as WE *(thanks AndehX)*
|
||||
- Renamed `VIN` to `AUDIO` in config files and the command line switch `--resetconfig` to `--reset`
|
||||
- Added experimental support for GBxCart RW revisions other than v1.3 and fixed a crash when connecting to unknown revisions of the GBxCart RW
|
||||
|
|
@ -239,7 +241,6 @@ The author would like to thank the following very kind people for their help and
|
|||
- Added taskbar progress visualization on Windows systems
|
||||
|
||||
### v0.9β (released 2020-12-17)
|
||||
|
||||
- Confirmed support for BX2006_TSOP_64BALL with GL128S
|
||||
- Confirmed support for SD007_48BALL_64M_V2 with GL032M11BAIR4
|
||||
- Added support for 4050_4400_4000_4350_36L0R_V5 with M36L0R8060T/M36L0T8060T
|
||||
|
|
@ -257,7 +258,7 @@ The author would like to thank the following very kind people for their help and
|
|||
- Added backup and restore of 1M SRAM save data in GBA mode
|
||||
- Confirmed support for BX2006_TSOPBGA_0106 with M29W640GB6AZA6 *(thanks LucentW)*
|
||||
- Confirmed support for AGB-E05-01 with GL128S
|
||||
- Improved writing speed for MSP55LV128M, S29GL128 and similar flash chips (requires GBxCart RW firmware R23 or higher)
|
||||
- Improved writing speed for MSP55LV128M, S29GL128 and similar flash chips (requires GBxCart RW firmware R23 or newer)
|
||||
- Before flashing a ROM it will now be checked if its logo data and header checksum are valid and a warning will be shown if not
|
||||
- Added support for SD007_BV5_V3 with 29LV160BE-90PFTN *(thanks LucentW)*
|
||||
- Added support for SD007_BV5_V3 with HY29LV160BT *(thanks LucentW)*
|
||||
|
|
@ -278,17 +279,17 @@ The author would like to thank the following very kind people for their help and
|
|||
- Fixed an issue with Raspberry Pi compatibility *(thanks ClassicOldSong)*
|
||||
- Confirmed support for SD007_TSOP_48BALL with AM29LV160DB *(thanks marv17)*
|
||||
- Fixed timeout errors with ROMs that have non-standard file sizes (e.g. trimmed files)
|
||||
- Improved writing speed for most Game Boy reproduction cartridges by up to 40% (requires GBxCart RW firmware R24 or higher)
|
||||
- Improved writing speed for M36L0R and similar flash chips by up to 80% (requires GBxCart RW firmware R24 or higher)
|
||||
- Improved writing speed for most Game Boy reproduction cartridges by up to 40% (requires GBxCart RW firmware R24 or newer)
|
||||
- Improved writing speed for M36L0R and similar flash chips by up to 80% (requires GBxCart RW firmware R24 or newer)
|
||||
- Confirmed support for 4400 with 4400L0ZDQ0 *(thanks Zeii)*
|
||||
- Backup and restore save data of flash chips manufactured by SANYO requires GBxCart RW firmware R24 or higher; a warning message for this will now be displayed in necessary cases
|
||||
- Backup and restore save data of flash chips manufactured by SANYO requires GBxCart RW firmware R24 or newer; a warning message for this will now be displayed in necessary cases
|
||||
- Added the option to check for updates at application start *(thanks Icesythe7 and JFox for the suggestion and help)*
|
||||
- Added support for BX2006_TSOPBGA_0106 with K8D6316UTM-PI07 *(thanks LucentW)*
|
||||
- Added support for the currently available insideGadgets Game Boy Advance flash cartridges *(thanks AlexiG)*
|
||||
- Added a Game Boy Camera album viewer and picture extractor
|
||||
|
||||
### v1.0 (released 2021-01-01)
|
||||
- Added a firmware check when writing to insideGadgets Game Boy Advance flash cartridges (requires GBxCart RW firmware R20 or higher)
|
||||
- Added a firmware check when writing to insideGadgets Game Boy Advance flash cartridges (requires GBxCart RW firmware R20 or newer)
|
||||
- Confirmed support for Mr Flash 64M (rebranded BUNG Doctor GB Card 64M)
|
||||
- Fixed a problem with writing to the insideGadgets 512 KB Game Boy flash cartridge
|
||||
|
||||
|
|
@ -301,7 +302,7 @@ The author would like to thank the following very kind people for their help and
|
|||
- 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/v1.2.1 (released 2021-01-16)
|
||||
### v1.2.1 (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)*
|
||||
|
|
@ -327,14 +328,22 @@ The author would like to thank the following very kind people for their help and
|
|||
- Added support for AGB-E05-01 with MX29GL128FHT2I-90G *(thanks antPL)*
|
||||
- Added support for official cartridges with the HuC-1 memory bank controller; tested with “Pokémon Card GB” (DMG-ACXJ-JPN)
|
||||
- Added support for official cartridges with the HuC-3 memory bank controller; tested with “Robot Poncots Sun Version” (DMG-HREJ-JPN)
|
||||
- Added support for official cartridges with the TAMA5 memory bank controller; tested with “Game de Hakken!! Tamagotchi Osutchi to Mesutchi” (DMG-AOMJ-JPN) (requires GBxCart RW firmware R26 or higher)
|
||||
- Added preliminary support for official GBA Video cartridges with 3D Memory; tested with “Shrek 2” (AGB-M2SE-USA) *(thanks to endrift’s article [“Dumping the Undumped”](https://mgba.io/2015/10/20/dumping-the-undumped/))* – requires a future firmware update of GBxCart RW
|
||||
- Added support for official cartridges with the TAMA5 memory bank controller; tested with “Game de Hakken!! Tamagotchi Osutchi to Mesutchi” (DMG-AOMJ-JPN) (requires GBxCart RW firmware R26 or newer)
|
||||
- Added preliminary support for official GBA Video cartridges with 3D Memory; tested with “Shrek 2” (AGB-M2SE-USA) *(thanks to endrift’s article [“Dumping the Undumped”](https://mgba.io/2015/10/20/dumping-the-undumped/))* (requires a future firmware update of GBxCart RW)
|
||||
- Added support for optionally saving and restoring RTC registers of official TAMA5 cartridges inside the save file
|
||||
- Experimental support for optionally saving RTC registers of official MBC3+RTC+SRAM+BATTERY cartridges inside the save file using the 48 bytes save format explained on the [BGB website](https://bgb.bircd.org/rtcsave.html) was added. Latching the RTC register and restoring RTC register values to the cartridge is not supported at this time as it requires a new GBxCart RW hardware device revision.
|
||||
- Added support for 4050_4400_4000_4350_36L0R_V5 with 4050L0YTQ2 *(thanks Shinichi999)*
|
||||
- Fixed GUI support on macOS Big Sur *(thanks paarongiroux)*
|
||||
- Added support for official cartridges with the MBC1M memory bank controller; tested with “Bomberman Collection” (DMG-ABCJ-JPN); save data backup is untested but should work
|
||||
- Added support for official cartridges with the MMM01 memory bank controller; tested with “Momotarou Collection 2” (DMG-AM3J-JPN) (requires GBxCart RW firmware R26 or higher)
|
||||
- Added support for official cartridges with the MMM01 memory bank controller; tested with “Momotarou Collection 2” (DMG-AM3J-JPN) (requires GBxCart RW firmware R26 or newer)
|
||||
- Support for optionally saving and restoring RTC registers of official HuC-3+RTC+SRAM+BATTERY cartridges inside the save file using the 12 bytes save format used by the [hhugboy emulator](https://github.com/tzlion/hhugboy) was added.
|
||||
- Added support for SD007_TSOP_48BALL with K8D3216UTC *(thanks marv17)*
|
||||
|
||||
### v1.4.1 (released 2021-03-15)
|
||||
- Added ROM and map backup support for official Nintendo Power GB Memory cartridges (DMG-MMSA-JPN); save data handling and ROM writing is not supported yet
|
||||
- Fixed a minor bug with save data backup and restore (the bug did not cause damage)
|
||||
- Added preliminary support for 4050M0Y0Q0-39VF512 with 4050M0Y0Q0 (requires a future firmware update of GBxCart RW)
|
||||
- Added preliminary support for official cartridges with the MBC7 memory bank controller; tested with “Korokoro Kirby” (CGB-KKKJ-JPN) (requires a future firmware update of GBxCart RW)
|
||||
- Added support for official cartridges with the M161 memory bank controller; tested with “Mani 4 in 1: Tetris + Alleyway + Yakuman + Tennis” (DMG-601CHN) (requires GBxCart RW firmware R26 or newer)
|
||||
- Added support for B104 with MSP55LV128 *(thanks Zelante)*
|
||||
- Added save data backup and restore support for official cartridges with ATMEL AT29LV512 flash chips; tested with a copy of “Mario Kart: Super Circuit” (AGB-AMKP-EUR)
|
||||
|
|
|
|||
4
setup.py
4
setup.py
|
|
@ -4,12 +4,12 @@ with open("README.md", "r", encoding="utf-8") as fh: long_description = fh.read(
|
|||
|
||||
setuptools.setup(
|
||||
name="FlashGBX",
|
||||
version="1.4",
|
||||
version="1.4.1",
|
||||
author="Lesserkuma",
|
||||
description="Reads and writes Game Boy and Game Boy Advance cartridge data. Currently supports the GBxCart RW hardware device by insideGadgets.",
|
||||
url="https://github.com/lesserkuma/FlashGBX",
|
||||
packages=setuptools.find_packages(),
|
||||
install_requires=['PySide2', 'pyserial', 'setuptools', 'requests', 'Pillow'],
|
||||
install_requires=['PySide2', 'pyserial', 'Pillow', 'setuptools', 'requests'],
|
||||
include_package_data=True,
|
||||
classifiers=[
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user