mirror of
https://github.com/lesserkuma/FlashGBX.git
synced 2026-09-10 09:55:29 -05:00
3.26
This commit is contained in:
@@ -1,4 +1,9 @@
|
||||
# Release notes
|
||||
### v3.26 (released 2023-04-18)
|
||||
- Fixed a bug that made exporting Game Boy Camera pictures with a frame not work *(thanks Ell)*
|
||||
- Fixed a bug with Game Boy ROM write verification on sectors smaller than 0x4000 bytes *(thanks KOOORAY)*
|
||||
- Improved auto-detect for the BennVenn MBC3000 RTC cart
|
||||
|
||||
### v3.25 (released 2023-04-14)
|
||||
- Bundles GBxCart RW v1.4/v1.4a firmware version R41+L9 (minor improvements)
|
||||
- Fixed an issue with the Game Boy Camera Album Viewer *(thanks CodyWick13)*
|
||||
|
||||
@@ -1017,7 +1017,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
||||
if dontShowAgainCameraSavePopup: self.SETTINGS.setValue("SkipCameraSavePopup", "enabled")
|
||||
if answer == QtWidgets.QMessageBox.Yes:
|
||||
self.CAMWIN = None
|
||||
self.CAMWIN = PocketCameraWindow(self, icon=self.windowIcon(), file=self.CONN.INFO["last_path"], config_path=Util.CONFIG_PATH)
|
||||
self.CAMWIN = PocketCameraWindow(self, icon=self.windowIcon(), file=self.CONN.INFO["last_path"], config_path=Util.CONFIG_PATH, app_path=Util.APP_PATH)
|
||||
self.CAMWIN.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
|
||||
self.CAMWIN.setModal(True)
|
||||
self.CAMWIN.run()
|
||||
@@ -2690,7 +2690,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
||||
data = self.CONN.INFO["data"]
|
||||
|
||||
self.CAMWIN = None
|
||||
self.CAMWIN = PocketCameraWindow(self, icon=self.windowIcon(), file=data, config_path=Util.CONFIG_PATH)
|
||||
self.CAMWIN = PocketCameraWindow(self, icon=self.windowIcon(), file=data, config_path=Util.CONFIG_PATH, app_path=Util.APP_PATH)
|
||||
self.CAMWIN.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
|
||||
self.CAMWIN.setModal(True)
|
||||
self.CAMWIN.run()
|
||||
|
||||
@@ -17,6 +17,7 @@ class PocketCameraWindow(QtWidgets.QDialog):
|
||||
CUR_EXPORT_PATH = "."
|
||||
CUR_PC = None
|
||||
CUR_PALETTE = 3
|
||||
APP_PATH = "."
|
||||
CONFIG_PATH = "."
|
||||
APP = None
|
||||
PALETTES = [
|
||||
@@ -28,12 +29,13 @@ class PocketCameraWindow(QtWidgets.QDialog):
|
||||
[ 240, 240, 240, 134, 200, 100, 58, 96, 132, 30, 30, 30 ], # Game Boy Color (USA/EUR)
|
||||
]
|
||||
|
||||
def __init__(self, app, file=None, icon=None, config_path="."):
|
||||
def __init__(self, app, file=None, icon=None, config_path=".", app_path="."):
|
||||
QtWidgets.QDialog.__init__(self)
|
||||
self.setAcceptDrops(True)
|
||||
if icon is not None: self.setWindowIcon(QtGui.QIcon(icon))
|
||||
self.CUR_FILE = file
|
||||
self.CONFIG_PATH = config_path
|
||||
self.APP_PATH = app_path
|
||||
self.setWindowTitle("FlashGBX – GB Camera Album Viewer")
|
||||
self.setWindowFlags((self.windowFlags() | QtCore.Qt.MSWindowsFixedSizeDialogHint) & ~QtCore.Qt.WindowContextHelpButtonHint)
|
||||
|
||||
@@ -343,7 +345,7 @@ class PocketCameraWindow(QtWidgets.QDialog):
|
||||
frame = True
|
||||
own_frame = self.CONFIG_PATH + "/pc_frame.png"
|
||||
if not os.path.exists(own_frame):
|
||||
shutil.copy(self.APP.APP_PATH + "/res/pc_frame.png", own_frame)
|
||||
shutil.copy(self.APP_PATH + "/res/pc_frame.png", own_frame)
|
||||
with open(own_frame, "rb") as f: frame = f.read()
|
||||
|
||||
if index == 31: frame = False # last seen image
|
||||
|
||||
@@ -7,9 +7,9 @@ from enum import Enum
|
||||
|
||||
# Common constants
|
||||
APPNAME = "FlashGBX"
|
||||
VERSION_PEP440 = "3.25"
|
||||
VERSION_PEP440 = "3.26"
|
||||
VERSION = "v{:s}".format(VERSION_PEP440)
|
||||
VERSION_TIMESTAMP = 1681495829
|
||||
VERSION_TIMESTAMP = 1681817120
|
||||
DEBUG = False
|
||||
DEBUG_LOG = []
|
||||
APP_PATH = ""
|
||||
@@ -809,4 +809,4 @@ def dprint(*args, **kwargs):
|
||||
DEBUG_LOG = DEBUG_LOG[-32768:]
|
||||
if DEBUG:
|
||||
msg = "{:s}{:s}".format(ANSI.CLEAR_LINE, msg)
|
||||
#print(msg)
|
||||
print(msg)
|
||||
|
||||
@@ -17,7 +17,7 @@ class GbxDevice:
|
||||
DEVICE_NAME = "GBxCart RW"
|
||||
DEVICE_MIN_FW = 1
|
||||
DEVICE_MAX_FW = 9
|
||||
DEVICE_LATEST_FW_TS = { 4:1619427330, 5:1681395695, 6:1681395696 }
|
||||
DEVICE_LATEST_FW_TS = { 4:1681739002, 5:1681395695, 6:1681395696 }
|
||||
|
||||
DEVICE_CMD = {
|
||||
"NULL":0x30,
|
||||
@@ -114,7 +114,7 @@ class GbxDevice:
|
||||
FAST_READ = False
|
||||
SKIPPING = False
|
||||
BAUDRATE = 1000000
|
||||
MAX_BUFFER_LEN = 0x2000
|
||||
MAX_BUFFER_LEN = 0x800
|
||||
DEVICE_TIMEOUT = 0.75
|
||||
WRITE_DELAY = False
|
||||
READ_ERRORS = 0
|
||||
@@ -144,14 +144,12 @@ class GbxDevice:
|
||||
if not self.LoadFirmwareVersion() and max_baud >= 1700000:
|
||||
dev.close()
|
||||
self.BAUDRATE = 1700000
|
||||
self.MAX_BUFFER_LEN = 0x2000
|
||||
dev = serial.Serial(ports[i], self.BAUDRATE, timeout=0.1)
|
||||
self.DEVICE = dev
|
||||
if not self.LoadFirmwareVersion():
|
||||
if not self.LoadFirmwareVersion() or self.FW["pcb_ver"] not in (5, 6, 101):
|
||||
dev.close()
|
||||
self.DEVICE = None
|
||||
self.BAUDRATE = 1000000
|
||||
self.MAX_BUFFER_LEN = 0x100
|
||||
continue
|
||||
elif max_baud >= 1700000 and self.FW["pcb_ver"] in (5, 6, 101) and self.BAUDRATE < 1700000:
|
||||
self.ChangeBaudRate(baudrate=1700000)
|
||||
@@ -176,15 +174,17 @@ class GbxDevice:
|
||||
self.DEVICE = None
|
||||
conn_msg.append([3, "The GBxCart RW device on port " + ports[i] + " requires a firmware update to work with this software. Please try again after updating it to version L" + str(self.DEVICE_MIN_FW) + " or higher.<br><br>Firmware updates are available at <a href=\"https://www.gbxcart.com/\">https://www.gbxcart.com/</a>."])
|
||||
continue
|
||||
#elif self.FW["fw_ver"] < self.DEVICE_MAX_FW:
|
||||
# conn_msg.append([1, "The GBxCart RW device on port " + ports[i] + " is running an older firmware version. Please consider updating to version L" + str(self.DEVICE_MAX_FW) + " to make use of the latest features.<br><br>Firmware updates are available at <a href=\"https://www.gbxcart.com/\">https://www.gbxcart.com/</a>."])
|
||||
elif self.FW["fw_ver"] > self.DEVICE_MAX_FW:
|
||||
elif self.FW["fw_ts"] > self.DEVICE_LATEST_FW_TS[self.FW["pcb_ver"]]:
|
||||
conn_msg.append([0, "Note: The GBxCart RW device on port " + ports[i] + " is running a firmware version that is newer than what this version of FlashGBX was developed to work with, so errors may occur."])
|
||||
|
||||
if (self.FW["pcb_ver"] not in (4, 5, 6, 101)): # only the v1.3, v1.4, v1.4a, Mini v1.1 PCB revisions are supported
|
||||
if self.FW["pcb_ver"] not in (4, 5, 6, 101): # only the v1.3, v1.4, v1.4a, Mini v1.1 PCB revisions are supported
|
||||
dev.close()
|
||||
self.DEVICE = None
|
||||
continue
|
||||
elif self.FW["pcb_ver"] in (5, 6, 101) and self.BAUDRATE > 1000000:
|
||||
self.MAX_BUFFER_LEN = 0x2000
|
||||
else:
|
||||
self.MAX_BUFFER_LEN = 0x800
|
||||
|
||||
conn_msg.append([0, "For help please visit the insideGadgets Discord: https://gbxcart.com/discord"])
|
||||
|
||||
@@ -213,7 +213,6 @@ class GbxDevice:
|
||||
self.DEVICE.reset_output_buffer()
|
||||
self._write(self.DEVICE_CMD["OFW_PCB_VER"])
|
||||
temp = self.DEVICE.read(1)
|
||||
#if len(temp) == 0: return False
|
||||
pcb = temp[0]
|
||||
if pcb == b'': return False
|
||||
self._write(self.DEVICE_CMD["OFW_FW_VER"])
|
||||
@@ -255,12 +254,10 @@ class GbxDevice:
|
||||
self._write(self.DEVICE_CMD["OFW_USART_1_7M_SPEED"])
|
||||
self.Close()
|
||||
self.BAUDRATE = baudrate
|
||||
self.MAX_BUFFER_LEN = 0x2000
|
||||
elif baudrate == 1000000:
|
||||
self._write(self.DEVICE_CMD["OFW_USART_1_0M_SPEED"])
|
||||
self.Close()
|
||||
self.BAUDRATE = baudrate
|
||||
self.MAX_BUFFER_LEN = 0x100
|
||||
|
||||
def CanSetVoltageManually(self):
|
||||
return False
|
||||
@@ -377,8 +374,10 @@ class GbxDevice:
|
||||
return self.FW["pcb_ver"] in (4, 5, 6)
|
||||
|
||||
def FirmwareUpdateAvailable(self):
|
||||
if self.FW["pcb_ver"] not in (5, 6): return False
|
||||
return (self.FW["pcb_ver"] in (4, 5, 6) and self.FW["fw_ts"] < self.DEVICE_LATEST_FW_TS[self.FW["pcb_ver"]])
|
||||
if self.FW["pcb_ver"] not in (4, 5, 6): return False
|
||||
if (self.FW["pcb_ver"] in (4, 5, 6) and self.FW["fw_ts"] < self.DEVICE_LATEST_FW_TS[self.FW["pcb_ver"]]):
|
||||
if self.FW["pcb_ver"] == 4: self.FW_UPDATE_REQ = True
|
||||
return True
|
||||
|
||||
def GetFirmwareUpdaterClass(self):
|
||||
if self.FW["pcb_ver"] == 4: # v1.3
|
||||
@@ -1115,7 +1114,10 @@ class GbxDevice:
|
||||
buffer += temp
|
||||
if not self.NO_PROG_UPDATE:
|
||||
self.SetProgress({"action":"READ", "bytes_added":len(temp)})
|
||||
|
||||
|
||||
if self.MODE == "DMG":
|
||||
self._set_fw_variable("DMG_READ_CS_PULSE", 0)
|
||||
|
||||
return buffer
|
||||
|
||||
def ReadRAM_MBC7(self, address, length):
|
||||
@@ -1168,6 +1170,8 @@ class GbxDevice:
|
||||
buffer.append(data)
|
||||
self.SetProgress({"action":"UPDATE_POS", "abortable":False, "pos":i+1})
|
||||
|
||||
self._set_fw_variable("DMG_READ_CS_PULSE", 0)
|
||||
|
||||
self.NO_PROG_UPDATE = npu
|
||||
return buffer
|
||||
|
||||
@@ -2128,11 +2132,8 @@ class GbxDevice:
|
||||
end_bank = math.ceil((buffer_pos + args["bl_size"]) / rom_bank_size)
|
||||
rom_banks = end_bank
|
||||
|
||||
dprint("start_address=0x{:X}, end_address=0x{:X}, start_bank=0x{:X}, rom_banks=0x{:X}".format(start_address, end_address, start_bank, rom_banks))
|
||||
|
||||
dprint("start_address=0x{:X}, end_address=0x{:X}, start_bank=0x{:X}, rom_banks=0x{:X}, buffer_len=0x{:X}, max_length=0x{:X}".format(start_address, end_address, start_bank, rom_banks, buffer_len, max_length))
|
||||
bank = start_bank
|
||||
|
||||
#for bank in range(0, rom_banks):
|
||||
while bank < rom_banks:
|
||||
# ↓↓↓ Switch ROM bank
|
||||
if self.MODE == "DMG":
|
||||
@@ -2141,17 +2142,16 @@ class GbxDevice:
|
||||
self._write(self.DEVICE_CMD["DMG_MBC_RESET"], wait=True)
|
||||
(start_address, bank_size) = _mbc.SelectBankROM(bank)
|
||||
end_address = start_address + bank_size
|
||||
buffer_len = _mbc.GetROMBankSize()
|
||||
buffer_len = min(buffer_len, _mbc.GetROMBankSize())
|
||||
if "verify_write" in args:
|
||||
buffer_len = min(buffer_len, bank_size)
|
||||
#if "start_addr" in flashcart.CONFIG and bank == 0: start_address = flashcart.CONFIG["start_addr"]
|
||||
buffer_len = min(buffer_len, bank_size, len(args["verify_write"]))
|
||||
end_address = start_address + bank_size
|
||||
start_address += (buffer_pos % rom_bank_size)
|
||||
if end_address > start_address + args["verify_len"]:
|
||||
end_address = start_address + args["verify_len"]
|
||||
|
||||
# dprint("{:X}/{:X}/{:X}".format(start_address, bank_size, buffer_len))
|
||||
elif self.MODE == "AGB":
|
||||
if "verify_write" in args:
|
||||
buffer_len = min(buffer_len, len(args["verify_write"]))
|
||||
if "flash_bank_select_type" in cart_type and cart_type["flash_bank_select_type"] > 0:
|
||||
flashcart.SelectBankROM(bank)
|
||||
temp = end_address - start_address
|
||||
@@ -2163,8 +2163,6 @@ class GbxDevice:
|
||||
pos = start_address
|
||||
lives = 20
|
||||
|
||||
# dprint("pos_total=0x{:X}, start_address=0x{:X}, end_address=0x{:X}".format(pos_total, start_address, end_address))
|
||||
|
||||
while pos < end_address:
|
||||
temp = bytearray()
|
||||
if self.CANCEL:
|
||||
@@ -2184,26 +2182,26 @@ class GbxDevice:
|
||||
temp = self.ReadROM_3DMemory(address=pos, length=buffer_len, max_length=max_length)
|
||||
else:
|
||||
if self.FW["fw_ver"] >= 9 and "verify_write" in args and (self.MODE != "AGB" or args["verify_base_pos"] > 0xC9):
|
||||
# Verify mode (by checksum)
|
||||
dprint("Checksum verification (verify_base_pos=0x{:X}, pos=0x{:X}, pos_total=0x{:X}, buffer_len=0x{:X})".format(args["verify_base_pos"], pos, pos_total, buffer_len))
|
||||
# Verify mode (by CRC32)
|
||||
dprint("CRC32 verification (verify_base_pos=0x{:X}, pos=0x{:X}, pos_total=0x{:X}, buffer_len=0x{:X})".format(args["verify_base_pos"], pos, pos_total, buffer_len))
|
||||
if self.MODE == "DMG":
|
||||
self._set_fw_variable("ADDRESS", pos)
|
||||
elif self.MODE == "AGB":
|
||||
self._set_fw_variable("ADDRESS", pos >> 1)
|
||||
self._write(self.DEVICE_CMD["CALC_CRC32"])
|
||||
self._write(bytearray(struct.pack(">I", buffer_len)))
|
||||
checksum_expected = zlib.crc32(args["verify_write"][pos_total:pos_total+buffer_len])
|
||||
checksum_calculated = struct.unpack(">I", self._read(4))[0]
|
||||
dprint("Expected Checksum: 0x{:X}".format(checksum_expected))
|
||||
dprint("Calculated Checksum: 0x{:X}".format(checksum_calculated))
|
||||
if checksum_expected == checksum_calculated:
|
||||
crc32_expected = zlib.crc32(args["verify_write"][pos_total:pos_total+buffer_len])
|
||||
crc32_calculated = struct.unpack(">I", self._read(4))[0]
|
||||
dprint("Expected CRC32: 0x{:X}".format(crc32_expected))
|
||||
dprint("Calculated CRC32: 0x{:X}".format(crc32_calculated))
|
||||
if crc32_expected == crc32_calculated:
|
||||
pos += buffer_len
|
||||
pos_total += buffer_len
|
||||
dprint("Verification successful between 0x{:X} and 0x{:X}".format(pos_total-buffer_len, pos_total))
|
||||
dprint("CRC32 verification successful between 0x{:X} and 0x{:X}".format(pos_total-buffer_len, pos_total))
|
||||
self.SetProgress({"action":"UPDATE_POS", "pos":args["verify_from"]+pos_total})
|
||||
continue
|
||||
else:
|
||||
dprint("Mismatch during verification between 0x{:X} and 0x{:X}".format(pos_total, pos_total+buffer_len))
|
||||
dprint("Mismatch during CRC32 verification between 0x{:X} and 0x{:X}".format(pos_total, pos_total+buffer_len))
|
||||
return pos_total
|
||||
else:
|
||||
# Normal read
|
||||
@@ -3468,7 +3466,7 @@ class GbxDevice:
|
||||
if self.MODE == "DMG" and _mbc.HasFlashBanks(): _mbc.SelectBankFlash(bank)
|
||||
time.sleep(delay)
|
||||
if self.DEVICE is None:
|
||||
raise ConnectionAbortedError("An critical connection error occured while writing 0x{:X} bytes at position 0x{:X} ({:s}). Please re-connect the device and try again from the beginning.".format(buffer_len, buffer_pos, Util.formatFileSize(size=buffer_pos, asInt=False)))
|
||||
raise ConnectionAbortedError("A critical connection error occured while writing 0x{:X} bytes at position 0x{:X} ({:s}). Please re-connect the device and try again from the beginning.".format(buffer_len, buffer_pos, Util.formatFileSize(size=buffer_pos, asInt=False)))
|
||||
|
||||
self.CANCEL_ARGS = {}
|
||||
self.CANCEL = False
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -301,7 +301,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, crizzlycruz, Därk, Davidish, DevDavisNunez, Diddy_Kong, djedditt, Dr-InSide, dyf2007, easthighNerd, EchelonPrime, edo999, EmperorOfTigers, endrift, Erba Verde, ethanstrax, eveningmoose, Falknör, FerrantePescara, frarees, Frost Clock, gboh, gekkio, Godan, Grender, HDR, Herax, Hiccup, hiks, howie0210, iamevn, Icesythe7, Jayro, Jenetrix, JFox, joyrider3774, JS7457, julgr, Kaede, kscheel, kyokohunter, litlemoran, LovelyA72, Luca DS, LucentW, manuelcm1, marv17, metroid-maniac, Mr_V, orangeglo, paarongiroux, Paradoxical, Rairch, Raphaël BOICHOT, redalchemy, RetroGorek, RevZ, s1cp, Satumox, Sgt.DoudouMiel, Shinichi999, sillyhatday, Sithdown, skite2001, Smelly-Ghost, Stitch, Super Maker, t5b6_de, Tauwasser, Timville, twitnic, velipso, Veund, voltagex, Voultar, Wkr, x7l7j8cc, xactoes, Zeii, Zelante, zvxr
|
||||
2358, 90sFlav, AcoVanConis, AdmirtheSableye, AlexiG, ALXCO-Hardware, AndehX, antPL, bbsan, BennVenn, ccs21, ClassicOldSong, CodyWick13, Corborg, crizzlycruz, 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, Jayro, Jenetrix, JFox, joyrider3774, JS7457, julgr, Kaede, KOOORAY, kscheel, kyokohunter, litlemoran, LovelyA72, Luca DS, LucentW, manuelcm1, marv17, metroid-maniac, Mr_V, orangeglo, paarongiroux, Paradoxical, Rairch, Raphaël BOICHOT, redalchemy, RetroGorek, RevZ, s1cp, Satumox, Sgt.DoudouMiel, Shinichi999, sillyhatday, Sithdown, skite2001, Smelly-Ghost, Stitch, Super Maker, t5b6_de, Tauwasser, Timville, twitnic, velipso, Veund, voltagex, Voultar, Wkr, x7l7j8cc, xactoes, Zeii, Zelante, zvxr
|
||||
|
||||
## DISCLAIMER
|
||||
|
||||
|
||||
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="3.25",
|
||||
version="3.26",
|
||||
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