FlashGBX 4.1__py3-none-any.whl → 4.3__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/Flashcart.py CHANGED
@@ -708,6 +708,7 @@ class Flashcart_DMG_BUNG_16M(Flashcart):
708
708
  self.CartWrite([[0x2000, 0x02]], fast_write=False)
709
709
  self.CartWrite([[0x6AAA, 0x90]], fast_write=True)
710
710
  cart_flash_id = list(self.CartRead(0, 4))
711
+ verified = False
711
712
  if rom != cart_flash_id and cart_flash_id == self.CONFIG["flash_ids"][0]:
712
713
  self.Reset()
713
714
  verified = True
FlashGBX/LK_Device.py CHANGED
@@ -116,7 +116,7 @@ class LK_Device(ABC):
116
116
  "AGB_IRQ_ENABLED":[8, 0x10],
117
117
  }
118
118
 
119
- ACTIONS = {"ROM_READ":1, "SAVE_READ":2, "SAVE_WRITE":3, "ROM_WRITE":4, "ROM_WRITE_VERIFY":4, "SAVE_WRITE_VERIFY":3, "RTC_WRITE":5}
119
+ ACTIONS = {"ROM_READ":1, "SAVE_READ":2, "SAVE_WRITE":3, "ROM_WRITE":4, "ROM_WRITE_VERIFY":4, "SAVE_WRITE_VERIFY":3, "RTC_WRITE":5, "DETECT_CART":6}
120
120
  SUPPORTED_CARTS = {}
121
121
 
122
122
  FW = {}
@@ -229,8 +229,14 @@ class LK_Device(ABC):
229
229
  #################################################################
230
230
 
231
231
  def IsSupportedMbc(self, mbc):
232
- return mbc in ( 0x00, 0x01, 0x02, 0x03, 0x05, 0x06, 0x08, 0x09, 0x0B, 0x0D, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x20, 0x22, 0xFC, 0xFD, 0xFE, 0xFF, 0x101, 0x103, 0x104, 0x105, 0x110, 0x201, 0x202, 0x203, 0x204, 0x205 )
232
+ return mbc in ( 0x00, 0x01, 0x02, 0x03, 0x05, 0x06, 0x08, 0x09, 0x0B, 0x0D, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x20, 0x22, 0xFC, 0xFD, 0xFE, 0xFF, 0x101, 0x103, 0x104, 0x105, 0x110, 0x201, 0x202, 0x203, 0x204, 0x205, 0x206 )
233
233
 
234
+ def IsUnregistered(self):
235
+ if "unregistered" in self.FW:
236
+ return self.FW["unregistered"]
237
+ else:
238
+ return False
239
+
234
240
  def TryConnect(self, port, baudrate):
235
241
  dprint("Trying to connect to {:s} at baud rate {:d} ({:s})".format(port, baudrate, type(self).__module__))
236
242
  try:
@@ -635,11 +641,11 @@ class LK_Device(ABC):
635
641
  ret = self._read(1)
636
642
  if ret != 0x01:
637
643
  if ret is False:
638
- msg = "Error: No response while trying to write to the device."
644
+ msg = "Error: No response while trying to communicate with the device."
639
645
  time.sleep(0.5)
640
646
  self.DEVICE.reset_input_buffer()
641
647
  else:
642
- msg = "Error: Bad response “{:s}” while trying to write to the device.".format(str(ret))
648
+ msg = "Error: Bad response “{:s}” while trying to communicate with the device.".format(str(ret))
643
649
  print(f"{ANSI.RED}{msg}{ANSI.RESET}")
644
650
  dprint(msg)
645
651
  #self.CANCEL_ARGS.update({"info_type":"msgbox_critical", "info_msg":"A critical communication error occured during a write. Please avoid passive USB hubs, try different USB ports/cables and re-connect the device."})
@@ -741,7 +747,7 @@ class LK_Device(ABC):
741
747
  if self.DEVICE.in_waiting == 0:
742
748
  dprint("Waiting for ACK...")
743
749
  hp -= 1
744
- time.sleep(0.05)
750
+ time.sleep(0.1)
745
751
  continue
746
752
  temp = self.DEVICE.read(self.DEVICE.in_waiting)
747
753
  if len(temp) >= 1: temp = temp[len(temp) - 1]
@@ -751,6 +757,13 @@ class LK_Device(ABC):
751
757
  self._write(self.DEVICE_CMD["QUERY_CART_PWR"])
752
758
  time.sleep(0.05)
753
759
  hp -= 1
760
+
761
+ if hp == 0:
762
+ self.DEVICE.close()
763
+ self.DEVICE = None
764
+ self.ERROR = True
765
+ raise BrokenPipeError("Couldn’t power on the cartridge.")
766
+
754
767
  self.DEVICE.timeout = self.DEVICE_TIMEOUT
755
768
 
756
769
  self._write(self.DEVICE_CMD["QUERY_CART_PWR"])
@@ -854,21 +867,25 @@ class LK_Device(ABC):
854
867
  def GetSupportedCartridgesAGB(self):
855
868
  return (list(self.SUPPORTED_CARTS['AGB'].keys()), list(self.SUPPORTED_CARTS['AGB'].values()))
856
869
 
857
- def SetProgress(self, args):
870
+ def SetProgress(self, args, signal=None):
858
871
  if self.CANCEL and args["action"] not in ("ABORT", "FINISHED", "ERROR"): return
859
872
  if "pos" in args: self.POS = args["pos"]
860
873
  if args["action"] == "UPDATE_POS": self.INFO["transferred"] = args["pos"]
874
+ if signal is None:
875
+ signal = self.SIGNAL
876
+
861
877
  try:
862
- self.SIGNAL.emit(args)
878
+ signal.emit(args)
863
879
  except AttributeError:
864
- if self.SIGNAL is not None:
865
- self.SIGNAL(args)
880
+ if signal is not None:
881
+ signal(args)
866
882
 
867
883
  if args["action"] == "INITIALIZE":
868
884
  if self.CanPowerCycleCart(): self.CartPowerOn() # Ensure cart is powered
869
885
  self.POS = 0
870
886
  elif args["action"] == "FINISHED":
871
887
  self.POS = 0
888
+ signal = None
872
889
  self.SIGNAL = None
873
890
 
874
891
  def Debug(self):
@@ -905,7 +922,7 @@ class LK_Device(ABC):
905
922
  header = self.ReadROM(0, 0x180)
906
923
 
907
924
  if ".dev" in Util.VERSION_PEP440 or Util.DEBUG:
908
- with open("debug_header.bin", "wb") as f: f.write(header)
925
+ with open(Util.CONFIG_PATH + "/debug_header.bin", "wb") as f: f.write(header)
909
926
 
910
927
  # Parse ROM header
911
928
  if self.MODE == "DMG":
@@ -1069,7 +1086,19 @@ class LK_Device(ABC):
1069
1086
 
1070
1087
  return data
1071
1088
 
1072
- def DetectCartridge(self, mbc=None, limitVoltage=False, checkSaveType=True):
1089
+ def _DetectCartridge(self, args): # Wrapper for thread call
1090
+ self.SetProgress({"action":"INITIALIZE", "abortable":False, "method":"DETECT_CART"})
1091
+ signal = self.SIGNAL
1092
+ self.SIGNAL = None
1093
+ ret = self.DoDetectCartridge(mbc=None, limitVoltage=args["limitVoltage"], checkSaveType=args["checkSaveType"], signal=signal)
1094
+ self.INFO["detect_cart"] = ret
1095
+ self.INFO["last_action"] = self.ACTIONS["DETECT_CART"]
1096
+ self.INFO["action"] = None
1097
+ self.SIGNAL = signal
1098
+ self.SetProgress({"action":"FINISHED"})
1099
+ return True
1100
+
1101
+ def DoDetectCartridge(self, mbc=None, limitVoltage=False, checkSaveType=True, signal=None):
1073
1102
  self.SIGNAL = None
1074
1103
  self.CANCEL = False
1075
1104
  self.ERROR = False
@@ -1079,8 +1108,10 @@ class LK_Device(ABC):
1079
1108
  sram_unstable = None
1080
1109
  save_size = None
1081
1110
  checkBatterylessSRAM = False
1111
+ _apot = 0
1082
1112
 
1083
1113
  # Header
1114
+ if signal is not None: self.SetProgress({"action":"UPDATE_INFO", "text":"Detecting ROM..."}, signal=signal)
1084
1115
  info = self.ReadInfo(checkRtc=True)
1085
1116
  if self.MODE == "DMG" and mbc is None:
1086
1117
  mbc = info["mapper_raw"]
@@ -1097,6 +1128,7 @@ class LK_Device(ABC):
1097
1128
  self._set_fw_variable("AUTO_POWEROFF_TIME", 5000)
1098
1129
 
1099
1130
  # Detect Flash Cart
1131
+ if signal is not None: self.SetProgress({"action":"UPDATE_INFO", "text":"Detecting Flash..."}, signal=signal)
1100
1132
  ret = self.DetectFlash(limitVoltage=limitVoltage)
1101
1133
  if ret is False: return False
1102
1134
  (cart_types, cart_type_id, flash_id, cfi_s, cfi, detected_size) = ret
@@ -1113,6 +1145,7 @@ class LK_Device(ABC):
1113
1145
  elif self.MODE == "AGB" and "flash_bank_select_type" in cart_type and cart_type["flash_bank_select_type"] > 1:
1114
1146
  checkSaveType = False
1115
1147
  elif self.MODE == "DMG" and "mbc" in cart_type and cart_type["mbc"] == 0x105: # G-MMC1
1148
+ if signal is not None: self.SetProgress({"action":"UPDATE_INFO", "text":"Detecting GB-Memory..."}, signal=signal)
1116
1149
  header = self.ReadROM(0, 0x180)
1117
1150
  data = RomFileDMG(header).GetHeader()
1118
1151
  _mbc = DMG_MBC().GetInstance(args={"mbc":cart_type["mbc"]}, cart_write_fncptr=self._cart_write, cart_read_fncptr=self._cart_read, cart_powercycle_fncptr=self.CartPowerCycleOrAskReconnect, clk_toggle_fncptr=self._clk_toggle)
@@ -1131,6 +1164,7 @@ class LK_Device(ABC):
1131
1164
 
1132
1165
  # Save Type and Size
1133
1166
  if checkSaveType:
1167
+ if signal is not None: self.SetProgress({"action":"UPDATE_INFO", "text":"Detecting save type..."}, signal=signal)
1134
1168
  if self.MODE == "DMG":
1135
1169
  save_size = 131072
1136
1170
  save_type = 0x04
@@ -1148,6 +1182,8 @@ class LK_Device(ABC):
1148
1182
  args = { 'mode':2, 'path':None, 'mbc':mbc, 'save_type':save_type, 'rtc':False, 'detect':True }
1149
1183
  elif self.MODE == "AGB":
1150
1184
  args = { 'mode':2, 'path':None, 'mbc':mbc, 'save_type':8, 'rtc':False, 'detect':True }
1185
+ else:
1186
+ return
1151
1187
 
1152
1188
  ret = self._BackupRestoreRAM(args=args)
1153
1189
 
@@ -1175,6 +1211,10 @@ class LK_Device(ABC):
1175
1211
  if self.INFO["data"][i:i+3] != bytearray([self.INFO["data"][i]] * 3):
1176
1212
  check = False
1177
1213
  break
1214
+
1215
+ if self.INFO["data"][0:0x8000] == self.INFO["data"][0x8000:0x10000]: # MBCX
1216
+ check = True
1217
+
1178
1218
  if check:
1179
1219
  save_size = 32768
1180
1220
  save_type = 0x03
@@ -1201,7 +1241,13 @@ class LK_Device(ABC):
1201
1241
  if flash_save_id != 0 and flash_save_id in Util.AGB_Flash_Save_Chips:
1202
1242
  save_size = Util.AGB_Flash_Save_Chips_Sizes[list(Util.AGB_Flash_Save_Chips).index(flash_save_id)]
1203
1243
  save_chip = Util.AGB_Flash_Save_Chips[flash_save_id]
1204
- if save_size == 131072:
1244
+
1245
+ if flash_save_id in (0xBF5B, 0xFFFF): # Bootlegs
1246
+ if self.INFO["data"][0:0x10000] == self.INFO["data"][0x10000:0x20000]:
1247
+ save_type = 4
1248
+ else:
1249
+ save_type = 5
1250
+ elif save_size == 131072:
1205
1251
  save_type = 5
1206
1252
  elif save_size == 65536:
1207
1253
  save_type = 4
@@ -1395,6 +1441,8 @@ class LK_Device(ABC):
1395
1441
  command = "DMG_CART_READ"
1396
1442
  elif self.MODE == "AGB":
1397
1443
  command = "AGB_CART_READ"
1444
+ else:
1445
+ raise NotImplementedError
1398
1446
 
1399
1447
  for n in range(0, num):
1400
1448
  self._write(self.DEVICE_CMD[command])
@@ -1944,7 +1992,7 @@ class LK_Device(ABC):
1944
1992
  chunk_len = max_length if left > max_length else left
1945
1993
  chunk_from = offset + chunk_pos
1946
1994
  chunk_to = offset + chunk_pos + chunk_len
1947
- dprint(f"Running CRC32 verification, comparing between source 0x{chunk_from:x}~0x{chunk_to:x} and target 0x{address+chunk_pos:x}~0x{address+chunk_pos+chunk_len:x}")
1995
+ dprint(f"Running CRC32 verification, comparing between source 0x{chunk_from:X}~0x{chunk_to:X} and target 0x{address+chunk_pos:X}~0x{address+chunk_pos+chunk_len:X}")
1948
1996
  crc32_expected = zlib.crc32(buffer[chunk_from:chunk_to])
1949
1997
 
1950
1998
  for i in range(0, 2 if (reset is True and flashcart is not None) else 1): # for retrying with reset
@@ -2008,6 +2056,9 @@ class LK_Device(ABC):
2008
2056
  self.SetAGBReadMethod(0)
2009
2057
  self._write(self.DEVICE_CMD["SET_MODE_AGB"], wait=self.FW["fw_ver"] >= 12)
2010
2058
 
2059
+ else:
2060
+ raise NotImplementedError
2061
+
2011
2062
  rom = self._cart_read(0, 8)
2012
2063
 
2013
2064
  dprint("Resetting and unlocking all cart types")
@@ -2182,7 +2233,7 @@ class LK_Device(ABC):
2182
2233
  flash_id_methods.append([we - 1, i, list(cmp), cfi_buffer, flash_id_cmds[i]["read_identifier"]])
2183
2234
 
2184
2235
  if ".dev" in Util.VERSION_PEP440 or Util.DEBUG:
2185
- with open("debug_cfi.bin", "wb") as f: f.write(cfi_buffer)
2236
+ with open(Util.CONFIG_PATH + "/debug_cfi.bin", "wb") as f: f.write(cfi_buffer)
2186
2237
  try:
2187
2238
  magic = "{:s}{:s}{:s}".format(chr(cfi_buffer[0x20]), chr(cfi_buffer[0x22]), chr(cfi_buffer[0x24]))
2188
2239
  d_swap = (0, 0)
@@ -2199,7 +2250,7 @@ class LK_Device(ABC):
2199
2250
  for j in range(0, len(cfi_buffer)):
2200
2251
  cfi_buffer[j] = bitswap(cfi_buffer[j], d_swap[j2])
2201
2252
  if ".dev" in Util.VERSION_PEP440 or Util.DEBUG:
2202
- with open("debug_cfi_d0d1+d6d7.bin", "wb") as f: f.write(cfi_buffer)
2253
+ with open(Util.CONFIG_PATH + "/debug_cfi_d0d1+d6d7.bin", "wb") as f: f.write(cfi_buffer)
2203
2254
  else:
2204
2255
  cfi_buffer = None
2205
2256
  except:
@@ -2281,6 +2332,8 @@ class LK_Device(ABC):
2281
2332
  supp_flash_types = self.GetSupportedCartridgesDMG()
2282
2333
  elif self.MODE == "AGB":
2283
2334
  supp_flash_types = self.GetSupportedCartridgesAGB()
2335
+ else:
2336
+ raise NotImplementedError
2284
2337
 
2285
2338
  if "flash_size" in supp_flash_types[1][flash_types[0]]:
2286
2339
  size = supp_flash_types[1][flash_types[0]]["flash_size"]
@@ -2381,6 +2434,9 @@ class LK_Device(ABC):
2381
2434
  def FlashROM(self, fncSetProgress=None, args=None):
2382
2435
  self.DoTransfer(4, fncSetProgress, args)
2383
2436
 
2437
+ def DetectCartridge(self, fncSetProgress=None, args=None):
2438
+ self.DoTransfer(5, fncSetProgress, args)
2439
+
2384
2440
  #################################################################
2385
2441
 
2386
2442
  def _BackupROM(self, args):
@@ -2416,8 +2472,10 @@ class LK_Device(ABC):
2416
2472
 
2417
2473
  # Firmware check L8
2418
2474
  if self.FW["fw_ver"] < 8 and flashcart and "enable_pullups" in cart_type:
2419
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type requires at least firmware version L8.", "abortable":False})
2420
- return False
2475
+ #self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type requires at least firmware version L8.", "abortable":False})
2476
+ #return False
2477
+ print("{:s}Note: This cartridge may not be fully compatible with your {:s} device running an old or legacy firmware version.{:s}".format(ANSI.YELLOW, self.FW["pcb_name"], ANSI.RESET))
2478
+ del(cart_type["enable_pullups"])
2421
2479
  # Firmware check L8
2422
2480
 
2423
2481
  buffer_len = 0x4000
@@ -2712,12 +2770,11 @@ class LK_Device(ABC):
2712
2770
  pos_total += len(temp)
2713
2771
 
2714
2772
  if "verify_write" in args:
2715
- #if pos_total >= len(args["verify_write"]): break
2716
2773
  check = args["verify_write"][pos_total-len(temp):pos_total]
2717
2774
  if temp[:len(check)] != check:
2718
2775
  if ".dev" in Util.VERSION_PEP440 or Util.DEBUG:
2719
2776
  dprint("Writing 0x{:X} bytes to debug_verify_0x{:X}.bin".format(len(temp), pos_total-len(temp)))
2720
- with open("debug_verify_0x{:X}.bin".format(pos_total-len(temp)), "ab") as f: f.write(temp)
2777
+ with open(Util.CONFIG_PATH + "/debug_verify_0x{:X}.bin".format(pos_total-len(temp)), "ab") as f: f.write(temp)
2721
2778
 
2722
2779
  for i in range(0, pos_total):
2723
2780
  if (i < len(args["verify_write"]) - 1) and (i < pos_total - 1) and args["verify_write"][i] != buffer[i]:
@@ -2818,7 +2875,7 @@ class LK_Device(ABC):
2818
2875
 
2819
2876
  # Check for ROM loops
2820
2877
  self.INFO["loop_detected"] = False
2821
- temp = min(0x2000000, len(buffer))
2878
+ temp = len(buffer)
2822
2879
  while temp > 0x4000:
2823
2880
  temp = temp >> 1
2824
2881
  if (buffer[0:0x4000] == buffer[temp:temp+0x4000]):
@@ -2861,6 +2918,8 @@ class LK_Device(ABC):
2861
2918
  _agb_gpio = AGB_GPIO(args={"rtc":True}, cart_write_fncptr=self._cart_write, cart_read_fncptr=self._cart_read, cart_powercycle_fncptr=self.CartPowerCycleOrAskReconnect, clk_toggle_fncptr=self._clk_toggle)
2862
2919
  if _agb_gpio.HasRTC() is not True: return False
2863
2920
  ret = _agb_gpio.WriteRTCDict(args["rtc_dict"])
2921
+ else:
2922
+ raise NotImplementedError
2864
2923
  return ret
2865
2924
 
2866
2925
  def _BackupRestoreRAM(self, args):
@@ -2872,6 +2931,12 @@ class LK_Device(ABC):
2872
2931
  empty_data_byte = 0x00
2873
2932
  extra_size = 0
2874
2933
  audio_low = False
2934
+
2935
+ # Initialization
2936
+ ram_banks = 0
2937
+ buffer_len = 0
2938
+ sram_5 = 0
2939
+ temp = None
2875
2940
 
2876
2941
  cart_type = None
2877
2942
  if "cart_type" in args and args["cart_type"] >= 0:
@@ -3052,6 +3117,7 @@ class LK_Device(ABC):
3052
3117
  if args["rtc"] is True:
3053
3118
  extra_size = 0x10
3054
3119
 
3120
+ action = None
3055
3121
  if args["mode"] == 2: # Backup
3056
3122
  action = "SAVE_READ"
3057
3123
  buffer = bytearray()
@@ -3467,7 +3533,14 @@ class LK_Device(ABC):
3467
3533
  return True
3468
3534
 
3469
3535
  def _FlashROM(self, args):
3536
+ # Initialization
3470
3537
  self.FAST_READ = True
3538
+ temp = None
3539
+ rom_bank_size = 0
3540
+ end_bank = 0
3541
+ pos_from = 0
3542
+ verify_len = 0
3543
+
3471
3544
  if "buffer" in args:
3472
3545
  data_import = args["buffer"]
3473
3546
  else:
@@ -3549,14 +3622,18 @@ class LK_Device(ABC):
3549
3622
  # Firmware check L5
3550
3623
  # Firmware check L8
3551
3624
  if (self.FW["fw_ver"] < 8 and "enable_pullups" in cart_type and cart_type["enable_pullups"] is True):
3552
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type requires at least firmware version L8.", "abortable":False})
3553
- return False
3625
+ #self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type requires at least firmware version L8.", "abortable":False})
3626
+ #return False
3627
+ print("{:s}Note: This cartridge may not be fully compatible with your {:s} device running an old or legacy firmware version.{:s}".format(ANSI.YELLOW, self.FW["pcb_name"], ANSI.RESET))
3628
+ del(cart_type["enable_pullups"])
3554
3629
  # Firmware check L8
3555
3630
  # Firmware check L12
3556
3631
  if (self.FW["fw_ver"] < 12 and "set_irq_high" in cart_type and cart_type["set_irq_high"] is True):
3557
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type requires at least firmware version L12.", "abortable":False})
3558
- return False
3559
- if (self.FW["fw_ver"] < 12 and "status_register_mask" in cart_type and cart_type["status_register_mask"] is True):
3632
+ #self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type requires at least firmware version L12.", "abortable":False})
3633
+ #return False
3634
+ print("{:s}Note: This cartridge may not be fully compatible with your {:s} device running an old or legacy firmware version.{:s}".format(ANSI.YELLOW, self.FW["pcb_name"], ANSI.RESET))
3635
+ del(cart_type["set_irq_high"])
3636
+ if (self.FW["fw_ver"] < 12 and "status_register_mask" in cart_type):
3560
3637
  self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type requires at least firmware version L12.", "abortable":False})
3561
3638
  return False
3562
3639
  # Firmware check L12
@@ -3704,7 +3781,7 @@ class LK_Device(ABC):
3704
3781
  else:
3705
3782
  dprint("Hidden sector data:", args["buffer_map"])
3706
3783
  if ".dev" in Util.VERSION_PEP440 or Util.DEBUG:
3707
- with open("debug_mmsa_map.bin", "wb") as f: f.write(args["buffer_map"])
3784
+ with open(Util.CONFIG_PATH + "/debug_mmsa_map.bin", "wb") as f: f.write(args["buffer_map"])
3708
3785
  data_map_import = copy.copy(args["buffer_map"])
3709
3786
  data_map_import = bytearray(data_map_import)
3710
3787
  dprint("Hidden sector data loaded")
@@ -3793,6 +3870,7 @@ class LK_Device(ABC):
3793
3870
  self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type is currently not supported for ROM writing.", "abortable":False})
3794
3871
  return False
3795
3872
 
3873
+ we = 0x00
3796
3874
  if flashcart.WEisWR():
3797
3875
  we = 0x01 # FLASH_WE_PIN_WR
3798
3876
  self._write(we)
@@ -3806,7 +3884,6 @@ class LK_Device(ABC):
3806
3884
  self._write(we) # FLASH_WE_PIN_WR_RESET
3807
3885
  dprint("Using WR+RESET as WE")
3808
3886
  else:
3809
- we = 0x00
3810
3887
  self._write(we) # unset
3811
3888
 
3812
3889
  for i in range(0, 6):
@@ -4030,9 +4107,6 @@ class LK_Device(ABC):
4030
4107
  sector_pos = sector_offsets.index(sector[:2])
4031
4108
  start_bank = math.floor(buffer_pos / rom_bank_size)
4032
4109
  end_bank = math.ceil((buffer_pos + sector[1]) / rom_bank_size)
4033
- # print(hex(start_address), hex(end_address), start_bank, end_bank)
4034
- # print(hex(sector_offsets[sector_pos][0]), sector_pos)
4035
- # print("")
4036
4110
  elif self.MODE == "DMG":
4037
4111
  dprint("Writing sector:", hex(sector[0]), hex(sector[1]))
4038
4112
  buffer_pos = sector[0]
@@ -4043,12 +4117,88 @@ class LK_Device(ABC):
4043
4117
  sector_pos = sector_offsets.index(sector[:2])
4044
4118
  start_bank = math.floor(buffer_pos / rom_bank_size)
4045
4119
  end_bank = math.ceil((buffer_pos + sector[1]) / rom_bank_size)
4046
- # print(hex(start_address), hex(end_address), start_bank, end_bank)
4047
- # print(hex(sector_offsets[sector_pos][0]), sector_pos)
4048
- # print("")
4049
4120
 
4050
- #for bank in range(start_bank, end_bank):
4051
4121
  bank = start_bank
4122
+
4123
+ # ↓↓↓ Check if data matches already
4124
+ if self.FW["fw_ver"] >= 10 and not (flashcart and cart_type["command_set"] == "GBAMP"):
4125
+ if "verify_write" in args and args["verify_write"] is True:
4126
+ buffer_pos_matchcheck = buffer_pos
4127
+ verified = False
4128
+ ts_se_start = time.time()
4129
+ while bank < end_bank:
4130
+ status = None
4131
+ # ↓↓↓ Switch ROM bank
4132
+ if self.MODE == "DMG":
4133
+ if _mbc.ResetBeforeBankChange(bank) is True:
4134
+ dprint("Resetting the MBC")
4135
+ self._write(self.DEVICE_CMD["DMG_MBC_RESET"], wait=True)
4136
+ (start_address, bank_size) = _mbc.SelectBankROM(bank)
4137
+ if flashcart.PulseResetAfterWrite():
4138
+ if bank == 0:
4139
+ if self.FW["fw_ver"] < 2:
4140
+ self._write(self.DEVICE_CMD["OFW_GB_CART_MODE"])
4141
+ else:
4142
+ self._write(self.DEVICE_CMD["SET_MODE_DMG"], wait=self.FW["fw_ver"] >= 12)
4143
+ self._write(self.DEVICE_CMD["DMG_MBC_RESET"], wait=True)
4144
+ # else:
4145
+ # self._write(self.DEVICE_CMD["OFW_GB_FLASH_BANK_1_COMMAND_WRITES"])
4146
+ self._set_fw_variable("DMG_ROM_BANK", bank)
4147
+
4148
+ buffer_len = min(buffer_len, bank_size)
4149
+ if "start_addr" in flashcart.CONFIG and bank == 0: start_address = flashcart.CONFIG["start_addr"]
4150
+ end_address = start_address + bank_size
4151
+ start_address += (buffer_pos % rom_bank_size)
4152
+ if end_address > start_address + sector[1]:
4153
+ end_address = start_address + sector[1]
4154
+
4155
+ elif self.MODE == "AGB":
4156
+ if "flash_bank_select_type" in cart_type and cart_type["flash_bank_select_type"] > 0:
4157
+ if bank != current_bank:
4158
+ flashcart.Reset(full_reset=True)
4159
+ flashcart.SelectBankROM(bank)
4160
+ temp = end_address - start_address
4161
+ start_address %= cart_type["flash_bank_size"]
4162
+ end_address = min(cart_type["flash_bank_size"], start_address + temp)
4163
+ current_bank = bank
4164
+ # ↑↑↑ Switch ROM bank
4165
+
4166
+ pos = start_address
4167
+ #dprint("pos=0x{:X}, buffer_pos=0x{:X}, start_address=0x{:X}, end_address=0x{:X}".format(pos, buffer_pos_matchcheck, start_address, end_address))
4168
+ verified = self.CompareCRC32(buffer=data_import, offset=buffer_pos_matchcheck, length=end_address - pos, address=pos, flashcart=flashcart, reset=True)
4169
+ self.SetProgress({"action":"UPDATE_POS", "pos":buffer_pos_matchcheck})
4170
+ if verified is not True:
4171
+ break
4172
+ buffer_pos_matchcheck += (end_address - pos)
4173
+ bank += 1
4174
+
4175
+ if verified is True:
4176
+ dprint("Skipping sector #{:d}, because the CRC32 matched".format(sector_pos))
4177
+ if flashcart.FlashCommandsOnBank1(): _mbc.SelectBankROM(bank)
4178
+ self.NO_PROG_UPDATE = True
4179
+ se_ret = flashcart.SectorErase(pos=pos, buffer_pos=buffer_pos, skip=verified)
4180
+ self.NO_PROG_UPDATE = False
4181
+
4182
+ if self.CANCEL:
4183
+ cancel_args = {"action":"ABORT", "abortable":False}
4184
+ cancel_args.update(self.CANCEL_ARGS)
4185
+ self.CANCEL_ARGS = {}
4186
+ self.ERROR_ARGS = {}
4187
+ self.SetProgress(cancel_args)
4188
+ if self.CanPowerCycleCart(): self.CartPowerCycle()
4189
+ return
4190
+
4191
+ ts_se_elapsed = time.time() - ts_se_start
4192
+ if se_ret:
4193
+ sector_size = se_ret
4194
+ dprint("Next sector size: 0x{:X}".format(sector_size))
4195
+ buffer_pos += sector_size
4196
+ continue
4197
+ else:
4198
+ verified = False
4199
+ bank = start_bank
4200
+ # ↑↑↑ Check if data matches already
4201
+
4052
4202
  while bank < end_bank:
4053
4203
  if self.CANCEL:
4054
4204
  cancel_args = {"action":"ABORT", "abortable":False}
@@ -4116,44 +4266,20 @@ class LK_Device(ABC):
4116
4266
  se_ret = None
4117
4267
  if chip_erase is False:
4118
4268
  if sector_pos < len(sector_offsets) and buffer_pos == sector_offsets[sector_pos][0]:
4119
- len_rest = end_address - pos
4120
- skip_se = False
4121
4269
  ts_se_start = time.time()
4122
- if self.FW["fw_ver"] >= 12 and "compare_sectors" in args and args["compare_sectors"] is True and sector[1] <= len_rest and not (flashcart and cart_type["command_set"] == "GBAMP"):
4123
- verified = self.CompareCRC32(buffer=data_import, offset=sector[0], length=sector[1], address=start_address, flashcart=flashcart, reset=True)
4124
- if verified is True:
4125
- skip_se = True
4126
- elif verified is not True and len(verified) == 2:
4127
- dprint("Writing sector #{:d}, because the CRC32 didn’t match: 0x{:X} ≠ 0x{:X}".format(sector_pos, verified[0], verified[1]))
4128
- verified = False
4129
- skip_se = False
4130
-
4131
- if self.CANCEL:
4132
- cancel_args = {"action":"ABORT", "abortable":False}
4133
- cancel_args.update(self.CANCEL_ARGS)
4134
- self.CANCEL_ARGS = {}
4135
- self.ERROR_ARGS = {}
4136
- self.SetProgress(cancel_args)
4137
- if self.CanPowerCycleCart(): self.CartPowerCycle()
4138
- return
4139
-
4140
- if skip_se is True:
4141
- dprint("Skipping sector #{:d}, because the CRC32 matched".format(sector_pos))
4142
- self.SetProgress({"action":"UPDATE_POS", "pos":buffer_pos, "sector_pos":sector_pos, "force_update":True})
4143
- else:
4144
- if sector not in verify_sectors:
4145
- verify_sectors.append(sector)
4146
- dprint("Erasing sector #{:d} at position 0x{:X} (0x{:X})".format(sector_pos, buffer_pos, pos))
4147
- self.SetProgress({"action":"UPDATE_POS", "pos":buffer_pos, "force_update":True})
4148
- if self.CanPowerCycleCart(): self.CartPowerOn()
4270
+ dprint("Erasing sector #{:d} at position 0x{:X} (0x{:X})".format(sector_pos, buffer_pos, pos))
4271
+ self.SetProgress({"action":"UPDATE_POS", "pos":buffer_pos, "force_update":True})
4272
+ if self.CanPowerCycleCart(): self.CartPowerOn()
4149
4273
 
4150
4274
  sector_pos += 1
4151
4275
  if flashcart.FlashCommandsOnBank1(): _mbc.SelectBankROM(bank)
4152
4276
  self.NO_PROG_UPDATE = True
4153
- se_ret = flashcart.SectorErase(pos=pos, buffer_pos=buffer_pos, skip=skip_se)
4277
+ se_ret = flashcart.SectorErase(pos=pos, buffer_pos=buffer_pos, skip=False)
4154
4278
  self.NO_PROG_UPDATE = False
4155
4279
  if "from_user" in self.CANCEL_ARGS and self.CANCEL_ARGS["from_user"]:
4156
4280
  continue
4281
+ if sector not in verify_sectors:
4282
+ verify_sectors.append(sector)
4157
4283
 
4158
4284
  ts_se_elapsed = time.time() - ts_se_start
4159
4285
  if se_ret:
@@ -4161,11 +4287,6 @@ class LK_Device(ABC):
4161
4287
  sector_size = se_ret
4162
4288
  dprint("Next sector size: 0x{:X}".format(sector_size))
4163
4289
  skip_init = False
4164
-
4165
- if skip_se:
4166
- buffer_pos += sector_size
4167
- pos += sector_size
4168
- continue
4169
4290
  # ↑↑↑ Sector erase
4170
4291
 
4171
4292
  if se_ret is not False:
@@ -4313,7 +4434,7 @@ class LK_Device(ABC):
4313
4434
  if "verify_write" in args and args["verify_write"] is True:
4314
4435
  self.SetProgress({"action":"INITIALIZE", "method":"ROM_WRITE_VERIFY", "size":len(data_import), "flash_offset":flash_offset})
4315
4436
  if ".dev" in Util.VERSION_PEP440 or Util.DEBUG:
4316
- with open("debug_verify.bin", "wb") as f: pass
4437
+ with open(Util.CONFIG_PATH + "/debug_verify.bin", "wb") as f: pass
4317
4438
 
4318
4439
  current_bank = None
4319
4440
  broken_sectors = []
@@ -4502,6 +4623,8 @@ class LK_Device(ABC):
4502
4623
  self.CANCEL_ARGS = {}
4503
4624
  self.READ_ERRORS = 0
4504
4625
  self.WRITE_ERRORS = 0
4626
+ _apot = 0
4627
+
4505
4628
  if self.IsConnected():
4506
4629
  _apoe = False
4507
4630
  if self.CanPowerCycleCart():
@@ -4524,6 +4647,7 @@ class LK_Device(ABC):
4524
4647
  elif args['mode'] == 2: ret = self._BackupRestoreRAM(args)
4525
4648
  elif args['mode'] == 3: ret = self._BackupRestoreRAM(args)
4526
4649
  elif args['mode'] == 4: ret = self._FlashROM(args)
4650
+ elif args['mode'] == 5: ret = self._DetectCartridge(args)
4527
4651
  elif args['mode'] == 0xFF: self.Debug()
4528
4652
  if self.FW is None: return False
4529
4653
  if self.FW["fw_ver"] >= 2 and self.FW["pcb_name"] == "GBxCart RW":
FlashGBX/Mapper.py CHANGED
@@ -75,8 +75,8 @@ class DMG_MBC:
75
75
  return DMG_Unlicensed_Sachen(args=args, cart_write_fncptr=cart_write_fncptr, cart_read_fncptr=cart_read_fncptr, cart_powercycle_fncptr=cart_powercycle_fncptr, clk_toggle_fncptr=clk_toggle_fncptr)
76
76
  elif mbc_id == 0x205: # 0x205:'Datel Orbit V2',
77
77
  return DMG_Unlicensed_DatelOrbitV2(args=args, cart_write_fncptr=cart_write_fncptr, cart_read_fncptr=cart_read_fncptr, cart_powercycle_fncptr=cart_powercycle_fncptr, clk_toggle_fncptr=clk_toggle_fncptr)
78
- # elif mbc_id == 0x206: # 0x206:'Datel MegaMem',
79
- # return DMG_Unlicensed_DatelMegaMem(args=args, cart_write_fncptr=cart_write_fncptr, cart_read_fncptr=cart_read_fncptr, cart_powercycle_fncptr=cart_powercycle_fncptr, clk_toggle_fncptr=clk_toggle_fncptr)
78
+ elif mbc_id == 0x206: # 0x206:'MBCX',
79
+ return DMG_Unlicensed_MBCX(args=args, cart_write_fncptr=cart_write_fncptr, cart_read_fncptr=cart_read_fncptr, cart_powercycle_fncptr=cart_powercycle_fncptr, clk_toggle_fncptr=clk_toggle_fncptr)
80
80
  else:
81
81
  self.__init__(args=args, cart_write_fncptr=cart_write_fncptr, cart_read_fncptr=cart_read_fncptr, cart_powercycle_fncptr=cart_powercycle_fncptr, clk_toggle_fncptr=clk_toggle_fncptr)
82
82
  return self
@@ -269,7 +269,7 @@ class DMG_MBC3(DMG_MBC):
269
269
 
270
270
  def HasRTC(self):
271
271
  dprint("Checking for RTC")
272
- if self.MBC_ID not in (0x0F, 0x10, 0x110):
272
+ if self.MBC_ID not in (0x0F, 0x10, 0x110, 0x206):
273
273
  dprint("No RTC because mapper value is not used for RTC:", self.MBC_ID)
274
274
  return False
275
275
  self.EnableRAM(enable=False)
@@ -831,6 +831,7 @@ class DMG_GMMC1(DMG_MBC5):
831
831
  def CalcChecksum(self, buffer):
832
832
  header = RomFileDMG(buffer[:0x180]).GetHeader()
833
833
  target_chk_value = 0
834
+ target_sha1_value = 0
834
835
  if header["game_title"] == "NP M-MENU MENU":
835
836
  target_sha1_value = "15f5d445c0b2fdf4221cf2a986a4a5cb8dfda131"
836
837
  target_chk_value = 0x19E8
@@ -1531,6 +1532,44 @@ class DMG_Unlicensed_DatelOrbitV2(DMG_MBC):
1531
1532
  def GetMaxROMSize(self):
1532
1533
  return 128*1024
1533
1534
 
1535
+ class DMG_Unlicensed_MBCX(DMG_MBC3):
1536
+ def GetName(self):
1537
+ return "MBCX"
1538
+
1539
+ def HasFlashBanks(self):
1540
+ return True
1541
+
1542
+ def SelectBankFlash(self, index):
1543
+ dprint(self.GetName(), "|SelectBankFlash()|", index)
1544
+
1545
+ commands = [
1546
+ [ 0x0000, 0x05 ],
1547
+ [ 0x4000, 0x82 ],
1548
+ [ 0xA000, index ],
1549
+ [ 0x0000, 0x00 ]
1550
+ ]
1551
+ self.CURRENT_FLASH_BANK = index
1552
+ self.CartWrite(commands, delay=0.1)
1553
+
1554
+ def SelectBankROM(self, index):
1555
+ dprint(self.GetName(), index)
1556
+
1557
+ if (index % 512 == 0) or (self.CURRENT_FLASH_BANK != math.floor(index / 512)):
1558
+ self.SelectBankFlash(math.floor(index / 512))
1559
+ self.CURRENT_ROM_BANK = index
1560
+ index = index % 512
1561
+
1562
+ commands = [
1563
+ [ 0x3000, ((index >> 8) & 0xFF) ],
1564
+ [ 0x2100, index & 0xFF ],
1565
+ ]
1566
+
1567
+ self.CartWrite(commands)
1568
+ return (0x4000, self.ROM_BANK_SIZE)
1569
+
1570
+ def GetMaxROMSize(self):
1571
+ return 32*1024*1024
1572
+
1534
1573
 
1535
1574
  class AGB_GPIO:
1536
1575
  CART_WRITE_FNCPTR = None
FlashGBX/PocketCamera.py CHANGED
@@ -110,7 +110,7 @@ class PocketCamera:
110
110
  offset = 0x2000 + (index * 0x1000)
111
111
  elif index == 30:
112
112
  offset = 0x11FC
113
- elif index == 31:
113
+ else:
114
114
  offset = 0
115
115
  imgbuffer = self.DATA[offset:offset+0x1000]
116
116
  return self.ConvertPicture(imgbuffer)
@@ -138,7 +138,7 @@ class PocketCamera:
138
138
  frame.paste(pic, (left, top))
139
139
  pic = frame
140
140
 
141
- pic = pic.resize((pic.width * scale, pic.height * scale), Image.NEAREST)
141
+ pic = pic.resize((pic.width * scale, pic.height * scale), Image.Resampling.NEAREST)
142
142
 
143
143
  ext = os.path.splitext(path)[1]
144
144
  if ext == "" or ext.lower() == ".png":