FlashGBX 3.37__py3-none-any.whl → 4.0__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/fw_GBFlash.py ADDED
@@ -0,0 +1,426 @@
1
+ # -*- coding: utf-8 -*-
2
+ # FlashGBX
3
+ # Author: Lesserkuma (github.com/lesserkuma)
4
+
5
+ import zipfile, serial, struct, time, datetime
6
+ try:
7
+ from . import Util
8
+ except ImportError:
9
+ import Util
10
+
11
+ class FirmwareUpdater():
12
+ PORT = None
13
+ DEVICE = None
14
+
15
+ def __init__(self, app_path=".", port=None):
16
+ self.APP_PATH = app_path
17
+ self.PORT = port
18
+
19
+ def PackPacket(self, packet):
20
+ values = list(packet.values())[:-2]
21
+ data = struct.pack(">IBHHH", *values)
22
+ if packet["payload_len"] > 0:
23
+ data += list(packet.values())[-2]
24
+ data += struct.pack(">I", packet["outro"])
25
+ if len(data) % 2 == 1: data += b'\00'
26
+ return data
27
+
28
+ def GetPacket(self):
29
+ hp = 100
30
+ while self.DEVICE.in_waiting == 0:
31
+ time.sleep(0.001)
32
+ hp -= 1
33
+ if hp <= 0:
34
+ return None
35
+ keys = ["intro", "sender", "seq_no", "command", "payload_len"]
36
+ values = struct.unpack(">IBHHH", self.DEVICE.read(11))
37
+ data = dict(zip(keys, values))
38
+ data["payload"] = self.DEVICE.read(data["payload_len"])
39
+ data["outro"] = struct.unpack(">I", self.DEVICE.read(4))[0]
40
+ return data
41
+
42
+ def CRC16(self, data):
43
+ CRCTableAbs = [
44
+ 0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401,
45
+ 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400,
46
+ ]
47
+ wCRC = 0xFFFF
48
+
49
+ for i in range(len(data)):
50
+ chChar = data[i]
51
+ wCRC = (CRCTableAbs[(chChar ^ wCRC) & 0x0F] ^ (wCRC >> 4))
52
+ wCRC = (CRCTableAbs[((chChar >> 4) ^ wCRC) & 0x0F] ^ (wCRC >> 4))
53
+
54
+ return wCRC
55
+
56
+ def TryConnect(self, port):
57
+ seq_no = 1
58
+ packet = {
59
+ "intro":0x48484A4A,
60
+ "sender":0,
61
+ "seq_no":seq_no,
62
+ "command":0x21,
63
+ "payload_len":0,
64
+ "payload":bytearray(),
65
+ "outro":0x4A4A4848,
66
+ }
67
+ data = self.PackPacket(packet)
68
+
69
+ self.DEVICE = None
70
+ try:
71
+ self.DEVICE = serial.Serial(port, 2000000, timeout=0.1)
72
+ self.DEVICE.write(b'\xF1')
73
+ self.DEVICE.read(1)
74
+ self.DEVICE.write(b'\x01')
75
+ self.DEVICE.close()
76
+ time.sleep(3)
77
+ self.DEVICE = serial.Serial(port, 2000000, timeout=0.1)
78
+
79
+ except serial.serialutil.SerialException:
80
+ return False
81
+
82
+ self.DEVICE.write(data)
83
+ time.sleep(0.1)
84
+ self.DEVICE.read(self.DEVICE.in_waiting)
85
+ self.DEVICE.write(data)
86
+ data = self.GetPacket()
87
+ if data is None:
88
+ self.DEVICE = None
89
+ return False
90
+ if data["seq_no"] != seq_no:
91
+ self.DEVICE = None
92
+ return False
93
+ if data["command"] != 0x21:
94
+ self.DEVICE = None
95
+ return False
96
+ if struct.unpack(">H", data["payload"][1:3])[0] != 0x03:
97
+ self.DEVICE = None
98
+ return False
99
+ return data
100
+
101
+ def WriteFirmware(self, zipfn, fncSetStatus):
102
+ with zipfile.ZipFile(zipfn) as archive:
103
+ with archive.open("fw.bin") as f: fw_data = bytearray(f.read())
104
+
105
+ fncSetStatus("Connecting...")
106
+ if self.PORT is None:
107
+ ports = []
108
+ comports = serial.tools.list_ports.comports()
109
+ for i in range(0, len(comports)):
110
+ if comports[i].vid == 0x1A86 and comports[i].pid == 0x7523:
111
+ ports.append(comports[i].device)
112
+ if len(ports) == 0:
113
+ fncSetStatus("No device found.")
114
+ return 2
115
+
116
+ for port in ports:
117
+ data = self.TryConnect(port)
118
+ if data is not False:
119
+ break
120
+ else:
121
+ data = self.TryConnect(self.PORT)
122
+
123
+ if self.DEVICE is None:
124
+ fncSetStatus("No device found.")
125
+ return 2
126
+
127
+ data["program_size"] = struct.unpack(">H", data["payload"][3:5])[0]
128
+ data["page_size"] = struct.unpack(">H", data["payload"][7:9])[0]
129
+ page_size = data["page_size"]
130
+ num_packets = len(fw_data) / page_size
131
+ num_packets = int(-(-num_packets // 1)) # round up
132
+
133
+ fncSetStatus("Updating firmware...", setProgress=0)
134
+ seq_no = 2
135
+
136
+ pos = 0
137
+ packet_index = 1
138
+ while pos < num_packets:
139
+ buffer = fw_data[pos*page_size:pos*page_size+page_size]
140
+ packet_len = len(buffer)
141
+ buffer += struct.pack(">H", self.CRC16(buffer))
142
+ buffer = struct.pack(">H", packet_len) + buffer
143
+ buffer = struct.pack(">H", packet_index) + buffer
144
+
145
+ packet = {
146
+ "intro":0x48484A4A,
147
+ "sender":0,
148
+ "seq_no":seq_no,
149
+ "command":0x24,
150
+ "payload_len":len(buffer),
151
+ "payload":buffer,
152
+ "outro":0x4A4A4848,
153
+ }
154
+ data = self.PackPacket(packet)
155
+
156
+ self.DEVICE.write(data)
157
+ data = self.GetPacket()
158
+
159
+ if data["seq_no"] != seq_no:
160
+ fncSetStatus("Incorrect sequence number.")
161
+ time.sleep(1)
162
+ continue
163
+ if data["command"] != 0x24:
164
+ fncSetStatus("Incorrect command.")
165
+ time.sleep(1)
166
+ continue
167
+ if struct.unpack(">H", data["payload"][0:2])[0] != packet_index:
168
+ fncSetStatus("Incorrect data packet number.")
169
+ time.sleep(1)
170
+ continue
171
+ if data["payload"][2] != 0x01:
172
+ fncSetStatus("Write failed.")
173
+ time.sleep(1)
174
+ continue
175
+
176
+ percent = packet_index / num_packets * 100
177
+ fncSetStatus(text="Updating firmware... Do not unplug the device!", setProgress=percent)
178
+ pos += 1
179
+ seq_no += 1
180
+ packet_index += 1
181
+
182
+ if pos == num_packets:
183
+ payload = bytearray()
184
+ payload += struct.pack(">H", self.CRC16(fw_data))
185
+ payload += struct.pack(">H", ~self.CRC16(fw_data) & 0xFFFF)
186
+ packet = {
187
+ "intro":0x48484A4A,
188
+ "sender":0,
189
+ "seq_no":seq_no,
190
+ "command":0x23,
191
+ "payload_len":4,
192
+ "payload":payload,
193
+ "outro":0x4A4A4848,
194
+ }
195
+ data = self.PackPacket(packet)
196
+ self.DEVICE.write(data)
197
+ data = self.GetPacket()
198
+ if data["payload"][0] != 1:
199
+ fncSetStatus(text="Update failed!", enableUI=True)
200
+
201
+ self.DEVICE.close()
202
+ time.sleep(0.8)
203
+ fncSetStatus("Done.")
204
+ time.sleep(0.2)
205
+ return 1
206
+
207
+ try:
208
+ from .pyside import QtCore, QtWidgets, QtGui, QDesktopWidget
209
+ class FirmwareUpdaterWindow(QtWidgets.QDialog):
210
+ APP = None
211
+ DEVICE = None
212
+ FWUPD = None
213
+ DEV_NAME = "GBFlash"
214
+ FW_VER = ""
215
+ PCB_VER = ""
216
+
217
+ def __init__(self, app, app_path, file=None, icon=None, device=None):
218
+ QtWidgets.QDialog.__init__(self)
219
+ if icon is not None: self.setWindowIcon(QtGui.QIcon(icon))
220
+ self.setStyleSheet("QMessageBox { messagebox-text-interaction-flags: 5; }")
221
+ self.setWindowTitle("FlashGBX – Firmware Updater for GBFlash")
222
+ self.setWindowFlags((self.windowFlags() | QtCore.Qt.MSWindowsFixedSizeDialogHint) & ~QtCore.Qt.WindowContextHelpButtonHint)
223
+
224
+ self.APP = app
225
+ if device is not None:
226
+ self.FWUPD = FirmwareUpdater(app_path, device.GetPort())
227
+ self.DEV_NAME = device.GetName()
228
+ self.FW_VER = device.GetFirmwareVersion(more=True)
229
+ self.PCB_VER = device.GetPCBVersion()
230
+ self.DEVICE = device
231
+ else:
232
+ self.APP.QT_APP.processEvents()
233
+ text = "This Firmware Updater is for GBFlash devices only. Please only proceed if your device is a GBFlash."
234
+ msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Warning, windowTitle="FlashGBX", text=text, standardButtons=QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel)
235
+ msgbox.setDefaultButton(QtWidgets.QMessageBox.Ok)
236
+ answer = msgbox.exec()
237
+ if answer == QtWidgets.QMessageBox.Cancel: return
238
+ self.FWUPD = FirmwareUpdater(app_path, None)
239
+
240
+ self.layout = QtWidgets.QGridLayout()
241
+ self.layout.setContentsMargins(-1, 8, -1, 8)
242
+ self.layout.setSizeConstraint(QtWidgets.QLayout.SetFixedSize)
243
+ self.layout_device = QtWidgets.QVBoxLayout()
244
+
245
+ # ↓↓↓ Current Device Information
246
+ self.grpDeviceInfo = QtWidgets.QGroupBox("Current Firmware")
247
+ self.grpDeviceInfo.setMinimumWidth(420)
248
+ self.grpDeviceInfoLayout = QtWidgets.QVBoxLayout()
249
+ self.grpDeviceInfoLayout.setContentsMargins(-1, 3, -1, -1)
250
+ rowDeviceInfo1 = QtWidgets.QHBoxLayout()
251
+ self.lblDeviceName = QtWidgets.QLabel("Device:")
252
+ self.lblDeviceName.setMinimumWidth(120)
253
+ self.lblDeviceNameResult = QtWidgets.QLabel("GBFlash")
254
+ rowDeviceInfo1.addWidget(self.lblDeviceName)
255
+ rowDeviceInfo1.addWidget(self.lblDeviceNameResult)
256
+ rowDeviceInfo1.addStretch(1)
257
+ self.grpDeviceInfoLayout.addLayout(rowDeviceInfo1)
258
+ rowDeviceInfo3 = QtWidgets.QHBoxLayout()
259
+ self.lblDeviceFWVer = QtWidgets.QLabel("Firmware version:")
260
+ self.lblDeviceFWVer.setMinimumWidth(120)
261
+ self.lblDeviceFWVerResult = QtWidgets.QLabel("L12")
262
+ rowDeviceInfo3.addWidget(self.lblDeviceFWVer)
263
+ rowDeviceInfo3.addWidget(self.lblDeviceFWVerResult)
264
+ rowDeviceInfo3.addStretch(1)
265
+ self.grpDeviceInfoLayout.addLayout(rowDeviceInfo3)
266
+ self.grpDeviceInfo.setLayout(self.grpDeviceInfoLayout)
267
+ self.layout_device.addWidget(self.grpDeviceInfo)
268
+ # ↑↑↑ Current Device Information
269
+
270
+ # ↓↓↓ Available Firmware Updates
271
+ self.grpAvailableFwUpdates = QtWidgets.QGroupBox("Available Firmware")
272
+ self.grpAvailableFwUpdates.setMinimumWidth(400)
273
+ self.grpAvailableFwUpdatesLayout = QtWidgets.QVBoxLayout()
274
+ self.grpAvailableFwUpdatesLayout.setContentsMargins(-1, 3, -1, -1)
275
+
276
+ rowDeviceInfo4 = QtWidgets.QHBoxLayout()
277
+ self.lblDeviceFWVer2 = QtWidgets.QLabel("Firmware version:")
278
+ self.lblDeviceFWVer2.setMinimumWidth(120)
279
+ self.lblDeviceFWVer2Result = QtWidgets.QLabel("(Please choose the PCB version)")
280
+ rowDeviceInfo4.addWidget(self.lblDeviceFWVer2)
281
+ rowDeviceInfo4.addWidget(self.lblDeviceFWVer2Result)
282
+ rowDeviceInfo4.addStretch(1)
283
+ self.grpAvailableFwUpdatesLayout.addLayout(rowDeviceInfo4)
284
+
285
+ self.rowUpdate = QtWidgets.QHBoxLayout()
286
+ self.btnUpdate = QtWidgets.QPushButton("Install Firmware Update")
287
+ self.btnUpdate.setMinimumWidth(200)
288
+ self.btnUpdate.setContentsMargins(20, 20, 20, 20)
289
+ self.connect(self.btnUpdate, QtCore.SIGNAL("clicked()"), lambda: [ self.UpdateFirmware() ])
290
+ self.rowUpdate.addStretch()
291
+ self.rowUpdate.addWidget(self.btnUpdate)
292
+ self.rowUpdate.addStretch()
293
+
294
+ self.grpAvailableFwUpdatesLayout.addSpacing(3)
295
+ self.grpAvailableFwUpdatesLayout.addItem(self.rowUpdate)
296
+ self.grpAvailableFwUpdates.setLayout(self.grpAvailableFwUpdatesLayout)
297
+ self.layout_device.addWidget(self.grpAvailableFwUpdates)
298
+ # ↑↑↑ Available Firmware Updates
299
+
300
+ self.grpStatus = QtWidgets.QGroupBox("")
301
+ self.grpStatusLayout = QtWidgets.QGridLayout()
302
+ self.prgStatus = QtWidgets.QProgressBar()
303
+ self.prgStatus.setMinimum(0)
304
+ self.prgStatus.setMaximum(1000)
305
+ self.prgStatus.setValue(0)
306
+ self.lblStatus = QtWidgets.QLabel("Ready.")
307
+
308
+ self.grpStatusLayout.addWidget(self.prgStatus, 1, 0)
309
+ self.grpStatusLayout.addWidget(self.lblStatus, 2, 0)
310
+
311
+ self.grpStatus.setLayout(self.grpStatusLayout)
312
+ self.layout_device.addWidget(self.grpStatus)
313
+
314
+ self.grpFooterLayout = QtWidgets.QHBoxLayout()
315
+ self.btnClose = QtWidgets.QPushButton("&Close")
316
+ self.connect(self.btnClose, QtCore.SIGNAL("clicked()"), lambda: [ self.reject() ])
317
+ self.grpFooterLayout.addStretch()
318
+ self.grpFooterLayout.addWidget(self.btnClose)
319
+ self.layout_device.addItem(self.grpFooterLayout)
320
+
321
+ self.layout.addLayout(self.layout_device, 0, 0)
322
+ self.setLayout(self.layout)
323
+
324
+ self.lblDeviceNameResult.setText(self.DEV_NAME + " " + self.PCB_VER)
325
+ self.lblDeviceFWVerResult.setText(self.FW_VER)
326
+ self.SetPCBVersion()
327
+
328
+ def SetPCBVersion(self):
329
+ file_name = self.FWUPD.APP_PATH + "/res/fw_GBFlash.zip"
330
+
331
+ with zipfile.ZipFile(file_name) as zip:
332
+ with zip.open("fw.ini") as f: ini_file = f.read()
333
+ ini_file = ini_file.decode(encoding="utf-8")
334
+ self.INI = Util.IniSettings(ini=ini_file, main_section="Firmware")
335
+ self.OFW_VER = self.INI.GetValue("fw_ver")
336
+ self.OFW_BUILDTS = self.INI.GetValue("fw_buildts")
337
+ self.OFW_TEXT = self.INI.GetValue("fw_text")
338
+
339
+ self.lblDeviceFWVer2Result.setText("{:s} ({:s})".format(self.OFW_VER, datetime.datetime.fromtimestamp(int(self.OFW_BUILDTS)).astimezone().replace(microsecond=0).isoformat()))
340
+
341
+ def run(self):
342
+ try:
343
+ self.layout.update()
344
+ self.layout.activate()
345
+ screenGeometry = QDesktopWidget().screenGeometry(self)
346
+ x = (screenGeometry.width() - self.width()) / 2
347
+ y = (screenGeometry.height() - self.height()) / 2
348
+ self.move(x, y)
349
+ self.show()
350
+ except:
351
+ return
352
+
353
+ def hideEvent(self, event):
354
+ if self.DEVICE is None:
355
+ self.APP.ConnectDevice()
356
+ self.APP.activateWindow()
357
+
358
+ def reject(self):
359
+ if self.CloseDialog():
360
+ super().reject()
361
+
362
+ def CloseDialog(self):
363
+ if self.btnClose.isEnabled() is False:
364
+ text = "<b>WARNING:</b> If you close this window while a firmware update is still running, it may leave the device in an unbootable state. You can still recover it by running the Firmware Updater again later.<br><br>Are you sure you want to close this window?"
365
+ msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Warning, windowTitle="FlashGBX", text=text, standardButtons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
366
+ msgbox.setDefaultButton(QtWidgets.QMessageBox.No)
367
+ answer = msgbox.exec()
368
+ if answer == QtWidgets.QMessageBox.No: return False
369
+ return True
370
+
371
+ def UpdateFirmware(self):
372
+ file_name = self.FWUPD.APP_PATH + "/res/fw_GBFlash.zip"
373
+
374
+ if self.APP.CONN is None or self.APP.CONN.BootloaderReset() is False:
375
+ self.APP.DisconnectDevice()
376
+ text = "Please follow these steps to proceed with the firmware update:<ol><li>Unplug your GBFlash device.</li><li>On your GBFlash circuit board, push and hold the small button (U22) while plugging the USB cable back in.</li><li>If done right, the blue LED labeled “ACT” should now keep blinking twice.</li><li>Click OK to continue.</li></ol>"
377
+ msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Information, windowTitle="FlashGBX", text=text, standardButtons=QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel)
378
+ msgbox.setDefaultButton(QtWidgets.QMessageBox.Ok)
379
+ msgbox.setTextFormat(QtCore.Qt.TextFormat.RichText)
380
+ answer = msgbox.exec()
381
+ if answer == QtWidgets.QMessageBox.Cancel: return
382
+ else:
383
+ self.APP.DisconnectDevice()
384
+ time.sleep(1)
385
+
386
+ self.btnUpdate.setEnabled(False)
387
+ self.btnClose.setEnabled(False)
388
+
389
+ while True:
390
+ ret = self.FWUPD.WriteFirmware(file_name, self.SetStatus)
391
+ if ret == 1:
392
+ text = "The firmware update is complete!"
393
+ if self.PCB_VER != "v1.3":
394
+ text += "\n\nPlease re-connect the USB cable now."
395
+ self.btnUpdate.setEnabled(True)
396
+ self.btnClose.setEnabled(True)
397
+ msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Information, windowTitle="FlashGBX", text=text, standardButtons=QtWidgets.QMessageBox.Ok)
398
+ answer = msgbox.exec()
399
+ self.DEVICE = None
400
+ self.reject()
401
+ return True
402
+ elif ret == 2:
403
+ text = "The firmware update has failed. Please try again."
404
+ self.btnUpdate.setEnabled(True)
405
+ self.btnClose.setEnabled(True)
406
+ msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="FlashGBX", text=text, standardButtons=QtWidgets.QMessageBox.Ok)
407
+ answer = msgbox.exec()
408
+ return False
409
+ elif ret == 3:
410
+ text = "The firmware update file is corrupted. Please re-install the application."
411
+ self.btnUpdate.setEnabled(True)
412
+ self.btnClose.setEnabled(True)
413
+ msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="FlashGBX", text=text, standardButtons=QtWidgets.QMessageBox.Ok)
414
+ answer = msgbox.exec()
415
+ return False
416
+
417
+ def SetStatus(self, text, enableUI=False, setProgress=None):
418
+ self.lblStatus.setText("Status: {:s}".format(text))
419
+ if setProgress is not None:
420
+ self.prgStatus.setValue(setProgress * 10)
421
+ if enableUI:
422
+ self.btnUpdate.setEnabled(True)
423
+ self.btnClose.setEnabled(True)
424
+ self.APP.QT_APP.processEvents()
425
+ except ImportError:
426
+ pass
@@ -295,7 +295,7 @@ class FirmwareUpdaterWindow(QtWidgets.QDialog):
295
295
  lives = 10
296
296
  buffer = bytearray()
297
297
 
298
- msgWarnBadResponse = "Failed to update your GBxCart RW {:s} ({:s})!\n\nThe firmware update failed as the device is not responding correctly. Please ensure you use a <a href=\"https://www.gbxcart.com/\">genuine GBxCart RW</a>, re-connect using a different USB cable and try again.\n\n⚠️ Note that FlashGBX is not designed to be used with feature-stripped clone hardware such as the license-violating “FLASH&nbsp;BOY” series devices. These will not work as intended and have a considerable risk of causing damage.".format(self.PCB_VER, self.FW_VER).replace("\n", "<br>")
298
+ msgWarnBadResponse = "Failed to update your GBxCart RW {:s} ({:s})!\n\nThe firmware update failed as the device is not responding correctly. Please ensure you use a <a href=\"https://www.gbxcart.com/\">genuine GBxCart RW</a>, re-connect using a different USB cable and try again.\n\n⚠️ Please note that FlashGBX does not work with the “FLASH&nbsp;BOY” series devices.".format(self.PCB_VER, self.FW_VER).replace("\n", "<br>")
299
299
 
300
300
  fncSetStatus(text="Status: Waiting for bootloader...", setProgress=0)
301
301
  if self.ResetAVR(delay) is False: