FlashGBX 3.37__py3-none-any.whl → 4.0.1__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/FlashGBX.py +14 -7
- FlashGBX/FlashGBX_CLI.py +201 -24
- FlashGBX/FlashGBX_GUI.py +636 -204
- FlashGBX/Flashcart.py +184 -83
- FlashGBX/GBMemory.py +4 -5
- FlashGBX/LK_Device.py +4533 -0
- FlashGBX/Mapper.py +534 -356
- FlashGBX/RomFileAGB.py +92 -2
- FlashGBX/RomFileDMG.py +1 -1
- FlashGBX/UserInputDialog.py +20 -0
- FlashGBX/Util.py +95 -47
- FlashGBX/fw_GBFlash.py +426 -0
- FlashGBX/fw_GBxCartRW_v1_3.py +1 -1
- FlashGBX/fw_JoeyJr.py +472 -0
- FlashGBX/hw_GBFlash.py +244 -0
- FlashGBX/hw_GBxCartRW.py +200 -3777
- FlashGBX/hw_JoeyJr.py +309 -0
- FlashGBX/res/Third Party Notices.md +342 -0
- FlashGBX/res/config.zip +0 -0
- FlashGBX/res/fw_GBFlash.zip +0 -0
- FlashGBX/res/fw_GBxCart_RW_v1_3.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-3.37.dist-info → FlashGBX-4.0.1.dist-info}/METADATA +36 -16
- FlashGBX-4.0.1.dist-info/RECORD +43 -0
- FlashGBX/hw_GBxCartRW_ofw.py +0 -2599
- FlashGBX-3.37.dist-info/RECORD +0 -36
- {FlashGBX-3.37.dist-info → FlashGBX-4.0.1.dist-info}/LICENSE +0 -0
- {FlashGBX-3.37.dist-info → FlashGBX-4.0.1.dist-info}/WHEEL +0 -0
- {FlashGBX-3.37.dist-info → FlashGBX-4.0.1.dist-info}/entry_points.txt +0 -0
- {FlashGBX-3.37.dist-info → FlashGBX-4.0.1.dist-info}/top_level.txt +0 -0
FlashGBX/hw_GBFlash.py
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# FlashGBX
|
|
3
|
+
# Author: Lesserkuma (github.com/lesserkuma)
|
|
4
|
+
|
|
5
|
+
# pylint: disable=wildcard-import, unused-wildcard-import
|
|
6
|
+
from .LK_Device import *
|
|
7
|
+
|
|
8
|
+
class GbxDevice(LK_Device):
|
|
9
|
+
DEVICE_NAME = "GBFlash"
|
|
10
|
+
DEVICE_MIN_FW = 1
|
|
11
|
+
DEVICE_MAX_FW = 12
|
|
12
|
+
DEVICE_LATEST_FW_TS = { 5:1719609931, 10:1719609931, 11:1719609931, 12:1719609931, 13:1719609931 }
|
|
13
|
+
PCB_VERSIONS = { 5:'', 12:'v1.2', 13:'v1.3' }
|
|
14
|
+
|
|
15
|
+
def __init__(self):
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
def Initialize(self, flashcarts, port=None, max_baud=2000000):
|
|
19
|
+
if self.IsConnected(): self.DEVICE.close()
|
|
20
|
+
conn_msg = []
|
|
21
|
+
ports = []
|
|
22
|
+
if port is not None:
|
|
23
|
+
ports = [ port ]
|
|
24
|
+
else:
|
|
25
|
+
comports = serial.tools.list_ports.comports()
|
|
26
|
+
for i in range(0, len(comports)):
|
|
27
|
+
if comports[i].vid == 0x1A86 and comports[i].pid == 0x7523:
|
|
28
|
+
ports.append(comports[i].device)
|
|
29
|
+
if len(ports) == 0: return False
|
|
30
|
+
|
|
31
|
+
for i in range(0, len(ports)):
|
|
32
|
+
if self.TryConnect(ports[i], max_baud):
|
|
33
|
+
self.BAUDRATE = max_baud
|
|
34
|
+
dev = serial.Serial(ports[i], self.BAUDRATE, timeout=0.1)
|
|
35
|
+
self.DEVICE = dev
|
|
36
|
+
else:
|
|
37
|
+
continue
|
|
38
|
+
|
|
39
|
+
if self.FW is None or self.FW == {}: continue
|
|
40
|
+
|
|
41
|
+
dprint(f"Found a {self.DEVICE_NAME}")
|
|
42
|
+
dprint("Firmware information:", self.FW)
|
|
43
|
+
# dprint("Baud rate:", self.BAUDRATE)
|
|
44
|
+
|
|
45
|
+
if self.DEVICE is None or not self.IsConnected():
|
|
46
|
+
self.DEVICE = None
|
|
47
|
+
if self.FW is not None:
|
|
48
|
+
conn_msg.append([0, "Couldn’t communicate with the " + self.DEVICE_NAME + " device on port " + ports[i] + ". Please disconnect and reconnect the device, then try again."])
|
|
49
|
+
continue
|
|
50
|
+
elif self.FW is None or self.FW["pcb_ver"] not in self.PCB_VERSIONS.keys() or "cfw_id" not in self.FW or self.FW["cfw_id"] != 'L' or self.FW["fw_ver"] < self.DEVICE_MIN_FW: # Not a CFW by Lesserkuma
|
|
51
|
+
dprint("Incompatible firmware:", self.FW)
|
|
52
|
+
dev.close()
|
|
53
|
+
self.DEVICE = None
|
|
54
|
+
continue
|
|
55
|
+
elif self.FW["fw_ts"] > self.DEVICE_LATEST_FW_TS[self.FW["pcb_ver"]]:
|
|
56
|
+
conn_msg.append([0, "Note: The " + self.DEVICE_NAME + " device on port " + ports[i] + " is running a firmware version that is newer than what this version of FlashGBX was developed to work with, so errors may occur."])
|
|
57
|
+
|
|
58
|
+
self.MAX_BUFFER_READ = 0x1000
|
|
59
|
+
self.MAX_BUFFER_WRITE = 0x800
|
|
60
|
+
|
|
61
|
+
self.PORT = ports[i]
|
|
62
|
+
self.DEVICE.timeout = self.DEVICE_TIMEOUT
|
|
63
|
+
|
|
64
|
+
conn_msg.append([0, "For help with your GBFlash device, please visit the GitHub page: https://github.com/simonkwng/GBFlash"])
|
|
65
|
+
|
|
66
|
+
# Load Flash Cartridge Handlers
|
|
67
|
+
self.UpdateFlashCarts(flashcarts)
|
|
68
|
+
|
|
69
|
+
# Stop after first found device
|
|
70
|
+
break
|
|
71
|
+
|
|
72
|
+
return conn_msg
|
|
73
|
+
|
|
74
|
+
def LoadFirmwareVersion(self):
|
|
75
|
+
dprint("Querying firmware version")
|
|
76
|
+
try:
|
|
77
|
+
self.DEVICE.timeout = 0.075
|
|
78
|
+
self.DEVICE.reset_input_buffer()
|
|
79
|
+
self.DEVICE.reset_output_buffer()
|
|
80
|
+
self._write(self.DEVICE_CMD["QUERY_FW_INFO"])
|
|
81
|
+
size = self.DEVICE.read(1)
|
|
82
|
+
self.DEVICE.timeout = self.DEVICE_TIMEOUT
|
|
83
|
+
if len(size) == 0:
|
|
84
|
+
dprint("No response")
|
|
85
|
+
self.FW = None
|
|
86
|
+
return False
|
|
87
|
+
size = struct.unpack("B", size)[0]
|
|
88
|
+
if size != 8: return False
|
|
89
|
+
data = self._read(size)
|
|
90
|
+
info = data[:8]
|
|
91
|
+
keys = ["cfw_id", "fw_ver", "pcb_ver", "fw_ts"]
|
|
92
|
+
values = struct.unpack(">cHBI", bytearray(info))
|
|
93
|
+
self.FW = dict(zip(keys, values))
|
|
94
|
+
self.FW["cfw_id"] = self.FW["cfw_id"].decode('ascii')
|
|
95
|
+
self.FW["fw_dt"] = datetime.datetime.fromtimestamp(self.FW["fw_ts"]).astimezone().replace(microsecond=0).isoformat()
|
|
96
|
+
self.FW["ofw_ver"] = None
|
|
97
|
+
self.FW["pcb_name"] = None
|
|
98
|
+
self.FW["cart_power_ctrl"] = False
|
|
99
|
+
self.FW["bootloader_reset"] = False
|
|
100
|
+
if self.FW["cfw_id"] == "L" and self.FW["fw_ver"] >= 12:
|
|
101
|
+
size = self._read(1)
|
|
102
|
+
name = self._read(size)
|
|
103
|
+
if len(name) > 0:
|
|
104
|
+
try:
|
|
105
|
+
self.FW["pcb_name"] = name.decode("UTF-8").replace("\x00", "").strip()
|
|
106
|
+
except:
|
|
107
|
+
self.FW["pcb_name"] = "Unnamed Device"
|
|
108
|
+
self.DEVICE_NAME = self.FW["pcb_name"]
|
|
109
|
+
|
|
110
|
+
# Cartridge Power Control support
|
|
111
|
+
self.FW["cart_power_ctrl"] = True if self._read(1) == 1 else False
|
|
112
|
+
|
|
113
|
+
# Reset to bootloader support
|
|
114
|
+
self.FW["bootloader_reset"] = True if self._read(1) == 1 else False
|
|
115
|
+
|
|
116
|
+
return True
|
|
117
|
+
|
|
118
|
+
except Exception as e:
|
|
119
|
+
dprint("Disconnecting due to an error", e, sep="\n")
|
|
120
|
+
try:
|
|
121
|
+
if self.DEVICE.isOpen():
|
|
122
|
+
self.DEVICE.reset_input_buffer()
|
|
123
|
+
self.DEVICE.reset_output_buffer()
|
|
124
|
+
self.DEVICE.close()
|
|
125
|
+
self.DEVICE = None
|
|
126
|
+
except:
|
|
127
|
+
pass
|
|
128
|
+
return False
|
|
129
|
+
|
|
130
|
+
def ChangeBaudRate(self, _):
|
|
131
|
+
dprint("Baudrate change is not supported.")
|
|
132
|
+
|
|
133
|
+
def CheckActive(self):
|
|
134
|
+
if time.time() < self.LAST_CHECK_ACTIVE + 1: return True
|
|
135
|
+
dprint("Checking if device is active")
|
|
136
|
+
if self.DEVICE is None: return False
|
|
137
|
+
if self.FW["pcb_name"] is None:
|
|
138
|
+
if self.LoadFirmwareVersion():
|
|
139
|
+
self.LAST_CHECK_ACTIVE = time.time()
|
|
140
|
+
return True
|
|
141
|
+
else:
|
|
142
|
+
return False
|
|
143
|
+
try:
|
|
144
|
+
self._get_fw_variable("CART_MODE")
|
|
145
|
+
self.LAST_CHECK_ACTIVE = time.time()
|
|
146
|
+
return True
|
|
147
|
+
except Exception as e:
|
|
148
|
+
dprint("Disconnecting...", e)
|
|
149
|
+
try:
|
|
150
|
+
if self.DEVICE.isOpen():
|
|
151
|
+
self.DEVICE.reset_input_buffer()
|
|
152
|
+
self.DEVICE.reset_output_buffer()
|
|
153
|
+
self.DEVICE.close()
|
|
154
|
+
self.DEVICE = None
|
|
155
|
+
except:
|
|
156
|
+
pass
|
|
157
|
+
return False
|
|
158
|
+
|
|
159
|
+
def GetFirmwareVersion(self, more=False):
|
|
160
|
+
s = "{:s}{:d}".format(self.FW["cfw_id"], self.FW["fw_ver"])
|
|
161
|
+
if self.FW["pcb_name"] == None:
|
|
162
|
+
s += " <unverified>"
|
|
163
|
+
if more:
|
|
164
|
+
s += " ({:s})".format(self.FW["fw_dt"])
|
|
165
|
+
return s
|
|
166
|
+
|
|
167
|
+
def GetFullNameExtended(self, more=False):
|
|
168
|
+
if more:
|
|
169
|
+
return "{:s} – Firmware {:s} ({:s}) on {:s}".format(self.GetFullName(), self.GetFirmwareVersion(), self.FW["fw_dt"], self.GetPort())
|
|
170
|
+
else:
|
|
171
|
+
return "{:s} – Firmware {:s} ({:s})".format(self.GetFullName(), self.GetFirmwareVersion(), self.GetPort())
|
|
172
|
+
|
|
173
|
+
def CanSetVoltageManually(self):
|
|
174
|
+
return False
|
|
175
|
+
|
|
176
|
+
def CanSetVoltageAutomatically(self):
|
|
177
|
+
return True
|
|
178
|
+
|
|
179
|
+
def CanPowerCycleCart(self):
|
|
180
|
+
return self.FW["cart_power_ctrl"]
|
|
181
|
+
|
|
182
|
+
def GetSupprtedModes(self):
|
|
183
|
+
return ["DMG", "AGB"]
|
|
184
|
+
|
|
185
|
+
def IsSupported3dMemory(self):
|
|
186
|
+
return True
|
|
187
|
+
|
|
188
|
+
def IsClkConnected(self):
|
|
189
|
+
return True
|
|
190
|
+
|
|
191
|
+
def SupportsFirmwareUpdates(self):
|
|
192
|
+
return True
|
|
193
|
+
|
|
194
|
+
def FirmwareUpdateAvailable(self):
|
|
195
|
+
if self.FW["pcb_ver"] == 5: # unofficial firmware
|
|
196
|
+
self.FW_UPDATE_REQ = True
|
|
197
|
+
return True
|
|
198
|
+
if self.FW["fw_ts"] < self.DEVICE_LATEST_FW_TS[self.FW["pcb_ver"]]:
|
|
199
|
+
return True
|
|
200
|
+
self.FW_UPDATE_REQ = False
|
|
201
|
+
return False
|
|
202
|
+
|
|
203
|
+
def GetFirmwareUpdaterClass(self):
|
|
204
|
+
try:
|
|
205
|
+
from . import fw_GBFlash
|
|
206
|
+
return (None, fw_GBFlash.FirmwareUpdaterWindow)
|
|
207
|
+
except:
|
|
208
|
+
return None
|
|
209
|
+
|
|
210
|
+
def ResetLEDs(self):
|
|
211
|
+
pass
|
|
212
|
+
|
|
213
|
+
def SupportsBootloaderReset(self):
|
|
214
|
+
return self.FW["bootloader_reset"]
|
|
215
|
+
|
|
216
|
+
def BootloaderReset(self):
|
|
217
|
+
if not self.SupportsBootloaderReset(): return False
|
|
218
|
+
dprint("Resetting to bootloader...")
|
|
219
|
+
try:
|
|
220
|
+
self._write(self.DEVICE_CMD["BOOTLOADER_RESET"], wait=True)
|
|
221
|
+
self._write(1)
|
|
222
|
+
self.Close()
|
|
223
|
+
return True
|
|
224
|
+
except Exception as e:
|
|
225
|
+
print("Disconnecting...", e)
|
|
226
|
+
return False
|
|
227
|
+
|
|
228
|
+
def SupportsAudioAsWe(self):
|
|
229
|
+
return not (self.FW["pcb_ver"] < 13 and self.CanPowerCycleCart())
|
|
230
|
+
|
|
231
|
+
def GetMode(self):
|
|
232
|
+
if self.FW["fw_ts"] == 1681900614: return self.MODE
|
|
233
|
+
return super().GetMode()
|
|
234
|
+
|
|
235
|
+
def SetAutoPowerOff(self, value):
|
|
236
|
+
value &= 0xFFFFFFFF
|
|
237
|
+
#if value == 0 or value > 5000: value = 1500
|
|
238
|
+
return super().SetAutoPowerOff(value)
|
|
239
|
+
|
|
240
|
+
def GetFullName(self):
|
|
241
|
+
if self.FW["pcb_ver"] < 13 and self.CanPowerCycleCart():
|
|
242
|
+
return "{:s} {:s} + PLUGIN 01".format(self.GetName(), self.GetPCBVersion())
|
|
243
|
+
else:
|
|
244
|
+
return "{:s} {:s}".format(self.GetName(), self.GetPCBVersion())
|