From 14d401a3f95c6fc738919698a0bd00f68bd8612c Mon Sep 17 00:00:00 2001 From: Lesserkuma Date: Tue, 5 Jul 2022 16:41:32 +0200 Subject: [PATCH] 3.15 --- CHANGES.md | 5 ++ FlashGBX/FlashGBX_GUI.py | 6 +- FlashGBX/Flashcart.py | 4 +- FlashGBX/Util.py | 2 +- FlashGBX/config/fc_AGB_GL256S.txt | 17 ++++ .../config/fc_DMG_FerranteCrafts_32KB.txt | 3 +- FlashGBX/config/fc_DMG_iG_1MB_2.txt | 52 ++++++++++++ FlashGBX/config/fc_DMG_iG_2MB.txt | 27 ++++++- FlashGBX/config/fc_DMG_iG_2MB_2.txt | 76 ++++++++++++++++++ FlashGBX/config/fc_DMG_iG_4MB_2.txt | 71 ++++++++++++++++ FlashGBX/hw_GBxCartRW.py | 9 ++- FlashGBX/hw_GBxCartRW_ofw.py | 12 +-- FlashGBX/res/config.zip | Bin 148139 -> 149749 bytes README.md | 3 + setup.py | 2 +- 15 files changed, 268 insertions(+), 21 deletions(-) create mode 100644 FlashGBX/config/fc_DMG_iG_1MB_2.txt create mode 100644 FlashGBX/config/fc_DMG_iG_2MB_2.txt create mode 100644 FlashGBX/config/fc_DMG_iG_4MB_2.txt diff --git a/CHANGES.md b/CHANGES.md index e296afc..09daf3f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,4 +1,9 @@ # Release notes +### v3.15 (released 2022-07-05) +- Improved support for several flash cartridge types +- Confirmed support for the Catskull 32k Gameboy Flash Cart *(thanks CodyWick13)* +- Minor bug fixes and improvements + ### v3.14 (released 2022-06-11) - Fixed a bug with extracting the Game Boy Camera’s Game Face image *(thanks 2358)* - Improved the default file names, now includes the ROM revision information as well diff --git a/FlashGBX/FlashGBX_GUI.py b/FlashGBX/FlashGBX_GUI.py index eccbbe4..51f66d1 100644 --- a/FlashGBX/FlashGBX_GUI.py +++ b/FlashGBX/FlashGBX_GUI.py @@ -2,7 +2,7 @@ # FlashGBX # Author: Lesserkuma (github.com/lesserkuma) -import sys, os, time, datetime, re, json, platform, subprocess, requests, webbrowser, pkg_resources, struct, math +import sys, os, time, datetime, json, platform, subprocess, requests, webbrowser, pkg_resources, struct, math from .pyside import QtCore, QtWidgets, QtGui, QApplication from .RomFileDMG import RomFileDMG from .RomFileAGB import RomFileAGB @@ -2297,9 +2297,9 @@ class FlashGBX_GUI(QtWidgets.QWidget): except ImportError: pass - try: + if callable(getattr(qt_app, "exec", None)): qt_app.exec() # PySide6 - except AttributeError: + else: qt_app.exec_() # PySide2 qt_app = QApplication(sys.argv) diff --git a/FlashGBX/Flashcart.py b/FlashGBX/Flashcart.py index 47af10c..b5284cd 100644 --- a/FlashGBX/Flashcart.py +++ b/FlashGBX/Flashcart.py @@ -179,8 +179,8 @@ class Flashcart: time.sleep(0.001) def VerifyFlashID(self): - if "read_identifier" not in self.CONFIG["commands"]: return False - if len(self.CONFIG["flash_ids"]) == 0: return False + if "read_identifier" not in self.CONFIG["commands"]: return (False, []) + if len(self.CONFIG["flash_ids"]) == 0: return (False, []) if "power_cycle" in self.CONFIG and self.CONFIG["power_cycle"] is True: self.CART_POWERCYCLE_FNCPTR() self.Reset() diff --git a/FlashGBX/Util.py b/FlashGBX/Util.py index 890617e..e311a85 100644 --- a/FlashGBX/Util.py +++ b/FlashGBX/Util.py @@ -7,7 +7,7 @@ from enum import Enum # Common constants APPNAME = "FlashGBX" -VERSION_PEP440 = "3.14" +VERSION_PEP440 = "3.15" VERSION = "v{:s}".format(VERSION_PEP440) DEBUG = False diff --git a/FlashGBX/config/fc_AGB_GL256S.txt b/FlashGBX/config/fc_AGB_GL256S.txt index a67e25e..7bcbf7e 100644 --- a/FlashGBX/config/fc_AGB_GL256S.txt +++ b/FlashGBX/config/fc_AGB_GL256S.txt @@ -9,6 +9,7 @@ "voltage":3.3, "flash_size":0x2000000, "sector_size":0x20000, + "chip_erase_timeout":120, "command_set":"AMD", "commands":{ "reset":[ @@ -38,6 +39,22 @@ [ null, null, null ], [ "SA", 0xFFFF, 0xFFFF ] ], + "chip_erase":[ + [ 0xAAA, 0xA9 ], + [ 0x555, 0x56 ], + [ 0xAAA, 0x80 ], + [ 0xAAA, 0xA9 ], + [ 0x555, 0x56 ], + [ 0xAAA, 0x10 ] + ], + "chip_erase_wait_for":[ + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ 0, 0xFFFF, 0xFFFF ] + ], "buffer_write":[ [ 0xAAA, 0xA9 ], [ 0x555, 0x56 ], diff --git a/FlashGBX/config/fc_DMG_FerranteCrafts_32KB.txt b/FlashGBX/config/fc_DMG_FerranteCrafts_32KB.txt index 43ea70d..7e9aa8d 100644 --- a/FlashGBX/config/fc_DMG_FerranteCrafts_32KB.txt +++ b/FlashGBX/config/fc_DMG_FerranteCrafts_32KB.txt @@ -1,7 +1,8 @@ { "type":"DMG", "names":[ - "Ferrante Crafts cart 32 KB" + "Ferrante Crafts cart 32 KB", + "Catskull 32k Gameboy Flash Cart" ], "flash_ids":[ [ 0xBF, 0xB5, 0x01, 0xFF ] diff --git a/FlashGBX/config/fc_DMG_iG_1MB_2.txt b/FlashGBX/config/fc_DMG_iG_1MB_2.txt new file mode 100644 index 0000000..346d8dd --- /dev/null +++ b/FlashGBX/config/fc_DMG_iG_1MB_2.txt @@ -0,0 +1,52 @@ +{ + "type":"DMG", + "names":[ + "insideGadgets 1 MB, 32 KB FRAM v2.0" + ], + "flash_ids":[], + "voltage":5, + "flash_size":0x100000, + "start_addr":0, + "first_bank":1, + "write_pin":"WR", + "chip_erase_timeout":120, + "command_set":"AMD", + "commands":{ + "reset":[ + [ 0, 0xF0 ] + ], + "read_identifier":[ + [ 0xAAA, 0xAA ], + [ 0x555, 0x55 ], + [ 0xAAA, 0x90 ] + ], + "chip_erase":[ + [ 0xAAA, 0xAA ], + [ 0x555, 0x55 ], + [ 0xAAA, 0x80 ], + [ 0xAAA, 0xAA ], + [ 0x555, 0x55 ], + [ 0xAAA, 0x10 ] + ], + "chip_erase_wait_for":[ + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ 0, 0xFF, 0xFF ] + ], + "single_write":[ + [ 0xAAA, 0xAA ], + [ 0x555, 0x55 ], + [ 0xAAA, 0xA0 ], + [ "PA", "PD" ] + ], + "single_write_wait_for":[ + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ] + ] + } +} diff --git a/FlashGBX/config/fc_DMG_iG_2MB.txt b/FlashGBX/config/fc_DMG_iG_2MB.txt index 5bc4a6b..eca763e 100644 --- a/FlashGBX/config/fc_DMG_iG_2MB.txt +++ b/FlashGBX/config/fc_DMG_iG_2MB.txt @@ -1,17 +1,22 @@ { "type":"DMG", "names":[ - "insideGadgets 2 MB, 128 KB SRAM/32 KB FRAM" + "insideGadgets 2 MB, 128 KB SRAM/32 KB FRAM (T)" ], "flash_ids":[ - [ 0x01, 0x01, 0xD2, 0xD2 ], - [ 0x01, 0x01, 0xD8, 0xD8 ] + [ 0x01, 0x01, 0xD2, 0xD2 ] ], "voltage":5, "flash_size":0x200000, "start_addr":0, "first_bank":1, "write_pin":"WR", + "sector_size":[ + [0x10000, 31], + [0x8000, 1], + [0x2000, 2], + [0x4000, 1] + ], "chip_erase_timeout":120, "command_set":"AMD", "commands":{ @@ -39,6 +44,22 @@ [ null, null, null ], [ 0, 0xFF, 0xFF ] ], + "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", 0xFF, 0xFF ] + ], "single_write":[ [ 0xAAA, 0xAA ], [ 0x555, 0x55 ], diff --git a/FlashGBX/config/fc_DMG_iG_2MB_2.txt b/FlashGBX/config/fc_DMG_iG_2MB_2.txt new file mode 100644 index 0000000..6b42de5 --- /dev/null +++ b/FlashGBX/config/fc_DMG_iG_2MB_2.txt @@ -0,0 +1,76 @@ +{ + "type":"DMG", + "names":[ + "insideGadgets 2 MB, 128 KB SRAM/32 KB FRAM (B)" + ], + "flash_ids":[ + [ 0x01, 0x01, 0xD8, 0xD8 ] + ], + "voltage":5, + "flash_size":0x200000, + "start_addr":0, + "first_bank":1, + "write_pin":"WR", + "sector_size":[ + [0x4000, 1], + [0x2000, 2], + [0x8000, 1], + [0x10000, 31] + ], + "chip_erase_timeout":120, + "command_set":"AMD", + "commands":{ + "reset":[ + [ 0, 0xF0 ] + ], + "read_identifier":[ + [ 0xAAA, 0xAA ], + [ 0x555, 0x55 ], + [ 0xAAA, 0x90 ] + ], + "chip_erase":[ + [ 0xAAA, 0xAA ], + [ 0x555, 0x55 ], + [ 0xAAA, 0x80 ], + [ 0xAAA, 0xAA ], + [ 0x555, 0x55 ], + [ 0xAAA, 0x10 ] + ], + "chip_erase_wait_for":[ + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ 0, 0xFF, 0xFF ] + ], + "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", 0xFF, 0xFF ] + ], + "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 ] + ] + } +} diff --git a/FlashGBX/config/fc_DMG_iG_4MB_2.txt b/FlashGBX/config/fc_DMG_iG_4MB_2.txt new file mode 100644 index 0000000..ce303e6 --- /dev/null +++ b/FlashGBX/config/fc_DMG_iG_4MB_2.txt @@ -0,0 +1,71 @@ +{ + "type":"DMG", + "names":[ + "insideGadgets 4 MB (S29JL032J)" + ], + "flash_ids":[ + [ 0x01, 0x01, 0x56, 0x56 ] + ], + "voltage":5, + "flash_size":0x400000, + "start_addr":0x4000, + "first_bank":0, + "write_pin":"WR", + "sector_size_from_cfi":true, + "chip_erase_timeout":60, + "command_set":"AMD", + "commands":{ + "reset":[ + [ 0, 0xF0 ] + ], + "read_identifier":[ + [ 0xAAA, 0xAA ], + [ 0x555, 0x55 ], + [ 0xAAA, 0x90 ] + ], + "chip_erase":[ + [ 0xAAA, 0xAA ], + [ 0x555, 0x55 ], + [ 0xAAA, 0x80 ], + [ 0xAAA, 0xAA ], + [ 0x555, 0x55 ], + [ 0xAAA, 0x10 ] + ], + "chip_erase_wait_for":[ + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ 0, 0xFF, 0xFF ] + ], + "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", 0xFF, 0xFF ] + ], + "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 ] + ] + } +} diff --git a/FlashGBX/hw_GBxCartRW.py b/FlashGBX/hw_GBxCartRW.py index 4433c30..c5ace0d 100644 --- a/FlashGBX/hw_GBxCartRW.py +++ b/FlashGBX/hw_GBxCartRW.py @@ -1394,7 +1394,7 @@ class GbxDevice: self._write(self.DEVICE_CMD["SET_VOLTAGE_5V"]) time.sleep(0.1) self._write(self.DEVICE_CMD["SET_MODE_DMG"]) - elif self.MODE == "DMG": + elif self.MODE == "AGB": self._write(self.DEVICE_CMD["SET_MODE_AGB"]) for f in range(1, len(supported_carts)): @@ -1446,13 +1446,14 @@ class GbxDevice: size = supp_flash_types[1][flash_types[0]]["flash_size"] size_undetected = False for i in range(0, len(flash_types)): - if size != supp_flash_types[1][flash_types[i]]["flash_size"]: - size_undetected = True + if "flash_size" in supp_flash_types[1][flash_types[i]]: + if size != supp_flash_types[1][flash_types[i]]["flash_size"]: + size_undetected = True if size_undetected: if isinstance(cfi, dict) and "device_size" in cfi: for i in range(0, len(flash_types)): - if cfi['device_size'] == supp_flash_types[1][flash_types[i]]["flash_size"]: + if "flash_size" in supp_flash_types[1][flash_types[i]] and cfi['device_size'] == supp_flash_types[1][flash_types[i]]["flash_size"]: flash_type_id = flash_types[i] size_undetected = False break diff --git a/FlashGBX/hw_GBxCartRW_ofw.py b/FlashGBX/hw_GBxCartRW_ofw.py index 0d5cd2f..8459ead 100644 --- a/FlashGBX/hw_GBxCartRW_ofw.py +++ b/FlashGBX/hw_GBxCartRW_ofw.py @@ -5,7 +5,7 @@ # This code is used for official firmware of GBxCart v1.3 only and this code is pure chaos, sorry # Refer to hw_GBxCartRW.py for the much cleaner rewrite (used for GBxCart RW v1.4 and firmware L1 on v1.3) -import time, math, struct, traceback, zlib, copy, hashlib, os, platform, datetime +import time, math, struct, traceback, zlib, copy, hashlib, os, datetime import serial, serial.tools.list_ports from serial import SerialException from .RomFileDMG import RomFileDMG @@ -1146,7 +1146,7 @@ class GbxDevice: if header is False or len(header) != 0x180: raise Exception("Couldn’t read the cartridge information. Please try again.") if Util.DEBUG: with open("debug_header.bin", "wb") as f: f.write(header) - + # Check for DACS dacs_8m = False if header[0x04:0x04+0x9C] == bytearray([0x00] * 0x9C): @@ -1490,10 +1490,10 @@ class GbxDevice: break self.INFO["dump_info"]["agb_savelib"] = temp_ver self.INFO["dump_info"]["agb_save_flash_id"] = None - if "FLASH" in temp_ver: - agb_save_flash_id = self.ReadFlashSaveID() - if agb_save_flash_id is not False and len(agb_save_flash_id) == 3: - self.INFO["dump_info"]["agb_save_flash_id"] = agb_save_flash_id + #if "FLASH" in temp_ver: + # agb_save_flash_id = self.ReadFlashSaveID() + # if agb_save_flash_id is not False and len(agb_save_flash_id) == 3: + # self.INFO["dump_info"]["agb_save_flash_id"] = agb_save_flash_id self.INFO["rom_checksum_calc"] = chk diff --git a/FlashGBX/res/config.zip b/FlashGBX/res/config.zip index 42df668159df6215557ae835b7f3c4982c1e6801..8f42583c4d9161e4f79103e8fe67f85a762cd56f 100644 GIT binary patch delta 5152 zcmZvf2|Shg_s8$^;K?4@$#P}6E^d}<&rUR!NJx@oi!6yG%UoF!QI`0YpRIZgAuEcs|I*VWJ z%<#_g52>Z$2#ItF1FS4WoUy~}V3&q)g4f@e)4fHXE4~6Tj8m-KMy=691o>U%pC>!d9~>;PK0w+T-#^0RFrST)g5-|ZvHXHQzC-)vx_n| zQysf!I_-C9I%r&P2q}rq%yir|<}~xeP%n4C%P=*qrB8e{Rw^drV5bIeLaViC)Vbsn z4+hWPGCtGOW>+tI&f|;1#WTW;k8_7@H4ap!4PTend69di^x5{BL9NO3>yxH|l?yey zqmL?UY@RW!YQ9S|6g<*>^|GvV!g#4lg{@aaxpC{qat>wj9xi?6-F
#sZ)Q&DMr3vYLdU)vJZ!Pz@q)m)MR}v5>J2rM<5{bk~$|nW8Tn8$0C|_gv z8Kg{vtvGqOQKA%?ROicR7}^H z_B#rF3HSSXqXYOjUeZ+SCh6oC;LmkBLKp<5&06$EOHgO&6RRMDAktC#v@^IQZ9$%rI#BPRi2;K^GegCEjcpjcPXRaiL}EcIbpOQn772Selppl&9pIS40$Qcu-iMnb8(3Fiyj<%KN}o9)G5H%+seVl zJIKac)4{@9i;%$C;UKChVC?zUG{qn-w?VCbLjH1Ety9ag+=hEfv%ij4DlC@dfBrBW zuz7K+)Z&&}-t(cK`s4E6y$vHRMh5!u-Vf$)F)|uwlAbBPS(iw=SQ8nltBbiYs)M^8 zb)Pie&I}=|MvIU0$o)=rtvV=uliR_4d{f%Z)3KIs1~UcTo)UBnAQG_TS|Q(4o}f0_QX_UUla(QI42e#B2A4iZTapEU4$jR-J?zFFXoQo;of zM2Z@J811I;O3%w}(2~-rbWlvM`)R(NrE{sUyT$&T>I=nB6LFKPOATpz8$vy}>--cS#^|Rdtm7%S9#&TKjx2FbsdY~5I*=%1b3oUj_STPMA$`@>dLxbEv7!Zj zt{SbEW2R zWZOF-W7WF(3d3QwU)n&_5reyfDNQ@}=CWEpv~Ko}oAF+$KKA7BmL3n2&f~^*ZV_3G zv`FTM>g?UZ@m(1@dXm-@Sq@6(hGh+lx}d^Ie)(I{-J)J+!ZeoEHuhili?y^K6&w-_ zvK8OxTTm~kep>y;kszkzl^&U7QC4EMlKlG!uF!K@XGKzztURe_b(hcgi*4bRu66G^ z)GV@r_MUz_RMxw2w?VI?aL|I9Dz~|L9OLv;C|4eBaxQ^Pj`&sXPq((GC)HnM1UY71 zi)q!qxJf>=s*0+_gUdFg4P_hY`~+pIuPyR;P^=lT@C&&rMP!Qdf2!qO4Vn^VZ;*zn zO%?DjQ&|a6wZIxB_KwNMv@)wvW1$mO!K~rK?ghuijxUU8eOA_!Y#bGu`0Ie!JE4&s zAvMTX+1^0eHbB{i-_aE(dTgL<-DLq@T`E6SPnR$_SjvqZvq&yGBjW1)ojt?PlLDb+ zd%ly5{MIw|?M zYk<3fY@e$aZZctaIHWPGQ_Dk`1>Gy7b4n?z-7Ky6xA_JKL@9T-yG0 zTBuhmROQ(oz4XG(4K>U8<$5W`wGZ!cH|KNz*0ROYOU>=(y*BlsBd+&cY2=1j<@nf! z98W4;J88E^MsOfmI@{1SUy_`s0ddt-hYYWkciChzuH4 zHBu$Y%*4+_bk#29DQ2Im@E%~i=enzp{PM-xi^Y}HzL{0znXz!bo_+%z3U(Kc5U7FY zTbDb%%C|b^UCo}M?dJlgs%1X;R4_uWJy~rj+wn7x`FQ)W^JNlTN+u%HR+*dh_2wiU zn^JhZ--uqA#CH?$(nrM`{aDB`3RZb(zhXi*cqWGK#qO{O+eRGPuSI=vULlV9V(k8e zEi8fV!({3RI~KRC5I;O-N&@x9wo?e(S`ziaQlkmG61S^*2wO-B-H)};5q2DIPa60W zb#YtxBw^caM1wHt8-(4A+ZqoDTSXcT!*(hJ;PJ)MXdo77N7&pl=pHQdJYk2(z&>xi zBJAH}P=BnIKM;>MlSTch{W`eKM0h^+96PQ15Z-wZ)ReS#>-nEM=!h(;$uB&kAHFV; ziOeJuIr!yJI@^&m2sm^G*$9T^P+kx!hjL;9_Xu|!bR#C9S`O9Xp~@W~D%~)P0-cJe z2%zR6{6K(=^1=vdGOEdAWwRDx)e*B65k^KOkyemSMpZGteB23|$uMImV3AQ3EV_k2 zGV&0~0~dKzl_&k#T8b;A__Y)l#paM+kY#EHFOobj~ z0yHbY=RI-=^ae*YKwc45lRYtsBPJ5^F1f5x^53(D7fKMSh)N+ekgkX-@^`EB3$HSm z$R+F`p1DO4rm+T#iYN{1*hwHoC5YO=ZY5YuEuKJGIHH0sCD^R$0D+cp)DM)EAzFG% zAa`YmJV2&0%q3wOf~W7mkvmv{h-XI@j+n^G)pKhjd|!?5^DDq#ef*ys{LftjyeX&} z7En(-oI`;RUkAMuSRw}v#q+&~2o{}2? z@K_z?1Kz6WI?P}{;SPar&(3MaKSoj_yw6S?gO$ZB7Ef|ozxcAY0z7!&b(NJN;b z!HE5x2=MBJDrc!dm17jc@oHtzgZv4es-ZgA33~#GsY8?n?A1{%tTK{7DG;%V_98&A z_iNWtXU!f&nlh1&P9kC%kErS+B1A!ZAA*5kb@=5xM&v_C+Dv3ixpj!~3lm}o@6Rw8mT8Hr#$Xc*DDih9wiHL(kTCh2` z{kf11QDwE5>RyEvX&Yo*lu0OIA%b$E~?BhUBVd?X{2?0cMg32 zUi0mM<6a~G-&+nhu`Nj?gd|QeG3Q*BQRZ+_Y;HC%HP8nM?uFMHNINwSZXwgF{*pxHDW^pFG2;}tP z%wNagjEQh;?EP-$-(SSOwu*N;xb$tOe_zYK?bMm)F5pXHB3u{Oirk8S9glzhXXe01 zAC*IWmqD^V{JG)iBO0vNhYfyQ0kisW@u-R%#lMJz0c1%Zz;**v88hBOuz1MW)IT9$ z^D-g!4ox4`gLb`-RK zK}5m%EinA(7~!eIJ)Rf}yb!o$5o72nS|vPE#<1*GPT*_|cSrfQSUh<$&K9{q6V3(z z!RBywi3gBP@N>9XAv z8p)FTR&P`;jVKAFt&Og>l-}n*{`01H`S{H7J->6#^PJ~4Z}(3Y^+wn66t^rLNi`k~nR_z&L^VIN+QBehfw_NQS0M9~WkE&d zweiuxI@1}a6*iQZAH4GT$}qQgbF+KRln;YGS0#pKvvh{p7TeRVUH>?$yG2TBmvHlX zLD=n$3)E!J?@xYmQ_WqSz1ktV``}>6UxyZSH|2TD8;n>gXW0j2xj#%j>u=r~bnboU zZ09NsN9%(rwukzZH~lzgSN6FdPP9+A3tBv46+S;Qq%T2QKI{9Oggq;CYfU|)mfp@< zZoV{&Khi#=#?L>jQts)pX#VB}p{?tJd9t250qtq>8+t60bA1vYPl+2)^pDXk0DzGhYA9~i< zB(aK@Ic;4DzcD{xXo&yB;8R3E94z$BGZS2{XkP+8l^>raJ!`G1!x;ki-jrd%#=WRs zl_^=-EO6qZUUT_dafbpmm>)j6l9vC)1miZuPCZcTThCKzYSnz6Dm80#pC7AK@Si10 zGm>B0%*~9hl;L zTaI^|?Uucf=g#D@R4$iZl<>ZE2VXwCznR_m!O-SlUi_w`dwkmpN)iqmt$ebwt3CRc z+?)P4HU*?^>*>4rIx?-TXs9HiR$b;2GsN$YV)gCm_F<-sEYkA| z+tzb^E4TdO;)=rlekTVb_38@imY8E?VKA}9QCK%0@7MV2?j%n!CyS+-s!e zI^_hx#~TuJ*?QgwBAl1b@lqLZz0sc;*^!v?OrzPJ7k*f4b;lImz;eaZ9cdeT9GZ6U z7G*98KNH#-QuD}X=Arb(3ojPldH6m`$-L&rjvSx*vtbL%FLpaEQZwkRyfnCi$Jy3U zc5dDL)b!>6sq6C;z3OWZjPmqr)9sbmA-s73PUTDQ7(CMF+sMd--N_CAcFlKF2QI(j z#uRE){Pye+EX3vyFw2~h;6n$4iVcs^~pGo`ib--`Z!!{ z2OHpU(+Ms_GVdFH%CWmknt`w@W1=1ZceDO!fGy?q{`I=HD_)4I;zjvP*w_XIz)Ci@ zV$mp{LRxTxAejjyMCaY&;h`B;1#LsD!PLq{5S)uNA;=J`h{IwHN!Sti)ev)7bw@d3(@4rx6z^<`&BQ3y6i?S7_hew{ z+D&r(}ju_%e0gx3(;G}TC$EpWM`2v(V>^7SOe*U zEC+L06HajBkV1v9kwa?BI#7BzNg*k?&mm){k(?PpC&0t(3tCShdpKc6a?M;N3hbtk zEhw5}uFM1?V>o_jqV`I2tbvD0AlaNui4HhpP69Ha&zz*y%@E~K;$j>8wiLX%Usxhx z%>CsEZj~bysN<5((dr)JL0nL>AUSE|X+h8xNU|W~az87|d4@tqq0a)_ijfwNAPZQ` z!#pwCNue^R;*m}Sw2K0V31Y6RL2$kXX@Hw0DNK7-SQ4=t?6v$NuA|UB7_}r-XqA-} ziH~kT@LL1fwI?mHto*IMg?$@bg(!YZRH29{@S8^HAfGInDOi)JtY!o^n&~K5YmKGE z?iAuiI&i_7l%^vFD5M56Y{+a<^y;WZ^tU1C1Z=klfBjlB7&E`xk1y_knH@Hh@45B4t9_Xe z?G|N%HFhL-6dbW5ouW}ELHJb%$l8--r`c?KsyBCGy*-&j;X2W@_=KT!xMz>;#Avz$ zK@9M9_=0v)XcJU9U~ATC5Cy&^i23e5f|een4x{#1Nq*c>{gm>q*&_{IPHXuQYV-Y3Ak5J2sFNK^grM3$p?SVQ}oZ5Tv~J|Fc^rT z&VYpIk|<3f>KvR{%aR{z|4{-oo$*ZO)jtueet}eBu``*?gdU=u$uLcx!%=5!EM~0~ z+y56xx?m#(ab8KSCMqu!yI>A;-Y|l#Z_soYa3QG%W$USpIqpKj?vH?tE9nf)LR|@q zcm;=Dv5}ZHQB3&_d~_uTnbz^#2y1);Yuw1?`_5XF4=A?w9o(G6#wn)yH`ut7-9+oc z+zD%c4+WFhb;6jp#}FV7l29sGl+en9f}apXd63c2FrR|QJ|np4K~mE26M@(bfwd=D zP{TA)bhsyB93~u@#BLJC?3BPDFOAhe(~C5NR@-_JPX-G^wG38=?UOveP#!}m3@hbG zOb&-!9jbFYuwwRIWOhnai8Y5Px~5`KQox#!>`fGLWf@!iU;j_Bo+xmP44j-pW=BVL zQA|b_6y}mc<#9`t$zv{IV{(u*m%OwzDeZv_n9D)^g;?0wklbTc`{v_j9DL^&zJ za&L0*0!Kxe4pQu%GF+d;Sn~*rQGwa>NJUx~OR+&!;LpRRh7(MPZu29L4J{CouL+VY S>P3qpzmgmVW1ku(|NR%+JY94E diff --git a/README.md b/README.md index 945f2ac..1b46583 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,8 @@ Available in the GitHub [Releases](https://github.com/lesserkuma/FlashGBX/releas * Windows Setup: An installer that will add the application to the start menu and optionally create a desktop icon * Windows Portable: Have everything in one place including the config files +These work for installing fresh and upgrading from an older version. + ### Run using Python (Linux, macOS, Windows) #### Installing @@ -93,6 +95,7 @@ Use this command in a Terminal or Command Prompt window to launch the installed - 29LV Series Flash BOY with 29LV160DB - BLAZE Xploder GB - BUNG Doctor GB Card 64M + - Catskull 32k Gameboy Flash Cart - DIY cart with AM29F010 - DIY cart with AM29F016 - DIY cart with AM29F032 diff --git a/setup.py b/setup.py index 3a566ce..afc0641 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.14", + version="3.15", 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",