mirror of
https://github.com/lesserkuma/FlashGBX.git
synced 2026-04-25 16:19:24 -05:00
2.1
This commit is contained in:
parent
167176ee40
commit
6e45e3ce9a
12
CHANGES.md
12
CHANGES.md
|
|
@ -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 endrift’s 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 [orangelo’s 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 orangeglo’s [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)*
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ]
|
||||
]
|
||||
}
|
||||
}
|
||||
60
FlashGBX/config/fc_AGB_Flash2Advance_Ultra_64M.txt
Normal file
60
FlashGBX/config/fc_AGB_Flash2Advance_Ultra_64M.txt
Normal 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 ]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
"type":"AGB",
|
||||
"names":[
|
||||
"36L0R8-39VF512 with M36L0R8060B",
|
||||
"36L0R8-39VF512 with M36L0R8060B"
|
||||
"4350Q2 with 4350LLYBQ2"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0x20, 0x00, 0x0D, 0x88 ],
|
||||
|
|
|
|||
58
FlashGBX/config/fc_DMG_AM29F080_MBC1_WR.txt
Normal file
58
FlashGBX/config/fc_DMG_AM29F080_MBC1_WR.txt
Normal 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 ]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 ],
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 doesn’t 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 doesn’t 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 doesn’t 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 doesn’t 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
|
||||
|
|
|
|||
|
|
@ -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 cartridge’s Flash ID ({:s}) didn’t match the cartridge type selection.".format(' '.join(format(x, '02X') for x in flash_id)))
|
||||
return False
|
||||
print("WARNING: This cartridge’s Flash ID ({:s}) didn’t 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)
|
||||
|
|
|
|||
|
|
@ -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.
12
README.md
12
README.md
|
|
@ -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)
|
||||
|
|
|
|||
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.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",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user