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/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())