This commit is contained in:
Lesserkuma 2021-07-15 12:16:48 +02:00
parent 77818e539d
commit 4883088a1e
17 changed files with 157 additions and 69 deletions

View File

@ -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)*

View File

@ -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:

View File

@ -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 += " Its possible that its too large which may cause the flashing to fail."
msg += " Its possible that its 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']:

View File

@ -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 its possible that its too large which may cause the flashing to fail."
msg += " You can still give it a try, but its possible that its 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())

View File

@ -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 = {}

View File

@ -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("Couldnt 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):

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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

View File

@ -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.

View File

@ -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 doesnt 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 youre 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 youre 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`.

View File

@ -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",