mirror of
https://github.com/lesserkuma/FlashGBX.git
synced 2026-04-25 16:19:24 -05:00
2.5
This commit is contained in:
parent
77818e539d
commit
4883088a1e
|
|
@ -1,4 +1,9 @@
|
|||
# Release notes
|
||||
### v2.5 (released 2021-07-15)
|
||||
- Added support for 4350Q2 with 4050V0YBQ1
|
||||
- Fixed Real Time Clock register access for MBC3B and MBC30 cartridges on the GBxCart RW v1.4 hardware
|
||||
- Added support for SD007_BV5 with 29LV160TE-70PFTN *(thanks RetroGorek)*
|
||||
|
||||
### v2.4 (released 2021-06-20)
|
||||
- Added support for 4050_4400_4000_4350_36L0R_6108 with M36L0R7050B *(thanks Jayro)*
|
||||
- Added support for AGB-E05-02 with JS28F128 *(thanks marv17)*
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ def LoadConfig(args):
|
|||
ret.append([1, "The application was recently updated and some flashcart handler files have been updated as well. You will find backup copies of them in your configuration directory.\n\nUpdated files:\n" + rf_list[:-1]])
|
||||
fc_files = glob.glob("{0:s}/fc_*.txt".format(config_path))
|
||||
else:
|
||||
ret.append([2, "{:s} not found. This is required to load new flash cartridge type configurations after updating.\n".format(app_path + "/res/config.zip")])
|
||||
print("WARNING: {:s} not found. This is required to load new flash cartridge type configurations after updating.".format(app_path + "/res/config.zip"))
|
||||
|
||||
# Read flash cart types
|
||||
for file in fc_files:
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ class FlashGBX_CLI():
|
|||
# Ask interactively if no args set
|
||||
if args.action is None:
|
||||
actions = ["info", "backup-rom", "flash-rom", "backup-save", "restore-save", "erase-save", "gbcamera-extract", "debug-test-save"]
|
||||
print("Select Operation:\n 1) Read Cartridge Information\n 2) Backup ROM\n 3) Flash ROM\n 4) Backup Save Data\n 5) Restore Save Data\n 6) Erase Save Data\n 7) Extract Game Boy Camera Pictures\n")
|
||||
print("Select Operation:\n 1) Read Cartridge Information\n 2) Backup ROM\n 3) Write ROM\n 4) Backup Save Data\n 5) Restore Save Data\n 6) Erase Save Data\n 7) Extract Game Boy Camera Pictures\n")
|
||||
args.action = input("Enter number 1-7 [1]: ").lower().strip()
|
||||
print("")
|
||||
try:
|
||||
|
|
@ -252,9 +252,9 @@ class FlashGBX_CLI():
|
|||
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:
|
||||
print("{:s}The ROM was flashed and verified successfully!{:s}".format(ANSI.GREEN, ANSI.RESET))
|
||||
print("{:s}The ROM was written and verified successfully!{:s}".format(ANSI.GREEN, ANSI.RESET))
|
||||
else:
|
||||
print("ROM flashing complete!")
|
||||
print("ROM writing complete!")
|
||||
|
||||
elif self.CONN.INFO["last_action"] == 1: # Backup ROM
|
||||
self.CONN.INFO["last_action"] = 0
|
||||
|
|
@ -527,7 +527,7 @@ class FlashGBX_CLI():
|
|||
|
||||
detected = self.CONN.AutoDetectFlash(limitVoltage)
|
||||
if len(detected) == 0:
|
||||
print("\n{:s}No pre-configured flash cartridge type was detected.{:s} You can still manually specify one using the “--flashcart-handler” command line switch -- look for similar PCB text and/or flash chip markings. However, chances are this cartridge is currently not supported for flashing with {:s}.\n".format(ANSI.YELLOW, ANSI.RESET, APPNAME))
|
||||
print("\n{:s}No pre-configured flash cartridge type was detected.{:s} You can still manually specify one using the “--flashcart-handler” command line switch -- look for similar PCB text and/or flash chip markings. However, chances are this cartridge is currently not supported for ROM writing with {:s}.\n".format(ANSI.YELLOW, ANSI.RESET, APPNAME))
|
||||
|
||||
(flash_id, cfi_s, cfi) = self.CONN.CheckFlashChip(limitVoltage)
|
||||
if cfi_s == "":
|
||||
|
|
@ -736,7 +736,7 @@ class FlashGBX_CLI():
|
|||
return
|
||||
|
||||
if args.path == "auto":
|
||||
print("{:s}No ROM file for flashing was selected.{:s}".format(ANSI.RED, ANSI.RESET))
|
||||
print("{:s}No ROM file for writing was selected.{:s}".format(ANSI.RED, ANSI.RESET))
|
||||
return
|
||||
else:
|
||||
path = args.path
|
||||
|
|
@ -757,7 +757,7 @@ class FlashGBX_CLI():
|
|||
if "flash_size" in carts[cart_type]:
|
||||
if rom_size > carts[cart_type]['flash_size']:
|
||||
msg = "The selected flash cartridge type seems to support ROMs that are up to {:.2f} MB in size, but the file you selected is {:.2f} MB.".format(carts[cart_type]['flash_size'] / 1024 / 1024, os.path.getsize(path)/1024/1024)
|
||||
msg += " It’s possible that it’s too large which may cause the flashing to fail."
|
||||
msg += " It’s possible that it’s too large which may cause the ROM writing to fail."
|
||||
print("{:s}{:s}{:s}".format(ANSI.YELLOW, msg, ANSI.RESET))
|
||||
answer = input("Do you want to continue? [y/N]: ").strip().lower()
|
||||
print("")
|
||||
|
|
@ -776,7 +776,7 @@ class FlashGBX_CLI():
|
|||
reverse_sectors = True
|
||||
print("Will be writing to the cartridge with reversed flash sectors.")
|
||||
elif 'sector_reversal' in carts[cart_type]:
|
||||
print("The selected flash cartridge type is reported to sometimes have reversed sectors. You can use the “--reversed-sectors” command line switch if the cartridge is not working after flashing.")
|
||||
print("The selected flash cartridge type is reported to sometimes have reversed sectors. You can use the “--reversed-sectors” command line switch if the cartridge is not working after writing the ROM.")
|
||||
|
||||
prefer_chip_erase = args.prefer_chip_erase is True
|
||||
if not prefer_chip_erase and 'chip_erase' in carts[cart_type]['commands'] and 'sector_erase' in carts[cart_type]['commands']:
|
||||
|
|
|
|||
|
|
@ -2,11 +2,10 @@
|
|||
# FlashGBX
|
||||
# Author: Lesserkuma (github.com/lesserkuma)
|
||||
|
||||
import sys, os, time, datetime, re, json, platform, subprocess, argparse, requests, webbrowser, pkg_resources, traceback
|
||||
import sys, os, time, datetime, re, json, platform, subprocess, requests, webbrowser, pkg_resources
|
||||
from PySide2 import QtCore, QtWidgets, QtGui
|
||||
from .RomFileDMG import RomFileDMG
|
||||
from .RomFileAGB import RomFileAGB
|
||||
from .PocketCamera import PocketCamera
|
||||
from .PocketCameraWindow import PocketCameraWindow
|
||||
#from .GBMemoryWindow import GBMemoryWindow
|
||||
from .Util import APPNAME, VERSION, VERSION_PEP440, ANSI
|
||||
|
|
@ -85,7 +84,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
self.cmbDMGCartridgeTypeResult.currentIndexChanged.connect(self.CartridgeTypeChanged)
|
||||
|
||||
rowActionsGeneral3 = QtWidgets.QHBoxLayout()
|
||||
self.btnFlashROM = QtWidgets.QPushButton("&Flash ROM")
|
||||
self.btnFlashROM = QtWidgets.QPushButton("&Write ROM")
|
||||
self.btnFlashROM.setStyleSheet("min-height: 17px;")
|
||||
self.connect(self.btnFlashROM, QtCore.SIGNAL("clicked()"), self.FlashROM)
|
||||
rowActionsGeneral3.addWidget(self.btnFlashROM)
|
||||
|
|
@ -787,9 +786,9 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
|
||||
self.lblStatus4a.setText("Done!")
|
||||
if "verified" in self.PROGRESS.PROGRESS and self.PROGRESS.PROGRESS["verified"] == True:
|
||||
msgbox.setText("The ROM was flashed and verified successfully!")
|
||||
msgbox.setText("The ROM was written and verified successfully!")
|
||||
else:
|
||||
msgbox.setText("ROM flashing complete!")
|
||||
msgbox.setText("ROM writing complete!")
|
||||
if not dontShowAgain:
|
||||
msgbox.exec()
|
||||
dontShowAgain = cb.isChecked()
|
||||
|
|
@ -921,7 +920,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
else:
|
||||
detected = self.CONN.AutoDetectFlash(limitVoltage)
|
||||
if len(detected) == 0:
|
||||
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Question, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text="No pre-configured flash cartridge type was detected. You can still try and manually select one from the list -- look for similar PCB text and/or flash chip markings. However, chances are this cartridge is currently not supported for flashing with " + APPNAME + ".\n\nWould you like " + APPNAME + " to run a flash chip query? This may help adding support for your flash cartridge in the future.", standardButtons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
|
||||
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Question, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text="No pre-configured flash cartridge type was detected. You can still try and manually select one from the list -- look for similar PCB text and/or flash chip markings. However, chances are this cartridge is currently not supported for ROM writing with " + APPNAME + ".\n\nWould you like " + APPNAME + " to run a flash chip query? This may help adding support for your flash cartridge in the future.", standardButtons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
|
||||
msgbox.setDefaultButton(QtWidgets.QMessageBox.Yes)
|
||||
if self.CONN.GetMode() == "DMG":
|
||||
msgbox.setCheckBox(cb)
|
||||
|
|
@ -1150,9 +1149,9 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
|
||||
while path == "":
|
||||
if self.CONN.GetMode() == "DMG":
|
||||
path = QtWidgets.QFileDialog.getOpenFileName(self, "Flash ROM", last_dir, "Game Boy ROM File (*.gb *.gbc *.sgb *.bin);;All Files (*.*)")[0]
|
||||
path = QtWidgets.QFileDialog.getOpenFileName(self, "Write ROM", last_dir, "Game Boy ROM File (*.gb *.gbc *.sgb *.bin);;All Files (*.*)")[0]
|
||||
elif self.CONN.GetMode() == "AGB":
|
||||
path = QtWidgets.QFileDialog.getOpenFileName(self, "Flash ROM", last_dir, "Game Boy Advance ROM File (*.gba *.srl);;All Files (*.*)")[0]
|
||||
path = QtWidgets.QFileDialog.getOpenFileName(self, "Write ROM", last_dir, "Game Boy Advance ROM File (*.gba *.srl);;All Files (*.*)")[0]
|
||||
|
||||
if (path == ""): return
|
||||
|
||||
|
|
@ -1170,7 +1169,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
if "flash_size" in carts[cart_type]:
|
||||
if rom_size > carts[cart_type]['flash_size']:
|
||||
msg = "The selected flash cartridge type seems to support ROMs that are up to {:.2f} MB in size, but the file you selected is {:.2f} MB.".format(carts[cart_type]['flash_size'] / 1024 / 1024, os.path.getsize(path)/1024/1024)
|
||||
msg += " You can still give it a try, but it’s possible that it’s too large which may cause the flashing to fail."
|
||||
msg += " You can still give it a try, but it’s possible that it’s too large which may cause the ROM writing to fail."
|
||||
answer = QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), msg, QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel)
|
||||
if answer == QtWidgets.QMessageBox.Cancel: return
|
||||
|
||||
|
|
@ -1189,7 +1188,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
|
||||
reverse_sectors = False
|
||||
if 'sector_reversal' in carts[cart_type]:
|
||||
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Question, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text="The selected flash cartridge type is reported to sometimes have reversed sectors. If the cartridge is not working after flashing, try reversed sectors.")
|
||||
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Question, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text="The selected flash cartridge type is reported to sometimes have reversed sectors. If the cartridge is not working after writing the ROM, try reversed sectors.")
|
||||
button_normal = msgbox.addButton("Normal", QtWidgets.QMessageBox.ActionRole)
|
||||
button_reversed = msgbox.addButton("Reversed", QtWidgets.QMessageBox.ActionRole)
|
||||
button_cancel = msgbox.addButton("&Cancel", QtWidgets.QMessageBox.RejectRole)
|
||||
|
|
@ -1465,7 +1464,17 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
|
||||
def ReadCartridge(self, resetStatus=True):
|
||||
if not self.CheckDeviceAlive(): return
|
||||
self.btnHeaderRefresh.setEnabled(False)
|
||||
self.lblStatus4a.setText("Reading cartridge data...")
|
||||
self.SetProgressBars(min=0, max=0, value=1)
|
||||
qt_app.processEvents()
|
||||
data = self.CONN.ReadInfo(setPinsAsInputs=True)
|
||||
self.btnHeaderRefresh.setEnabled(True)
|
||||
self.btnHeaderRefresh.setFocus()
|
||||
self.SetProgressBars(min=0, max=100, value=0)
|
||||
#if "has_rtc" in data and data["has_rtc"] is True: print("Real Time Clock cartridge detected.")
|
||||
self.lblStatus4a.setText("Ready.")
|
||||
qt_app.processEvents()
|
||||
|
||||
if data == False or len(data) == 0:
|
||||
self.DisconnectDevice()
|
||||
|
|
@ -1662,7 +1671,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
if args["method"] == "ROM_READ":
|
||||
self.grpStatus.setTitle("Transfer Status (Backup ROM)")
|
||||
elif args["method"] == "ROM_WRITE":
|
||||
self.grpStatus.setTitle("Transfer Status (Flash ROM)")
|
||||
self.grpStatus.setTitle("Transfer Status (Write ROM)")
|
||||
elif args["method"] == "ROM_WRITE_VERIFY":
|
||||
self.grpStatus.setTitle("Transfer Status (Verify Flash)")
|
||||
elif args["method"] == "SAVE_READ":
|
||||
|
|
@ -1882,8 +1891,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
if self.btnHeaderRefresh.isEnabled() and self.grpActions.isEnabled() and e.mimeData().hasUrls:
|
||||
for url in e.mimeData().urls():
|
||||
if platform.system() == 'Darwin':
|
||||
# pylint: disable=undefined-variable
|
||||
fn = str(NSURL.URLWithString_(str(url.toString())).filePathURL().path())
|
||||
fn = str(NSURL.URLWithString_(str(url.toString())).filePathURL().path()) # type: ignore
|
||||
else:
|
||||
fn = str(url.toLocalFile())
|
||||
|
||||
|
|
@ -1904,8 +1912,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
e.accept()
|
||||
for url in e.mimeData().urls():
|
||||
if platform.system() == 'Darwin':
|
||||
# pylint: disable=undefined-variable
|
||||
fn = str(NSURL.URLWithString_(str(url.toString())).filePathURL().path())
|
||||
fn = str(NSURL.URLWithString_(str(url.toString())).filePathURL().path()) # type: ignore
|
||||
else:
|
||||
fn = str(url.toLocalFile())
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@
|
|||
# Author: Lesserkuma (github.com/lesserkuma)
|
||||
|
||||
import time, copy, math, struct
|
||||
from .Util import ANSI, dprint, bitswap
|
||||
from . import Util
|
||||
from .Util import dprint, bitswap
|
||||
|
||||
class Flashcart:
|
||||
CONFIG = {}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
import time, datetime, struct, math, hashlib
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from .RomFileDMG import RomFileDMG
|
||||
from .Util import ANSI, dprint
|
||||
from .Util import dprint
|
||||
from . import Util
|
||||
|
||||
class DMG_MBC:
|
||||
|
|
@ -201,37 +201,49 @@ class DMG_MBC3(DMG_MBC):
|
|||
def EnableRAM(self, enable=True):
|
||||
dprint(self.GetName(), "|", enable)
|
||||
commands = [
|
||||
[ 0x6000, 0x01 if enable else 0x00 ],
|
||||
#[ 0x6000, 0x01 if enable else 0x00 ],
|
||||
[ 0x0000, 0x0A if enable else 0x00 ],
|
||||
]
|
||||
self.CartWrite(commands)
|
||||
|
||||
def HasRTC(self):
|
||||
dprint(self.GetName())
|
||||
self.EnableRAM(enable=True)
|
||||
ram1 = self.CartRead(0xA000, 0x10)
|
||||
self.LatchRTC()
|
||||
self.CartWrite([ [0x4000, 0x08] ])
|
||||
ram2 = self.CartRead(0xA000, 0x10)
|
||||
if self.MBC_ID != 16: return False
|
||||
self.EnableRAM(enable=False)
|
||||
#return (self.MBC_ID == 0x10)
|
||||
self.EnableRAM(enable=True)
|
||||
self.CartWrite([ [0x4000, 0x08] ])
|
||||
self.LatchRTC()
|
||||
ram1 = self.CartRead(0xA000, 0x10)
|
||||
ram2 = ram1
|
||||
t1 = time.time()
|
||||
t2 = 0
|
||||
while t2 < (t1 + 1):
|
||||
self.LatchRTC()
|
||||
ram2 = self.CartRead(0xA000, 0x10)
|
||||
if ram1 != ram2: break
|
||||
t2 = time.time()
|
||||
dprint("RTC_S {:02X} != {:02X}?".format(ram1[0], ram2[0]), ram1 != ram2)
|
||||
time.sleep(0.1)
|
||||
return (ram1 != ram2)
|
||||
|
||||
def GetRTCBufferSize(self):
|
||||
return 0x30
|
||||
|
||||
def LatchRTC(self):
|
||||
self.EnableRAM(enable=True)
|
||||
self.CartWrite([
|
||||
[ 0x6000, 0 ],
|
||||
[ 0x6000, 1 ],
|
||||
])
|
||||
self.CLK_TOGGLE_FNCPTR(5)
|
||||
self.CLK_TOGGLE_FNCPTR(60)
|
||||
self.CartWrite([ [ 0x0000, 0x0A ] ])
|
||||
time.sleep(0.01)
|
||||
self.CLK_TOGGLE_FNCPTR(60)
|
||||
self.CartWrite([ [ 0x6000, 0x00 ] ])
|
||||
self.CLK_TOGGLE_FNCPTR(60)
|
||||
self.CartWrite([ [ 0x6000, 0x01 ] ])
|
||||
time.sleep(0.01)
|
||||
|
||||
def ReadRTC(self):
|
||||
self.EnableRAM(enable=True)
|
||||
#self.EnableRAM(enable=True)
|
||||
buffer = bytearray()
|
||||
for i in range(0x08, 0x0D):
|
||||
self.CLK_TOGGLE_FNCPTR(60)
|
||||
self.CartWrite([ [0x4000, i] ])
|
||||
buffer.extend(struct.pack("<I", self.CartRead(0xA000)))
|
||||
buffer.extend(buffer) # copy
|
||||
|
|
@ -239,15 +251,12 @@ class DMG_MBC3(DMG_MBC):
|
|||
# Add timestamp of backup time
|
||||
ts = int(time.time())
|
||||
buffer.extend(struct.pack("<Q", ts))
|
||||
|
||||
dstr = ' '.join(format(x, '02X') for x in buffer)
|
||||
dprint("[{:02X}] {:s}".format(int(len(dstr)/3) + 1, dstr))
|
||||
|
||||
|
||||
return buffer
|
||||
|
||||
def WriteRTC(self, buffer, advance=False):
|
||||
dprint(buffer)
|
||||
self.LatchRTC()
|
||||
#self.LatchRTC()
|
||||
if advance:
|
||||
try:
|
||||
dt_now = datetime.datetime.fromtimestamp(time.time())
|
||||
|
|
@ -299,14 +308,76 @@ class DMG_MBC3(DMG_MBC):
|
|||
except Exception as e:
|
||||
print("Couldn’t update the RTC register values\n", e)
|
||||
|
||||
dprint("New values: RTC_S=0x{:02X}, RTC_M=0x{:02X}, RTC_H=0x{:02X}, RTC_DL=0x{:02X}, RTC_DH=0x{:02X}".format(buffer[0x00], buffer[0x04], buffer[0x08], buffer[0x0C], buffer[0x10]))
|
||||
|
||||
# Unlock and latch RTC
|
||||
self.CLK_TOGGLE_FNCPTR(50)
|
||||
self.CartWrite([ [ 0x0000, 0x0A ] ])
|
||||
self.CLK_TOGGLE_FNCPTR(50)
|
||||
self.CartWrite([ [ 0x6000, 0x00 ] ])
|
||||
self.CLK_TOGGLE_FNCPTR(50)
|
||||
self.CartWrite([ [ 0x6000, 0x01 ] ])
|
||||
time.sleep(0.01)
|
||||
|
||||
# Halt RTC
|
||||
self.CLK_TOGGLE_FNCPTR(50)
|
||||
self.CartWrite([ [ 0x4000, 0x0C ] ])
|
||||
self.CLK_TOGGLE_FNCPTR(50)
|
||||
self.CartWrite([ [ 0xA000, 0x40 ] ])
|
||||
time.sleep(0.1)
|
||||
|
||||
# Write to registers
|
||||
for i in range(0x08, 0x0D):
|
||||
self.CLK_TOGGLE_FNCPTR(50)
|
||||
self.CartWrite([ [ 0x4000, i ] ])
|
||||
self.CLK_TOGGLE_FNCPTR(50)
|
||||
data = struct.unpack("<I", buffer[(i-8)*4:(i-8)*4+4])[0] & 0xFF
|
||||
self.CartWrite([ [ 0xA000, data ] ])
|
||||
time.sleep(0.1)
|
||||
|
||||
# Latch RTC
|
||||
self.CLK_TOGGLE_FNCPTR(50)
|
||||
self.CartWrite([ [ 0x6000, 0x00 ] ])
|
||||
self.CLK_TOGGLE_FNCPTR(50)
|
||||
self.CartWrite([ [ 0x6000, 0x01 ] ])
|
||||
time.sleep(0.1)
|
||||
return
|
||||
for i in range(0, 5):
|
||||
self.CLK_TOGGLE_FNCPTR(50)
|
||||
self.CartWrite([ [ 0x6000, 0x00 ] ])
|
||||
self.CLK_TOGGLE_FNCPTR(50)
|
||||
self.CartWrite([ [ 0x6000, 0x01 ] ])
|
||||
time.sleep(0.1)
|
||||
self.CLK_TOGGLE_FNCPTR(50)
|
||||
self.CartWrite([ [ 0x4000, 0x0B ] ])
|
||||
time.sleep(0.1)
|
||||
dprint("Day = {:d}".format(self.CartRead(0xA000)))
|
||||
self.CLK_TOGGLE_FNCPTR(50)
|
||||
self.CartWrite([ [ 0x4000, 0x0A ] ])
|
||||
time.sleep(0.1)
|
||||
dprint("Hour = {:d}".format(self.CartRead(0xA000)))
|
||||
self.CLK_TOGGLE_FNCPTR(50)
|
||||
self.CartWrite([ [ 0x4000, 0x09 ] ])
|
||||
time.sleep(0.1)
|
||||
dprint("Minutes = {:d}".format(self.CartRead(0xA000)))
|
||||
self.CLK_TOGGLE_FNCPTR(50)
|
||||
self.CartWrite([ [ 0x4000, 0x08 ] ])
|
||||
time.sleep(0.1)
|
||||
dprint("Seconds = {:d}".format(self.CartRead(0xA000)))
|
||||
time.sleep(0.5)
|
||||
#import sys
|
||||
#sys.exit()
|
||||
return
|
||||
for i in range(0x08, 0x0D):
|
||||
self.CartWrite([ [0x4000, i] ])
|
||||
data = struct.unpack("<I", buffer[(i-8)*4:(i-8)*4+4])[0] & 0xFF
|
||||
dprint("Writing 0x{:X} to 0x{:X}".format(data, i))
|
||||
dprint("Writing 0x{:02X} to 0x{:02X}".format(data, i))
|
||||
self.CartWrite([ [0xA000, data] ])
|
||||
self.CLK_TOGGLE_FNCPTR(5)
|
||||
self.LatchRTC()
|
||||
self.CLK_TOGGLE_FNCPTR(1)
|
||||
time.sleep(0.1)
|
||||
#self.LatchRTC()
|
||||
#self.CLK_TOGGLE_FNCPTR(1)
|
||||
self.EnableRAM(enable=False)
|
||||
|
||||
class DMG_MBC5(DMG_MBC):
|
||||
def GetName(self):
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# FlashGBX
|
||||
# Author: Lesserkuma (github.com/lesserkuma)
|
||||
|
||||
from PIL import Image, ImageDraw
|
||||
from PIL import Image
|
||||
from PIL.PngImagePlugin import PngInfo
|
||||
import os, hashlib
|
||||
import email.utils
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# FlashGBX
|
||||
# Author: Lesserkuma (github.com/lesserkuma)
|
||||
|
||||
import hashlib, re, zlib, sys, string
|
||||
import hashlib, re, zlib, string
|
||||
|
||||
class RomFileAGB:
|
||||
ROMFILE_PATH = None
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# FlashGBX
|
||||
# Author: Lesserkuma (github.com/lesserkuma)
|
||||
|
||||
import hashlib, re, sys, string, datetime
|
||||
import hashlib, re, string
|
||||
from . import Util
|
||||
|
||||
class RomFileDMG:
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from enum import Enum
|
|||
|
||||
# Common constants
|
||||
APPNAME = "FlashGBX"
|
||||
VERSION_PEP440 = "2.4"
|
||||
VERSION_PEP440 = "2.5"
|
||||
VERSION = "v{:s}".format(VERSION_PEP440)
|
||||
DEBUG = False
|
||||
|
||||
|
|
|
|||
|
|
@ -5,14 +5,16 @@
|
|||
"4350Q2 with 4350LLYBQ2",
|
||||
"4050_4400_4000_4350_36L0R_V5 with M36L0R8060T",
|
||||
"36L0R8-39VF512 with M36L0R8060T",
|
||||
"4050_4400_4000_4350_36L0R_V5 with 4050L0YTQ2"
|
||||
"4050_4400_4000_4350_36L0R_V5 with 4050L0YTQ2",
|
||||
"4350Q2 with 4050V0YBQ1"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0x20, 0x00, 0x0D, 0x88 ],
|
||||
[ 0x8A, 0x00, 0x10, 0x88 ],
|
||||
[ 0x20, 0x00, 0x0E, 0x88 ],
|
||||
[ 0x20, 0x00, 0x0E, 0x88 ],
|
||||
[ 0x8A, 0x00, 0x0E, 0x88 ]
|
||||
[ 0x8A, 0x00, 0x0E, 0x88 ],
|
||||
[ 0x8A, 0x00, 0x1C, 0x88 ]
|
||||
],
|
||||
"voltage":3.3,
|
||||
"flash_size":0x2000000,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
"SD007_BV5_V3 with 29LV160BE-90PFTN",
|
||||
"SD007_TSOP_48BALL with M29W160ET",
|
||||
"SD007_48BALL_64M_V2 with M29W160ET",
|
||||
"SD007_48BALL_64M_V8 with M29W160ET"
|
||||
"SD007_48BALL_64M_V8 with M29W160ET",
|
||||
"SD007_BV5 with 29LV160TE-70PFTN"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0xAE, 0xAE, 0xC4, 0xC4 ],
|
||||
|
|
@ -16,7 +17,8 @@
|
|||
[ 0x04, 0x04, 0x4A, 0x4A ],
|
||||
[ 0x20, 0x20, 0xC4, 0xC4 ],
|
||||
[ 0x20, 0x20, 0xC4, 0xC4 ],
|
||||
[ 0x20, 0x20, 0xC4, 0xC4 ]
|
||||
[ 0x20, 0x20, 0xC4, 0xC4 ],
|
||||
[ 0x04, 0x04, 0xC4, 0xC4 ]
|
||||
],
|
||||
"voltage":3.3,
|
||||
"flash_size":0x200000,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# FlashGBX
|
||||
# Author: Lesserkuma (github.com/lesserkuma)
|
||||
|
||||
import zlib, zipfile, os, serial, struct, time, re, math, platform
|
||||
import zipfile, os, serial, struct, time, re, math, platform
|
||||
from PySide2 import QtCore, QtWidgets, QtGui
|
||||
from . import Util
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from serial import SerialException
|
|||
from .RomFileDMG import RomFileDMG
|
||||
from .RomFileAGB import RomFileAGB
|
||||
from .Mapper import DMG_MBC, AGB_GPIO
|
||||
from .Flashcart import Flashcart, Flashcart_DMG_MMSA, CFI
|
||||
from .Flashcart import Flashcart, Flashcart_DMG_MMSA
|
||||
from .Util import ANSI, dprint, bitswap, ParseCFI
|
||||
from . import Util
|
||||
|
||||
|
|
@ -156,10 +156,10 @@ class GbxDevice:
|
|||
elif self.FW["fw_ver"] < self.DEVICE_MIN_FW:
|
||||
dev.close()
|
||||
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 R" + 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>."])
|
||||
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 R" + 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>."])
|
||||
# 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:
|
||||
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."])
|
||||
|
||||
|
|
@ -473,7 +473,7 @@ class GbxDevice:
|
|||
self._write(self.DEVICE_CMD["OFW_QUERY_CART_PWR"])
|
||||
if self._read(1) == 0:
|
||||
self._write(self.DEVICE_CMD["OFW_CART_PWR_ON"])
|
||||
time.sleep(0.2)
|
||||
time.sleep(0.1)
|
||||
self.DEVICE.reset_input_buffer() # bug workaround
|
||||
|
||||
def GetMode(self):
|
||||
|
|
@ -550,7 +550,7 @@ class GbxDevice:
|
|||
data = RomFileDMG(header).GetHeader()
|
||||
|
||||
_mbc = DMG_MBC().GetInstance(args={"mbc":data["features_raw"]}, cart_write_fncptr=self._cart_write, cart_read_fncptr=self._cart_read, clk_toggle_fncptr=self._clk_toggle)
|
||||
self.INFO["has_rtc"] = _mbc.HasRTC() is True
|
||||
data["has_rtc"] = _mbc.HasRTC() is True
|
||||
|
||||
elif self.MODE == "AGB":
|
||||
data = RomFileAGB(header).GetHeader()
|
||||
|
|
@ -1515,7 +1515,7 @@ class GbxDevice:
|
|||
else:
|
||||
_mbc.EnableMapper()
|
||||
|
||||
if args["rtc"] is True and _mbc.HasRTC():
|
||||
if args["rtc"] is True:
|
||||
extra_size = _mbc.GetRTCBufferSize()
|
||||
|
||||
_mbc.EnableRAM(enable=True)
|
||||
|
|
@ -1793,7 +1793,7 @@ class GbxDevice:
|
|||
self.INFO["transferred"] = len(buffer)
|
||||
# Real Time Clock
|
||||
if args["rtc"] is True:
|
||||
if self.MODE == "DMG" and _mbc.HasRTC():
|
||||
if self.MODE == "DMG" and args["rtc"] is True:
|
||||
_mbc.LatchRTC()
|
||||
temp = _mbc.ReadRTC()
|
||||
elif self.MODE == "AGB":
|
||||
|
|
@ -1810,7 +1810,7 @@ class GbxDevice:
|
|||
if args["rtc"] is True:
|
||||
advance = args["rtc_advance"]
|
||||
dprint("rtc_advance:", advance)
|
||||
if self.MODE == "DMG" and _mbc.HasRTC():
|
||||
if self.MODE == "DMG" and args["rtc"] is True:
|
||||
_mbc.WriteRTC(buffer[-_mbc.GetRTCBufferSize():], advance=advance)
|
||||
elif self.MODE == "AGB":
|
||||
_agb_gpio = AGB_GPIO(args={"rtc":True}, cart_write_fncptr=self._cart_write, cart_read_fncptr=self._cart_read, clk_toggle_fncptr=self._clk_toggle)
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -99,6 +99,7 @@ for Windows, Linux, macOS
|
|||
- SD007_48BALL_64M_V6 with 36VF3204
|
||||
- SD007_48BALL_64M_V6 with 29DL163BD-90
|
||||
- SD007_48BALL_64M_V8 with M29W160ET
|
||||
- SD007_BV5 with 29LV160TE-70PFTN
|
||||
- SD007_BV5_DRV with M29W320DT
|
||||
- SD007_BV5_DRV with S29GL032M90TFIR4
|
||||
- SD007_BV5_V2 with HY29LV160TT
|
||||
|
|
@ -126,6 +127,7 @@ for Windows, Linux, macOS
|
|||
- 29LV128DBT2C-90Q and ALTERA CPLD
|
||||
- 36L0R8-39VF512 with M36L0R8060B
|
||||
- 36L0R8-39VF512 with M36L0R8060T
|
||||
- 4350Q2 with 4050V0YBQ1
|
||||
- 4350Q2 with 4350LLYBQ2
|
||||
- 4050M0Y0Q0-39VF512 with 4050M0Y0Q0
|
||||
- 4050_4400_4000_4350_36L0R_V5 with 4050L0YTQ2
|
||||
|
|
@ -189,15 +191,15 @@ Use this command in a Terminal or Command Prompt window to launch the installed
|
|||
|
||||
* If something doesn’t work as expected, first try to clean the game cartridge contacts (best with IPA 99.9%+ on a cotton swab) and reconnect the device. An unstable cartridge connection is the most common reason for read or write errors.
|
||||
|
||||
* Depending on your system configuration, you may have to use `pip` and `python` commands instead of `pip3` and `python3`.
|
||||
|
||||
* On Linux systems, you may run into a *Permission Error* problem when trying to connect to USB devices without *sudo* privileges. To grant yourself the necessary permissions temporarily, you can run `sudo chmod 0666 /dev/ttyUSB0` (replace with actual device path) before running the app. For a permanent solution, add yourself to the usergroup that has access to serial devices by default (e.g. *dialout* on Debian-based distros; `sudo adduser $USER dialout`) and then reboot the system.
|
||||
|
||||
* 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.
|
||||
|
||||
* On some Linux systems like Fedora, you may need to install the `python3-pillow-qt` package manually in order for the GUI mode to work.
|
||||
|
||||
* Depending on your system configuration, you may have to use `pip` and `python` commands instead of `pip3` and `python3`.
|
||||
|
||||
* If you’re using macOS version 10.13 or older, there may be no driver for the *insideGadgets GBxCart RW device* installed on your system. You can either upgrade your macOS version to 10.14+ or manually install a driver which is available [here](https://github.com/adrianmihalko/ch340g-ch34g-ch34x-mac-os-x-driver).
|
||||
* If you’re using macOS version 10.13 or older, there may be no driver for the *insideGadgets GBxCart RW* device installed on your system. You can either upgrade your macOS version to 10.14+ or manually install a driver which is available [here](https://github.com/adrianmihalko/ch340g-ch34g-ch34x-mac-os-x-driver).
|
||||
|
||||
* If you run into an error that says `TypeError: 'Shiboken.ObjectType' object is not iterable`, you can try to uninstall and re-install the Python package *PySide2*, or you can run FlashGBX in command line interface mode using the command `python3 -m FlashGBX --cli`.
|
||||
|
||||
|
|
|
|||
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="2.4",
|
||||
version="2.5",
|
||||
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",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user