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/Mapper.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # FlashGBX
3
- # Author: Lesserkuma (github.com/lesserkuma)
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
- # print("RTCReadData(): i={:d}/temp={:X}/bit={:x}/data={:x}".format(i, temp, bit, data))
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
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # FlashGBX
3
- # Author: Lesserkuma (github.com/lesserkuma)
3
+ # Author: Lesserkuma (github.com/Lesserkuma)
4
4
 
5
5
  from PIL import Image
6
6
  from PIL.PngImagePlugin import PngInfo
@@ -1,12 +1,13 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # FlashGBX
3
- # Author: Lesserkuma (github.com/lesserkuma)
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/lesserkuma)
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
- data["unchanged"] = copy.copy(data)
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/lesserkuma)
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
- data["unchanged"] = copy.copy(data)
144
- if not unchanged:
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"]:
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # FlashGBX
3
- # Author: Lesserkuma (github.com/lesserkuma)
3
+ # Author: Lesserkuma (github.com/Lesserkuma)
4
4
 
5
5
  from .pyside import QtCore, QtWidgets, QtGui
6
6
 
FlashGBX/Util.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # FlashGBX
3
- # Author: Lesserkuma (github.com/lesserkuma)
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.3"
11
+ VERSION_PEP440 = "4.6"
12
12
  VERSION = "v{:s}".format(VERSION_PEP440)
13
- VERSION_TIMESTAMP = 1731015769
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
- magic = "{:s}{:s}{:s}".format(chr(buffer[0x20]), chr(buffer[0x22]), chr(buffer[0x24]))
414
- if magic != "QRY": # nothing swapped
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"]["unchanged"]
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
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # FlashGBX
3
- # Author: Lesserkuma (github.com/lesserkuma)
3
+ # Author: Lesserkuma (github.com/Lesserkuma)
4
4
 
5
5
  from . import FlashGBX
6
6
  FlashGBX.main()
FlashGBX/fw_GBFlash.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # FlashGBX
3
- # Author: Lesserkuma (github.com/lesserkuma)
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
- data["outro"] = struct.unpack(">I", self.DEVICE.read(4))[0]
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:
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # FlashGBX
3
- # Author: Lesserkuma (github.com/lesserkuma)
3
+ # Author: Lesserkuma (github.com/Lesserkuma)
4
4
 
5
5
  import zipfile, os, serial, struct, time, re, math
6
6
  from .pyside import QtCore, QtWidgets, QtGui, QDesktopWidget
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # FlashGBX
3
- # Author: Lesserkuma (github.com/lesserkuma)
3
+ # Author: Lesserkuma (github.com/Lesserkuma)
4
4
 
5
5
  import zipfile, serial, struct, time, random, hashlib, datetime
6
6
  try:
FlashGBX/fw_JoeyJr.py CHANGED
@@ -1,8 +1,9 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # FlashGBX
3
- # Author: Lesserkuma (github.com/lesserkuma)
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="Device not accessible.", enableUI=True)
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/lesserkuma)
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:1730731680, 10:1730731680, 11:1730731680, 12:1730731680, 13:1730731680 }
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"] < self.DEVICE_LATEST_FW_TS[self.FW["pcb_ver"]]:
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/lesserkuma)
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:1722774120, 6:1722774120, 2:0, 90:0, 100:0 }
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=2000000):
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, 1700000, 2000000):
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 >= 1700000 and self.FW is not None and "pcb_ver" in self.FW and self.FW["pcb_ver"] in (5, 6, 101) and self.BAUDRATE < 1700000:
53
- self.ChangeBaudRate(baudrate=1700000)
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
- 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."])
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 == 1700000:
177
- self._write(self.DEVICE_CMD["OFW_USART_1_7M_SPEED"])
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"] < self.DEVICE_LATEST_FW_TS[self.FW["pcb_ver"]]:
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"] < self.DEVICE_LATEST_FW_TS[self.FW["pcb_ver"]]:
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/lesserkuma)
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 = 1722774120
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"] < self.DEVICE_LATEST_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
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # FlashGBX
3
- # Author: Lesserkuma (github.com/lesserkuma)
3
+ # Author: Lesserkuma (github.com/Lesserkuma)
4
4
  #
5
5
  # PySide abstraction layer contributed by J-Fox
6
6
  #
FlashGBX/res/config.zip CHANGED
Binary file
Binary file
Binary file
Binary file
Binary file