From 2dffc534ca111773e460c8fcfb4ae3ea069fff8a Mon Sep 17 00:00:00 2001 From: Lesserkuma Date: Fri, 27 May 2022 11:06:35 +0200 Subject: [PATCH] 3.12 --- CHANGES.md | 6 +++ FlashGBX/FlashGBX.py | 3 +- FlashGBX/FlashGBX_CLI.py | 85 +++++++++++++++++++++++++++++++-------- FlashGBX/RomFileDMG.py | 15 +++++-- FlashGBX/Util.py | 2 +- FlashGBX/hw_GBxCartRW.py | 1 + FlashGBX/res/config.zip | Bin 147653 -> 147653 bytes README.md | 1 + setup.py | 2 +- 9 files changed, 91 insertions(+), 24 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 513d479..971c430 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,4 +1,10 @@ # Release notes +### v3.12 (released 2022-05-27) +- Added proper detection of the Sachen 8B-001 mono unlicensed cartridge *(thanks voltagex)* +- Fixed an issue with dumping large-size GBA Video cartridges in CLI mode +- Added the option to generate ROM dump reports in CLI mode +- Minor bug fixes and improvements + ### v3.11 (released 2022-05-25) - Added the option to generate ROM dump reports for game preservation purposes *(thanks Hiccup)* - Bundles GBxCart RW v1.4 firmware version R35+L7 (improves SRAM access on reproduction cartridges and Game Boy Camera access) diff --git a/FlashGBX/FlashGBX.py b/FlashGBX/FlashGBX.py index 05eadc3..4eb875b 100644 --- a/FlashGBX/FlashGBX.py +++ b/FlashGBX/FlashGBX.py @@ -127,7 +127,7 @@ def main(portableMode=False): ap_cli2 = parser.add_argument_group('optional command line interface arguments') ap_cli2.add_argument("--dmg-romsize", choices=["auto", "32kb", "64kb", "128kb", "256kb", "512kb", "1mb", "2mb", "4mb", "8mb", "16mb", "32mb"], type=str.lower, default="auto", help="set size of Game Boy cartridge ROM data") - ap_cli2.add_argument("--dmg-mbc", choices=["auto", "1", "2", "3", "5", "6", "7"], type=str.lower, default="auto", help="set memory bank controller type of Game Boy cartridge") + ap_cli2.add_argument("--dmg-mbc", type=str.lower, default="auto", help="set memory bank controller type of Game Boy cartridge") ap_cli2.add_argument("--dmg-savesize", choices=["auto", "4k", "16k", "64k", "256k", "512k", "1m", "eeprom2k", "eeprom4k", "tama5", "4m"], type=str.lower, default="auto", help="set size of Game Boy cartridge save data") ap_cli2.add_argument("--agb-romsize", choices=["auto", "1mb", "2mb", "4mb", "8mb", "16mb", "32mb", "64mb", "128mb", "256mb"], type=str.lower, default="auto", help="set size of Game Boy Advance cartridge ROM data") ap_cli2.add_argument("--agb-savetype", choices=["auto", "eeprom4k", "eeprom64k", "sram256k", "flash512k", "flash1m", "dacs8m", "sram512k", "sram1m"], type=str.lower, default="auto", help="set type of Game Boy Advance cartridge save data") @@ -138,6 +138,7 @@ def main(portableMode=False): ap_cli2.add_argument("--reversed-sectors", action="store_true", help="use reversed flash sectors if possible") ap_cli2.add_argument("--force-5v", action="store_true", help="force 5V when writing Game Boy flash cartridges") ap_cli2.add_argument("--no-verify-write", action="store_true", help="do not verify written data") + ap_cli2.add_argument("--generate-dump-report", action="store_true", help="generate dump reports when making a ROM backup") ap_cli2.add_argument("--save-filename-add-datetime", action="store_true", help="adds a timestamp to the file name of save data backups") ap_cli2.add_argument("--gbcamera-palette", choices=["grayscale", "dmg", "sgb", "cgb1", "cgb2", "cgb3"], type=str.lower, default="grayscale", help="sets the palette of pictures extracted from Game Boy Camera saves") ap_cli2.add_argument("--gbcamera-outfile-format", choices=["png", "bmp", "gif", "jpg"], type=str.lower, default="png", help="sets the file format of saved pictures extracted from Game Boy Camera saves") diff --git a/FlashGBX/FlashGBX_CLI.py b/FlashGBX/FlashGBX_CLI.py index 833e8a6..d59aa1e 100644 --- a/FlashGBX/FlashGBX_CLI.py +++ b/FlashGBX/FlashGBX_CLI.py @@ -264,6 +264,13 @@ class FlashGBX_CLI(): pass def FinishOperation(self): + time_elapsed = None + speed = None + if "time_start" in self.PROGRESS.PROGRESS and self.PROGRESS.PROGRESS["time_start"] > 0: + time_elapsed = time.time() - self.PROGRESS.PROGRESS["time_start"] + speed = "{:.2f} KB/s".format((self.CONN.INFO["transferred"] / 1024.0) / time_elapsed) + self.PROGRESS.PROGRESS["time_start"] = 0 + if self.CONN.INFO["last_action"] == 4: # Flash ROM self.CONN.INFO["last_action"] = 0 if "verified" in self.PROGRESS.PROGRESS and self.PROGRESS.PROGRESS["verified"] == True: @@ -273,6 +280,25 @@ class FlashGBX_CLI(): elif self.CONN.INFO["last_action"] == 1: # Backup ROM self.CONN.INFO["last_action"] = 0 + dump_report = False + dumpinfo_file = "" + if self.ARGS["argparsed"].generate_dump_report is True: + try: + dump_report = self.CONN.GetDumpReport() + if dump_report is not False: + if time_elapsed is not None and speed is not None: + dump_report = dump_report.replace("%TRANSFER_RATE%", speed) + dump_report = dump_report.replace("%TIME_ELAPSED%", Util.formatProgressTime(time_elapsed)) + else: + dump_report = dump_report.replace("%TRANSFER_RATE%", "N/A") + dump_report = dump_report.replace("%TIME_ELAPSED%", "N/A") + dumpinfo_file = os.path.splitext(self.CONN.INFO["last_path"])[0] + ".txt" + with open(dumpinfo_file, "wb") as f: + f.write(bytearray([ 0xEF, 0xBB, 0xBF ])) # UTF-8 BOM + f.write(dump_report.encode("UTF-8")) + except Exception as e: + print("ERROR: {:s}".format(str(e))) + if self.CONN.GetMode() == "DMG": print("CRC32: {:08x}".format(self.CONN.INFO["file_crc32"])) print("SHA-1: {:s}\n".format(self.CONN.INFO["file_sha1"])) @@ -304,7 +330,7 @@ class FlashGBX_CLI(): else: msg += "\nThis may indicate a bad dump, however this can be normal for some reproduction cartridges, unlicensed games, prototypes, patched games and intentional overdumps." print("{:s}{:s}{:s}".format(ANSI.YELLOW, msg, ANSI.RESET)) - + elif self.CONN.INFO["last_action"] == 2: # Backup RAM self.CONN.INFO["last_action"] = 0 if not "debug" in self.ARGS and self.CONN.INFO["transferred"] == 131072: # 128 KB @@ -598,7 +624,7 @@ class FlashGBX_CLI(): stok = True s += "Save Type: {:s}\n".format(Util.AGB_Header_Save_Types[6]) data["save_type"] = 6 - + if stok is False: s += "Save Type: Not detected\n" @@ -732,12 +758,18 @@ class FlashGBX_CLI(): print("{:s}Couldn’t determine MBC type, will try to use MBC5. It can also be manually set with the “--dmg-mbc” command line switch.{:s}".format(ANSI.YELLOW, ANSI.RESET)) mbc = 0x19 else: - mbc = int(args.dmg_mbc) - if mbc == 2: mbc = 0x06 - elif mbc == 3: mbc = 0x13 - elif mbc == 5: mbc = 0x19 - elif mbc == 6: mbc = 0x20 - elif mbc == 7: mbc = 0x22 + if args.dmg_mbc.startswith("0x"): + mbc = int(args.dmg_mbc[2:], 16) + elif args.dmg_mbc.isnumeric(): + mbc = int(args.dmg_mbc) + if mbc == 2: mbc = 0x06 + elif mbc == 3: mbc = 0x13 + elif mbc == 5: mbc = 0x19 + elif mbc == 6: mbc = 0x20 + elif mbc == 7: mbc = 0x22 + else: mbc = 0x19 + else: + mbc = 0x19 if args.dmg_romsize == "auto": try: @@ -786,7 +818,6 @@ class FlashGBX_CLI(): print("Canceled.") return - try: f = open(path, "ab+") f.close() @@ -818,11 +849,25 @@ class FlashGBX_CLI(): if not "names" in carts[i]: continue if carts[i]["type"] != self.CONN.GetMode(): continue if args.flashcart_type in carts[i]["names"] and "flash_size" in carts[i]: - print("Selected flash cartridge type: {:s}".format(args.flashcart_type)) + print("Selected cartridge type: {:s}\n".format(args.flashcart_type)) rom_size = carts[i]["flash_size"] cart_type = i break - + if cart_type == 0: + print("ERROR: Couldn’t select the selected cartridge type.\n") + else: + if self.CONN.GetMode() == "AGB": + cart_types = self.CONN.GetSupportedCartridgesAGB() + if "flash_type" in header: + print("Selected cartridge type: {:s}\n".format(cart_types[0][i])) + cart_type = header["flash_type"] + elif header['logo_correct'] and header['3d_memory'] is True: + for i in range(0, len(cart_types[0])): + if "3d_memory" in cart_types[1][i]: + print("Selected cartridge type: {:s}\n".format(cart_types[0][i])) + cart_type = i + break + self.CONN.TransferData(args={ 'mode':1, 'path':path, 'mbc':mbc, 'rom_size':rom_size, 'agb_rom_size':rom_size, 'start_addr':0, 'fast_read_mode':True, 'cart_type':cart_type }, signal=self.PROGRESS.SetProgress) def FlashROM(self, args, header): @@ -960,12 +1005,18 @@ class FlashGBX_CLI(): print("{:s}Couldn’t determine MBC type, will try to use MBC5. It can also be manually set with the “--dmg-mbc” command line switch.{:s}".format(ANSI.YELLOW, ANSI.RESET)) mbc = 0x19 else: - mbc = int(args.dmg_mbc) - if mbc == 2: mbc = 0x06 - elif mbc == 3: mbc = 0x13 - elif mbc == 5: mbc = 0x19 - elif mbc == 6: mbc = 0x20 - elif mbc == 7: mbc = 0x22 + if args.dmg_mbc.startswith("0x"): + mbc = int(args.dmg_mbc[2:], 16) + elif args.dmg_mbc.isnumeric(): + mbc = int(args.dmg_mbc) + if mbc == 2: mbc = 0x06 + elif mbc == 3: mbc = 0x13 + elif mbc == 5: mbc = 0x19 + elif mbc == 6: mbc = 0x20 + elif mbc == 7: mbc = 0x22 + else: mbc = 0x19 + else: + mbc = 0x19 if args.dmg_savesize == "auto": try: diff --git a/FlashGBX/RomFileDMG.py b/FlashGBX/RomFileDMG.py index 15b91a2..8023c9e 100644 --- a/FlashGBX/RomFileDMG.py +++ b/FlashGBX/RomFileDMG.py @@ -225,10 +225,17 @@ class RomFileDMG: data["rom_checksum"] = 0x55E6 data["game_title"] = "SACHEN 4B-006" elif sachen_hash == bytearray([ 0xD8, 0x24, 0xD2, 0xB2, 0x71, 0x6B, 0x08, 0xFA, 0xEA, 0xA4, 0xFB, 0xD9, 0x7D, 0x81, 0x94, 0x57, 0x46, 0x77, 0x91, 0x60 ]): - data["rom_size_raw"] = 0x03 - data["mapper_raw"] = 0x204 - data["rom_checksum"] = 0x8E9F - data["game_title"] = "SACHEN 4B-007" + sachen_hash2 = hashlib.sha1(buffer[0x0:0x80]).digest() + if sachen_hash2 == bytearray([ 0x20, 0x17, 0x3B, 0x95, 0xFB, 0x1A, 0xAC, 0x81, 0x6C, 0x66, 0xF5, 0x62, 0x11, 0xF4, 0x96, 0xFB, 0xFB, 0x88, 0x03, 0xBC ]): + data["rom_size_raw"] = 0x04 + data["mapper_raw"] = 0x204 + data["rom_checksum"] = 0x657A + data["game_title"] = "SACHEN 8B-001" + else: + data["rom_size_raw"] = 0x03 + data["mapper_raw"] = 0x204 + data["rom_checksum"] = 0x8E9F + data["game_title"] = "SACHEN 4B-007" elif sachen_hash == bytearray([ 0x19, 0x3E, 0xF8, 0xE2, 0x12, 0x8A, 0x24, 0x10, 0xFE, 0xE9, 0xEA, 0x27, 0xC9, 0x1B, 0xC4, 0xDD, 0x04, 0x74, 0x1B, 0xA8 ]): data["rom_size_raw"] = 0x03 data["mapper_raw"] = 0x204 diff --git a/FlashGBX/Util.py b/FlashGBX/Util.py index e799dd1..92e853a 100644 --- a/FlashGBX/Util.py +++ b/FlashGBX/Util.py @@ -7,7 +7,7 @@ from enum import Enum # Common constants APPNAME = "FlashGBX" -VERSION_PEP440 = "3.11" +VERSION_PEP440 = "3.12" VERSION = "v{:s}".format(VERSION_PEP440) DEBUG = False diff --git a/FlashGBX/hw_GBxCartRW.py b/FlashGBX/hw_GBxCartRW.py index ec77b0e..135baaa 100644 --- a/FlashGBX/hw_GBxCartRW.py +++ b/FlashGBX/hw_GBxCartRW.py @@ -1990,6 +1990,7 @@ class GbxDevice: # Clean up self.INFO["last_action"] = self.INFO["action"] self.INFO["action"] = None + self.INFO["last_path"] = args["path"] self.SetProgress({"action":"FINISHED"}) return True diff --git a/FlashGBX/res/config.zip b/FlashGBX/res/config.zip index 04d69945db126d0b64bcb6d633ba17347e64840c..2d2b3e104dd70070c5ec998b7e8441f397749eba 100644 GIT binary patch delta 1300 zcmYk5T}YE*6vx}a-jG>@;OExVrq0c!F1NYOkBNj-3~#hAQq$!}nF)f0(9OiKE{doN zH=-=4)D-F_x+wZWcF~1WfwexMAm~CO!V(m^=>IoEZxZ>1?r5zs?t})UGVv5YCDfb27K? zpkAGyOYF2!hw^Pf_?K+x!@L1DYn(DYY#fPyEupM_pCdOX4kd+|1D>oFO|!%^Ign{>lk$ zg5P%9ryJp7bYXj@7~Mk`L}f;a!NVoE4CkM~=EwupNtxEB6I#cPQrfF%X?(sEmCV~6 z*n|1319|7N=>FM(8JU~P(4Bd{j0Tk0KjB!Mcmw7MC#GcnCFMt4$j9vm)%(42p_bWG zj<;c+Do1{2zi_s>ku#rjqn7!*8^6WevJ3h2u<##CY^%Wc#QEh4IL{KoS*t*Q=H5z! zmn*S5=e1SXG4(?DcdO`>&RHIVCp>gQ`SL?JeGt$KH+?jIOM}@oZt4LmO0H2Kf7J{{eHX=^O7HL$6Q?l$1^UR$r{X{@nirx z$Nds71@KeBIiY)l244?iOwK8U5h8De(-%S?=EV>kW?wD1V_i5mCEi?z({esk2WPb4 zuzHgBb=0SGQ$2cee!m_*b7lihd!|uW@2O!d7}{{qJp~c zjY#dHGLeWNx=XU~q6@{sY}7>;5tKw!WGPzqKj(c8?|b*-&;L9==e%=jAZ}_PuK$AR zF*}^3^o5slf<0YGK{dmUPxGeKDOKQO0xs@|_pbu_t-| z7S<{~!Mzd|9fy_GDbu@zFIzE(ybPN)M@L`{qLZfFzha#^jSrRsPt zPLdPyaF0z5V&a)R z$l&!sJT2wjL3C>Vh|YYFwMkc3U?$~b73lA?n)uZ>SK>Lz{gtds>DVsvp9Z&t^n5;q RvwdBn6RN^p$akw)=6|EL%Z&g4 diff --git a/README.md b/README.md index f8186ed..9cd9bf5 100644 --- a/README.md +++ b/README.md @@ -336,6 +336,7 @@ The author would like to thank the following very kind people for their help and - Timville (sample cartridge contribution, flash chip info) - twitnic (flash chip info) - Veund (flash chip info) +- voltagex (bug reports) - Voultar (bug reports, feature suggestions) - Wkr (flash chip info) - x7l7j8cc (flash chip info) diff --git a/setup.py b/setup.py index f5935cc..f287b3a 100644 --- a/setup.py +++ b/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.11", + version="3.12", author="Lesserkuma", description="Reads and writes Game Boy and Game Boy Advance cartridge data. Supported hardware: GBxCart RW v1.3 and v1.4 by insideGadgets.", url="https://github.com/lesserkuma/FlashGBX",