mirror of
https://github.com/lesserkuma/FlashGBX.git
synced 2026-08-25 02:05:14 -05:00
3.33
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
# Release notes
|
||||
### v3.33
|
||||
- Minor bug fixes and improvements *(thanks Eldram, Grender)*
|
||||
|
||||
### v3.32 (released 2023-07-25)
|
||||
- Added support for M5M29-39VF512 with M5M29HD528 *(thanks marv17)*
|
||||
- Added support for SD007_BV5_V3 with 26LV160BTC
|
||||
|
||||
@@ -433,7 +433,7 @@ class FlashGBX_CLI():
|
||||
def DisconnectDevice(self):
|
||||
try:
|
||||
devname = self.CONN.GetFullNameExtended()
|
||||
self.CONN.Close()
|
||||
self.CONN.Close(cartPowerOff=True)
|
||||
print("Disconnected from {:s}".format(devname))
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -202,7 +202,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
||||
self.mnuConfig.addAction("Check for &updates on application startup", lambda: [ self.EnableUpdateCheck() ])
|
||||
self.mnuConfig.addAction("&Append date && time to filename of save data backups", lambda: self.SETTINGS.setValue("SaveFileNameAddDateTime", str(self.mnuConfig.actions()[1].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")))
|
||||
self.mnuConfig.addAction("Prefer full &chip erase", lambda: self.SETTINGS.setValue("PreferChipErase", str(self.mnuConfig.actions()[2].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")))
|
||||
self.mnuConfig.addAction("&Verify written data", lambda: self.SETTINGS.setValue("VerifyData", str(self.mnuConfig.actions()[3].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")))
|
||||
self.mnuConfig.addAction("&Verify transferred data", lambda: self.SETTINGS.setValue("VerifyData", str(self.mnuConfig.actions()[3].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")))
|
||||
self.mnuConfig.addAction("&Limit voltage to 3.3V when detecting Game Boy flash cartridges", lambda: self.SETTINGS.setValue("AutoDetectLimitVoltage", str(self.mnuConfig.actions()[4].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")))
|
||||
self.mnuConfig.addAction("Limit &baud rate to 1Mbps for GBxCart RW v1.4 devices", lambda: [ self.SETTINGS.setValue("LimitBaudRate", str(self.mnuConfig.actions()[5].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")), self.SetLimitBaudRate() ])
|
||||
self.mnuConfig.addAction("Always &generate ROM dump reports", lambda: self.SETTINGS.setValue("GenerateDumpReports", str(self.mnuConfig.actions()[6].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")))
|
||||
@@ -564,7 +564,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
||||
def DisconnectDevice(self):
|
||||
try:
|
||||
devname = self.CONN.GetFullNameExtended()
|
||||
self.CONN.Close()
|
||||
self.CONN.Close(cartPowerOff=True)
|
||||
self.CONN = None
|
||||
self.DEVICES = {}
|
||||
print("Disconnected from {:s}".format(devname))
|
||||
@@ -1085,11 +1085,13 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
||||
if self.CONN.GetMode() == "AGB" and "Batteryless SRAM" in Util.AGB_Header_Save_Types[self.cmbAGBSaveTypeResult.currentIndex()]:
|
||||
temp1 = self.cmbAGBCartridgeTypeResult.currentIndex()
|
||||
temp2 = self.cmbAGBSaveTypeResult.currentIndex()
|
||||
temp3 = self.CONN.INFO["dump_info"]["batteryless_sram"]
|
||||
if "batteryless_sram" in self.CONN.INFO["dump_info"]:
|
||||
temp3 = self.CONN.INFO["dump_info"]["batteryless_sram"]
|
||||
self.ReadCartridge(resetStatus=False)
|
||||
self.cmbAGBCartridgeTypeResult.setCurrentIndex(temp1)
|
||||
self.cmbAGBSaveTypeResult.setCurrentIndex(temp2)
|
||||
self.CONN.INFO["dump_info"]["batteryless_sram"] = temp3
|
||||
if "batteryless_sram" in self.CONN.INFO["dump_info"]:
|
||||
self.CONN.INFO["dump_info"]["batteryless_sram"] = temp3
|
||||
else:
|
||||
self.ReadCartridge(resetStatus=False)
|
||||
|
||||
@@ -1717,7 +1719,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
||||
self.lblStatus4a.setText("Testing ({:s} 1/2)...".format(test_patterns_names[0]))
|
||||
self.SetProgressBars(min=0, max=len(test_patterns)+3, value=0)
|
||||
qt_app.processEvents()
|
||||
args = { "mode":2, "path":path, "mbc":mbc, "save_type":save_type, "rtc":rtc }
|
||||
args = { "mode":2, "path":path, "mbc":mbc, "save_type":save_type, "rtc":False }
|
||||
t = threading.Thread(target=lambda a: self.CONN.TransferData(args=a, signal=None), args=[args])
|
||||
t.start()
|
||||
while t.is_alive():
|
||||
@@ -1764,7 +1766,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
||||
self.SetProgressBars(min=0, max=len(test_patterns)+3, value=i+2)
|
||||
qt_app.processEvents()
|
||||
towrite = test_patterns[i]
|
||||
args = { "mode":3, "path":path, "mbc":mbc, "save_type":save_type, "rtc":rtc, "rtc_advance":rtc_advance, "erase":erase, "verify_write":False, "buffer":towrite }
|
||||
args = { "mode":3, "path":path, "mbc":mbc, "save_type":save_type, "rtc":False, "rtc_advance":rtc_advance, "erase":erase, "verify_write":False, "buffer":towrite }
|
||||
t = threading.Thread(target=lambda a: self.CONN.TransferData(args=a, signal=None), args=[args])
|
||||
t.start()
|
||||
while t.is_alive():
|
||||
@@ -1776,7 +1778,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
||||
self.CONN.CartPowerOff()
|
||||
time.sleep(0.5)
|
||||
self.CONN.CartPowerOn()
|
||||
args = { "mode":2, "path":path, "mbc":mbc, "save_type":save_type, "rtc":rtc }
|
||||
args = { "mode":2, "path":path, "mbc":mbc, "save_type":save_type, "rtc":False }
|
||||
t = threading.Thread(target=lambda a: self.CONN.TransferData(args=a, signal=None), args=[args])
|
||||
t.start()
|
||||
while t.is_alive():
|
||||
@@ -1791,14 +1793,14 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
||||
self.lblStatus4a.setText("Restoring original save data...")
|
||||
self.SetProgressBars(min=0, max=len(test_patterns)+3, value=len(test_patterns)+2)
|
||||
qt_app.processEvents()
|
||||
args = { "mode":3, "path":path, "mbc":mbc, "save_type":save_type, "rtc":rtc, "rtc_advance":rtc_advance, "erase":erase, "verify_write":False, "buffer":save1 }
|
||||
args = { "mode":3, "path":path, "mbc":mbc, "save_type":save_type, "rtc":False, "rtc_advance":rtc_advance, "erase":erase, "verify_write":False, "buffer":save1 }
|
||||
t = threading.Thread(target=lambda a: self.CONN.TransferData(args=a, signal=None), args=[args])
|
||||
t.start()
|
||||
while t.is_alive():
|
||||
qt_app.processEvents()
|
||||
time.sleep(0.02)
|
||||
t.join()
|
||||
args = { "mode":2, "path":path, "mbc":mbc, "save_type":save_type, "rtc":rtc }
|
||||
args = { "mode":2, "path":path, "mbc":mbc, "save_type":save_type, "rtc":False }
|
||||
t = threading.Thread(target=lambda a: self.CONN.TransferData(args=a, signal=None), args=[args])
|
||||
t.start()
|
||||
while t.is_alive():
|
||||
@@ -1820,8 +1822,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
||||
if test_ok == 0:
|
||||
towrite = save1
|
||||
readback = save2
|
||||
with open("debug_savetest_1.bin", "wb") as f: f.write(towrite[:len(readback)])
|
||||
with open("debug_savetest_2.bin", "wb") as f: f.write(readback)
|
||||
with open(Util.CONFIG_PATH + "/debug_stress_test_1.bin", "wb") as f: f.write(towrite[:len(readback)])
|
||||
with open(Util.CONFIG_PATH + "/debug_stress_test_2.bin", "wb") as f: f.write(readback)
|
||||
except:
|
||||
pass
|
||||
if test_ok > 0:
|
||||
@@ -2344,7 +2346,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
||||
try:
|
||||
if save_type is not None and save_type is not False:
|
||||
if self.CONN.GetMode() == "DMG":
|
||||
self.cmbDMGHeaderSaveTypeResult.setCurrentIndex(save_type)
|
||||
self.cmbDMGHeaderSaveTypeResult.setCurrentIndex(Util.DMG_Header_RAM_Sizes_Map.index(save_type))
|
||||
elif self.CONN.GetMode() == "AGB":
|
||||
self.cmbAGBSaveTypeResult.setCurrentIndex(save_type)
|
||||
except:
|
||||
@@ -2392,7 +2394,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
||||
else:
|
||||
if self.CONN.GetMode() == "DMG":
|
||||
try:
|
||||
temp = "{:s}".format(Util.DMG_Header_RAM_Sizes[save_type])
|
||||
temp = "{:s}".format(Util.DMG_Header_RAM_Sizes[Util.DMG_Header_RAM_Sizes_Map.index(save_type)])
|
||||
except:
|
||||
temp = "Unknown"
|
||||
elif self.CONN.GetMode() == "AGB":
|
||||
|
||||
@@ -263,6 +263,9 @@ class DMG_MBC3(DMG_MBC):
|
||||
|
||||
def HasRTC(self):
|
||||
dprint("Checking for RTC")
|
||||
if self.MBC_ID not in (0x0F, 0x10, 0x110):
|
||||
dprint("No RTC because mapper value is not used for RTC:", self.MBC_ID)
|
||||
return False
|
||||
self.EnableRAM(enable=False)
|
||||
self.EnableRAM(enable=True)
|
||||
self.LatchRTC()
|
||||
@@ -271,12 +274,12 @@ class DMG_MBC3(DMG_MBC):
|
||||
for i in range(0x08, 0x0D):
|
||||
self.CLK_TOGGLE_FNCPTR(60)
|
||||
self.CartWrite([ [0x4000, i] ])
|
||||
data = self.CartRead(0xA000, 0x800)
|
||||
data = self.CartRead(0xA880, 0x100)
|
||||
if len(data) == 0: return False
|
||||
if data[0] in (0, 0xFF): continue
|
||||
skipped = False
|
||||
if data != bytearray([data[0]] * 0x800):
|
||||
dprint("No RTC because whole bank is not the same value", data[0])
|
||||
if data != bytearray([data[0]] * 0x100):
|
||||
dprint("No RTC because whole bank is not the same value:", data[0])
|
||||
skipped = True
|
||||
break
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@ from enum import Enum
|
||||
|
||||
# Common constants
|
||||
APPNAME = "FlashGBX"
|
||||
VERSION_PEP440 = "3.32"
|
||||
VERSION_PEP440 = "3.33"
|
||||
VERSION = "v{:s}".format(VERSION_PEP440)
|
||||
VERSION_TIMESTAMP = 1690298775
|
||||
VERSION_TIMESTAMP = 1695636983
|
||||
DEBUG = False
|
||||
DEBUG_LOG = []
|
||||
APP_PATH = ""
|
||||
@@ -19,8 +19,8 @@ AGB_Header_ROM_Sizes = [ "64 KiB", "128 KiB", "256 KiB", "512 KiB", "1 MiB", "2
|
||||
AGB_Header_ROM_Sizes_Map = [ 0x10000, 0x20000, 0x40000, 0x80000, 0x100000, 0x200000, 0x400000, 0x800000, 0x1000000, 0x2000000, 0x4000000, 0x8000000, 0x10000000 ]
|
||||
AGB_Header_Save_Types = [ "None", "4K EEPROM (512 Bytes)", "64K EEPROM (8 KiB)", "256K SRAM/FRAM (32 KiB)", "512K FLASH (64 KiB)", "1M FLASH (128 KiB)", "8M DACS (1 MiB)", "Unlicensed 512K SRAM (64 KiB)", "Unlicensed 1M SRAM (128 KiB)", "Unlicensed Batteryless SRAM" ]
|
||||
AGB_Header_Save_Sizes = [ 0, 512, 8192, 32768, 65536, 131072, 1048576, 65536, 131072, 0 ]
|
||||
AGB_Flash_Save_Chips = { 0xBFD4:"SST 39VF512", 0x1F3D:"Atmel AT29LV512", 0xC21C:"Macronix MX29L512", 0x321B:"Panasonic MN63F805MNP", 0xC209:"Macronix MX29L010", 0x6213:"SANYO LE26FV10N1TS", 0xBF5B:"Unlicensed SST SST49LF080A" }
|
||||
AGB_Flash_Save_Chips_Sizes = [ 0x10000, 0x10000, 0x10000, 0x10000, 0x20000, 0x20000, 0x20000 ]
|
||||
AGB_Flash_Save_Chips = { 0xBFD4:"SST 39VF512", 0x1F3D:"Atmel AT29LV512", 0xC21C:"Macronix MX29L512", 0x321B:"Panasonic MN63F805MNP", 0xC209:"Macronix MX29L010", 0x6213:"SANYO LE26FV10N1TS", 0xBF5B:"Unlicensed SST SST49LF080A", 0xFFFF:"Unlicensed 0xFFFF" }
|
||||
AGB_Flash_Save_Chips_Sizes = [ 0x10000, 0x10000, 0x10000, 0x10000, 0x20000, 0x20000, 0x20000, 0x20000 ]
|
||||
|
||||
DMG_Header_Mapper = { 0x00:'None', 0x01:'MBC1', 0x02:'MBC1+SRAM', 0x03:'MBC1+SRAM+BATTERY', 0x06:'MBC2+SRAM+BATTERY', 0x0F:'MBC3+RTC+BATTERY', 0x10:'MBC3+RTC+SRAM+BATTERY', 0x110:'MBC30+RTC+SRAM+BATTERY', 0x12:'MBC3+SRAM', 0x13:'MBC3+SRAM+BATTERY', 0x19:'MBC5', 0x1A:'MBC5+SRAM', 0x1B:'MBC5+SRAM+BATTERY', 0x1C:'MBC5+RUMBLE', 0x1E:'MBC5+RUMBLE+SRAM+BATTERY', 0x20:'MBC6+SRAM+FLASH+BATTERY', 0x22:'MBC7+ACCELEROMETER+EEPROM', 0x101:'MBC1M', 0x103:'MBC1M+SRAM+BATTERY', 0x0B:'MMM01', 0x0D:'MMM01+SRAM+BATTERY', 0xFC:'MAC-GBD+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', 0x201:'Unlicensed 256M Mapper', 0x202:'Unlicensed Wisdom Tree Mapper', 0x203:'Unlicensed Xploder GB Mapper', 0x204:'Unlicensed Sachen Mapper', 0x205:'Unlicensed Datel Orbit V2 Mapper' }
|
||||
DMG_Mapper_Types = { "None":[ 0x00, 0x08, 0x09 ], "MBC1":[ 0x01, 0x02, 0x03 ], "MBC2":[ 0x05, 0x06 ], "MBC3":[ 0x0F, 0x10, 0x11, 0x12, 0x13 ], "MBC30":[ 0x110 ], "MBC5":[ 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E ], "MBC6":[ 0x20 ], "MBC7":[ 0x22 ], "MBC1M":[ 0x101, 0x103 ], "MMM01":[ 0x0B, 0x0D ], "MAC-GBD":[ 0xFC ], "G-MMC1":[ 0x105 ], "M161":[ 0x104 ], "HuC-1":[ 0xFF ], "HuC-3":[ 0xFE ], "TAMA5":[ 0xFD ], "Unlicensed 256M Multi Cart Mapper":[ 0x201 ], "Unlicensed Wisdom Tree Mapper":[ 0x202 ], "Unlicensed Xploder GB Mapper":[ 0x203 ], "Unlicensed Sachen Mapper":[ 0x204 ], "Unlicensed Datel Orbit V2 Mapper":[ 0x205 ] }
|
||||
|
||||
@@ -154,6 +154,7 @@ class GbxDevice:
|
||||
continue
|
||||
elif max_baud >= 1700000 and self.FW["pcb_ver"] in (5, 6, 101) and self.BAUDRATE < 1700000:
|
||||
self.ChangeBaudRate(baudrate=1700000)
|
||||
self.DEVICE.close()
|
||||
dev = serial.Serial(ports[i], self.BAUDRATE, timeout=0.1)
|
||||
self.DEVICE = dev
|
||||
|
||||
@@ -250,12 +251,9 @@ class GbxDevice:
|
||||
if not self.IsConnected(): return
|
||||
if baudrate == 1700000:
|
||||
self._write(self.DEVICE_CMD["OFW_USART_1_7M_SPEED"])
|
||||
self.Close()
|
||||
self.BAUDRATE = baudrate
|
||||
elif baudrate == 1000000:
|
||||
self._write(self.DEVICE_CMD["OFW_USART_1_0M_SPEED"])
|
||||
self.Close()
|
||||
self.BAUDRATE = baudrate
|
||||
self.BAUDRATE = baudrate
|
||||
|
||||
def CanSetVoltageManually(self):
|
||||
return False
|
||||
@@ -316,14 +314,15 @@ class GbxDevice:
|
||||
print(str(e))
|
||||
return False
|
||||
|
||||
def Close(self):
|
||||
def Close(self, cartPowerOff=False):
|
||||
if self.IsConnected():
|
||||
try:
|
||||
if self.FW["pcb_ver"] in (5, 6, 101):
|
||||
self._write(self.DEVICE_CMD["OFW_CART_MODE"])
|
||||
self._read(1)
|
||||
self._write(self.DEVICE_CMD["OFW_CART_PWR_OFF"])
|
||||
self._write(self.DEVICE_CMD["SET_ADDR_AS_INPUTS"])
|
||||
if cartPowerOff:
|
||||
if self.FW["pcb_ver"] in (5, 6, 101):
|
||||
self._write(self.DEVICE_CMD["OFW_CART_MODE"])
|
||||
self._read(1)
|
||||
self._write(self.DEVICE_CMD["OFW_CART_PWR_OFF"])
|
||||
self._write(self.DEVICE_CMD["SET_ADDR_AS_INPUTS"])
|
||||
self.DEVICE.close()
|
||||
except:
|
||||
self.DEVICE = None
|
||||
@@ -445,7 +444,7 @@ class GbxDevice:
|
||||
# On MacOS it’s possible not all bytes are transmitted successfully,
|
||||
# even though we’re using flush() which is the tcdrain function.
|
||||
# Still looking for a better solution than delaying here.
|
||||
if platform.system() == "Darwin": # or self.WRITE_DELAY is True:
|
||||
if platform.system() == "Darwin" or self.WRITE_DELAY is True:
|
||||
time.sleep(0.00125)
|
||||
|
||||
if wait: return self.wait_for_ack()
|
||||
@@ -624,7 +623,7 @@ class GbxDevice:
|
||||
return self.MODE
|
||||
|
||||
def SetMode(self, mode, delay=0.1):
|
||||
self.CartPowerOff(delay=delay)
|
||||
# self.CartPowerOff(delay=delay)
|
||||
if mode == "DMG":
|
||||
self._write(self.DEVICE_CMD["SET_MODE_DMG"])
|
||||
self._write(self.DEVICE_CMD["SET_VOLTAGE_5V"])
|
||||
@@ -866,45 +865,60 @@ class GbxDevice:
|
||||
# Save Type and Size
|
||||
if checkSaveType:
|
||||
if self.MODE == "DMG":
|
||||
save_type = 5
|
||||
save_size = 131072
|
||||
save_type = 0x04
|
||||
if mbc == 0x20: # MBC6
|
||||
save_size = 1081344
|
||||
save_type = 6
|
||||
save_type = 0x104
|
||||
return (info, save_size, save_type, save_chip, sram_unstable, cart_types, cart_type_id, cfi_s, cfi, flash_id)
|
||||
elif mbc == 0x22: # MBC7
|
||||
save_type = 8
|
||||
save_type = 0x102
|
||||
save_size = 512
|
||||
elif mbc == 0xFD: # TAMA5
|
||||
save_size = 32
|
||||
save_type = 9
|
||||
save_type = 0x103
|
||||
return (info, save_size, save_type, save_chip, sram_unstable, cart_types, cart_type_id, cfi_s, cfi, flash_id)
|
||||
args = { 'mode':2, 'path':None, 'mbc':mbc, 'save_type':save_type, 'rtc':False }
|
||||
elif self.MODE == "AGB":
|
||||
args = { 'mode':2, 'path':None, 'mbc':mbc, 'save_type':8, 'rtc':False }
|
||||
|
||||
ret = self._BackupRestoreRAM(args=args)
|
||||
|
||||
|
||||
if ret is not False and "data" in self.INFO:
|
||||
save_size = Util.find_size(self.INFO["data"], len(self.INFO["data"]))
|
||||
else:
|
||||
save_size = 0
|
||||
|
||||
try:
|
||||
save_type = Util.DMG_Header_RAM_Sizes_Map[Util.DMG_Header_RAM_Sizes_Flasher_Map.index(save_size)]
|
||||
except:
|
||||
save_size = 0
|
||||
save_type = 0
|
||||
|
||||
if self.MODE == "DMG":
|
||||
if save_size > 0x20:
|
||||
if save_size in Util.DMG_Header_RAM_Sizes_Flasher_Map:
|
||||
save_type = Util.DMG_Header_RAM_Sizes_Flasher_Map.index(save_size)
|
||||
if mbc == 0x22: # MBC7
|
||||
if save_size == 256:
|
||||
save_type = 7
|
||||
elif save_size == 512:
|
||||
save_type = 8
|
||||
elif len(self.INFO["data"]) >= 0x12000 and self.INFO["data"][0x12000:0x14000] == bytearray([self.INFO["data"][0x12000]] * 0x2000):
|
||||
if self.INFO["data"][0x8000:0x10000] == bytearray([self.INFO["data"][0x8000]] * 0x8000):
|
||||
save_size = 32768
|
||||
save_type = 3
|
||||
else:
|
||||
if mbc == 0x22: # MBC7
|
||||
if save_size == 256:
|
||||
save_type = 0x101
|
||||
elif save_size == 512:
|
||||
save_type = 0x102
|
||||
elif save_size > 0x10000: # MBC30+RTC?
|
||||
check = True
|
||||
for i in range(0x8000, 0x10000, 0x40):
|
||||
if self.INFO["data"][i:i+3] != bytearray([self.INFO["data"][i]] * 3):
|
||||
check = False
|
||||
break
|
||||
if check:
|
||||
save_size = 32768
|
||||
save_type = 0x03
|
||||
else:
|
||||
check = True
|
||||
for i in range(0x1A000, 0x20000, 0x40):
|
||||
if self.INFO["data"][i:i+3] != bytearray([self.INFO["data"][i]] * 3):
|
||||
check = False
|
||||
break
|
||||
if check:
|
||||
save_size = 65536
|
||||
save_type = 4
|
||||
save_type = 0x05
|
||||
|
||||
elif self.MODE == "AGB":
|
||||
# Check for FLASH
|
||||
@@ -2076,7 +2090,6 @@ class GbxDevice:
|
||||
|
||||
buffer_len = 0x4000
|
||||
|
||||
self.INFO["dump_info"] = {}
|
||||
self.INFO["dump_info"]["timestamp"] = datetime.datetime.now().astimezone().replace(microsecond=0).isoformat()
|
||||
self.INFO["dump_info"]["file_name"] = args["path"]
|
||||
self.INFO["dump_info"]["file_size"] = args["rom_size"]
|
||||
@@ -2449,7 +2462,10 @@ class GbxDevice:
|
||||
msg = "This cartridge uses a mapper that is not supported by {:s} using your {:s} device. An updated hardware revision is required.".format(Util.APPNAME, self.GetFullName())
|
||||
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":msg, "abortable":False})
|
||||
return False
|
||||
save_size = Util.DMG_Header_RAM_Sizes_Flasher_Map[Util.DMG_Header_RAM_Sizes_Map.index(args["save_type"])]
|
||||
if "save_size" in args:
|
||||
save_size = args["save_size"]
|
||||
else:
|
||||
save_size = Util.DMG_Header_RAM_Sizes_Flasher_Map[Util.DMG_Header_RAM_Sizes_Map.index(args["save_type"])]
|
||||
ram_banks = _mbc.GetRAMBanks(save_size)
|
||||
buffer_len = min(0x200, _mbc.GetRAMBankSize())
|
||||
self._write(self.DEVICE_CMD["SET_MODE_DMG"])
|
||||
@@ -2522,7 +2538,10 @@ class GbxDevice:
|
||||
self._write(self.DEVICE_CMD["SET_MODE_AGB"])
|
||||
self._write(self.DEVICE_CMD["SET_VOLTAGE_3_3V"])
|
||||
buffer_len = 0x2000
|
||||
save_size = Util.AGB_Header_Save_Sizes[args["save_type"]]
|
||||
if "save_size" in args:
|
||||
save_size = args["save_size"]
|
||||
else:
|
||||
save_size = Util.AGB_Header_Save_Sizes[args["save_type"]]
|
||||
ram_banks = math.ceil(save_size / 0x10000)
|
||||
agb_flash_chip = 0
|
||||
|
||||
@@ -2539,7 +2558,7 @@ class GbxDevice:
|
||||
return False
|
||||
buffer_len = 0x1000
|
||||
(agb_flash_chip, _) = ret
|
||||
if agb_flash_chip == 0xBF5B: # Bootlegs
|
||||
if agb_flash_chip in (0xBF5B, 0xFFFF): # Bootlegs
|
||||
buffer_len = 0x800
|
||||
elif args["save_type"] == 6: # DACS
|
||||
self._write(self.DEVICE_CMD["AGB_BOOTUP_SEQUENCE"], wait=True)
|
||||
@@ -2661,7 +2680,7 @@ class GbxDevice:
|
||||
end_address = min(save_size, bank_size)
|
||||
|
||||
if save_size > bank_size:
|
||||
if args["save_type"] == 8 or agb_flash_chip == 0xBF5B: # Bootleg 1M
|
||||
if args["save_type"] == 8 or agb_flash_chip in (0xBF5B, 0xFFFF): # Bootleg 1M
|
||||
dprint("Switching to bootleg save bank {:d}".format(bank))
|
||||
self._cart_write(0x1000000, bank)
|
||||
elif args["save_type"] == 5: # FLASH 1M
|
||||
|
||||
@@ -253,10 +253,11 @@ class GbxDevice:
|
||||
except SerialException:
|
||||
return False
|
||||
|
||||
def Close(self):
|
||||
def Close(self, cartPowerOff=False):
|
||||
if self.IsConnected():
|
||||
try:
|
||||
self.set_mode(self.DEVICE_CMD["SET_PINS_AS_INPUTS"])
|
||||
if cartPowerOff:
|
||||
self.set_mode(self.DEVICE_CMD["SET_PINS_AS_INPUTS"])
|
||||
self.DEVICE.close()
|
||||
except:
|
||||
self.DEVICE = None
|
||||
|
||||
@@ -73,7 +73,7 @@ Use this command in a Terminal or Command Prompt window to launch the installed
|
||||
- MBC1M
|
||||
- MMM01
|
||||
- MAC-GBD (Game Boy Camera)
|
||||
- G-MMC1 (GB Memory)
|
||||
- G-MMC1 (GB-Memory Cartridge)
|
||||
- M161
|
||||
- HuC-1
|
||||
- HuC-3
|
||||
@@ -318,7 +318,7 @@ Many different reproduction cartridges share their flash chip command set, so ev
|
||||
|
||||
The author would like to thank the following very kind people for their help, contributions or documentation (in alphabetical order):
|
||||
|
||||
2358, 90sFlav, AcoVanConis, AdmirtheSableye, AlexiG, ALXCO-Hardware, AndehX, antPL, bbsan, BennVenn, ccs21, ClassicOldSong, CodyWick13, Corborg, Cristóbal, crizzlycruz, Crystal, Därk, Davidish, DevDavisNunez, Diddy_Kong, djedditt, Dr-InSide, dyf2007, easthighNerd, EchelonPrime, edo999, Ell, EmperorOfTigers, endrift, Erba Verde, ethanstrax, eveningmoose, Falknör, FerrantePescara, frarees, Frost Clock, gboh, gekkio, Godan, Grender, HDR, Herax, Hiccup, hiks, howie0210, iamevn, Icesythe7, ide, Jayro, Jenetrix, JFox, joyrider3774, JS7457, julgr, Kaede, kane159, KOOORAY, kscheel, kyokohunter, Leitplanke, litlemoran, LovelyA72, Luca DS, LucentW, manuelcm1, marv17, Merkin, metroid-maniac, Mr_V, olDirdey, orangeglo, paarongiroux, Paradoxical, Rairch, Raphaël BOICHOT, redalchemy, RetroGorek, RevZ, s1cp, Satumox, Sgt.DoudouMiel, SH, Shinichi999, Sillyhatday, Sithdown, skite2001, Smelly-Ghost, Stitch, Super Maker, t5b6_de, Tauwasser, Timville, twitnic, velipso, Veund, voltagex, Voultar, wickawack, Wkr, x7l7j8cc, xactoes, yosoo, Zeii, Zelante, zipplet, Zoo, zvxr
|
||||
2358, 90sFlav, AcoVanConis, AdmirtheSableye, AlexiG, ALXCO-Hardware, AndehX, antPL, bbsan, BennVenn, ccs21, ClassicOldSong, CodyWick13, Corborg, Cristóbal, crizzlycruz, Crystal, Därk, Davidish, DevDavisNunez, Diddy_Kong, djedditt, Dr-InSide, dyf2007, easthighNerd, EchelonPrime, edo999, Eldram, Ell, EmperorOfTigers, endrift, Erba Verde, ethanstrax, eveningmoose, Falknör, FerrantePescara, frarees, Frost Clock, gboh, gekkio, Godan, Grender, HDR, Herax, Hiccup, hiks, howie0210, iamevn, Icesythe7, ide, Jayro, Jenetrix, JFox, joyrider3774, JS7457, julgr, Kaede, kane159, KOOORAY, kscheel, kyokohunter, Leitplanke, litlemoran, LovelyA72, Luca DS, LucentW, manuelcm1, marv17, Merkin, metroid-maniac, Mr_V, olDirdey, orangeglo, paarongiroux, Paradoxical, Rairch, Raphaël BOICHOT, redalchemy, RetroGorek, RevZ, s1cp, Satumox, Sgt.DoudouMiel, SH, Shinichi999, Sillyhatday, Sithdown, skite2001, Smelly-Ghost, Stitch, Super Maker, t5b6_de, Tauwasser, Timville, twitnic, velipso, Veund, voltagex, Voultar, wickawack, Wkr, x7l7j8cc, xactoes, yosoo, Zeii, Zelante, zipplet, Zoo, zvxr
|
||||
|
||||
## DISCLAIMER
|
||||
|
||||
|
||||
2
setup.py
2
setup.py
@@ -8,7 +8,7 @@ with open("README.md", "r", encoding="utf-8") as fh: long_description = fh.read(
|
||||
|
||||
setuptools.setup(
|
||||
name="FlashGBX",
|
||||
version="3.32",
|
||||
version="3.33",
|
||||
author="Lesserkuma",
|
||||
description="Reads and writes Game Boy and Game Boy Advance cartridge data using the GBxCart RW by insideGadgets",
|
||||
url="https://github.com/lesserkuma/FlashGBX",
|
||||
|
||||
Reference in New Issue
Block a user