This commit is contained in:
Lesserkuma 2021-05-05 12:55:18 +02:00
parent 167176ee40
commit 6e45e3ce9a
19 changed files with 513 additions and 398 deletions

View File

@ -1,4 +1,14 @@
# Release notes
### v2.1 (released 2021-05-05)
- Fixed support for SD007_TSOP_29LV017D with L017D70VC *(thanks marv17 and 90sFlav)*
- Added support for a DIY cart with MBC1 and AM29F080 *(thanks skite2001)*
- Added support for SD007_TSOP_48BALL_V8 with 29LV320CTTC *(thanks Jayro)*
- Added the MBC5+SRAM mapper type which is officially unused, but is actually used by GB Studio *(thanks Jayro)*
- The GBxCart RW v1.3 firmware updater should now also work if the device is below firmware version R19
- Adjusted the baudrate used for updating the firmware which fixes a problem on some macOS systems
- Added support for Flash2Advance Ultra 64M with 2× 28F320C3B
- Confirmed support for 4350Q2 with 4350LLYBQ2
### v2.0 (released 2021-05-01)
- Added an integrated firmware updater for GBxCart v1.3 devices which includes the latest official firmware version at time of FlashGBX release; also supports external firmware files
- Added support for the new GBxCart RW v1.4 hardware
@ -19,7 +29,7 @@
- Same as above but already integrated into the official firmware of GBxCart RW v1.4
- Added support for official cartridges with the MBC6 memory bank controller including its flash memory; tested with “Net de Get: Minigame @ 100” (CGB-BMVJ-JPN) *(thanks to endrifts research at [gbdev](https://gbdev.gg8.se/forums/viewtopic.php?id=544))* (requires GBxCart RW firmware version L1+)
- Previously preliminarily added mapper support including for MBC7 and GBA Video cartridges is now working (requires GBxCart RW firmware version L1+)
- Added support for writing compilation ROMs to Nintendo Power GB Memory Cartridges (DMG-MMSA-JPN); requires a .map file in the same directory as the ROM file; all this can be generated using [orangelos GBNP ROM builder website](https://orangeglo.github.io/gbnp/index.html)
- Added support for writing compilation ROMs to Nintendo Power GB Memory Cartridges (DMG-MMSA-JPN); requires a .map file in the same directory as the ROM file; all this can be generated using orangeglos [GBNP ROM builder website](https://orangeglo.github.io/gbnp/index.html)
- Confirmed support for GB-M968 with 29LV160DB *(thanks bbsan)*
- Added support for ROM backup as well as save data backup and restore for 8M FLASH DACS cartridges; tested with “Hikaru no Go 3 Joy Carry Cartridge” (AGB-GHTJ-JPN)
- Confirmed support for SD007_TSOP_29LV017D with L017D70VC *(thanks marv17)*

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_M36L0R705.txt", "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" ]
deprecated_files = [ "fc_AGB_M36L0R705.txt", "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" ]
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")

View File

@ -659,15 +659,26 @@ class FlashGBX_GUI(QtWidgets.QWidget):
self.mnuTools.actions()[2].setEnabled(True)
if dev.FirmwareUpdateAvailable():
dontShowAgain = str(self.SETTINGS.value("SkipFirmwareUpdate", default="disabled")).lower() == "enabled"
if not dontShowAgain:
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Information, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text="A firmware update for your {:s} is available.\nDo you want to update now?".format(dev.GetFullName()), standardButtons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, defaultButton=QtWidgets.QMessageBox.Yes)
cb = QtWidgets.QCheckBox("Ignore firmware updates", checked=dontShowAgain)
msgbox.setCheckBox(cb)
if not dontShowAgain or dev.FW_UPDATE_REQ:
if dev.FW_UPDATE_REQ:
text = "A firmware update for your {:s} device is required to use this software. Do you want to update now?".format(dev.GetFullName())
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Warning, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=text, standardButtons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, defaultButton=QtWidgets.QMessageBox.Yes)
else:
text = "A firmware update for your {:s} device is available. Do you want to update now?".format(dev.GetFullName())
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Information, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=text, standardButtons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, defaultButton=QtWidgets.QMessageBox.Yes)
cb = QtWidgets.QCheckBox("Ignore firmware updates", checked=dontShowAgain)
msgbox.setCheckBox(cb)
answer = msgbox.exec()
dontShowAgain = cb.isChecked()
if dontShowAgain: self.SETTINGS.setValue("SkipFirmwareUpdate", "enabled")
if answer == QtWidgets.QMessageBox.Yes:
self.ShowFirmwareUpdateWindow()
if dev.FW_UPDATE_REQ:
if answer == QtWidgets.QMessageBox.Yes:
self.ShowFirmwareUpdateWindow()
elif not Util.DEBUG:
self.DisconnectDevice()
else:
dontShowAgain = cb.isChecked()
if dontShowAgain: self.SETTINGS.setValue("SkipFirmwareUpdate", "enabled")
if answer == QtWidgets.QMessageBox.Yes:
self.ShowFirmwareUpdateWindow()
else:
self.mnuTools.actions()[2].setEnabled(False)

View File

@ -443,44 +443,6 @@ class DMG_MBC6(DMG_MBC):
])
self.SelectBankROM(self.CURRENT_ROM_BANK)
return flash_id
'''
def Test(self):
self.EnableFlash(enable=True, enable_write=True)
self.CartWrite([
[ 0x2000, 0x01 ],
[ 0x3000, 0x02 ],
[ 0x7555, 0xAA ],
[ 0x4AAA, 0x55 ],
[ 0x7555, 0x80 ],
[ 0x7555, 0xAA ],
[ 0x4AAA, 0x55 ],
[ 0x4000, 0x30 ],
])
with open("mbc6.bin", "rb") as f: buffer = f.read()
for j in range(0, int(len(buffer)/128)):
self.CartWrite([
[ 0x2000, 0x01 ],
[ 0x3000, 0x02 ],
[ 0x7555, 0xAA ],
[ 0x4AAA, 0x55 ],
[ 0x7555, 0xA0 ],
])
self.SelectBankROM(1)
commands = []
for i in range(0, 128):
commands.append([0x4000 + (j*128+i), buffer[j*128+i]])
commands.append([0x4000 + (j*128) + 127, 0x00])
self.CartWrite(commands)
time.sleep(0.01)
self.CartWrite([[0x4000 + (j*128) + 127, 0xF0]])
flash_id = self.CartRead(0x4000, 8)
self.SelectBankROM(self.CURRENT_ROM_BANK)
return flash_id
'''
class DMG_MBC7(DMG_MBC):
def GetName(self):

View File

@ -7,7 +7,7 @@ from enum import Enum
# Common constants
APPNAME = "FlashGBX"
VERSION_PEP440 = "2.0"
VERSION_PEP440 = "2.1"
VERSION = "v{:s}".format(VERSION_PEP440)
DEBUG = False
@ -18,7 +18,7 @@ AGB_Header_Save_Sizes = [ 0, 512, 8192, 32768, 65536, 131072, 65536, 131072, 103
AGB_Global_CRC32 = 0
AGB_Flash_Save_Chips = { 0xBFD4:"SST 39VF512", 0x1F3D:"Atmel AT29LV512", 0xC21C:"Macronix MX29L512", 0x321B:"Panasonic MN63F805MNP", 0xC209:"Macronix MX29L010", 0x6213:"SANYO LE26FV10N1TS" }
DMG_Header_Mapper = { 0x00:'None', 0x01:'MBC1', 0x02:'MBC1+SRAM', 0x03:'MBC1+SRAM+BATTERY', 0x06:'MBC2+SRAM+BATTERY', 0x10:'MBC3+RTC+SRAM+BATTERY', 0x13:'MBC3+SRAM+BATTERY', 0x19:'MBC5', 0x1B:'MBC5+SRAM+BATTERY', 0x1C:'MBC5+RUMBLE', 0x1E:'MBC5+RUMBLE+SRAM+BATTERY', 0x20:'MBC6+SRAM+FLASH+BATTERY', 0x22:'MBC7+ACCELEROMETER+EEPROM', 0x101:'MBC1M', 0x103:'MBC1M+SRAM+BATTERY', 0x0B:'MMM01', 0x0D:'MMM01+SRAM+BATTERY', 0xFC:'GBD+SRAM+BATTERY', 0x105:'G-MMC1+SRAM+BATTERY', 0x104:'M161', 0xFF:'HuC-1+IR+SRAM+BATTERY', 0xFE:'HuC-3+RTC+SRAM+BATTERY', 0xFD:'TAMA5+RTC+EEPROM' }
DMG_Header_Mapper = { 0x00:'None', 0x01:'MBC1', 0x02:'MBC1+SRAM', 0x03:'MBC1+SRAM+BATTERY', 0x06:'MBC2+SRAM+BATTERY', 0x10:'MBC3+RTC+SRAM+BATTERY', 0x13:'MBC3+SRAM+BATTERY', 0x19:'MBC5', 0x1A:'MBC5+SRAM', 0x1B:'MBC5+SRAM+BATTERY', 0x1C:'MBC5+RUMBLE', 0x1E:'MBC5+RUMBLE+SRAM+BATTERY', 0x20:'MBC6+SRAM+FLASH+BATTERY', 0x22:'MBC7+ACCELEROMETER+EEPROM', 0x101:'MBC1M', 0x103:'MBC1M+SRAM+BATTERY', 0x0B:'MMM01', 0x0D:'MMM01+SRAM+BATTERY', 0xFC:'GBD+SRAM+BATTERY', 0x105:'G-MMC1+SRAM+BATTERY', 0x104:'M161', 0xFF:'HuC-1+IR+SRAM+BATTERY', 0xFE:'HuC-3+RTC+SRAM+BATTERY', 0xFD:'TAMA5+RTC+EEPROM' }
DMG_Header_ROM_Sizes = [ "32 KB", "64 KB", "128 KB", "256 KB", "512 KB", "1 MB", "2 MB", "4 MB", "8 MB" ]
DMG_Header_ROM_Sizes_Map = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 ]
DMG_Header_ROM_Sizes_Flasher_Map = [ 2, 4, 8, 16, 32, 64, 128, 256, 512 ] # Number of ROM banks

View File

@ -1,76 +1,76 @@
{
"type":"AGB",
"names":[
"Flash2Advance 256M with 2x 28F128J3A150"
],
"flash_ids":[
[ 0x89, 0x00, 0x89, 0x00, 0x18, 0x00, 0x18, 0x00 ]
],
"voltage":3.3,
"flash_size":0x2000000,
"sector_size":0x40000,
"buffer_size":64,
"command_set":"INTEL",
"commands":{
"unlock":[
[ 0x130ECA8, 0x5354, 1 ],
[ 0x002468A, 0x1234, 5 ],
[ 0x000ECA8, 0x5354, 1 ],
[ 0x002468A, 0x5354, 1 ],
[ 0x002468A, 0x5678, 5 ],
[ 0x130ECA8, 0x5354, 1 ],
[ 0x002468A, 0x5354, 1 ],
[ 0x0ECA800, 0x5678, 1 ],
[ 0x00268A0, 0x1234, 1 ],
[ 0x002468A, 0xABCD, 5 ],
[ 0x130ECA8, 0x5354, 1 ],
[ 0x1E2468A, 0x9413, 1 ]
],
"reset":[
[ 0, 0xFF ],
[ 2, 0xFF ]
],
"read_identifier":[
[ 0, 0x90 ],
[ 2, 0x90 ]
],
"sector_erase":[
[ "SA", 0x20 ],
[ "SA", 0xD0 ],
[ "SA+2", 0x20 ],
[ "SA+2", 0xD0 ],
[ null, null ],
[ null, null ]
],
"sector_erase_wait_for":[
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ "SA", 0x80, 0xFFFF ],
[ "SA+2", 0x80, 0xFFFF ]
],
"buffer_write":[
[ "SA", 0xE8 ],
[ "SA+2", 0xE8 ],
[ "SA", "BS" ],
[ "SA+2", "BS" ],
[ "PA", "PD" ],
[ "SA", 0xD0 ],
[ "SA+2", 0xD0 ],
[ null, null ],
[ null, null ]
],
"buffer_write_wait_for":[
[ 0, 0x80, 0x8080 ],
[ 2, 0x80, 0x8080 ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ 0, 0x80, 0xFFFF ],
[ 2, 0x80, 0xFFFF ]
]
}
}
{
"type":"AGB",
"names":[
"Flash2Advance 256M with 2× 28F128J3A150"
],
"flash_ids":[
[ 0x89, 0x00, 0x89, 0x00, 0x18, 0x00, 0x18, 0x00 ]
],
"voltage":3.3,
"flash_size":0x2000000,
"sector_size":0x40000,
"buffer_size":64,
"command_set":"INTEL",
"commands":{
"unlock":[
[ 0x130ECA8, 0x5354, 1 ],
[ 0x002468A, 0x1234, 5 ],
[ 0x000ECA8, 0x5354, 1 ],
[ 0x002468A, 0x5354, 1 ],
[ 0x002468A, 0x5678, 5 ],
[ 0x130ECA8, 0x5354, 1 ],
[ 0x002468A, 0x5354, 1 ],
[ 0x0ECA800, 0x5678, 1 ],
[ 0x00268A0, 0x1234, 1 ],
[ 0x002468A, 0xABCD, 5 ],
[ 0x130ECA8, 0x5354, 1 ],
[ 0x1E2468A, 0x9413, 1 ]
],
"reset":[
[ 0, 0xFF ],
[ 2, 0xFF ]
],
"read_identifier":[
[ 0, 0x90 ],
[ 2, 0x90 ]
],
"sector_erase":[
[ "SA", 0x20 ],
[ "SA", 0xD0 ],
[ "SA+2", 0x20 ],
[ "SA+2", 0xD0 ],
[ null, null ],
[ null, null ]
],
"sector_erase_wait_for":[
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ "SA", 0x80, 0xFFFF ],
[ "SA+2", 0x80, 0xFFFF ]
],
"buffer_write":[
[ "SA", 0xE8 ],
[ "SA+2", 0xE8 ],
[ "SA", "BS" ],
[ "SA+2", "BS" ],
[ "PA", "PD" ],
[ "SA", 0xD0 ],
[ "SA+2", 0xD0 ],
[ null, null ],
[ null, null ]
],
"buffer_write_wait_for":[
[ 0, 0x80, 0x8080 ],
[ 2, 0x80, 0x8080 ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ 0, 0x80, 0xFFFF ],
[ 2, 0x80, 0xFFFF ]
]
}
}

View File

@ -0,0 +1,60 @@
{
"type":"AGB",
"names":[
"Flash2Advance Ultra 64M with 2× 28F320C3B"
],
"flash_ids":[
[ 0x89, 0x00, 0x89, 0x00, 0xC5, 0x88, 0xC5, 0x88 ]
],
"voltage":3.3,
"flash_size":0x800000,
"sector_size":[
[0x04000, 8],
[0x20000, 63]
],
"command_set":"INTEL",
"commands":{
"reset":[
[ 0, 0xFF ],
[ 2, 0xFF ]
],
"read_identifier":[
[ 0, 0x90 ],
[ 2, 0x90 ]
],
"sector_erase":[
[ "SA", 0x60 ],
[ "SA", 0xD0 ],
[ "SA", 0x20 ],
[ "SA", 0xD0 ],
[ "SA+2", 0x60 ],
[ "SA+2", 0xD0 ],
[ "SA+2", 0x20 ],
[ "SA+2", 0xD0 ],
[ null, null ],
[ null, null ]
],
"sector_erase_wait_for":[
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ "SA", 0x80, 0xFFFF ],
[ "SA+2", 0x80, 0xFFFF ]
],
"single_write":[
[ 0, 0x70 ],
[ 0, 0x10 ],
[ "PA", "PD" ]
],
"single_write_wait_for":[
[ 0, 0x80, 0x80 ],
[ null, null, null ],
[ null, null, null ]
]
}
}

View File

@ -2,7 +2,7 @@
"type":"AGB",
"names":[
"36L0R8-39VF512 with M36L0R8060B",
"36L0R8-39VF512 with M36L0R8060B"
"4350Q2 with 4350LLYBQ2"
],
"flash_ids":[
[ 0x20, 0x00, 0x0D, 0x88 ],

View File

@ -0,0 +1,58 @@
{
"type":"DMG",
"names":[
"DIY cart with MBC1 and AM29F080 @ WR"
],
"flash_ids":[
[ 0x20, 0xF1 ]
],
"voltage":5,
"flash_size":0x100000,
"start_addr":0,
"first_bank":1,
"write_pin":"WR",
"chip_erase_timeout":60,
"mbc":1,
"command_set":"AMD",
"commands":{
"reset":[
[ 0, 0xF0 ]
],
"read_identifier":[
[ 0x555, 0xAA ],
[ 0x2AA, 0x55 ],
[ 0x555, 0x90 ]
],
"read_cfi":[
[ 0x555, 0x98 ]
],
"chip_erase":[
[ 0x555, 0xAA ],
[ 0x2AA, 0x55 ],
[ 0x555, 0x80 ],
[ 0x555, 0xAA ],
[ 0x2AA, 0x55 ],
[ 0x555, 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":[
[ 0x555, 0xAA ],
[ 0x2AA, 0x55 ],
[ 0x555, 0xA0 ],
[ "PA", "PD" ]
],
"single_write_wait_for":[
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ]
]
}
}

View File

@ -3,12 +3,14 @@
"names":[
"SD007_BV5_V3 with AM29LV160MB",
"SD007_TSOP_48BALL with L160DB12VI",
"SD007_TSOP_48BALL with AM29LV160DB"
"SD007_TSOP_48BALL with AM29LV160DB",
"SD007_TSOP_29LV017D with L017D70VC"
],
"flash_ids":[
[ 0x02, 0x02, 0x4A, 0x4A ],
[ 0x02, 0x02, 0x4A, 0x4A ],
[ 0x02, 0x02, 0x4A, 0x4A ]
[ 0x02, 0x02, 0x4A, 0x4A ],
[ 0x02, 0xC8, 0x00, 0x00 ]
],
"voltage":5,
"flash_size":0x200000,

View File

@ -3,7 +3,7 @@
"names":[
"SD007_48BALL_64M with GL032M11BAIR4",
"SD007_48BALL_64M_V2 with GL032M11BAIR4",
"S29GL032N90T and ALTERA CPLD (no PCB text)"
"S29GL032N90T and ALTERA CPLD (MBC5)"
],
"flash_ids":[
[ 0x02, 0x02, 0x7D, 0x7D ],

View File

@ -7,8 +7,7 @@
"SD007_BV5_V3 with 29LV160BE-90PFTN",
"SD007_TSOP_48BALL with M29W160ET",
"SD007_48BALL_64M_V2 with M29W160ET",
"SD007_48BALL_64M_V8 with M29W160ET",
"SD007_TSOP_29LV017D with L017D70VC"
"SD007_48BALL_64M_V8 with M29W160ET"
],
"flash_ids":[
[ 0xAE, 0xAE, 0xC4, 0xC4 ],
@ -17,9 +16,7 @@
[ 0x04, 0x04, 0x4A, 0x4A ],
[ 0x20, 0x20, 0xC4, 0xC4 ],
[ 0x20, 0x20, 0xC4, 0xC4 ],
[ 0x20, 0x20, 0xC4, 0xC4 ],
[ 0x20, 0x20, 0xC4, 0xC4 ],
[ 0x02, 0xC8, 0x00, 0x00 ]
[ 0x20, 0x20, 0xC4, 0xC4 ]
],
"voltage":3.3,
"flash_size":0x200000,

View File

@ -1,10 +1,12 @@
{
"type":"DMG",
"names":[
"SD007_BV5_V2 with MX29LV320BTC"
"SD007_BV5_V2 with MX29LV320BTC",
"SD007_TSOP_48BALL_V8 with 29LV320CTTC"
],
"flash_ids":[
[ 0xC1, 0xC1, 0xA8, 0xA8 ]
[ 0xC1, 0xC1, 0xA8, 0xA8 ],
[ 0xC1, 0xC1, 0xA7, 0xA7 ]
],
"voltage":3.3,
"flash_size":0x400000,

View File

@ -2,7 +2,7 @@
# FlashGBX
# Author: Lesserkuma (github.com/lesserkuma)
import zlib, zipfile, os, serial, struct, time, re, math
import zlib, zipfile, os, serial, struct, time, re, math, platform
from PySide2 import QtCore, QtWidgets, QtGui
from . import Util
@ -177,8 +177,10 @@ class FirmwareUpdater(QtWidgets.QDialog):
return False
dev.write(b'0')
dev.flush()
if platform.system() == "Darwin": time.sleep(0.00125)
dev.write(struct.pack(">BIBB", 0x2A, 0x37653565, 0x31, 0))
dev.flush()
if platform.system() == "Darwin": time.sleep(0.00125)
self.APP.QT_APP.processEvents()
time.sleep(0.3 + delay)
dev.reset_input_buffer()
@ -208,7 +210,10 @@ class FirmwareUpdater(QtWidgets.QDialog):
fw = "{:s}<br><br><b>Please double check that this is a valid firmware file for the GBxCart RW v1.3. If it is invalid or an update for a different device, it may render your device unusable.</b>".format(path)
fn = None
text = "The following firmware will now be written to your GBxCart v1.3 device:<br>{:s}<br><br>Do you want to continue?".format(fw)
text = "The following firmware will now be written to your GBxCart v1.3 device:<br>- {:s}".format(fw)
#if platform.system() == "Darwin":
# text += "<br><br>DISCLAIMER: In rare occasions, the firmware update may reportedly fail on some macOS systems with unstable drivers, so please proceed at your own risk. If an error occurs, your device can still be recovered using the official firmware update tool by insideGadgets."
text += "<br><br>Do you want to continue?"
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Question, windowTitle="FlashGBX", text=text, standardButtons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
msgbox.setDefaultButton(QtWidgets.QMessageBox.Yes)
msgbox.setTextFormat(QtCore.Qt.TextFormat.RichText)
@ -247,7 +252,7 @@ class FirmwareUpdater(QtWidgets.QDialog):
chk = chk & 0xFF
chk = (~chk + 1) & 0xFF
if (chk != data["checksum"]):
self.lblStatus.setText("Status: Firmware checksum error.")
fncSetStatus("Status: Firmware checksum error.")
self.prgStatus.setValue(0)
self.btnUpdate.setEnabled(True)
self.btnClose.setEnabled(True)
@ -258,249 +263,258 @@ class FirmwareUpdater(QtWidgets.QDialog):
buffer += bytearray(data["data"])
if len(buffer) >= 7168:
self.lblStatus.setText("Status: Firmware file is too large.")
fncSetStatus("Status: Firmware file is too large.")
self.prgStatus.setValue(0)
self.btnUpdate.setEnabled(True)
self.btnClose.setEnabled(True)
self.grpAvailableFwUpdates.setEnabled(True)
return False
fw_buffer = buffer
self.APP.DisconnectDevice()
port = self.PORT
flash_ok = False
while not flash_ok:
delay = 0
lives = 10
buffer = bytearray()
self.lblStatus.setText("Status: Waiting for bootloader...")
if self.ResetAVR(delay) is False:
self.lblStatus.setText("Status: Device reboot error.")
self.prgStatus.setValue(0)
return False
while True:
try:
dev = serial.Serial(port=port, baudrate=57600, timeout=0.5)
except:
self.lblStatus.setText("Status: Device access error.")
self.prgStatus.setValue(0)
self.btnUpdate.setEnabled(True)
self.btnClose.setEnabled(True)
self.grpAvailableFwUpdates.setEnabled(True)
return False
dev.reset_input_buffer()
dev.reset_output_buffer()
dev.write(b"@@@")
dev.flush()
buffer = dev.read(0x11)
if (len(buffer) < 0x11) or (buffer[0:3] != b'TSB'):
dev.write(b"?")
dev.flush()
dev.close()
self.APP.QT_APP.processEvents()
time.sleep(1)
if len(buffer) != 0x11:
delay += 0.05
self.lblStatus.setText("Status: Waiting for bootloader... (+{:d}ms)".format(int(delay * 1000)))
if self.ResetAVR(delay) is False:
self.lblStatus.setText("Status: Device reboot error.")
self.prgStatus.setValue(0)
self.btnUpdate.setEnabled(True)
self.btnClose.setEnabled(True)
self.grpAvailableFwUpdates.setEnabled(True)
return False
lives -= 1
if lives < 0:
self.lblStatus.setText("Status: Device reboot error.")
self.prgStatus.setValue(0)
self.btnUpdate.setEnabled(True)
self.btnClose.setEnabled(True)
self.grpAvailableFwUpdates.setEnabled(True)
return False
continue
break
self.lblStatus.setText("Reading bootloader information...")
info = {}
keys = ["magic", "tsb_version", "tsb_status", "signature", "page_size", "flash_size", "eeprom_size", "unknown", "avr_jmp_identifier"]
values = struct.unpack("<3sHB3sBHHBB", bytearray(buffer[:-1]))
info = dict(zip(keys, values))
info["page_size"] *= 2
info["flash_size"] *= 2
info["eeprom_size"] += 1
if info["avr_jmp_identifier"] == 0x00:
info["jmp_mode"] = "relative"
info["device_type"] = "attiny"
elif info["avr_jmp_identifier"] == 0x0C:
info["jmp_mode"] = "absolute"
info["device_type"] = "attiny"
elif info["avr_jmp_identifier"] == 0xAA:
info["jmp_mode"] = "relative"
info["device_type"] = "atmega"
if info["page_size"] != 64 or info["flash_size"] != 7616 or info["eeprom_size"] != 512 or info["jmp_mode"] != "relative" or info["device_type"] != "atmega" or info["signature"] != b'\x1E\x93\x06':
self.btnUpdate.setEnabled(True)
self.btnClose.setEnabled(True)
self.grpAvailableFwUpdates.setEnabled(True)
self.lblStatus.setText("Status: Wrong device detected.")
return False
if (info["tsb_version"] < 32768):
info["tsb_version"] = int((info["tsb_version"] & 31) + ((info["tsb_version"] & 480) / 32) * 100 + ((info["tsb_version"] & 65024 ) / 512) * 10000 + 20000000)
else:
self.btnUpdate.setEnabled(True)
self.btnClose.setEnabled(True)
self.grpAvailableFwUpdates.setEnabled(True)
self.lblStatus.setText("Status: Wrong device detected.")
return False
#################
# Read user data
self.lblStatus.setText("Status: Reading user data...")
dev.write(b"c")
user_data = bytearray(dev.read(0x41))
info["tsb_timeout"] = user_data[2]
# Change timeout to 6s
self.lblStatus.setText("Status: Writing user data...")
user_data[2] = 254
dev.write(b"C")
dev.read(1)
dev.write(b"!")
dev.write(user_data)
dev.flush()
dev.read(0x41)
# Write firmware
self.lblStatus.setText("Status: Updating firmware... Do not unplug the device!")
iterations = math.ceil(len(fw_buffer) / 0x40)
if len(fw_buffer) < iterations * 0x40:
fw_buffer = fw_buffer + bytearray([0xFF] * ((iterations * 0x40) - len(fw_buffer)))
lives = 10
dev.write(b"F")
dev.flush()
ret = dev.read(1)
while ret != b"?":
dev.write(b"F")
dev.flush()
ret = dev.read(1)
lives -= 1
if lives == 0:
dev.write(b"?")
dev.flush()
dev.close()
self.lblStatus.setText("Status: Protocol error. Please try again.")
self.prgStatus.setValue(0)
self.btnUpdate.setEnabled(True)
self.btnClose.setEnabled(True)
self.grpAvailableFwUpdates.setEnabled(True)
return False
for i in range(0, iterations):
self.APP.QT_APP.processEvents()
dev.write(b"!")
dev.write(fw_buffer[i*0x40:i*0x40+0x40])
self.prgStatus.setValue((i*0x40+0x40) / len(fw_buffer) * 100)
if (dev.read(1) != b"?"):
dev.write(b"?")
dev.flush()
dev.close()
self.lblStatus.setText("Status: Write error. Please try again.")
self.prgStatus.setValue(0)
self.btnUpdate.setEnabled(True)
self.btnClose.setEnabled(True)
self.grpAvailableFwUpdates.setEnabled(True)
return False
dev.write(b"?")
dev.flush()
dev.read(1)
# verify flash
self.lblStatus.setText("Status: Verifying update...")
buffer2 = bytearray()
dev.write(b"f")
dev.flush()
for i in range(0, 0x1DC0, 0x40):
self.APP.QT_APP.processEvents()
dev.write(b"!")
dev.flush()
while dev.in_waiting == 0: time.sleep(0.01)
ret = bytearray(dev.read(0x40))
buffer2 += ret
self.prgStatus.setValue(len(buffer2) / 0x1DC0 * 100)
dev.read(1)
buffer2 = buffer2[:len(fw_buffer)]
if fw_buffer == buffer2:
self.lblStatus.setText("Status: Verification OK.")
self.APP.QT_APP.processEvents()
time.sleep(0.2)
else:
self.lblStatus.setText("Status: Verification error.")
self.prgStatus.setValue(0)
dev.write(b"?")
dev.flush()
dev.close()
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="FlashGBX", text="The firmware update was not successful. Do you want to try again?\n\nIf it doesnt work even after multiple retries, please use the official firmware updater instead.", standardButtons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, defaultButton=QtWidgets.QMessageBox.Yes)
answer = msgbox.exec()
if answer == QtWidgets.QMessageBox.Yes:
time.sleep(1)
continue
self.btnUpdate.setEnabled(True)
self.btnClose.setEnabled(True)
self.grpAvailableFwUpdates.setEnabled(True)
return False
# Change timeout to 1s
self.lblStatus.setText("Status: Writing user data...")
user_data[2] = 42
dev.write(b"C")
dev.flush()
ret = dev.read(1)
while ret != b"?":
dev.write(b"C")
dev.flush()
ret = dev.read(1)
lives -= 1
if lives == 0:
dev.write(b"?")
dev.flush()
dev.close()
self.btnUpdate.setEnabled(True)
self.btnClose.setEnabled(True)
self.grpAvailableFwUpdates.setEnabled(True)
self.lblStatus.setText("Status: User data update error. Please try again.")
return False
dev.write(b"!")
dev.write(user_data)
dev.flush()
dev.read(0x41)
# Restart
self.APP.QT_APP.processEvents()
time.sleep(0.1)
self.lblStatus.setText("Status: Restarting the device...")
dev.write(b"?")
dev.flush()
dev.close()
self.APP.QT_APP.processEvents()
time.sleep(0.8)
self.lblStatus.setText("Status: Done.")
self.APP.QT_APP.processEvents()
time.sleep(0.2)
self.DEVICE = None
while True:
ret = self.WriteFirmware(buffer, self.SetStatus)
if ret == 1: return True
elif ret == 2: return False
elif ret == 3: continue
def SetStatus(self, text, enableUI=False, setProgress=None):
self.lblStatus.setText(text)
if setProgress is not None:
self.prgStatus.setValue(setProgress)
if enableUI:
self.btnUpdate.setEnabled(True)
self.btnClose.setEnabled(True)
self.grpAvailableFwUpdates.setEnabled(True)
flash_ok = True
text = "The firmware update is complete!"
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Question, windowTitle="FlashGBX", text=text, standardButtons=QtWidgets.QMessageBox.Ok)
def WriteFirmware(self, data, fncSetStatus):
fw_buffer = data
port = self.PORT
delay = 0
lives = 10
buffer = bytearray()
fncSetStatus(text="Status: Waiting for bootloader...", setProgress=0)
if self.ResetAVR(delay) is False:
fncSetStatus(text="Status: Device reboot error.", enableUI=True)
self.prgStatus.setValue(0)
return 2
while True:
try:
dev = serial.Serial(port=port, baudrate=9600, timeout=1)
except:
fncSetStatus(text="Status: Device access error.", enableUI=True)
return 2
dev.reset_input_buffer()
dev.reset_output_buffer()
dev.write(b"@@@")
dev.flush()
if platform.system() == "Darwin": time.sleep(0.00125)
buffer = dev.read(0x11)
if (len(buffer) < 0x11) or (buffer[0:3] != b'TSB'):
dev.write(b"?")
dev.flush()
if platform.system() == "Darwin": time.sleep(0.00125)
dev.close()
self.APP.QT_APP.processEvents()
time.sleep(1)
if len(buffer) != 0x11:
delay += 0.05
fncSetStatus("Status: Waiting for bootloader... (+{:d}ms)".format(int(delay * 1000)))
if self.ResetAVR(delay) is False:
fncSetStatus(text="Status: Device reboot error.", enableUI=True)
return 2
lives -= 1
if lives < 0:
fncSetStatus(text="Status: Device reboot error.", enableUI=True)
return 2
continue
break
fncSetStatus("Reading bootloader information...")
info = {}
keys = ["magic", "tsb_version", "tsb_status", "signature", "page_size", "flash_size", "eeprom_size", "unknown", "avr_jmp_identifier"]
values = struct.unpack("<3sHB3sBHHBB", bytearray(buffer[:-1]))
info = dict(zip(keys, values))
info["page_size"] *= 2
info["flash_size"] *= 2
info["eeprom_size"] += 1
if info["avr_jmp_identifier"] == 0x00:
info["jmp_mode"] = "relative"
info["device_type"] = "attiny"
elif info["avr_jmp_identifier"] == 0x0C:
info["jmp_mode"] = "absolute"
info["device_type"] = "attiny"
elif info["avr_jmp_identifier"] == 0xAA:
info["jmp_mode"] = "relative"
info["device_type"] = "atmega"
if info["page_size"] != 64 or info["flash_size"] != 7616 or info["eeprom_size"] != 512 or info["jmp_mode"] != "relative" or info["device_type"] != "atmega" or info["signature"] != b'\x1E\x93\x06':
fncSetStatus(text="Status: Wrong device detected.", enableUI=True)
return 2
if (info["tsb_version"] < 32768):
info["tsb_version"] = int((info["tsb_version"] & 31) + ((info["tsb_version"] & 480) / 32) * 100 + ((info["tsb_version"] & 65024 ) / 512) * 10000 + 20000000)
else:
fncSetStatus(text="Status: Wrong device detected.", enableUI=True)
return 2
#################
# Read user data
fncSetStatus("Status: Reading user data...")
dev.write(b"c")
user_data = bytearray(dev.read(0x41))
info["tsb_timeout"] = user_data[2]
# Change timeout to 6s
fncSetStatus("Status: Writing user data...")
user_data[2] = 254
dev.write(b"C")
dev.read(1)
dev.write(b"!")
dev.write(user_data)
dev.flush()
if platform.system() == "Darwin": time.sleep(0.00125)
dev.read(0x41)
# Write firmware
fncSetStatus("Status: Updating firmware... Do not unplug the device!")
iterations = math.ceil(len(fw_buffer) / 0x40)
if len(fw_buffer) < iterations * 0x40:
fw_buffer = fw_buffer + bytearray([0xFF] * ((iterations * 0x40) - len(fw_buffer)))
lives = 10
dev.write(b"F")
dev.flush()
if platform.system() == "Darwin": time.sleep(0.00125)
ret = dev.read(1)
while ret != b"?":
dev.write(b"F")
dev.flush()
if platform.system() == "Darwin": time.sleep(0.00125)
ret = dev.read(1)
lives -= 1
if lives == 0:
dev.write(b"?")
dev.flush()
if platform.system() == "Darwin": time.sleep(0.00125)
dev.close()
fncSetStatus(text="Status: Protocol Error. Please try again.", enableUI=True)
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="FlashGBX", text="The firmware update was not successful (Protocol Error). Do you want to try again?\n\nIf it doesnt work even after multiple retries, please use the official firmware updater instead.", standardButtons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, defaultButton=QtWidgets.QMessageBox.Yes)
answer = msgbox.exec()
if answer == QtWidgets.QMessageBox.Yes:
time.sleep(1)
return 3
return 2
for i in range(0, iterations):
self.APP.QT_APP.processEvents()
dev.write(b"!")
dev.write(fw_buffer[i*0x40:i*0x40+0x40])
fncSetStatus(text="Status: Updating firmware... Do not unplug the device!", setProgress=(i*0x40+0x40) / len(fw_buffer) * 100)
ret = dev.read(1)
if (ret != b"?"):
dev.write(b"?")
dev.flush()
if platform.system() == "Darwin": time.sleep(0.00125)
dev.close()
fncSetStatus(text="Status: Write Error ({:s}). Please try again.".format(str(ret)), enableUI=True)
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="FlashGBX", text="The firmware update was not successful (Write Error, {:s}). Do you want to try again?\n\nIf it doesnt work even after multiple retries, you will have to use the official firmware updater to recover the firmware.".format(str(ret)), standardButtons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, defaultButton=QtWidgets.QMessageBox.Yes)
answer = msgbox.exec()
if answer == QtWidgets.QMessageBox.Yes:
time.sleep(1)
return 3
return 2
dev.write(b"?")
dev.flush()
if platform.system() == "Darwin": time.sleep(0.00125)
dev.read(1)
# verify flash
fncSetStatus("Status: Verifying update...")
buffer2 = bytearray()
dev.write(b"f")
dev.flush()
if platform.system() == "Darwin": time.sleep(0.00125)
for i in range(0, 0x1DC0, 0x40):
self.APP.QT_APP.processEvents()
dev.write(b"!")
dev.flush()
if platform.system() == "Darwin": time.sleep(0.00125)
while dev.in_waiting == 0: time.sleep(0.01)
ret = bytearray(dev.read(0x40))
buffer2 += ret
self.prgStatus.setValue(len(buffer2) / 0x1DC0 * 100)
dev.read(1)
buffer2 = buffer2[:len(fw_buffer)]
if fw_buffer == buffer2:
fncSetStatus("Status: Verification OK.")
self.APP.QT_APP.processEvents()
time.sleep(0.2)
else:
fncSetStatus(text="Status: Verification Error.", enableUI=True)
dev.write(b"?")
dev.flush()
if platform.system() == "Darwin": time.sleep(0.00125)
dev.close()
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="FlashGBX", text="The firmware update was not successful (Verification Error). Do you want to try again?\n\nIf it doesnt work even after multiple retries, please use the official firmware updater instead.", standardButtons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, defaultButton=QtWidgets.QMessageBox.Yes)
answer = msgbox.exec()
self.reject()
if answer == QtWidgets.QMessageBox.Yes:
time.sleep(1)
return 3
return 2
# Change timeout to 1s
fncSetStatus("Status: Writing user data...")
user_data[2] = 42
dev.write(b"C")
dev.flush()
if platform.system() == "Darwin": time.sleep(0.00125)
ret = dev.read(1)
while ret != b"?":
dev.write(b"C")
dev.flush()
if platform.system() == "Darwin": time.sleep(0.00125)
ret = dev.read(1)
lives -= 1
if lives == 0:
dev.write(b"?")
dev.flush()
if platform.system() == "Darwin": time.sleep(0.00125)
dev.close()
fncSetStatus(text="Status: User data update error. Please try again.", enableUI=True)
return 2
dev.write(b"!")
dev.write(user_data)
dev.flush()
if platform.system() == "Darwin": time.sleep(0.00125)
dev.read(0x41)
# Restart
self.APP.QT_APP.processEvents()
time.sleep(0.1)
fncSetStatus("Status: Restarting the device...")
dev.write(b"?")
dev.flush()
if platform.system() == "Darwin": time.sleep(0.00125)
dev.close()
self.APP.QT_APP.processEvents()
time.sleep(0.8)
fncSetStatus("Status: Done.")
self.APP.QT_APP.processEvents()
time.sleep(0.2)
self.DEVICE = None
self.btnUpdate.setEnabled(True)
self.btnClose.setEnabled(True)
self.grpAvailableFwUpdates.setEnabled(True)
flash_ok = True
text = "The firmware update is complete!"
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Question, windowTitle="FlashGBX", text=text, standardButtons=QtWidgets.QMessageBox.Ok)
answer = msgbox.exec()
self.reject()
return 1

View File

@ -7,7 +7,6 @@ import serial, serial.tools.list_ports
from serial import SerialException
from .RomFileDMG import RomFileDMG
from .RomFileAGB import RomFileAGB
#from .GBMemory import GBMemory
from .Mapper import DMG_MBC, AGB_GPIO
from .Flashcart import Flashcart, Flashcart_DMG_MMSA, CFI
from .Util import ANSI, dprint, bitswap, ParseCFI
@ -84,6 +83,7 @@ class GbxDevice:
SUPPORTED_CARTS = {}
FW = []
FW_UPDATE_REQ = False
MODE = None
PORT = ''
DEVICE = None
@ -234,7 +234,7 @@ class GbxDevice:
return ["DMG", "AGB"]
def IsSupportedMbc(self, mbc):
return mbc in ( 0x00, 0x01, 0x02, 0x03, 0x06, 0x0B, 0x0D, 0x10, 0x13, 0x19, 0x1B, 0x1C, 0x1E, 0x20, 0x22, 0xFC, 0xFD, 0xFE, 0xFF, 0x101, 0x103, 0x104, 0x105 )
return mbc in ( 0x00, 0x01, 0x02, 0x03, 0x06, 0x0B, 0x0D, 0x10, 0x13, 0x19, 0x1A, 0x1B, 0x1C, 0x1E, 0x20, 0x22, 0xFC, 0xFD, 0xFE, 0xFF, 0x101, 0x103, 0x104, 0x105 )
def IsSupported3dMemory(self):
return True
@ -1957,8 +1957,8 @@ class GbxDevice:
if "flash_ids" in cart_type:
(verified, flash_id) = flashcart.VerifyFlashID()
if not verified:
print("FAIL: This cartridges Flash ID ({:s}) didnt match the cartridge type selection.".format(' '.join(format(x, '02X') for x in flash_id)))
return False
print("WARNING: This cartridges Flash ID ({:s}) didnt match the cartridge type selection.".format(' '.join(format(x, '02X') for x in flash_id)))
#return False
# ↑↑↑ Read Flash ID
# ↓↓↓ Read Sector Map
@ -2156,16 +2156,6 @@ class GbxDevice:
self._read(1)
self.CartPowerOn()
#debug 369IN1
#self._set_fw_variable("TRANSFER_SIZE", 1)
#self._set_fw_variable("ADDRESS", 2)
#self._write(self.DEVICE_CMD["AGB_CART_WRITE_SRAM"])
#self._write(bytearray([7 << 4]))
#temp = self._read(1)
#print(temp)
#return
#debug 369IN1
ret = False
self.SIGNAL = signal
if args['mode'] == 1: ret = self._BackupROM(args)

View File

@ -117,6 +117,7 @@ class GbxDevice:
SUPPORTED_CARTS = {}
FW = []
FW_UPDATE_REQ = False
MODE = None
PORT = ''
DEVICE = None
@ -185,10 +186,11 @@ class GbxDevice:
self.DEVICE = None
return False
elif self.FW[0] < 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>."])
continue
#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>."])
#continue
self.FW_UPDATE_REQ = True
elif self.FW[0] < self.DEVICE_MAX_FW:
# TODO: not showing this for now
#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>."])
@ -196,7 +198,6 @@ class GbxDevice:
elif self.FW[0] > 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."])
pass
conn_msg.append([0, "NOTE: FlashGBX is now optimized for the custom high compatibility firmware. You can install it from the Tools menu."])
if self.FW[1] not in self.PCB_VERSIONS.keys():
dev.close()
@ -206,6 +207,8 @@ class GbxDevice:
if (self.FW[1] != 4):
conn_msg.append([0, "NOTE: This version of FlashGBX was developed to be used with GBxCart RW v1.3 and v1.3 Pro. Other revisions are untested and may not be fully compatible."])
else:
conn_msg.append([0, "NOTE: FlashGBX is now optimized for the custom high compatibility firmware. You can install it from the Tools menu."])
self.PORT = ports[i]
@ -344,7 +347,7 @@ class GbxDevice:
#if (int(self.FW[0]) >= 26):
# return mbc in ( 0x00, 0x01, 0x02, 0x03, 0x06, 0x0B, 0x0D, 0x10, 0x13, 0x19, 0x1B, 0x1C, 0x1E, 0xFC, 0xFD, 0xFE, 0xFF, 0x101, 0x103, 0x104, 0x105 )
#else:
return mbc in ( 0x00, 0x01, 0x02, 0x03, 0x06, 0x10, 0x13, 0x19, 0x1B, 0x1C, 0x1E, 0xFC, 0xFE, 0xFF, 0x101, 0x103 )
return mbc in ( 0x00, 0x01, 0x02, 0x03, 0x06, 0x10, 0x13, 0x19, 0x1A, 0x1B, 0x1C, 0x1E, 0xFC, 0xFE, 0xFF, 0x101, 0x103 )
def IsSupported3dMemory(self):
return False

Binary file not shown.

View File

@ -55,6 +55,7 @@ for Windows, Linux, macOS
- DIY cart with AM29F016/AM29F016B
- DIY cart with AM29F032/AM29F032B
- DIY cart with AT49F040
- DIY cart with MBC1 and AM29F080
- GB Smart 32M
- insideGadgets 32 KB
- insideGadgets 512 KB
@ -68,7 +69,8 @@ for Windows, Linux, macOS
- Development AGB Cartridge 128M Flash S, E201850
- Development AGB Cartridge 256M Flash S, E201868
- Flash2Advance 256M (non-ultra variant, with 2× 28F128J3A150)
- Flash2Advance 256M (with 2× 28F128J3A150)
- Flash2Advance Ultra 64M (with 2× 28F320C3B)
- insideGadgets 16 MB, 64K EEPROM with Solar Sensor and RTC options
- insideGadgets 32 MB, 1M FLASH with RTC option
- insideGadgets 32 MB, 512K FLASH
@ -84,7 +86,7 @@ for Windows, Linux, macOS
- GB-M968 with 29LV160DB
- GB-M968 with M29W160EB
- GB-M968 with MX29LV320ABTC
- ALTERA CPLD and S29GL032N90T (no PCB text)
- S29GL032N90T and ALTERA CPLD (configured for MBC5)
- SD007_48BALL_64M with GL032M11BAIR4
- SD007_48BALL_64M with M29W640
- SD007_48BALL_64M_V2 with GL032M11BAIR4
@ -112,9 +114,11 @@ for Windows, Linux, macOS
- Game Boy Advance
- 100BS6600_48BALL_V4 with 6600M0U0BE
- 28F256L03B-DRV with 256L30B
- 36L0R8-39VF512 with M36L0R8060B
- 36L0R8-39VF512 with M36L0R8060T
- 4350Q2 with 4350LLYBQ2
- 4050M0Y0Q0-39VF512 with 4050M0Y0Q0
- 4050_4400_4000_4350_36L0R_V5 with 4050L0YTQ2
- 4050_4400_4000_4350_36L0R_V5 with M36L0R7050T
@ -122,7 +126,6 @@ for Windows, Linux, macOS
- 4050_4400_4000_4350_36L0R_V5 with M36L0R8060T
- 4400 with 4400L0ZDQ0
- 4455_4400_4000_4350_36L0R_V3 with M36L0R7050T
- 100BS6600_48BALL_V4 with 6600M0U0BE
- AGB-E05-01 with GL128S
- AGB-E05-01 with MSP55LV128M
- AGB-E05-01 with MX29GL128FHT2I-90G
@ -184,6 +187,7 @@ This software is provided as-is and the developer is not responsible for any dam
The author would like to thank the following very kind people for their help and contributions (in alphabetical order):
- 90sFlav (flash chip info)
- AcoVanConis (bug reports)
- AlexiG (GBxCart RW hardware, bug reports, flash chip info)
- AndehX (app icon, flash chip info)
@ -195,6 +199,7 @@ The author would like to thank the following very kind people for their help and
- Frost Clock (flash chip info)
- howie0210 (flash chip info)
- Icesythe7 (feature suggestions)
- Jayro (flash chip info)
- JFox (help with properly packaging the app for pip)
- julgr (macOS help, testing)
- litlemoran (flash chip info)
@ -204,6 +209,7 @@ The author would like to thank the following very kind people for their help and
- paarongiroux (bug reports)
- Paradoxical (flash chip info)
- RevZ (Linux help, testing, bug reports, flash chip info)
- skite2001 (flash chip info)
- Super Maker (flash chip info, testing)
- Veund (flash chip info)
- Zeii (flash chip info)

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.0",
version="2.1",
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",