This commit is contained in:
Lesserkuma 2022-04-29 12:25:54 +02:00
parent 75d9886e3a
commit 681cfcd1de
20 changed files with 238 additions and 62 deletions

View File

@ -1,4 +1,9 @@
# Release notes
### v3.9 (released 2022-04-29)
- Added support for Ferrante Crafts cart 64 KB *(thanks FerrantePescara)*
- Added support for Ferrante Crafts cart 512 KB *(thanks FerrantePescara)*
- Fixed a bug with querying MBC3/MBC30 Real Time Clock values *(thanks HDR and AdmirtheSableye)*
### v3.8 (released 2022-04-21)
- Added support for AGB-E05-01 with MSP55LV100G *(thanks EmperorOfTigers)*
- Added support for DV15 with MSP55LV100G *(thanks zvxr)*

View File

@ -33,7 +33,7 @@ def LoadConfig(args):
(config_version, fc_files) = ReadConfigFiles(args=args)
if config_version != Util.VERSION:
# Rename old files that have since been replaced/renamed/merged
deprecated_files = [ "fc_AGB_TEST.txt", "fc_DMG_TEST.txt", "fc_AGB_Nintendo_E201850.txt", "fc_AGB_Nintendo_E201868.txt", "config.ini", "fc_DMG_MX29LV320ABTC.txt", "fc_DMG_iG_4MB_MBC3_RTC.txt", "fc_AGB_Flash2Advance.txt", "fc_AGB_MX29LV640_AUDIO.txt", "fc_AGB_M36L0R7050T.txt", "fc_AGB_M36L0R8060B.txt", "fc_AGB_M36L0R8060T.txt", "fc_AGB_iG_32MB_S29GL512N.txt" ]
deprecated_files = [ "fc_AGB_TEST.txt", "fc_DMG_TEST.txt", "fc_AGB_Nintendo_E201850.txt", "fc_AGB_Nintendo_E201868.txt", "config.ini", "fc_DMG_MX29LV320ABTC.txt", "fc_DMG_iG_4MB_MBC3_RTC.txt", "fc_AGB_Flash2Advance.txt", "fc_AGB_MX29LV640_AUDIO.txt", "fc_AGB_M36L0R7050T.txt", "fc_AGB_M36L0R8060B.txt", "fc_AGB_M36L0R8060T.txt", "fc_AGB_iG_32MB_S29GL512N.txt", "fc_DMG_SST39SF010_AUDIO.txt" ]
for file in deprecated_files:
if os.path.exists(config_path + "/" + file):
os.rename(config_path + "/" + file, config_path + "/" + file + "_" + datetime.datetime.now().strftime("%Y%m%d%H%M%S") + ".bak")
@ -59,17 +59,18 @@ def LoadConfig(args):
# Read flash cart types
for file in fc_files:
with open(file, encoding='utf-8') as f:
data = f.read()
specs_int = re.sub("(0x[0-9A-F]+)", lambda m: str(int(m.group(1), 16)), data) # hex numbers to int numbers, otherwise not valid json
try:
specs = json.loads(specs_int)
except:
ret.append([2, "The flashchip type file “{:s}” could not be parsed and needs to be fixed before it can be used.".format(os.path.basename(file))])
continue
for name in specs["names"]:
if not specs["type"] in flashcarts: continue # only DMG and AGB are supported right now
flashcarts[specs["type"]][name] = specs
if os.path.exists(file):
with open(file, encoding='utf-8') as f:
data = f.read()
specs_int = re.sub("(0x[0-9A-F]+)", lambda m: str(int(m.group(1), 16)), data) # hex numbers to int numbers, otherwise not valid json
try:
specs = json.loads(specs_int)
except:
ret.append([2, "The flashchip type file “{:s}” could not be parsed and needs to be fixed before it can be used.".format(os.path.basename(file))])
continue
for name in specs["names"]:
if not specs["type"] in flashcarts: continue # only DMG and AGB are supported right now
flashcarts[specs["type"]][name] = specs
return { "flashcarts":flashcarts, "config_ret":ret }

View File

@ -7,7 +7,7 @@ from enum import Enum
# Common constants
APPNAME = "FlashGBX"
VERSION_PEP440 = "3.8"
VERSION_PEP440 = "3.9"
VERSION = "v{:s}".format(VERSION_PEP440)
DEBUG = False

View File

@ -24,9 +24,6 @@
[ 0x2AAA, 0x55 ],
[ 0x5555, 0x90 ]
],
"read_cfi":[
[ 0x5555, 0x98 ]
],
"chip_erase":[
[ 0x5555, 0xAA ],
[ 0x2AAA, 0x55 ],

View File

@ -0,0 +1,54 @@
{
"type":"DMG",
"names":[
"Ferrante Crafts cart 32 KB"
],
"flash_ids":[
[ 0xBF, 0xB5, 0x01, 0xFF ]
],
"voltage":5,
"flash_size":0x8000,
"start_addr":0,
"first_bank":1,
"write_pin":"AUDIO",
"chip_erase_timeout":20,
"command_set":"AMD",
"commands":{
"reset":[
[ 0, 0xF0 ]
],
"read_identifier":[
[ 0x5555, 0xAA ],
[ 0x2AAA, 0x55 ],
[ 0x5555, 0x90 ]
],
"chip_erase":[
[ 0x5555, 0xAA ],
[ 0x2AAA, 0x55 ],
[ 0x5555, 0x80 ],
[ 0x5555, 0xAA ],
[ 0x2AAA, 0x55 ],
[ 0x5555, 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":[
[ 0x5555, 0xAA ],
[ 0x2AAA, 0x55 ],
[ 0x5555, 0xA0 ],
[ "PA", "PD" ]
],
"single_write_wait_for":[
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ]
]
}
}

View File

@ -0,0 +1,55 @@
{
"type":"DMG",
"names":[
"Ferrante Crafts cart 64 KB"
],
"flash_ids":[
[ 0xBF, 0xB5, 0x01, 0xFF ]
],
"voltage":5,
"flash_size":0x10000,
"start_addr":0,
"first_bank":1,
"flash_commands_on_bank_1":true,
"write_pin":"AUDIO",
"chip_erase_timeout":20,
"command_set":"AMD",
"commands":{
"reset":[
[ 0, 0xF0 ]
],
"read_identifier":[
[ 0x5555, 0xAA ],
[ 0x2AAA, 0x55 ],
[ 0x5555, 0x90 ]
],
"chip_erase":[
[ 0x5555, 0xAA ],
[ 0x2AAA, 0x55 ],
[ 0x5555, 0x80 ],
[ 0x5555, 0xAA ],
[ 0x2AAA, 0x55 ],
[ 0x5555, 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":[
[ 0x5555, 0xAA ],
[ 0x2AAA, 0x55 ],
[ 0x5555, 0xA0 ],
[ "PA", "PD" ]
],
"single_write_wait_for":[
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ]
]
}
}

View File

@ -1,8 +1,7 @@
{
"type":"DMG",
"names":[
"SD008-6810-V4 with MX29GL256EL",
"SD008-6810-V4 with unlabeled flash chip"
"SD008-6810-V4 with MX29GL256EL"
],
"flash_ids":[
[ 0xF3, 0xC3, 0x00, 0x01 ],

View File

@ -1,19 +1,19 @@
{
"type":"DMG",
"names":[
"Ferrante Crafts cart with SST39SF010A",
"GB-CART32K-A with SST39SF020A"
],
"flash_ids":[
[ 0xBF, 0xB5, 0x01, 0xFF ],
[ 0xBF, 0xB6, 0x01, 0xFF ]
],
"voltage":5,
"flash_size":0x8000,
"flash_size":0x10000,
"start_addr":0,
"first_bank":1,
"mbc":0x03,
"flash_commands_on_bank_1":true,
"write_pin":"AUDIO",
"chip_erase_timeout":60,
"chip_erase_timeout":20,
"command_set":"AMD",
"commands":{
"reset":[
@ -24,9 +24,6 @@
[ 0x2AAA, 0x55 ],
[ 0x5555, 0x90 ]
],
"read_cfi":[
[ 0x5555, 0x98 ]
],
"chip_erase":[
[ 0x5555, 0xAA ],
[ 0x2AAA, 0x55 ],

View File

@ -10,6 +10,7 @@
"flash_size":0x80000,
"start_addr":0,
"first_bank":1,
"mbc":0x03,
"flash_commands_on_bank_1":true,
"write_pin":"AUDIO",
"chip_erase_timeout":30,

View File

@ -0,0 +1,56 @@
{
"type":"DMG",
"names":[
"Ferrante Crafts cart 512 KB"
],
"flash_ids":[
[ 0xBF, 0xB7, 0x01, 0xFF ]
],
"voltage":5,
"flash_size":0x80000,
"start_addr":0,
"first_bank":1,
"mbc":0x19,
"flash_commands_on_bank_1":true,
"write_pin":"AUDIO",
"chip_erase_timeout":30,
"command_set":"AMD",
"commands":{
"reset":[
[ 0, 0xF0 ]
],
"read_identifier":[
[ 0x5555, 0xAA ],
[ 0x2AAA, 0x55 ],
[ 0x5555, 0x90 ]
],
"chip_erase":[
[ 0x5555, 0xAA ],
[ 0x2AAA, 0x55 ],
[ 0x5555, 0x80 ],
[ 0x5555, 0xAA ],
[ 0x2AAA, 0x55 ],
[ 0x5555, 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":[
[ 0x5555, 0xAA ],
[ 0x2AAA, 0x55 ],
[ 0x5555, 0xA0 ],
[ "PA", "PD" ]
],
"single_write_wait_for":[
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ]
]
}
}

View File

@ -3,7 +3,10 @@
"names":[
"SD007_T40_64BALL_TSOP28 with TC58FVB016FT-85"
],
"voltage":3.3,
"flash_ids":[
[ 0x98, 0x45, 0x00, 0x2A ]
],
"voltage":5,
"flash_size":0x200000,
"start_addr":0,
"first_bank":1,

View File

@ -10,7 +10,6 @@
],
"voltage":5,
"power_cycle":true,
"flash_size":0x80000,
"start_addr":0,
"first_bank":1,
"flash_commands_on_bank_1":true,

View File

@ -193,10 +193,10 @@ class FirmwareUpdaterWindow(QtWidgets.QDialog):
fw = ""
path = ""
if self.optCFW.isChecked():
fw = "Version {:s}".format(self.CFW_VER)
fw = self.CFW_VER
fn = "cfw.hex"
elif self.optOFW.isChecked():
fw = "Version {:s}".format(self.OFW_VER)
fw = self.OFW_VER
fn = "ofw.hex"
else:
path = self.APP.SETTINGS.value("LastDirFirmwareUpdate")
@ -298,7 +298,7 @@ class FirmwareUpdaterWindow(QtWidgets.QDialog):
if self.ResetAVR(delay) is False:
fncSetStatus(text="Status: Bootloader error.", enableUI=True)
self.prgStatus.setValue(0)
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="FlashGBX", text="The firmware update was not successful as the GBxCart RW bootloader is not responding. If it doesnt work even after multiple retries, please use the official firmware updater instead.", standardButtons=QtWidgets.QMessageBox.Ok)
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="FlashGBX", text="The firmware update failed as the device is not responding correctly. Please ensure you use a <a href=\"https://www.gbxcart.com/\">genuine GBxCart RW</a>, re-connect using a different USB cable and try again.\n\n⚠️ For safety reasons and to avoid potential fire hazards, do not use unauthorized clone hardware that have no electrical fuses, such as the “FLASH&nbsp;BOY” series.".replace("\n", "<br>"), standardButtons=QtWidgets.QMessageBox.Ok)
answer = msgbox.exec()
return 2

View File

@ -109,7 +109,7 @@ class FirmwareUpdaterWindow(QtWidgets.QDialog):
self.DEVICE = device
else:
self.APP.QT_APP.processEvents()
text = "This Firmware Updater is for insideGadgets GBxCart RW v1.4 devices only. Please only proceed if your device matches this hardware revision.\n\nGBxCart RW v1.3 can be updated only after connecting to it first. If you want to update another GBxCart RW hardware revision, please use the official firmware updater by insideGadgets instead."
text = "This Firmware Updater is for insideGadgets GBxCart RW v1.4 devices only. Please only proceed if your device matches this hardware revision.\n\nOlder GBxCart RW revisions can be updated only after connecting to them first."
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Warning, windowTitle="FlashGBX", text=text, standardButtons=QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel)
msgbox.setDefaultButton(QtWidgets.QMessageBox.Ok)
answer = msgbox.exec()

View File

@ -895,7 +895,7 @@ class GbxDevice:
return buffer
def ReadROM_3DMemory(self, address, length, max_length=512):
def ReadROM_3DMemory(self, address, length, max_length=64):
buffer_size = 0x1000
num = math.ceil(length / max_length)
dprint("Reading 0x{:X} bytes from cartridge ROM in {:d} iteration(s)".format(length, num))
@ -920,7 +920,7 @@ class GbxDevice:
return buffer
def ReadRAM(self, address, length, command=None, max_length=512):
def ReadRAM(self, address, length, command=None, max_length=64):
num = math.ceil(length / max_length)
dprint("Reading 0x{:X} bytes from cartridge RAM in {:d} iteration(s)".format(length, num))
if length > max_length: length = max_length
@ -1414,6 +1414,8 @@ class GbxDevice:
flashcart.Reset(full_reset=False)
dprint("Found the correct cartridge type!")
if self.CanPowerCycleCart(): self.CartPowerCycle()
# Check flash size
flash_type_id = 0
cfi_s = ""
@ -1426,19 +1428,20 @@ class GbxDevice:
supp_flash_types = self.GetSupportedCartridgesAGB()
(flash_id, cfi_s, cfi) = self.CheckFlashChip(limitVoltage=limitVoltage, cart_type=supp_flash_types[1][flash_type_id])
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 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"]:
flash_type_id = flash_types[i]
size_undetected = False
break
if "flash_size" in supp_flash_types[1][flash_types[0]]:
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 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"]:
flash_type_id = flash_types[i]
size_undetected = False
break
else:
(flash_id, cfi_s, cfi) = self.CheckFlashChip(limitVoltage=limitVoltage)

View File

@ -903,19 +903,20 @@ class GbxDevice:
supp_flash_types = self.GetSupportedCartridgesAGB()
(flash_id, cfi_s, cfi) = self.CheckFlashChip(limitVoltage=limitVoltage, cart_type=supp_flash_types[1][flash_type_id])
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 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"]:
flash_type_id = flash_types[i]
size_undetected = False
break
if "flash_size" in supp_flash_types[1][flash_types[0]]:
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 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"]:
flash_type_id = flash_types[i]
size_undetected = False
break
else:
(flash_id, cfi_s, cfi) = self.CheckFlashChip(limitVoltage=limitVoltage)

Binary file not shown.

Binary file not shown.

View File

@ -98,7 +98,9 @@ Use this command in a Terminal or Command Prompt window to launch the installed
- DIY cart with MX29LV640
- DIY cart with SST39SF040
- DMG-MBC5-32M-FLASH Development Cartridge, E201264
- Ferrante Crafts cart with SST39SF010A
- Ferrante Crafts cart 32 KB
- Ferrante Crafts cart 64 KB
- Ferrante Crafts cart 512 KB
- GB-CART32K-A with SST39SF020A
- GB Smart 32M
- HDR Game Boy Camera Flashcart
@ -237,7 +239,7 @@ Use this command in a Terminal or Command Prompt window to launch the installed
Many different reproduction cartridges share their flash chip command set, so even if yours is not on this list, it may still work fine or even be auto-detected as another one. Support for more cartridges can also be added by creating external config files that include the necessary flash chip commands.
*¹ = Cannot be auto-detected, select cartridge type manually*
*¹ = Cannot always be auto-detected, select cartridge type manually*
### Troubleshooting
@ -269,6 +271,7 @@ The author would like to thank the following very kind people for their help and
- 90sFlav (flash chip info)
- AcoVanConis (bug reports, flash chip info)
- AdmirtheSableye (bug reports)
- AlexiG (GBxCart RW hardware, bug reports, flash chip info)
- AndehX (app icon, flash chip info)
- antPL (flash chip info)
@ -285,9 +288,11 @@ The author would like to thank the following very kind people for their help and
- EmperorOfTigers (bug reports, flash chip info)
- endrift (research, mGBA emulator)
- eveningmoose (flash chip info)
- FerrantePescara (flash chip info)
- frarees (bug reports)
- Frost Clock (flash chip info)
- Grender (testing)
- HDR (testing)
- Herax (flash chip info)
- hiks (flash chip info)
- howie0210 (flash chip info, bug reports)

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="3.8",
version="3.9",
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",