FlashGBX 4.3__py3-none-any.whl → 4.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- FlashGBX/DataTransfer.py +1 -1
- FlashGBX/FlashGBX.py +4 -3
- FlashGBX/FlashGBX_CLI.py +36 -20
- FlashGBX/FlashGBX_GUI.py +359 -148
- FlashGBX/Flashcart.py +3 -2
- FlashGBX/GBMemory.py +4 -2
- FlashGBX/LK_Device.py +327 -233
- FlashGBX/Mapper.py +6 -27
- FlashGBX/PocketCamera.py +1 -1
- FlashGBX/PocketCameraWindow.py +32 -2
- FlashGBX/RomFileAGB.py +5 -2
- FlashGBX/RomFileDMG.py +8 -3
- FlashGBX/UserInputDialog.py +1 -1
- FlashGBX/Util.py +33 -11
- FlashGBX/__main__.py +1 -1
- FlashGBX/fw_GBFlash.py +20 -3
- FlashGBX/fw_GBxCartRW_v1_3.py +1 -1
- FlashGBX/fw_GBxCartRW_v1_4.py +1 -1
- FlashGBX/fw_JoeyJr.py +10 -3
- FlashGBX/hw_GBFlash.py +3 -3
- FlashGBX/hw_GBxCartRW.py +16 -16
- FlashGBX/hw_JoeyJr.py +3 -3
- FlashGBX/pyside.py +1 -1
- FlashGBX/res/config.zip +0 -0
- FlashGBX/res/fw_GBFlash.zip +0 -0
- FlashGBX/res/fw_GBxCart_RW_v1_4.zip +0 -0
- FlashGBX/res/fw_GBxCart_RW_v1_4a.zip +0 -0
- FlashGBX/res/fw_JoeyJr.zip +0 -0
- {FlashGBX-4.3.dist-info → flashgbx-4.6.dist-info}/METADATA +103 -57
- flashgbx-4.6.dist-info/RECORD +43 -0
- {FlashGBX-4.3.dist-info → flashgbx-4.6.dist-info}/WHEEL +1 -1
- FlashGBX-4.3.dist-info/RECORD +0 -43
- {FlashGBX-4.3.dist-info → flashgbx-4.6.dist-info}/entry_points.txt +0 -0
- {FlashGBX-4.3.dist-info → flashgbx-4.6.dist-info/licenses}/LICENSE +0 -0
- {FlashGBX-4.3.dist-info → flashgbx-4.6.dist-info}/top_level.txt +0 -0
FlashGBX/Mapper.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
# FlashGBX
|
|
3
|
-
# Author: Lesserkuma (github.com/
|
|
3
|
+
# Author: Lesserkuma (github.com/Lesserkuma)
|
|
4
4
|
|
|
5
5
|
import time, datetime, struct, math, hashlib
|
|
6
6
|
from dateutil.relativedelta import relativedelta
|
|
@@ -260,13 +260,6 @@ class DMG_MBC3(DMG_MBC):
|
|
|
260
260
|
def GetName(self):
|
|
261
261
|
return "MBC3"
|
|
262
262
|
|
|
263
|
-
def EnableRAM(self, enable=True):
|
|
264
|
-
dprint(self.GetName(), "|", enable)
|
|
265
|
-
commands = [
|
|
266
|
-
[ 0x0000, 0x0A if enable else 0x00 ],
|
|
267
|
-
]
|
|
268
|
-
self.CartWrite(commands)
|
|
269
|
-
|
|
270
263
|
def HasRTC(self):
|
|
271
264
|
dprint("Checking for RTC")
|
|
272
265
|
if self.MBC_ID not in (0x0F, 0x10, 0x110, 0x206):
|
|
@@ -472,20 +465,6 @@ class DMG_MBC5(DMG_MBC):
|
|
|
472
465
|
def GetName(self):
|
|
473
466
|
return "MBC5"
|
|
474
467
|
|
|
475
|
-
def EnableRAM(self, enable=True):
|
|
476
|
-
dprint(self.GetName(), "|", enable)
|
|
477
|
-
if enable:
|
|
478
|
-
commands = [
|
|
479
|
-
[ 0x6000, 0x01 ],
|
|
480
|
-
[ 0x0000, 0x0A ],
|
|
481
|
-
]
|
|
482
|
-
else:
|
|
483
|
-
commands = [
|
|
484
|
-
[ 0x0000, 0x00 ],
|
|
485
|
-
[ 0x6000, 0x00 ],
|
|
486
|
-
]
|
|
487
|
-
self.CartWrite(commands)
|
|
488
|
-
|
|
489
468
|
def SelectBankROM(self, index):
|
|
490
469
|
dprint(self.GetName(), "|", index)
|
|
491
470
|
|
|
@@ -701,7 +680,7 @@ class DMG_MMM01(DMG_MBC):
|
|
|
701
680
|
class DMG_GBD(DMG_MBC5):
|
|
702
681
|
def GetName(self):
|
|
703
682
|
return "MAC-GBD"
|
|
704
|
-
|
|
683
|
+
|
|
705
684
|
def SelectBankROM(self, index):
|
|
706
685
|
dprint(self.GetName(), "|", index)
|
|
707
686
|
commands = [
|
|
@@ -1647,7 +1626,7 @@ class AGB_GPIO:
|
|
|
1647
1626
|
temp = self.CartRead(self.GPIO_REG_DAT) & 0xFF
|
|
1648
1627
|
bit = (temp & 2) >> 1
|
|
1649
1628
|
data = (data >> 1) | (bit << 7)
|
|
1650
|
-
#
|
|
1629
|
+
# dprint("RTCReadData(): i={:d}/temp={:X}/bit={:x}/data={:x}".format(i, temp, bit, data))
|
|
1651
1630
|
return data
|
|
1652
1631
|
|
|
1653
1632
|
def RTCWriteData(self, data):
|
|
@@ -1703,7 +1682,8 @@ class AGB_GPIO:
|
|
|
1703
1682
|
status = self.RTCReadStatus()
|
|
1704
1683
|
else:
|
|
1705
1684
|
status = buffer[0]
|
|
1706
|
-
|
|
1685
|
+
|
|
1686
|
+
dprint("Status:", bin(status))
|
|
1707
1687
|
if (status >> 7) == 1:
|
|
1708
1688
|
dprint("No RTC because of set RTC Status Register Power Flag:", status >> 7 & 1)
|
|
1709
1689
|
return 1
|
|
@@ -1723,7 +1703,7 @@ class AGB_GPIO:
|
|
|
1723
1703
|
else:
|
|
1724
1704
|
rom2 = buffer[1:7]
|
|
1725
1705
|
|
|
1726
|
-
dprint(' '.join(format(x, '02X') for x in rom1), "/", ' '.join(format(x, '02X') for x in rom2))
|
|
1706
|
+
dprint("RTC Data:", ' '.join(format(x, '02X') for x in rom1), "/", ' '.join(format(x, '02X') for x in rom2))
|
|
1727
1707
|
if (rom1 == rom2):
|
|
1728
1708
|
dprint("No RTC because ROM data didn’t change:", rom1, rom2)
|
|
1729
1709
|
return 3
|
|
@@ -1908,7 +1888,6 @@ class AGB_GPIO:
|
|
|
1908
1888
|
}
|
|
1909
1889
|
|
|
1910
1890
|
if rtc_y == 0 and rtc_m == 0 and rtc_d == 0 and rtc_h == 0 and rtc_i == 0 and rtc_s == 0:
|
|
1911
|
-
#raise ValueError("Invalid RTC data")
|
|
1912
1891
|
d["string"] = "Invalid RTC data"
|
|
1913
1892
|
d["rtc_valid"] = False
|
|
1914
1893
|
else:
|
FlashGBX/PocketCamera.py
CHANGED
FlashGBX/PocketCameraWindow.py
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
# FlashGBX
|
|
3
|
-
# Author: Lesserkuma (github.com/
|
|
3
|
+
# Author: Lesserkuma (github.com/Lesserkuma)
|
|
4
4
|
|
|
5
5
|
import functools, os, json, platform, shutil
|
|
6
6
|
from PIL.ImageQt import ImageQt
|
|
7
7
|
from PIL import Image, ImageDraw
|
|
8
8
|
from .pyside import QtCore, QtWidgets, QtGui, QDesktopWidget
|
|
9
9
|
from .PocketCamera import PocketCamera
|
|
10
|
+
from .UserInputDialog import UserInputDialog
|
|
10
11
|
|
|
11
12
|
class PocketCameraWindow(QtWidgets.QDialog):
|
|
12
13
|
CUR_PIC = None
|
|
@@ -20,6 +21,7 @@ class PocketCameraWindow(QtWidgets.QDialog):
|
|
|
20
21
|
APP_PATH = "."
|
|
21
22
|
CONFIG_PATH = "."
|
|
22
23
|
APP = None
|
|
24
|
+
FORCE_EXIT = False
|
|
23
25
|
PALETTES = [
|
|
24
26
|
[ 255, 255, 255, 176, 176, 176, 104, 104, 104, 0, 0, 0 ], # Grayscale
|
|
25
27
|
[ 208, 217, 60, 120, 164, 106, 84, 88, 84, 36, 70, 36 ], # Game Boy
|
|
@@ -33,6 +35,8 @@ class PocketCameraWindow(QtWidgets.QDialog):
|
|
|
33
35
|
QtWidgets.QDialog.__init__(self)
|
|
34
36
|
self.setAcceptDrops(True)
|
|
35
37
|
if icon is not None: self.setWindowIcon(QtGui.QIcon(icon))
|
|
38
|
+
|
|
39
|
+
self.FORCE_EXIT = False
|
|
36
40
|
self.CUR_FILE = file
|
|
37
41
|
self.CONFIG_PATH = config_path
|
|
38
42
|
self.APP_PATH = app_path
|
|
@@ -188,7 +192,9 @@ class PocketCameraWindow(QtWidgets.QDialog):
|
|
|
188
192
|
self.CUR_PALETTE = len(self.PALETTES) - 1
|
|
189
193
|
|
|
190
194
|
if self.CUR_FILE is not None:
|
|
191
|
-
self.OpenFile(self.CUR_FILE)
|
|
195
|
+
if self.OpenFile(self.CUR_FILE) is False:
|
|
196
|
+
self.FORCE_EXIT = True
|
|
197
|
+
return
|
|
192
198
|
|
|
193
199
|
self.CUR_EXPORT_PATH = self.APP.SETTINGS.value("LastDirPocketCamera")
|
|
194
200
|
if self.CUR_EXPORT_PATH is None:
|
|
@@ -201,6 +207,9 @@ class PocketCameraWindow(QtWidgets.QDialog):
|
|
|
201
207
|
self.btnSaveAll.setFocus()
|
|
202
208
|
|
|
203
209
|
def run(self):
|
|
210
|
+
if self.FORCE_EXIT:
|
|
211
|
+
self.reject()
|
|
212
|
+
return
|
|
204
213
|
self.layout.update()
|
|
205
214
|
self.layout.activate()
|
|
206
215
|
screenGeometry = QDesktopWidget().screenGeometry(self)
|
|
@@ -217,6 +226,26 @@ class PocketCameraWindow(QtWidgets.QDialog):
|
|
|
217
226
|
self.UpdateViewer(self.CUR_INDEX)
|
|
218
227
|
|
|
219
228
|
def OpenFile(self, file):
|
|
229
|
+
if isinstance(file, bytearray) and len(file) == 0x100000 or isinstance(file, str) and os.path.getsize(file) == 0x100000:
|
|
230
|
+
dlg_args = {
|
|
231
|
+
"title":"Photo!",
|
|
232
|
+
"intro":"A Photo! save file was detected.\n\nPlease select the roll of pictures that you would like to load.",
|
|
233
|
+
"params": [
|
|
234
|
+
[ "index", "cmb", "Roll:", [ "Current Save Data" ] + [ "Flash Directory Slot {:d}".format(l) for l in range(1, 8) ], 0 ],
|
|
235
|
+
]
|
|
236
|
+
}
|
|
237
|
+
dlg = UserInputDialog(self, icon=self.windowIcon(), args=dlg_args)
|
|
238
|
+
if dlg.exec_() == 1:
|
|
239
|
+
result = dlg.GetResult()
|
|
240
|
+
index = result["index"].currentIndex()
|
|
241
|
+
if isinstance(file, str):
|
|
242
|
+
with open(file, "rb") as f:
|
|
243
|
+
file = bytearray(f.read())
|
|
244
|
+
file = file[0x20000 * index:][:0x20000]
|
|
245
|
+
else:
|
|
246
|
+
self.CUR_PC = None
|
|
247
|
+
return False
|
|
248
|
+
|
|
220
249
|
try:
|
|
221
250
|
self.CUR_PC = PocketCamera()
|
|
222
251
|
if self.CUR_PC.LoadFile(file) == False:
|
|
@@ -285,6 +314,7 @@ class PocketCameraWindow(QtWidgets.QDialog):
|
|
|
285
314
|
self.SavePicture(self.CUR_INDEX)
|
|
286
315
|
|
|
287
316
|
def btnClose_Clicked(self, event):
|
|
317
|
+
self.FORCE_EXIT = True
|
|
288
318
|
self.reject()
|
|
289
319
|
|
|
290
320
|
def hideEvent(self, event):
|
FlashGBX/RomFileAGB.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
# FlashGBX
|
|
3
|
-
# Author: Lesserkuma (github.com/
|
|
3
|
+
# Author: Lesserkuma (github.com/Lesserkuma)
|
|
4
4
|
|
|
5
5
|
import hashlib, re, zlib, string, os, json, copy, struct
|
|
6
6
|
from . import Util
|
|
@@ -121,6 +121,7 @@ class RomFileAGB:
|
|
|
121
121
|
def GetHeader(self, unchanged=False):
|
|
122
122
|
buffer = bytearray(self.ROMFILE)
|
|
123
123
|
data = {}
|
|
124
|
+
if len(buffer) < 0x180: return {}
|
|
124
125
|
hash = hashlib.sha1(buffer[0:0x180]).digest()
|
|
125
126
|
nocart_hashes = []
|
|
126
127
|
nocart_hashes.append(bytearray([ 0x4F, 0xE9, 0x3E, 0xEE, 0xBC, 0x55, 0x93, 0xFE, 0x2E, 0x23, 0x1A, 0x39, 0x86, 0xCE, 0x86, 0xC9, 0x5C, 0x11, 0x00, 0xDD ])) # Method 0
|
|
@@ -187,7 +188,9 @@ class RomFileAGB:
|
|
|
187
188
|
(data["game_title"] == "CARDE READER" and data["game_code"] == "PSAE" and data["header_checksum"] == 0x95):
|
|
188
189
|
data["ereader"] = True
|
|
189
190
|
|
|
190
|
-
|
|
191
|
+
if unchanged:
|
|
192
|
+
data["unchanged"] = copy.copy(data)
|
|
193
|
+
|
|
191
194
|
self.DATA = data
|
|
192
195
|
data["db"] = self.GetDatabaseEntry()
|
|
193
196
|
|
FlashGBX/RomFileDMG.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
# FlashGBX
|
|
3
|
-
# Author: Lesserkuma (github.com/
|
|
3
|
+
# Author: Lesserkuma (github.com/Lesserkuma)
|
|
4
4
|
|
|
5
5
|
import hashlib, re, string, struct, os, json, copy
|
|
6
6
|
from . import Util
|
|
@@ -140,8 +140,9 @@ class RomFileDMG:
|
|
|
140
140
|
data["rom_checksum_calc"] = self.CalcChecksumGlobal()
|
|
141
141
|
data["rom_checksum_correct"] = data["rom_checksum"] == data["rom_checksum_calc"]
|
|
142
142
|
|
|
143
|
-
|
|
144
|
-
|
|
143
|
+
if unchanged:
|
|
144
|
+
data["unchanged"] = copy.copy(data)
|
|
145
|
+
else:
|
|
145
146
|
# MBC2
|
|
146
147
|
if data["mapper_raw"] == 0x06:
|
|
147
148
|
data["ram_size_raw"] = 0x100
|
|
@@ -437,6 +438,10 @@ class RomFileDMG:
|
|
|
437
438
|
data["ram_size_raw"] = 0x03
|
|
438
439
|
data["mapper_raw"] = 0x206
|
|
439
440
|
|
|
441
|
+
# Photo!
|
|
442
|
+
if data["game_title"] == "PHOTO":
|
|
443
|
+
data["ram_size_raw"] = 0x204
|
|
444
|
+
|
|
440
445
|
if data["mapper_raw"] in Util.DMG_Header_Mapper:
|
|
441
446
|
data["mapper"] = Util.DMG_Header_Mapper[data["mapper_raw"]]
|
|
442
447
|
elif data["logo_correct"]:
|
FlashGBX/UserInputDialog.py
CHANGED
FlashGBX/Util.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
# FlashGBX
|
|
3
|
-
# Author: Lesserkuma (github.com/
|
|
3
|
+
# Author: Lesserkuma (github.com/Lesserkuma)
|
|
4
4
|
|
|
5
5
|
import math, time, datetime, copy, configparser, threading, os, platform, traceback, io, struct, re, statistics, random, sys
|
|
6
6
|
from io import StringIO
|
|
@@ -8,9 +8,9 @@ from enum import Enum
|
|
|
8
8
|
|
|
9
9
|
# Common constants
|
|
10
10
|
APPNAME = "FlashGBX"
|
|
11
|
-
VERSION_PEP440 = "4.
|
|
11
|
+
VERSION_PEP440 = "4.6"
|
|
12
12
|
VERSION = "v{:s}".format(VERSION_PEP440)
|
|
13
|
-
VERSION_TIMESTAMP =
|
|
13
|
+
VERSION_TIMESTAMP = 1769513530
|
|
14
14
|
DEBUG = False
|
|
15
15
|
DEBUG_LOG = []
|
|
16
16
|
APP_PATH = ""
|
|
@@ -20,17 +20,17 @@ AGB_Header_ROM_Sizes = [ "32 KiB", "64 KiB", "128 KiB", "256 KiB", "512 KiB", "1
|
|
|
20
20
|
AGB_Header_ROM_Sizes_Map = [ 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, 0x100000, 0x200000, 0x400000, 0x800000, 0x1000000, 0x2000000, 0x4000000, 0x8000000, 0x10000000, 0x20000000 ]
|
|
21
21
|
AGB_Header_Save_Types = [ "None", "4K EEPROM (512 Bytes)", "64K EEPROM (8 KiB)", "256K SRAM/FRAM (32 KiB)", "512K FLASH (64 KiB)", "1M FLASH (128 KiB)", "8M DACS (1 MiB)", "Unlicensed 512K SRAM (64 KiB)", "Unlicensed 1M SRAM (128 KiB)", "Unlicensed Batteryless SRAM" ]
|
|
22
22
|
AGB_Header_Save_Sizes = [ 0, 512, 8192, 32768, 65536, 131072, 1048576, 65536, 131072, 0 ]
|
|
23
|
-
AGB_Flash_Save_Chips = { 0xBFD4:"SST 39VF512", 0x1F3D:"Atmel AT29LV512", 0xC21C:"Macronix MX29L512", 0x321B:"Panasonic MN63F805MNP", 0xC209:"Macronix MX29L010", 0x6213:"SANYO LE26FV10N1TS", 0xBF5B:"Unlicensed SST49LF080A", 0xFFFF:"Unlicensed 0xFFFF" }
|
|
24
|
-
AGB_Flash_Save_Chips_Sizes = [ 0x10000, 0x10000, 0x10000, 0x10000, 0x20000, 0x20000, 0x20000, 0x20000 ]
|
|
23
|
+
AGB_Flash_Save_Chips = { 0xBFD4:"SST 39VF512", 0x1F3D:"Atmel AT29LV512", 0xC21C:"Macronix MX29L512", 0x321B:"Panasonic MN63F805MNP", 0xC209:"Macronix MX29L010", 0x6213:"SANYO LE26FV10N1TS", 0xBF4B:"Unlicensed SST25VF064C", 0xBF5B:"Unlicensed SST49LF080A", 0xBF6D:"Unlicensed SST39VF6401B", 0xFFFF:"Unlicensed 0xFFFF" }
|
|
24
|
+
AGB_Flash_Save_Chips_Sizes = [ 0x10000, 0x10000, 0x10000, 0x10000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000 ]
|
|
25
25
|
|
|
26
26
|
DMG_Header_Mapper = { 0x00:'None', 0x01:'MBC1', 0x02:'MBC1+SRAM', 0x03:'MBC1+SRAM+BATTERY', 0x06:'MBC2+SRAM+BATTERY', 0x0F:'MBC3+RTC+BATTERY', 0x10:'MBC3+RTC+SRAM+BATTERY', 0x110:'MBC30+RTC+SRAM+BATTERY', 0x12:'MBC3+SRAM', 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:'MAC-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', 0x201:'Unlicensed 256M Mapper', 0x202:'Unlicensed Wisdom Tree Mapper', 0x203:'Unlicensed Xploder GB Mapper', 0x204:'Unlicensed Sachen Mapper', 0x205:'Unlicensed Datel Orbit V2 Mapper', 0x206:'Unlicensed MBCX Mapper' }
|
|
27
27
|
DMG_Mapper_Types = { "None":[ 0x00, 0x08, 0x09 ], "MBC1":[ 0x01, 0x02, 0x03 ], "MBC2":[ 0x05, 0x06 ], "MBC3":[ 0x0F, 0x10, 0x11, 0x12, 0x13 ], "MBC30":[ 0x110 ], "MBC5":[ 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E ], "MBC6":[ 0x20 ], "MBC7":[ 0x22 ], "MBC1M":[ 0x101, 0x103 ], "MMM01":[ 0x0B, 0x0D ], "MAC-GBD":[ 0xFC ], "G-MMC1":[ 0x105 ], "M161":[ 0x104 ], "HuC-1":[ 0xFF ], "HuC-3":[ 0xFE ], "TAMA5":[ 0xFD ], "Unlicensed 256M Multi Cart Mapper":[ 0x201 ], "Unlicensed Wisdom Tree Mapper":[ 0x202 ], "Unlicensed Xploder GB Mapper":[ 0x203 ], "Unlicensed Sachen Mapper":[ 0x204 ], "Unlicensed Datel Orbit V2 Mapper":[ 0x205 ], "Unlicensed MBCX Mapper":[ 0x206 ] }
|
|
28
28
|
DMG_Header_ROM_Sizes = [ "32 KiB", "64 KiB", "128 KiB", "256 KiB", "512 KiB", "1 MiB", "2 MiB", "4 MiB", "8 MiB", "16 MiB", "32 MiB", "64 MiB", "128 MiB" ]
|
|
29
29
|
DMG_Header_ROM_Sizes_Map = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C ]
|
|
30
30
|
DMG_Header_ROM_Sizes_Flasher_Map = [ 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, 0x100000, 0x200000, 0x400000, 0x800000, 0x1000000, 0x2000000, 0x4000000, 0x8000000 ]
|
|
31
|
-
DMG_Header_RAM_Sizes = [ "None", "4K SRAM (512 Bytes)", "16K SRAM (2 KiB)", "64K SRAM (8 KiB)", "256K SRAM (32 KiB)", "512K SRAM (64 KiB)", "1M SRAM (128 KiB)", "MBC6 SRAM+FLASH (1.03 MiB)", "MBC7 2K EEPROM (256 Bytes)", "MBC7 4K EEPROM (512 Bytes)", "TAMA5 EEPROM (32 Bytes)", "Unlicensed 4M SRAM (512 KiB)", "Unlicensed 1M EEPROM (128 KiB)" ]
|
|
32
|
-
DMG_Header_RAM_Sizes_Map = [ 0x00, 0x100, 0x01, 0x02, 0x03, 0x05, 0x04, 0x104, 0x101, 0x102, 0x103, 0x201, 0x203, 0x204 ]
|
|
33
|
-
DMG_Header_RAM_Sizes_Flasher_Map = [ 0, 0x200, 0x800, 0x2000, 0x8000, 0x10000, 0x20000, 0x108000, 0x100, 0x200, 0x20, 0x80000, 0x20000, 0x80000 ] # RAM size in bytes
|
|
31
|
+
DMG_Header_RAM_Sizes = [ "None", "4K SRAM (512 Bytes)", "16K SRAM (2 KiB)", "64K SRAM (8 KiB)", "256K SRAM (32 KiB)", "512K SRAM (64 KiB)", "1M SRAM (128 KiB)", "MBC6 SRAM+FLASH (1.03 MiB)", "MBC7 2K EEPROM (256 Bytes)", "MBC7 4K EEPROM (512 Bytes)", "TAMA5 EEPROM (32 Bytes)", "Unlicensed 4M SRAM (512 KiB)", "Unlicensed 1M EEPROM (128 KiB)", "Unlicensed Photo! Directory (1 MiB)", "Unlicensed Batteryless SRAM" ]
|
|
32
|
+
DMG_Header_RAM_Sizes_Map = [ 0x00, 0x100, 0x01, 0x02, 0x03, 0x05, 0x04, 0x104, 0x101, 0x102, 0x103, 0x201, 0x203, 0x204, 0x205 ]
|
|
33
|
+
DMG_Header_RAM_Sizes_Flasher_Map = [ 0, 0x200, 0x800, 0x2000, 0x8000, 0x10000, 0x20000, 0x108000, 0x100, 0x200, 0x20, 0x80000, 0x20000, 0x100000, 0x80000 ] # RAM size in bytes
|
|
34
34
|
DMG_Header_SGB = { 0x00:'No support', 0x03:'Supported' }
|
|
35
35
|
DMG_Header_CGB = { 0x00:'No support', 0x80:'Supported', 0xC0:'Required' }
|
|
36
36
|
|
|
@@ -410,8 +410,14 @@ def EncodeBCD(value):
|
|
|
410
410
|
def ParseCFI(buffer):
|
|
411
411
|
buffer = copy.copy(buffer)
|
|
412
412
|
info = {}
|
|
413
|
-
|
|
414
|
-
|
|
413
|
+
magic_8bit = "{:s}{:s}{:s}".format(chr(buffer[0x10]), chr(buffer[0x11]), chr(buffer[0x12]))
|
|
414
|
+
magic_16bit = "{:s}{:s}{:s}".format(chr(buffer[0x20]), chr(buffer[0x22]), chr(buffer[0x24]))
|
|
415
|
+
buffer_conv = bytearray()
|
|
416
|
+
if magic_8bit == "QRY":
|
|
417
|
+
buffer_conv = bytearray(b for x in buffer for b in (x, x))
|
|
418
|
+
buffer = buffer_conv
|
|
419
|
+
|
|
420
|
+
if magic_8bit != "QRY" and magic_16bit != "QRY": # nothing swapped
|
|
415
421
|
return False
|
|
416
422
|
|
|
417
423
|
try:
|
|
@@ -522,7 +528,10 @@ def ConvertMapperTypeToMapper(mapper_type):
|
|
|
522
528
|
return 0
|
|
523
529
|
|
|
524
530
|
def GetDumpReport(di, device):
|
|
525
|
-
header = di["header"]
|
|
531
|
+
header = di["header"]
|
|
532
|
+
if "unchanged" in di["header"]:
|
|
533
|
+
header = di["header"]["unchanged"]
|
|
534
|
+
|
|
526
535
|
if "db" in di["header"]: header["db"] = di["header"]["db"]
|
|
527
536
|
if di["system"] == "DMG":
|
|
528
537
|
mode = "DMG"
|
|
@@ -925,6 +934,19 @@ def find_size(data, max_size, min_size=0x20):
|
|
|
925
934
|
break
|
|
926
935
|
return offset
|
|
927
936
|
|
|
937
|
+
def bitmap2pixmap(data, scale_factor=4):
|
|
938
|
+
try:
|
|
939
|
+
from .pyside import QtGui
|
|
940
|
+
from PIL.ImageQt import ImageQt
|
|
941
|
+
from PIL import Image
|
|
942
|
+
data_converted = data.convert("RGBA")
|
|
943
|
+
pixmap = QtGui.QPixmap.fromImage(ImageQt(data_converted.resize((data_converted.width * scale_factor, data_converted.height * scale_factor), Image.NEAREST)))
|
|
944
|
+
pixmap.setDevicePixelRatio(scale_factor)
|
|
945
|
+
return pixmap
|
|
946
|
+
except:
|
|
947
|
+
print("Couldn’t convert bitmap to pixmap.")
|
|
948
|
+
return False
|
|
949
|
+
|
|
928
950
|
def dprint(*args, **kwargs):
|
|
929
951
|
stack = traceback.extract_stack()
|
|
930
952
|
stack = stack[len(stack)-2]
|
FlashGBX/__main__.py
CHANGED
FlashGBX/fw_GBFlash.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
# FlashGBX
|
|
3
|
-
# Author: Lesserkuma (github.com/
|
|
3
|
+
# Author: Lesserkuma (github.com/Lesserkuma)
|
|
4
4
|
|
|
5
5
|
import zipfile, serial, struct, time, datetime
|
|
6
6
|
try:
|
|
@@ -36,7 +36,11 @@ class FirmwareUpdater():
|
|
|
36
36
|
values = struct.unpack(">IBHHH", self.DEVICE.read(11))
|
|
37
37
|
data = dict(zip(keys, values))
|
|
38
38
|
data["payload"] = self.DEVICE.read(data["payload_len"])
|
|
39
|
-
|
|
39
|
+
try:
|
|
40
|
+
data["outro"] = self.DEVICE.read(4)
|
|
41
|
+
data["outro"] = struct.unpack(">I", data["outro"])[0]
|
|
42
|
+
except struct.error:
|
|
43
|
+
return {"clone":True, "error": "Erroneous outro response: " + ''.join(format(x, '02X') for x in data["outro"])}
|
|
40
44
|
return data
|
|
41
45
|
|
|
42
46
|
def CRC16(self, data):
|
|
@@ -87,6 +91,9 @@ class FirmwareUpdater():
|
|
|
87
91
|
if data is None:
|
|
88
92
|
self.DEVICE = None
|
|
89
93
|
return False
|
|
94
|
+
if "error" in data:
|
|
95
|
+
self.DEVICE = None
|
|
96
|
+
return data
|
|
90
97
|
if data["seq_no"] != seq_no:
|
|
91
98
|
self.DEVICE = None
|
|
92
99
|
return False
|
|
@@ -120,6 +127,9 @@ class FirmwareUpdater():
|
|
|
120
127
|
else:
|
|
121
128
|
data = self.TryConnect(self.PORT)
|
|
122
129
|
|
|
130
|
+
if "error" in data:
|
|
131
|
+
fncSetStatus(text=data["error"], cloneError="clone" in data and data["clone"] is True)
|
|
132
|
+
return 2
|
|
123
133
|
if self.DEVICE is None:
|
|
124
134
|
fncSetStatus("No device found.")
|
|
125
135
|
return 2
|
|
@@ -409,8 +419,15 @@ try:
|
|
|
409
419
|
answer = msgbox.exec()
|
|
410
420
|
return False
|
|
411
421
|
|
|
412
|
-
def SetStatus(self, text, enableUI=False, setProgress=None):
|
|
422
|
+
def SetStatus(self, text, enableUI=False, setProgress=None, cloneError=False):
|
|
413
423
|
self.lblStatus.setText("Status: {:s}".format(text))
|
|
424
|
+
|
|
425
|
+
if cloneError:
|
|
426
|
+
text = "Your GBFlash device reported a registration error, which means it may be an illegitimate clone. If the error persists, try to get a refund from the seller.\r\n\r\n" + text
|
|
427
|
+
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="FlashGBX", text=text, standardButtons=QtWidgets.QMessageBox.Ok)
|
|
428
|
+
answer = msgbox.exec()
|
|
429
|
+
return False
|
|
430
|
+
|
|
414
431
|
if setProgress is not None:
|
|
415
432
|
self.prgStatus.setValue(setProgress * 10)
|
|
416
433
|
if enableUI:
|
FlashGBX/fw_GBxCartRW_v1_3.py
CHANGED
FlashGBX/fw_GBxCartRW_v1_4.py
CHANGED
FlashGBX/fw_JoeyJr.py
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
# FlashGBX
|
|
3
|
-
# Author: Lesserkuma (github.com/
|
|
3
|
+
# Author: Lesserkuma (github.com/Lesserkuma)
|
|
4
4
|
|
|
5
5
|
import zipfile, time, os, struct, serial, platform
|
|
6
|
+
from serial import SerialException
|
|
6
7
|
try:
|
|
7
8
|
from . import Util
|
|
8
9
|
except ImportError:
|
|
@@ -120,8 +121,14 @@ class FirmwareUpdater():
|
|
|
120
121
|
fncSetStatus(text="Connecting...")
|
|
121
122
|
try:
|
|
122
123
|
dev = serial.Serial(port, 2000000, timeout=0.2)
|
|
124
|
+
except SerialException as e:
|
|
125
|
+
if "Errno 13" in str(e) and platform.system() == "Linux":
|
|
126
|
+
fncSetStatus(text="No permission to use device! See README file.", enableUI=True)
|
|
127
|
+
else:
|
|
128
|
+
fncSetStatus(text="Device not accessible.", enableUI=True)
|
|
129
|
+
return 2
|
|
123
130
|
except:
|
|
124
|
-
fncSetStatus(text="
|
|
131
|
+
fncSetStatus(text="Unknown error while accessing the device.", enableUI=True)
|
|
125
132
|
return 2
|
|
126
133
|
dev.reset_input_buffer()
|
|
127
134
|
|
|
@@ -415,7 +422,7 @@ try:
|
|
|
415
422
|
verified = False
|
|
416
423
|
|
|
417
424
|
if verified is False:
|
|
418
|
-
text = "The firmware update file is corrupted."
|
|
425
|
+
text = "The firmware update file is corrupted or invalid."
|
|
419
426
|
self.btnUpdate.setEnabled(True)
|
|
420
427
|
self.btnClose.setEnabled(True)
|
|
421
428
|
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="FlashGBX", text=text, standardButtons=QtWidgets.QMessageBox.Ok)
|
FlashGBX/hw_GBFlash.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
# FlashGBX
|
|
3
|
-
# Author: Lesserkuma (github.com/
|
|
3
|
+
# Author: Lesserkuma (github.com/Lesserkuma)
|
|
4
4
|
|
|
5
5
|
# pylint: disable=wildcard-import, unused-wildcard-import
|
|
6
6
|
from .LK_Device import *
|
|
@@ -9,7 +9,7 @@ class GbxDevice(LK_Device):
|
|
|
9
9
|
DEVICE_NAME = "GBFlash"
|
|
10
10
|
DEVICE_MIN_FW = 1
|
|
11
11
|
DEVICE_MAX_FW = 12
|
|
12
|
-
DEVICE_LATEST_FW_TS = { 5:
|
|
12
|
+
DEVICE_LATEST_FW_TS = { 5:1747991884, 10:1747991884, 11:1747991884, 12:1747991884, 13:1747991884 }
|
|
13
13
|
PCB_VERSIONS = { 5:'', 12:'v1.2', 13:'v1.3' }
|
|
14
14
|
|
|
15
15
|
def __init__(self):
|
|
@@ -197,7 +197,7 @@ class GbxDevice(LK_Device):
|
|
|
197
197
|
if self.FW["pcb_ver"] == 5 or self.FW["fw_ts"] < 1730592000: # unofficial firmware
|
|
198
198
|
self.FW_UPDATE_REQ = True
|
|
199
199
|
return True
|
|
200
|
-
if self.FW["fw_ts"]
|
|
200
|
+
if self.FW["fw_ts"] != self.DEVICE_LATEST_FW_TS[self.FW["pcb_ver"]]:
|
|
201
201
|
return True
|
|
202
202
|
self.FW_UPDATE_REQ = False
|
|
203
203
|
return False
|
FlashGBX/hw_GBxCartRW.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
# FlashGBX
|
|
3
|
-
# Author: Lesserkuma (github.com/
|
|
3
|
+
# Author: Lesserkuma (github.com/Lesserkuma)
|
|
4
4
|
|
|
5
5
|
# pylint: disable=wildcard-import, unused-wildcard-import
|
|
6
6
|
from .LK_Device import *
|
|
@@ -9,13 +9,13 @@ class GbxDevice(LK_Device):
|
|
|
9
9
|
DEVICE_NAME = "GBxCart RW"
|
|
10
10
|
DEVICE_MIN_FW = 1
|
|
11
11
|
DEVICE_MAX_FW = 1
|
|
12
|
-
DEVICE_LATEST_FW_TS = { 4:1709317610, 5:
|
|
12
|
+
DEVICE_LATEST_FW_TS = { 4:1709317610, 5:1747991884, 6:1747991884, 2:0, 90:0, 100:0 }
|
|
13
13
|
PCB_VERSIONS = { 5:'v1.4', 6:'v1.4a/b/c', 2:'v1.1/v1.2', 4:'v1.3', 90:'XMAS v1.0', 100:'Mini v1.0' }
|
|
14
14
|
BAUDRATE = 1000000
|
|
15
15
|
MAX_BUFFER_READ = 0x1000
|
|
16
16
|
MAX_BUFFER_WRITE = 0x400
|
|
17
17
|
|
|
18
|
-
def Initialize(self, flashcarts=None, port=None, max_baud=
|
|
18
|
+
def Initialize(self, flashcarts=None, port=None, max_baud=1500000):
|
|
19
19
|
if self.IsConnected(): self.DEVICE.close()
|
|
20
20
|
if platform.system() == "Darwin": max_baud = 1000000
|
|
21
21
|
|
|
@@ -31,7 +31,7 @@ class GbxDevice(LK_Device):
|
|
|
31
31
|
if len(ports) == 0: return False
|
|
32
32
|
|
|
33
33
|
for i in range(0, len(ports)):
|
|
34
|
-
for baudrate in (1000000,
|
|
34
|
+
for baudrate in (1000000, 1500000):
|
|
35
35
|
if max_baud < baudrate: continue
|
|
36
36
|
try:
|
|
37
37
|
if self.TryConnect(ports[i], baudrate):
|
|
@@ -49,8 +49,8 @@ class GbxDevice(LK_Device):
|
|
|
49
49
|
continue
|
|
50
50
|
|
|
51
51
|
if self.FW is None or self.FW == {}: continue
|
|
52
|
-
if max_baud >=
|
|
53
|
-
self.ChangeBaudRate(baudrate=
|
|
52
|
+
if max_baud >= 1500000 and self.FW is not None and "pcb_ver" in self.FW and self.FW["pcb_ver"] in (5, 6, 101) and self.BAUDRATE < 1500000:
|
|
53
|
+
self.ChangeBaudRate(baudrate=1500000)
|
|
54
54
|
self.DEVICE.close()
|
|
55
55
|
dev = serial.Serial(ports[i], self.BAUDRATE, timeout=0.1)
|
|
56
56
|
self.DEVICE = dev
|
|
@@ -74,8 +74,8 @@ class GbxDevice(LK_Device):
|
|
|
74
74
|
self.MAX_BUFFER_WRITE = 0x100
|
|
75
75
|
|
|
76
76
|
conn_msg.append([0, "For help with your GBxCart RW device, please visit the insideGadgets Discord: https://gbxcart.com/discord"])
|
|
77
|
-
if self.FW["pcb_ver"] == 4:
|
|
78
|
-
|
|
77
|
+
#if self.FW["pcb_ver"] == 4:
|
|
78
|
+
# conn_msg.append([0, "Note: Your GBxCart RW hardware revision does not fully support the latest features due to technical limitations. Please consider upgrading to a newer device."])
|
|
79
79
|
|
|
80
80
|
self.PORT = ports[i]
|
|
81
81
|
self.DEVICE.timeout = self.DEVICE_TIMEOUT
|
|
@@ -173,8 +173,8 @@ class GbxDevice(LK_Device):
|
|
|
173
173
|
def ChangeBaudRate(self, baudrate):
|
|
174
174
|
if not self.IsConnected(): return
|
|
175
175
|
dprint("Changing baud rate to", baudrate)
|
|
176
|
-
if baudrate ==
|
|
177
|
-
self._write(self.DEVICE_CMD["
|
|
176
|
+
if baudrate == 1500000:
|
|
177
|
+
self._write(self.DEVICE_CMD["OFW_USART_1_5M_SPEED"])
|
|
178
178
|
elif baudrate == 1000000:
|
|
179
179
|
self._write(self.DEVICE_CMD["OFW_USART_1_0M_SPEED"])
|
|
180
180
|
self.BAUDRATE = baudrate
|
|
@@ -253,10 +253,10 @@ class GbxDevice(LK_Device):
|
|
|
253
253
|
return ["DMG"]
|
|
254
254
|
else:
|
|
255
255
|
return ["DMG", "AGB"]
|
|
256
|
-
|
|
256
|
+
|
|
257
257
|
def IsSupported3dMemory(self):
|
|
258
258
|
return True
|
|
259
|
-
|
|
259
|
+
|
|
260
260
|
def IsClkConnected(self):
|
|
261
261
|
return self.FW["pcb_ver"] in (5, 6, 101)
|
|
262
262
|
|
|
@@ -270,7 +270,7 @@ class GbxDevice(LK_Device):
|
|
|
270
270
|
dprint("LinkNLoad detected:", is_lnl)
|
|
271
271
|
if is_lnl: return False
|
|
272
272
|
return self.FW["pcb_ver"] in (2, 4, 5, 6, 90, 100, 101)
|
|
273
|
-
|
|
273
|
+
|
|
274
274
|
def FirmwareUpdateAvailable(self):
|
|
275
275
|
if self.FW["fw_ver"] == 0 and self.FW["pcb_ver"] in (2, 4, 90, 100, 101):
|
|
276
276
|
if self.FW["pcb_ver"] == 4:
|
|
@@ -279,12 +279,12 @@ class GbxDevice(LK_Device):
|
|
|
279
279
|
self.FW_UPDATE_REQ = 2
|
|
280
280
|
return True
|
|
281
281
|
if self.FW["pcb_ver"] not in (4, 5, 6): return False
|
|
282
|
-
if self.FW["pcb_ver"] in (5, 6) and self.FW["fw_ts"]
|
|
282
|
+
if self.FW["pcb_ver"] in (5, 6) and self.FW["fw_ts"] != self.DEVICE_LATEST_FW_TS[self.FW["pcb_ver"]]:
|
|
283
283
|
return True
|
|
284
|
-
if self.FW["pcb_ver"] == 4 and self.FW["fw_ts"]
|
|
284
|
+
if self.FW["pcb_ver"] == 4 and self.FW["fw_ts"] != self.DEVICE_LATEST_FW_TS[self.FW["pcb_ver"]]:
|
|
285
285
|
self.FW_UPDATE_REQ = True
|
|
286
286
|
return True
|
|
287
|
-
|
|
287
|
+
|
|
288
288
|
def GetFirmwareUpdaterClass(self):
|
|
289
289
|
if self is None or self.FW["pcb_ver"] in (5, 6): # v1.4 / v1.4a/b/c
|
|
290
290
|
try:
|
FlashGBX/hw_JoeyJr.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
# FlashGBX
|
|
3
|
-
# Author: Lesserkuma (github.com/
|
|
3
|
+
# Author: Lesserkuma (github.com/Lesserkuma)
|
|
4
4
|
|
|
5
5
|
# pylint: disable=wildcard-import, unused-wildcard-import
|
|
6
6
|
from .LK_Device import *
|
|
@@ -9,7 +9,7 @@ class GbxDevice(LK_Device):
|
|
|
9
9
|
DEVICE_NAME = "Joey Jr"
|
|
10
10
|
DEVICE_MIN_FW = 1
|
|
11
11
|
DEVICE_MAX_FW = 12
|
|
12
|
-
DEVICE_LATEST_FW_TS =
|
|
12
|
+
DEVICE_LATEST_FW_TS = 1747991884
|
|
13
13
|
PCB_VERSIONS = { -1:"", 0x01:"V2", 0x81:"V2", 0x02:"V2C", 0x82:"V2C", 0x03:"V2CC", 0x83:"V2CC/V2++" }
|
|
14
14
|
|
|
15
15
|
def __init__(self):
|
|
@@ -256,7 +256,7 @@ class GbxDevice(LK_Device):
|
|
|
256
256
|
if self.FW["cfw_id"] == "G":
|
|
257
257
|
self.FW_UPDATE_REQ = True
|
|
258
258
|
return True
|
|
259
|
-
if self.FW["fw_ts"]
|
|
259
|
+
if self.FW["fw_ts"] != self.DEVICE_LATEST_FW_TS:
|
|
260
260
|
return True
|
|
261
261
|
self.FW_UPDATE_REQ = False
|
|
262
262
|
return False
|
FlashGBX/pyside.py
CHANGED
FlashGBX/res/config.zip
CHANGED
|
Binary file
|
FlashGBX/res/fw_GBFlash.zip
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
FlashGBX/res/fw_JoeyJr.zip
CHANGED
|
Binary file
|