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/LK_Device.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, math, struct, traceback, zlib, copy, hashlib, os, datetime, platform, json, base64
6
6
  import serial, serial.tools.list_ports
@@ -31,7 +31,7 @@ class LK_Device(ABC):
31
31
  "OFW_FW_VER":0x56,
32
32
  "OFW_PCB_VER":0x68,
33
33
  "OFW_USART_1_0M_SPEED":0x3C,
34
- "OFW_USART_1_7M_SPEED":0x3E,
34
+ "OFW_USART_1_5M_SPEED":0x3E,
35
35
  "OFW_CART_PWR_ON":0x2F,
36
36
  "OFW_CART_PWR_OFF":0x2E,
37
37
  "OFW_QUERY_CART_PWR":0x5D,
@@ -114,6 +114,7 @@ class LK_Device(ABC):
114
114
  "PULLUPS_ENABLED":[8, 0x0E],
115
115
  "AUTO_POWEROFF_ENABLED":[8, 0x0F],
116
116
  "AGB_IRQ_ENABLED":[8, 0x10],
117
+ "DMG_AUDIO_ENABLED":[8, 0x11],
117
118
  }
118
119
 
119
120
  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}
@@ -146,6 +147,7 @@ class LK_Device(ABC):
146
147
  AGB_READ_METHODS = ["Single", "MemCpy", "Stream"]
147
148
  LAST_CHECK_ACTIVE = 0
148
149
  USER_ANSWER = None
150
+ SKIP_POWERCYCLE = False
149
151
 
150
152
  def __init__(self):
151
153
  pass
@@ -305,7 +307,7 @@ class LK_Device(ABC):
305
307
  for mode in flashcarts.keys():
306
308
  for key in sorted(flashcarts[mode].keys(), key=str.casefold):
307
309
  self.SUPPORTED_CARTS[mode][key] = flashcarts[mode][key]
308
-
310
+
309
311
  def IsConnected(self):
310
312
  if self.DEVICE is None: return False
311
313
  if not self.DEVICE.isOpen(): return False
@@ -679,6 +681,12 @@ class LK_Device(ABC):
679
681
  self.CartPowerCycle(delay=delay)
680
682
  return
681
683
 
684
+ if self.FW["fw_ver"] < 12:
685
+ self.CANCEL_ARGS.update({"info_type":"msgbox_critical", "info_msg":"This cartridge type requires at least firmware version L12."})
686
+ self.CANCEL = True
687
+ self.USER_ANSWER = None
688
+ return False
689
+
682
690
  mode = self.GetMode()
683
691
  var_state = self.GetVarState()
684
692
 
@@ -714,7 +722,7 @@ class LK_Device(ABC):
714
722
  continue
715
723
 
716
724
  def CartPowerCycle(self, delay=0.1):
717
- if self.CanPowerCycleCart():
725
+ if self.CanPowerCycleCart() and not self.SKIP_POWERCYCLE:
718
726
  dprint("Power cycling cartridge with a delay of {:.1f} seconds".format(delay))
719
727
  self.CartPowerOff(delay=delay)
720
728
  self.CartPowerOn(delay=delay)
@@ -836,6 +844,7 @@ class LK_Device(ABC):
836
844
  self._write(self.DEVICE_CMD["SET_VOLTAGE_5V"], wait=self.FW["fw_ver"] >= 12)
837
845
  self._set_fw_variable("DMG_READ_METHOD", self.DMG_READ_METHOD)
838
846
  self._set_fw_variable("CART_MODE", 1)
847
+ #if self.FW["fw_ver"] >= 14: self._set_fw_variable("DMG_AUDIO_ENABLED", 0)
839
848
  self.MODE = "DMG"
840
849
  elif mode == "AGB":
841
850
  self._write(self.DEVICE_CMD["SET_MODE_AGB"], wait=self.FW["fw_ver"] >= 12)
@@ -860,6 +869,7 @@ class LK_Device(ABC):
860
869
  dprint(f"Setting automatic power off time value to {value}")
861
870
  self._set_fw_variable("AUTO_POWEROFF_TIME", value)
862
871
  self._set_fw_variable("AUTO_POWEROFF_ENABLED", 1 if value != 0 else 0)
872
+ self.SKIP_POWERCYCLE = False if value != 0 else True
863
873
 
864
874
  def GetSupportedCartridgesDMG(self):
865
875
  return (list(self.SUPPORTED_CARTS['DMG'].keys()), list(self.SUPPORTED_CARTS['DMG'].values()))
@@ -889,13 +899,9 @@ class LK_Device(ABC):
889
899
  self.SIGNAL = None
890
900
 
891
901
  def Debug(self):
892
- # for i in range(0, 0x100000):
893
- # print(hex(i), self._set_fw_variable("ADDRESS", i), end="\r", flush=True)
894
902
  return
895
903
 
896
904
  def ReadInfo(self, setPinsAsInputs=False, checkRtc=True):
897
- self.Debug()
898
-
899
905
  if not self.IsConnected(): raise ConnectionError("Couldn’t access the the device.")
900
906
  data = {}
901
907
  self.SIGNAL = None
@@ -959,6 +965,7 @@ class LK_Device(ABC):
959
965
  data["rtc_string"] = _mbc.GetRTCString()
960
966
  except:
961
967
  data["rtc_string"] = "Invalid data"
968
+
962
969
  if _mbc.GetName() == "G-MMC1":
963
970
  try:
964
971
  temp = bytearray([0] * 0x100000)
@@ -976,6 +983,21 @@ class LK_Device(ABC):
976
983
  print(traceback.format_exc())
977
984
  print("{:s}An error occured while trying to read the hidden sector data of the NP GB-Memory cartridge.{:s}".format(ANSI.RED, ANSI.RESET))
978
985
 
986
+ elif _mbc.GetName() == "MAC-GBD":
987
+ dprint("Reading Game Boy Camera calibration data...")
988
+ _mbc.EnableRAM(True)
989
+ _mbc.SelectBankRAM(2)
990
+ temp = self.ReadRAM(address=0xFF2, length=0xE)
991
+ if temp != bytearray(temp[0] * len(temp)):
992
+ data["gbcamera_calibration1"] = temp
993
+ dprint("Game Boy Camera calibration data 1:", ''.join(format(x, '02X') for x in temp))
994
+ _mbc.SelectBankRAM(8)
995
+ temp = self.ReadRAM(address=0x1FF2, length=0xE)
996
+ if temp != bytearray(temp[0] * len(temp)):
997
+ data["gbcamera_calibration2"] = temp
998
+ dprint("Game Boy Camera calibration data 2:", ''.join(format(x, '02X') for x in temp))
999
+ _mbc.EnableRAM(False)
1000
+
979
1001
  elif self.MODE == "AGB":
980
1002
  # Unlock DACS carts on older firmware
981
1003
  if not self.CanPowerCycleCart() or self.FW["fw_ver"] == 1:
@@ -1084,6 +1106,7 @@ class LK_Device(ABC):
1084
1106
  if self.MODE == "DMG": #and setPinsAsInputs:
1085
1107
  self._write(self.DEVICE_CMD["SET_ADDR_AS_INPUTS"], wait=self.FW["fw_ver"] >= 12)
1086
1108
 
1109
+ #self.Debug()
1087
1110
  return data
1088
1111
 
1089
1112
  def _DetectCartridge(self, args): # Wrapper for thread call
@@ -1119,9 +1142,9 @@ class LK_Device(ABC):
1119
1142
 
1120
1143
  # Disable Auto Power Off
1121
1144
  _apoe = False
1122
- if self.CanPowerCycleCart():
1123
- self.CartPowerCycle()
1124
- if self.FW["fw_ver"] >= 12:
1145
+ if self.FW["fw_ver"] >= 12 and self.SKIP_POWERCYCLE is False:
1146
+ if self.CanPowerCycleCart():
1147
+ self.CartPowerCycle()
1125
1148
  _apoe = self._get_fw_variable("AUTO_POWEROFF_ENABLED") == 1
1126
1149
  if _apoe is True:
1127
1150
  _apot = self._get_fw_variable("AUTO_POWEROFF_TIME")
@@ -1135,8 +1158,11 @@ class LK_Device(ABC):
1135
1158
  supported_carts = list(self.SUPPORTED_CARTS[self.MODE].values())
1136
1159
  cart_type = supported_carts[cart_type_id]
1137
1160
 
1161
+ # Skip DMG save type detection
1162
+ if self.MODE == "DMG" and cart_type_id == 0: checkSaveType = False
1163
+
1138
1164
  # Preparations
1139
- if "command_set" in cart_type and cart_type["command_set"] in ("DMG-MBC5-32M-FLASH", "GBAMP"):
1165
+ if ("command_set" in cart_type and cart_type["command_set"] in ("DMG-MBC5-32M-FLASH", "GBAMP")) or ("dmg-mbc5-32m-flash" in cart_type):
1140
1166
  checkSaveType = False
1141
1167
  elif self.MODE == "AGB" and "flash_bank_select_type" in cart_type and cart_type["flash_bank_select_type"] == 1:
1142
1168
  save_size = 65536
@@ -1238,22 +1264,28 @@ class LK_Device(ABC):
1238
1264
  if ret is not False:
1239
1265
  (flash_save_id, _) = ret
1240
1266
  try:
1241
- if flash_save_id != 0 and flash_save_id in Util.AGB_Flash_Save_Chips:
1242
- save_size = Util.AGB_Flash_Save_Chips_Sizes[list(Util.AGB_Flash_Save_Chips).index(flash_save_id)]
1243
- save_chip = Util.AGB_Flash_Save_Chips[flash_save_id]
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:
1267
+ if flash_save_id != 0:
1268
+ if flash_save_id in Util.AGB_Flash_Save_Chips:
1269
+ save_size = Util.AGB_Flash_Save_Chips_Sizes[list(Util.AGB_Flash_Save_Chips).index(flash_save_id)]
1270
+ save_chip = Util.AGB_Flash_Save_Chips[flash_save_id]
1271
+ if flash_save_id in (0xBF4B, 0xBF5B, 0xFFFF, 0xBF6D): # Bootlegs
1272
+ if self.INFO["data"][0:0x20000] == bytearray([0xFF] * 0x20000):
1273
+ save_type = 5
1274
+ elif self.INFO["data"][0:0x10000] == self.INFO["data"][0x10000:0x20000]:
1275
+ save_type = 4
1276
+ else:
1277
+ save_type = 5
1278
+ elif save_size == 131072:
1249
1279
  save_type = 5
1250
- elif save_size == 131072:
1251
- save_type = 5
1252
- elif save_size == 65536:
1253
- save_type = 4
1280
+ elif save_size == 65536:
1281
+ save_type = 4
1282
+ else: # Other bootleg chips
1283
+ save_type = 0
1284
+ save_size = 0
1285
+ save_chip = f"Unknown FLASH save chip (0x{flash_save_id:04X})"
1254
1286
  except:
1255
1287
  pass
1256
-
1288
+
1257
1289
  if save_type is None:
1258
1290
  checkBatterylessSRAM = True
1259
1291
  if info["dacs_8m"] is True:
@@ -1284,8 +1316,8 @@ class LK_Device(ABC):
1284
1316
  save_size = Util.find_size(self.INFO["data"], len(self.INFO["data"]))
1285
1317
  eeprom_64k = self.INFO["data"]
1286
1318
  if eeprom_64k in (bytearray([0xFF] * len(eeprom_64k)), bytearray([0] * len(eeprom_64k))):
1287
- save_type = None
1288
1319
  save_size = 0
1320
+ save_type = 0
1289
1321
  elif (eeprom_4k == eeprom_64k[:len(eeprom_4k)]):
1290
1322
  save_type = 2
1291
1323
  save_size = 8192
@@ -1306,7 +1338,7 @@ class LK_Device(ABC):
1306
1338
  self.INFO["last_action"] = 0
1307
1339
  self.INFO["action"] = None
1308
1340
 
1309
- if self.CanPowerCycleCart() and _apoe is True:
1341
+ if self.CanPowerCycleCart() and _apoe is True and self.SKIP_POWERCYCLE is False:
1310
1342
  self._set_fw_variable("AUTO_POWEROFF_TIME", _apot)
1311
1343
 
1312
1344
  return (info, save_size, save_type, save_chip, sram_unstable, cart_types, cart_type_id, cfi_s, cfi, flash_id, detected_size)
@@ -1378,6 +1410,7 @@ class LK_Device(ABC):
1378
1410
 
1379
1411
  def ReadFlashSaveID(self):
1380
1412
  # Check if actually SRAM/FRAM
1413
+ dprint("Checking Flash ID of Save Memory")
1381
1414
  test1 = self._cart_read(0, 0x10, agb_save_flash=True)[4]
1382
1415
  self._cart_write_flash([[ 0x0004, test1 ^ 0xFF ]])
1383
1416
  test2 = self._cart_read(0, 0x10, agb_save_flash=True)[4]
@@ -1735,7 +1768,6 @@ class LK_Device(ABC):
1735
1768
  self._set_fw_variable("ADDRESS", address)
1736
1769
  elif self.MODE == "AGB":
1737
1770
  self._set_fw_variable("ADDRESS", address >> 1)
1738
- # print("==>", hex(self._get_fw_variable("ADDRESS")), hex(self._get_fw_variable("TRANSFER_SIZE")), hex(self._get_fw_variable("BUFFER_SIZE")))
1739
1771
 
1740
1772
  skip_init = True
1741
1773
 
@@ -1839,9 +1871,6 @@ class LK_Device(ABC):
1839
1871
  self._write(buffer[i*length:i*length+length])
1840
1872
  ret = self._read(1)
1841
1873
  if ret not in (0x01, 0x03):
1842
- #self.CANCEL_ARGS.update({"info_type":"msgbox_critical", "info_msg":"Flash write error (response = {:s}) in iteration {:d} while trying to write 0x{:X} bytes".format(str(ret), i, length)})
1843
- #self.CANCEL = True
1844
- #self.ERROR = True
1845
1874
  return False
1846
1875
 
1847
1876
  self._cart_write(address + length - 1, 0xFF)
@@ -1984,7 +2013,7 @@ class LK_Device(ABC):
1984
2013
  buffer2 = self.ReadROM(0x80, 0x40)
1985
2014
  return buffer1 == buffer2
1986
2015
 
1987
- def CompareCRC32(self, buffer, offset, length, address, flashcart=None, max_length=0x20000, reset=False):
2016
+ def CompareCRC32(self, buffer, offset, length, address, flashcart=None, max_length=0x20000, reset=False, mbc=None, bank=0):
1988
2017
  left = length
1989
2018
  chunk_pos = 0
1990
2019
  verified = False
@@ -2010,6 +2039,8 @@ class LK_Device(ABC):
2010
2039
  if crc32_expected != crc32_calculated:
2011
2040
  if i == 0 and flashcart is not None:
2012
2041
  flashcart.Reset(full_reset=True)
2042
+ if mbc is not None:
2043
+ mbc.SelectBankROM(bank)
2013
2044
  verified = (crc32_expected, crc32_calculated)
2014
2045
  continue
2015
2046
  else:
@@ -2065,11 +2096,24 @@ class LK_Device(ABC):
2065
2096
  cmds = []
2066
2097
  cmds_reset = []
2067
2098
  cmds_unlock_read = []
2068
- for f in range(1, len(supported_carts)):
2069
- cart_type = supported_carts[f]
2099
+
2100
+ for cart_type in sorted(supported_carts, key=lambda c: 'm29w640' not in c): # m29w640 first because of corruption risk
2101
+ f = supported_carts.index(cart_type)
2070
2102
  if "command_set" not in cart_type: continue
2071
2103
  if "manual_select" in cart_type and cart_type["manual_select"] is True: continue
2072
- if self.MODE == "DMG" and cart_type["command_set"] == "BLAZE_XPLODER":
2104
+ if self.MODE == "DMG" and "m29w640" in cart_type:
2105
+ self._cart_write_flash(cart_type["commands"]["reset"])
2106
+ rom1 = self._cart_read(0, 8)
2107
+ self._cart_write_flash(cart_type["commands"]["read_identifier"])
2108
+ rom2 = self._cart_read(0, 8)
2109
+ if rom1 != rom2 and list(rom2[:len(cart_type["flash_ids"][0])]) == cart_type["flash_ids"][0]:
2110
+ found = True
2111
+ flash_types.append(f)
2112
+ dprint("Found a M29W640 cartridge")
2113
+ self._cart_write_flash(cart_type["commands"]["reset"])
2114
+ break
2115
+ continue
2116
+ elif self.MODE == "DMG" and cart_type["command_set"] == "BLAZE_XPLODER":
2073
2117
  self._cart_read(0x102, 1)
2074
2118
  self._cart_write(6, 1)
2075
2119
  self._cart_write_flash(cart_type["commands"]["reset"])
@@ -2110,7 +2154,7 @@ class LK_Device(ABC):
2110
2154
  self._cart_write_flash(cart_type["commands"]["reset"])
2111
2155
  break
2112
2156
  continue
2113
- elif self.MODE == "DMG" and cart_type["command_set"] == "DMG-MBC5-32M-FLASH":
2157
+ elif self.MODE == "DMG" and "dmg-mbc5-32m-flash" in cart_type:
2114
2158
  self._set_we_pin_audio()
2115
2159
  self._cart_write_flash(cart_type["commands"]["unlock"], flashcart=False)
2116
2160
  self._cart_write_flash(cart_type["commands"]["reset"])
@@ -2200,6 +2244,7 @@ class LK_Device(ABC):
2200
2244
  self._cart_write(cmd[0], cmd[1], flashcart=True)
2201
2245
 
2202
2246
  flash_id_cmds = sorted(cmds, key=lambda x: x['read_identifier'][0][0])
2247
+ read_cfi_cmds = []
2203
2248
 
2204
2249
  rom_s = " ".join(format(x, '02X') for x in rom)
2205
2250
  if self.MODE == "DMG":
@@ -2225,41 +2270,13 @@ class LK_Device(ABC):
2225
2270
  cmp = self._cart_read(0, 8)
2226
2271
  self._cart_write_flash(flash_id_cmds[i]["reset"], flashcart=True)
2227
2272
  if rom != cmp: # ROM data changed
2228
- if "read_cfi" not in flash_id_cmds[i]:
2229
- flash_id_cmds[i]["read_cfi"] = [[ flash_id_cmds[i]["read_identifier"][0][0], 0x98 ]]
2230
- self._cart_write_flash(flash_id_cmds[i]["read_cfi"], flashcart=True)
2231
- cfi_buffer = self._cart_read(0, 0x400)
2232
- self._cart_write_flash(flash_id_cmds[i]["reset"], flashcart=True)
2233
2273
  flash_id_methods.append([we - 1, i, list(cmp), cfi_buffer, flash_id_cmds[i]["read_identifier"]])
2234
-
2235
- if ".dev" in Util.VERSION_PEP440 or Util.DEBUG:
2236
- with open(Util.CONFIG_PATH + "/debug_cfi.bin", "wb") as f: f.write(cfi_buffer)
2237
- try:
2238
- magic = "{:s}{:s}{:s}".format(chr(cfi_buffer[0x20]), chr(cfi_buffer[0x22]), chr(cfi_buffer[0x24]))
2239
- d_swap = (0, 0)
2240
- if magic == "QRY": # D0D1 not swapped
2241
- pass
2242
- elif magic == "RQZ": # D0D1 swapped
2243
- d_swap = [(0, 1)]
2244
- for j2 in range(0, len(d_swap)):
2245
- for j in range(0, len(cfi_buffer)):
2246
- cfi_buffer[j] = bitswap(cfi_buffer[j], d_swap[j2])
2247
- elif magic == "\x92\x91\x9A": # D0D1+D6D7 swapped
2248
- d_swap = [( 0, 1 ), ( 6, 7 )]
2249
- for j2 in range(0, len(d_swap)):
2250
- for j in range(0, len(cfi_buffer)):
2251
- cfi_buffer[j] = bitswap(cfi_buffer[j], d_swap[j2])
2252
- if ".dev" in Util.VERSION_PEP440 or Util.DEBUG:
2253
- with open(Util.CONFIG_PATH + "/debug_cfi_d0d1+d6d7.bin", "wb") as f: f.write(cfi_buffer)
2254
- else:
2255
- cfi_buffer = None
2256
- except:
2257
- cfi_buffer = None
2258
-
2259
2274
  if self.MODE == "DMG":
2260
2275
  flash_id_s += "[{:s}/{:4X}/{:2X}] {:s}\n".format(we_pins[we-1].ljust(5), flash_id_cmds[i]["read_identifier"][0][0], flash_id_cmds[i]["read_identifier"][0][1], ' '.join(format(x, '02X') for x in cmp))
2261
2276
  else:
2262
2277
  flash_id_s += "[{:6X}/{:4X}] {:s}\n".format(flash_id_cmds[i]["read_identifier"][0][0], flash_id_cmds[i]["read_identifier"][0][1], ' '.join(format(x, '02X') for x in cmp))
2278
+ flash_id_cmds[i]["read_cfi"] = [ flash_id_cmds[i]["read_identifier"][0][0], 0x98 ]
2279
+ read_cfi_cmds.append(flash_id_cmds[i]["read_cfi"])
2263
2280
 
2264
2281
  dprint(f"Found {len(flash_id_methods):d} result(s)")
2265
2282
  self._cart_write_flash([[0, 0xFF]], True)
@@ -2293,10 +2310,55 @@ class LK_Device(ABC):
2293
2310
 
2294
2311
  dprint("Compatible flash types:", [(index, supported_carts[index]["names"][0]) for index in flash_types])
2295
2312
 
2313
+ try:
2314
+ if len(flash_types) > 0 and "read_cfi" in supported_carts[flash_types[0]]["commands"]:
2315
+ read_cfi_cmd = supported_carts[flash_types[0]]["commands"]["read_cfi"]
2316
+ reset_cmd = supported_carts[flash_types[0]]["commands"]["reset"]
2317
+ else:
2318
+ if len(read_cfi_cmds) == 0:
2319
+ read_cfi_cmd = [ [0, 0x98] ]
2320
+ else:
2321
+ read_cfi_cmd = [ read_cfi_cmds[0] ]
2322
+ reset_cmd = flash_id_cmds[0]["reset"]
2323
+ self._cart_write_flash(read_cfi_cmd, flashcart=(self.MODE == "AGB"))
2324
+ cfi_buffer = self._cart_read(0, 0x400)
2325
+ self._cart_write_flash(reset_cmd, flashcart=(self.MODE == "AGB"))
2326
+
2327
+ if ".dev" in Util.VERSION_PEP440 or Util.DEBUG:
2328
+ with open(Util.CONFIG_PATH + "/debug_cfi.bin", "wb") as f: f.write(cfi_buffer)
2329
+
2330
+ found = False
2331
+ for o in ((0x20, 2), (0x10, 1)):
2332
+ magic = "{:s}{:s}{:s}".format(chr(cfi_buffer[o[0]]), chr(cfi_buffer[o[0] + (1 * o[1])]), chr(cfi_buffer[o[0] + (2 * o[1])]))
2333
+ dprint("CFI magic:", hex(o[0]), hex(o[0] + (1 * o[1])), hex(o[0] + (2 * o[1])), "=", str(magic))
2334
+ d_swap = (0, 0)
2335
+ if magic == "QRY": # D0D1 not swapped
2336
+ found = True
2337
+ elif magic == "RQZ": # D0D1 swapped
2338
+ d_swap = [(0, 1)]
2339
+ for j2 in range(0, len(d_swap)):
2340
+ for j in range(0, len(cfi_buffer)):
2341
+ cfi_buffer[j] = bitswap(cfi_buffer[j], d_swap[j2])
2342
+ found = True
2343
+ elif magic == "\x92\x91\x9A": # D0D1+D6D7 swapped
2344
+ d_swap = [( 0, 1 ), ( 6, 7 )]
2345
+ for j2 in range(0, len(d_swap)):
2346
+ for j in range(0, len(cfi_buffer)):
2347
+ cfi_buffer[j] = bitswap(cfi_buffer[j], d_swap[j2])
2348
+ if ".dev" in Util.VERSION_PEP440 or Util.DEBUG:
2349
+ with open(Util.CONFIG_PATH + "/debug_cfi_d0d1+d6d7.bin", "wb") as f: f.write(cfi_buffer)
2350
+ found = True
2351
+ if found: break
2352
+ if found is False:
2353
+ cfi_buffer = None
2354
+ except:
2355
+ cfi_buffer = None
2356
+
2296
2357
  if cfi_buffer is None or len(cfi_buffer) < 0x400:
2297
2358
  cfi = False
2298
2359
  else:
2299
2360
  cfi = ParseCFI(cfi_buffer)
2361
+
2300
2362
  if cfi is not False:
2301
2363
  cfi["raw"] = cfi_buffer
2302
2364
  s = ""
@@ -2472,9 +2534,7 @@ class LK_Device(ABC):
2472
2534
 
2473
2535
  # Firmware check L8
2474
2536
  if self.FW["fw_ver"] < 8 and flashcart and "enable_pullups" in cart_type:
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))
2537
+ 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.GetName(), ANSI.RESET))
2478
2538
  del(cart_type["enable_pullups"])
2479
2539
  # Firmware check L8
2480
2540
 
@@ -2535,9 +2595,6 @@ class LK_Device(ABC):
2535
2595
  self.INFO["dump_info"]["agb_read_method"] = "3D Memory"
2536
2596
 
2537
2597
  elif flashcart and "command_set" in cart_type and cart_type["command_set"] == "GBAMP":
2538
- # if not self.CanPowerCycleCart():
2539
- # self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type is not compatible with your " + self.DEVICE_NAME + " hardware revision due to missing cartridge power cycling support.", "abortable":False})
2540
- # return False
2541
2598
  self.INFO["dump_info"]["agb_read_method"] = "GBA Movie Player"
2542
2599
  if not "verify_write" in args: self.CartPowerCycleOrAskReconnect()
2543
2600
  flashcart.Unlock()
@@ -2608,9 +2665,6 @@ class LK_Device(ABC):
2608
2665
  else:
2609
2666
  rom_banks = 1
2610
2667
  rom_bank_size = 0x2000000
2611
-
2612
- #if "header" in self.INFO["dump_info"] and "dacs_8m" in self.INFO["dump_info"]["header"] and self.INFO["dump_info"]["header"]["dacs_8m"] is True:
2613
- # self.SetAGBReadMethod(0)
2614
2668
 
2615
2669
  if self.ERROR: return
2616
2670
 
@@ -2635,9 +2689,12 @@ class LK_Device(ABC):
2635
2689
  else:
2636
2690
  self._write(self.DEVICE_CMD["DISABLE_PULLUPS"], wait=True)
2637
2691
  dprint("Pullups disabled")
2692
+
2638
2693
  if self.FW["fw_ver"] >= 12:
2639
- if "enable_pullup_wr" in cart_type: # Joey Jr bug workaround
2640
- self._set_fw_variable("PULLUPS_ENABLED", 2 if cart_type["enable_pullup_wr"] is True else 0)
2694
+ if self.MODE == "DMG":
2695
+ # Joey Jr bug workaround
2696
+ enable_pullup_wr = 2 if (("enable_pullup_wr" in cart_type and cart_type["enable_pullup_wr"] is True) or ("force_wr_pullup" in args and args["force_wr_pullup"] is True)) else 0
2697
+ self._set_fw_variable("PULLUPS_ENABLED", enable_pullup_wr)
2641
2698
 
2642
2699
  buffer = bytearray(size)
2643
2700
  max_length = self.MAX_BUFFER_READ
@@ -2661,6 +2718,8 @@ class LK_Device(ABC):
2661
2718
  end_bank = math.ceil((buffer_pos + args["verify_len"]) / rom_bank_size)
2662
2719
  rom_banks = end_bank
2663
2720
  elif "bl_offset" in args:
2721
+ if "bl_layout" in args and args["bl_layout"] in (1, 2):
2722
+ args["bl_size"] <<= 1
2664
2723
  buffer_pos = args["bl_offset"]
2665
2724
  start_address = buffer_pos
2666
2725
  end_address = args["bl_offset"] + args["bl_size"]
@@ -2765,7 +2824,13 @@ class LK_Device(ABC):
2765
2824
  elif lives < 20:
2766
2825
  lives = 20
2767
2826
 
2768
- if file is not None: file.write(temp)
2827
+ if file is not None:
2828
+ if "bl_layout" in args and args["bl_layout"] == 1:
2829
+ file.write(temp[0x0000:0x2000])
2830
+ elif "bl_layout" in args and args["bl_layout"] == 2:
2831
+ file.write(temp[0x2000:0x4000])
2832
+ else:
2833
+ file.write(temp)
2769
2834
  buffer[pos_total:pos_total+len(temp)] = temp
2770
2835
  pos_total += len(temp)
2771
2836
 
@@ -2823,6 +2888,7 @@ class LK_Device(ABC):
2823
2888
 
2824
2889
  # Calculate Global Checksum
2825
2890
  if self.MODE == "DMG":
2891
+ self.INFO["dump_info"]["header"].update(RomFileDMG(buffer[:0x180]).GetHeader(unchanged=True))
2826
2892
  if _mbc.GetName() == "MMM01":
2827
2893
  self.INFO["dump_info"]["header"].update(RomFileDMG(buffer[-0x8000:-0x8000+0x180]).GetHeader(unchanged=True))
2828
2894
  elif _mbc.GetName() == "Sachen":
@@ -2942,9 +3008,12 @@ class LK_Device(ABC):
2942
3008
  if "cart_type" in args and args["cart_type"] >= 0:
2943
3009
  supported_carts = list(self.SUPPORTED_CARTS[self.MODE].values())
2944
3010
  cart_type = copy.deepcopy(supported_carts[args["cart_type"]])
3011
+
2945
3012
  if self.FW["fw_ver"] >= 12:
2946
- if "enable_pullup_wr" in cart_type: # Joey Jr bug workaround
2947
- self._set_fw_variable("PULLUPS_ENABLED", 2 if cart_type["enable_pullup_wr"] is True else 0)
3013
+ if self.MODE == "DMG":
3014
+ # Joey Jr bug workaround
3015
+ enable_pullup_wr = 2 if (("enable_pullup_wr" in cart_type and cart_type["enable_pullup_wr"] is True) or ("force_wr_pullup" in args and args["force_wr_pullup"] is True)) else 0
3016
+ self._set_fw_variable("PULLUPS_ENABLED", enable_pullup_wr)
2948
3017
 
2949
3018
  self._set_fw_variable("STATUS_REGISTER_MASK", 0x80)
2950
3019
  self._set_fw_variable("STATUS_REGISTER_VALUE", 0x80)
@@ -2960,7 +3029,9 @@ class LK_Device(ABC):
2960
3029
  save_size = args["save_size"]
2961
3030
  else:
2962
3031
  save_size = Util.DMG_Header_RAM_Sizes_Flasher_Map[Util.DMG_Header_RAM_Sizes_Map.index(args["save_type"])]
3032
+
2963
3033
  ram_banks = _mbc.GetRAMBanks(save_size)
3034
+
2964
3035
  buffer_len = min(0x200, _mbc.GetRAMBankSize())
2965
3036
  self._write(self.DEVICE_CMD["SET_MODE_DMG"], wait=self.FW["fw_ver"] >= 12)
2966
3037
  self._set_fw_variable("DMG_WRITE_CS_PULSE", 0)
@@ -3054,8 +3125,10 @@ class LK_Device(ABC):
3054
3125
  return False
3055
3126
  buffer_len = 0x1000
3056
3127
  (agb_flash_chip, _) = ret
3057
- if agb_flash_chip in (0xBF5B, 0xFFFF): # Bootlegs
3128
+ if agb_flash_chip in (0xBF4B, 0xBF5B, 0xFFFF): # Bootlegs
3058
3129
  buffer_len = 0x800
3130
+ elif agb_flash_chip == 0xBF6D:
3131
+ buffer_len = 0x8000
3059
3132
  elif args["save_type"] == 6: # DACS
3060
3133
  # self._write(self.DEVICE_CMD["AGB_BOOTUP_SEQUENCE"], wait=self.FW["fw_ver"] >= 12)
3061
3134
  empty_data_byte = 0xFF
@@ -3121,6 +3194,9 @@ class LK_Device(ABC):
3121
3194
  if args["mode"] == 2: # Backup
3122
3195
  action = "SAVE_READ"
3123
3196
  buffer = bytearray()
3197
+ if self.MODE == "DMG" and args["save_type"] == 0x204: # Unlicensed PHOTO!
3198
+ ram_banks = 16
3199
+
3124
3200
  elif args["mode"] == 3: # Restore
3125
3201
  action = "SAVE_WRITE"
3126
3202
  self.INFO["save_erase"] = args["erase"]
@@ -3128,6 +3204,9 @@ class LK_Device(ABC):
3128
3204
  buffer = bytearray([ empty_data_byte ] * save_size)
3129
3205
  if self.MODE == "DMG" and _mbc.GetName() == "Xploder GB":
3130
3206
  buffer[0] = 0x00
3207
+ elif self.MODE == "DMG" and _mbc.GetName() == "MAC-GBD":
3208
+ buffer[0x11B2:0x11D7] = bytearray.fromhex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D616769631115")
3209
+ buffer[0x11D7:0x11FC] = buffer[0x11B2:0x11D7]
3131
3210
  else:
3132
3211
  if args["path"] is None:
3133
3212
  if "buffer" in args:
@@ -3138,16 +3217,18 @@ class LK_Device(ABC):
3138
3217
  with open(args["path"], "rb") as f:
3139
3218
  buffer = bytearray(f.read())
3140
3219
 
3220
+ if self.MODE == "DMG" and args["save_type"] == 0x204: # Unlicensed PHOTO!
3221
+ ram_banks = 16
3222
+ if len(buffer) <= 0x20000:
3223
+ save_size = len(buffer)
3224
+ args["save_type"] = 0x04
3225
+
3141
3226
  # Fill too small file
3142
3227
  if not (self.MODE == "AGB" and args["save_type"] == 6): # Not DACS
3143
3228
  if args["mode"] == 3:
3144
3229
  while len(buffer) < save_size:
3145
3230
  buffer += bytearray(buffer)
3146
3231
 
3147
- #if self.MODE == "AGB" and "ereader" in self.INFO and self.INFO["ereader"] is True: # e-Reader
3148
- # buffer[0xFF80:0x10000] = bytearray([0] * 0x80)
3149
- # buffer[0x1FF80:0x20000] = bytearray([0] * 0x80)
3150
-
3151
3232
  # Main loop
3152
3233
  if not (args["mode"] == 2 and "verify_write" in args and args["verify_write"]):
3153
3234
  self.INFO["action"] = self.ACTIONS[action]
@@ -3183,7 +3264,7 @@ class LK_Device(ABC):
3183
3264
  end_address = min(save_size, bank_size)
3184
3265
 
3185
3266
  if save_size > bank_size:
3186
- if args["save_type"] == 8 or agb_flash_chip in (0xBF5B, 0xFFFF): # Bootleg 1M
3267
+ if args["save_type"] == 8 or agb_flash_chip in (0xBF4B, 0xBF5B, 0xFFFF, 0xBF6D): # Bootleg 1M
3187
3268
  dprint("Switching to bootleg save bank {:d}".format(bank))
3188
3269
  self._cart_write(0x1000000, bank)
3189
3270
  elif args["save_type"] == 5: # FLASH 1M
@@ -3198,10 +3279,6 @@ class LK_Device(ABC):
3198
3279
  else:
3199
3280
  dprint("Unknown bank switching method")
3200
3281
  time.sleep(0.05)
3201
-
3202
- # if "detect" in args and args["detect"] is True:
3203
- # start_address = end_address - 64
3204
- # buffer_len = 64
3205
3282
 
3206
3283
  max_length = 64
3207
3284
  dprint("start_address=0x{:X}, end_address=0x{:X}, buffer_len=0x{:X}, buffer_offset=0x{:X}".format(start_address, end_address, buffer_len, buffer_offset))
@@ -3259,7 +3336,6 @@ class LK_Device(ABC):
3259
3336
  continue
3260
3337
 
3261
3338
  if xe == 2 and in_temp[0] != in_temp[1]:
3262
- # print(in_temp[0], in_temp[1], sep="\n")
3263
3339
  self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Failed to read save data consistently. Please ensure that the cartridge contacts are clean.", "abortable":False})
3264
3340
  return False
3265
3341
 
@@ -3381,11 +3457,6 @@ class LK_Device(ABC):
3381
3457
 
3382
3458
  pos += buffer_len
3383
3459
  buffer_offset += buffer_len
3384
-
3385
- # if "detect" in args and args["detect"] is True:
3386
- # buffer += bytearray(end_address - 64)
3387
- # pos += end_address - 64
3388
- # buffer_offset += end_address - 64
3389
3460
 
3390
3461
  verified = False
3391
3462
  if args["mode"] == 2: # Backup
@@ -3421,6 +3492,13 @@ class LK_Device(ABC):
3421
3492
  if self.MODE == "AGB" and cart_type is not None and "flash_bank_select_type" in cart_type and cart_type["flash_bank_select_type"] == 1:
3422
3493
  buffer[5] = sram_5
3423
3494
 
3495
+ # PHOTO! rolls
3496
+ if self.MODE == "DMG" and args["save_type"] == 0x204:
3497
+ for i in range(8, 64):
3498
+ _mbc.SelectBankROM(i)
3499
+ buffer += self.ReadROM(0x4000, 0x4000)
3500
+ self.SetProgress({"action":"UPDATE_POS", "pos":len(buffer)})
3501
+
3424
3502
  if args["path"] is not None:
3425
3503
  if self.MODE == "DMG" and _mbc.GetName() == "MBC2":
3426
3504
  for i in range(0, len(buffer)):
@@ -3447,11 +3525,21 @@ class LK_Device(ABC):
3447
3525
  advance = "rtc_advance" in args and args["rtc_advance"]
3448
3526
  self.SetProgress({"action":"UPDATE_RTC", "method":"write"})
3449
3527
  if self.MODE == "DMG" and args["rtc"] is True:
3528
+ if "erase" in args and args["erase"] is True:
3529
+ buffer += bytearray([0] * _mbc.GetRTCBufferSize())
3450
3530
  _mbc.WriteRTC(buffer[-_mbc.GetRTCBufferSize():], advance=advance)
3451
3531
  elif self.MODE == "AGB":
3532
+ if "erase" in args and args["erase"] is True:
3533
+ buffer += bytearray([0xFF] * 0x10)
3452
3534
  _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)
3453
3535
  _agb_gpio.WriteRTC(buffer[-0x10:], advance=advance)
3454
3536
 
3537
+ # PHOTO! rolls
3538
+ if self.MODE == "DMG" and args["save_type"] == 0x204 and "cart_type" in args and args["cart_type"] != -1:
3539
+ if len(buffer) > 0x20000:
3540
+ self._FlashROM({'buffer': buffer[0x20000:0x100000], 'path':"", 'cart_type': args["cart_type"], 'override_voltage': False, 'prefer_chip_erase': False, 'fast_read_mode': True, 'verify_write': False, 'fix_header': False, 'fix_bootlogo': False, 'mbc': 252, 'bl_offset': 0x20000, 'bl_size': 0xE0000, 'bl_layout': 0, 'bl_save': True, 'flash_offset': 0x20000, 'flash_size': 0xE0000, 'mode': 4, 'photo_mode': True})
3541
+ args["verify_write"] = False
3542
+
3455
3543
  self.SetProgress({"action":"UPDATE_POS", "pos":len(buffer), "force_update":True})
3456
3544
 
3457
3545
  # ↓↓↓ Write verify
@@ -3484,7 +3572,7 @@ class LK_Device(ABC):
3484
3572
  buffer[0xFF80:0x10000] = self.INFO["data"][0xFF80:0x10000]
3485
3573
  buffer[0x1FF80:0x20000] = self.INFO["data"][0xFF80:0x10000]
3486
3574
 
3487
- elif (self.INFO["data"][:end_address] != buffer[:end_address]):
3575
+ if (self.INFO["data"][:end_address] != buffer[:end_address]):
3488
3576
  msg = ""
3489
3577
  count = 0
3490
3578
  time_start = time.time()
@@ -3540,6 +3628,7 @@ class LK_Device(ABC):
3540
3628
  end_bank = 0
3541
3629
  pos_from = 0
3542
3630
  verify_len = 0
3631
+ enable_pullup_wr = False
3543
3632
 
3544
3633
  if "buffer" in args:
3545
3634
  data_import = args["buffer"]
@@ -3552,6 +3641,20 @@ class LK_Device(ABC):
3552
3641
  if "start_addr" in args and args["start_addr"] > 0:
3553
3642
  data_import = bytearray(b'\xFF' * args["start_addr"]) + data_import
3554
3643
 
3644
+ # Batteryless SRAM
3645
+ if "bl_layout" in args and args["bl_layout"] in (1, 2):
3646
+ args["bl_size"] <<= 1
3647
+ args["flash_size"] <<= 1
3648
+ bl_data_import = bytearray(b'\xFF' * args["bl_size"])
3649
+
3650
+ if args["bl_layout"] == 1:
3651
+ for i in range(0, args["bl_size"] // 0x4000):
3652
+ bl_data_import[i*0x4000:i*0x4000+0x2000] = data_import[i*0x2000:i*0x2000+0x2000]
3653
+ elif args["bl_layout"] == 2:
3654
+ for i in range(0, args["bl_size"] // 0x4000):
3655
+ bl_data_import[i*0x4000+0x2000:i*0x4000+0x2000+0x2000] = data_import[i*0x2000:i*0x2000+0x2000]
3656
+ data_import = bl_data_import
3657
+
3555
3658
  # Pad data
3556
3659
  if len(data_import) > 0:
3557
3660
  if len(data_import) < 0x400:
@@ -3594,24 +3697,23 @@ class LK_Device(ABC):
3594
3697
 
3595
3698
  supported_carts = list(self.SUPPORTED_CARTS[self.MODE].values())
3596
3699
  cart_type = copy.deepcopy(supported_carts[args["cart_type"]])
3700
+ try:
3701
+ cart_name = cart_type["names"][0]
3702
+ except:
3703
+ cart_name = "Unknown"
3704
+
3597
3705
  if cart_type == "RETAIL": return False # Generic ROM Cartridge is not flashable
3598
3706
 
3599
- # Special carts
3600
- # if "power_cycle" in cart_type and cart_type["power_cycle"] is True and not self.CanPowerCycleCart():
3601
- # self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type is not flashable using FlashGBX and your " + self.DEVICE_NAME + " hardware revision due to missing cartridge power cycling support.", "abortable":False})
3602
- # return False
3603
- # Special carts
3604
- # Firmware check L1
3707
+ # Firmware check L2
3605
3708
  if (cart_type["type"] == "DMG" and "write_pin" in cart_type and cart_type["write_pin"] == "WR+RESET" and self.FW["fw_ver"] < 2) or (self.FW["fw_ver"] < 2 and ("pulse_reset_after_write" in cart_type and cart_type["pulse_reset_after_write"] is True)):
3606
- #self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type is not supported by FlashGBX using your " + self.DEVICE_NAME + " hardware revision and/or firmware version.", "abortable":False})
3607
3709
  self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type requires at least firmware version L2.", "abortable":False})
3608
3710
  return False
3609
- # Firmware check L1
3610
3711
  # Firmware check L2
3712
+ # Firmware check L3
3611
3713
  if (self.FW["fw_ver"] < 3 and ("command_set" in cart_type and cart_type["command_set"] == "SHARP") and ("buffer_write" in cart_type["commands"])):
3612
3714
  print("{:s}Note: Update your {:s} firmware to version L3 or higher for a better transfer rate with this cartridge.{:s}".format(ANSI.YELLOW, self.DEVICE_NAME, ANSI.RESET))
3613
3715
  del(cart_type["commands"]["buffer_write"])
3614
- # Firmware check L2
3716
+ # Firmware check L3
3615
3717
  # Firmware check L5
3616
3718
  if (self.FW["fw_ver"] < 5 and ("flash_commands_on_bank_1" in cart_type and cart_type["flash_commands_on_bank_1"] is True)):
3617
3719
  self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type requires at least firmware version L5.", "abortable":False})
@@ -3622,21 +3724,25 @@ class LK_Device(ABC):
3622
3724
  # Firmware check L5
3623
3725
  # Firmware check L8
3624
3726
  if (self.FW["fw_ver"] < 8 and "enable_pullups" in cart_type and cart_type["enable_pullups"] is True):
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))
3727
+ 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.GetName(), ANSI.RESET))
3628
3728
  del(cart_type["enable_pullups"])
3629
3729
  # Firmware check L8
3630
3730
  # Firmware check L12
3631
3731
  if (self.FW["fw_ver"] < 12 and "set_irq_high" in cart_type and cart_type["set_irq_high"] 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))
3732
+ print("{:s}Note: This cartridge may not be fully compatible with your {:s} device until updated to a newer firmware version.{:s}".format(ANSI.YELLOW, self.GetName(), ANSI.RESET))
3635
3733
  del(cart_type["set_irq_high"])
3636
3734
  if (self.FW["fw_ver"] < 12 and "status_register_mask" in cart_type):
3637
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type requires at least firmware version L12.", "abortable":False})
3735
+ if self.FW["pcb_name"] in ("GBxCart RW", ""):
3736
+ self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type requires a different firmware version. Please update your GBxCart RW firmware using the older FlashGBX v4.3 and try again.", "abortable":False})
3737
+ else:
3738
+ self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type requires at least firmware version L12.", "abortable":False})
3638
3739
  return False
3639
3740
  # Firmware check L12
3741
+ # Firmware check L14
3742
+ if (self.FW["fw_ver"] < 14 and "set_audio_high" in cart_type and cart_type["set_audio_high"] is True):
3743
+ self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type requires at least firmware version L14.", "abortable":False})
3744
+ return False
3745
+ # Firmware check L14
3640
3746
 
3641
3747
  # Ensure cart is powered
3642
3748
  if self.CanPowerCycleCart(): self.CartPowerOn()
@@ -3668,7 +3774,7 @@ class LK_Device(ABC):
3668
3774
  flashcart = Flashcart(config=cart_type, fncptr=fc_fncptr)
3669
3775
 
3670
3776
  rumble = "rumble" in flashcart.CONFIG and flashcart.CONFIG["rumble"] is True
3671
-
3777
+
3672
3778
  # ↓↓↓ Set Voltage
3673
3779
  if args["override_voltage"] is not False:
3674
3780
  if args["override_voltage"] == 5:
@@ -3680,20 +3786,22 @@ class LK_Device(ABC):
3680
3786
  elif flashcart.GetVoltage() == 5:
3681
3787
  self._write(self.DEVICE_CMD["SET_VOLTAGE_5V"], wait=self.FW["fw_ver"] >= 12)
3682
3788
  # ↑↑↑ Set Voltage
3683
-
3789
+
3684
3790
  # ↓↓↓ Pad data for full chip erase on sector erase mode
3685
3791
  if not flashcart.SupportsChipErase() and flashcart.SupportsSectorErase() and args["prefer_chip_erase"]:
3686
3792
  print("{:s}Note: Chip erase mode is not supported for this flash cartridge type. Sector erase mode will be used.{:s}\n".format(ANSI.YELLOW, ANSI.RESET))
3687
- flash_size = flashcart.GetFlashSize()
3688
- if flash_size is not False and len(data_import) < flash_size:
3689
- # Pad with FF till the end (with MemoryError fix)
3690
- pad_len = flash_size - len(data_import)
3691
- while pad_len > 0x2000000:
3692
- data_import += bytearray([0xFF] * 0x2000000)
3693
- pad_len -= 0x2000000
3694
- data_import += bytearray([0xFF] * (flash_size - len(data_import)))
3793
+ # Pad data if the user wants to erase the entire cartridge
3794
+ if data_import == bytearray([0xFF] * len(data_import)):
3795
+ flash_size = flashcart.GetFlashSize()
3796
+ if flash_size is not False and len(data_import) < flash_size:
3797
+ # Pad with FF till the end (with MemoryError fix)
3798
+ pad_len = flash_size - len(data_import)
3799
+ while pad_len > 0x2000000:
3800
+ data_import += bytearray([0xFF] * 0x2000000)
3801
+ pad_len -= 0x2000000
3802
+ data_import += bytearray([0xFF] * (flash_size - len(data_import)))
3695
3803
  # ↑↑↑ Pad data for full chip erase on sector erase mode
3696
-
3804
+
3697
3805
  # ↓↓↓ Flashcart configuration
3698
3806
  if self.FW["fw_ver"] >= 8:
3699
3807
  if "enable_pullups" in cart_type:
@@ -3704,9 +3812,11 @@ class LK_Device(ABC):
3704
3812
  self._write(self.DEVICE_CMD["DISABLE_PULLUPS"], wait=True)
3705
3813
  dprint("Pullups disabled")
3706
3814
  if self.FW["fw_ver"] >= 12:
3707
- if "enable_pullup_wr" in cart_type: # Joey Jr bug workaround
3708
- self._set_fw_variable("PULLUPS_ENABLED", 2 if cart_type["enable_pullup_wr"] is True else 0)
3709
- if self.MODE == "AGB":
3815
+ if self.MODE == "DMG":
3816
+ # Joey Jr bug workaround
3817
+ enable_pullup_wr = 2 if (("enable_pullup_wr" in cart_type and cart_type["enable_pullup_wr"] is True) or ("force_wr_pullup" in args and args["force_wr_pullup"] is True)) else 0
3818
+ self._set_fw_variable("PULLUPS_ENABLED", enable_pullup_wr)
3819
+ elif self.MODE == "AGB":
3710
3820
  self._set_fw_variable("AGB_IRQ_ENABLED", 1 if "set_irq_high" in cart_type else 0)
3711
3821
 
3712
3822
  _mbc = None
@@ -3793,17 +3903,13 @@ class LK_Device(ABC):
3793
3903
  temp = 0
3794
3904
  if command_set_type == "AMD":
3795
3905
  temp = 0x01
3796
- #self._write(0x01) # FLASH_COMMAND_SET_AMD
3797
- #self._set_fw_variable("FLASH_SHARP_VERIFY_SR", 0)
3798
3906
  dprint("Using AMD command set")
3799
3907
  elif command_set_type == "INTEL":
3800
3908
  temp = 0x02
3801
- #self._write(0x02) # FLASH_COMMAND_SET_INTEL
3802
3909
  self._set_fw_variable("FLASH_SHARP_VERIFY_SR", 0)
3803
3910
  dprint("Using Intel command set")
3804
3911
  elif command_set_type == "SHARP":
3805
3912
  temp = 0x02
3806
- #self._write(0x02) # FLASH_COMMAND_SET_INTEL
3807
3913
  self._set_fw_variable("FLASH_SHARP_VERIFY_SR", 1)
3808
3914
  dprint("Using Sharp/Intel command set")
3809
3915
  elif command_set_type in ("GBMEMORY", "DMG-MBC5-32M-FLASH"):
@@ -3944,6 +4050,8 @@ class LK_Device(ABC):
3944
4050
  _mbc.SelectBankROM(1)
3945
4051
  if we != 0x00:
3946
4052
  self._set_fw_variable("FLASH_WE_PIN", we)
4053
+ if self.FW["fw_ver"] >= 14 and "set_audio_high" in cart_type:
4054
+ self._set_fw_variable("DMG_AUDIO_ENABLED", 1 if "set_audio_high" in cart_type else 0)
3947
4055
  # ↑↑↑ Preparations
3948
4056
 
3949
4057
  # ↓↓↓ Read Flash ID
@@ -3970,8 +4078,6 @@ class LK_Device(ABC):
3970
4078
  if len(sector_offsets) > 0:
3971
4079
  flash_capacity = sector_offsets[-1][0] + sector_offsets[-1][1]
3972
4080
  if flash_capacity < len(data_import) and not (flashcart.SupportsChipErase() and args["prefer_chip_erase"]):
3973
- #self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"There are not enough flash sectors available to write this ROM. The maximum capacity is {:s}.".format(Util.formatFileSize(size=flash_capacity, asInt=False)), "abortable":False})
3974
- #return False
3975
4081
  sector_offsets = flashcart.GetSectorOffsets(rom_size=len(data_import), rom_bank_size=rom_bank_size)
3976
4082
 
3977
4083
  sector_offsets_hash = base64.urlsafe_b64encode(hashlib.sha1(str(sector_offsets).encode("UTF-8")).digest()).decode("ASCII", "ignore")[:4]
@@ -4026,7 +4132,6 @@ class LK_Device(ABC):
4026
4132
  bl_sectors = []
4027
4133
  for sector in sector_offsets:
4028
4134
  if flash_offset > sector[0]: continue
4029
- #if len(bl_sectors) > 0 and (flash_offset + flash_size) < (sector[0] + sector[1]): break
4030
4135
  if (flash_offset + flash_size) < sector[0]: break
4031
4136
  bl_sectors.append(sector)
4032
4137
  write_sectors = bl_sectors
@@ -4040,7 +4145,7 @@ class LK_Device(ABC):
4040
4145
 
4041
4146
  dprint("Sectors to update:", write_sectors)
4042
4147
  # ↑↑↑ Read Sector Map
4043
-
4148
+
4044
4149
  # ↓↓↓ Chip erase
4045
4150
  chip_erase = False
4046
4151
  if flashcart.SupportsChipErase() and not flash_offset > 0:
@@ -4055,7 +4160,7 @@ class LK_Device(ABC):
4055
4160
  self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"No erase method available.", "abortable":False})
4056
4161
  return False
4057
4162
  # ↑↑↑ Chip erase
4058
-
4163
+
4059
4164
  # ↓↓↓ Flash Write
4060
4165
  if chip_erase:
4061
4166
  write_sectors = [[ 0, len(data_import) ]]
@@ -4064,9 +4169,10 @@ class LK_Device(ABC):
4064
4169
  elif len(write_sectors) == 0:
4065
4170
  write_sectors = sector_offsets
4066
4171
 
4067
- self.SetProgress({"action":"INITIALIZE", "method":"ROM_WRITE", "size":len(data_import), "flash_offset":flash_offset, "sector_count":len(write_sectors)})
4172
+ if not "photo_mode" in args:
4173
+ self.SetProgress({"action":"INITIALIZE", "method":"ROM_WRITE", "size":len(data_import), "flash_offset":flash_offset, "sector_count":len(write_sectors)})
4174
+ self.INFO["action"] = self.ACTIONS["ROM_WRITE"]
4068
4175
  self.SetProgress({"action":"UPDATE_POS", "pos":flash_offset})
4069
- self.INFO["action"] = self.ACTIONS["ROM_WRITE"]
4070
4176
 
4071
4177
  if smallest_sector_size is not False:
4072
4178
  buffer_len = smallest_sector_size
@@ -4121,82 +4227,79 @@ class LK_Device(ABC):
4121
4227
  bank = start_bank
4122
4228
 
4123
4229
  # ↓↓↓ 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")
4230
+ if not chip_erase and self.FW["fw_ver"] >= 12 and "compare_sectors" in args and args["compare_sectors"] is True and not (flashcart and cart_type["command_set"] == "GBAMP"):
4231
+ buffer_pos_matchcheck = buffer_pos
4232
+ verified = False
4233
+ ts_se_start = time.time()
4234
+ while bank < end_bank:
4235
+ status = None
4236
+ # ↓↓↓ Switch ROM bank
4237
+ if self.MODE == "DMG":
4238
+ if _mbc.ResetBeforeBankChange(bank) is True:
4239
+ dprint("Resetting the MBC")
4240
+ self._write(self.DEVICE_CMD["DMG_MBC_RESET"], wait=True)
4241
+ (start_address, bank_size) = _mbc.SelectBankROM(bank)
4242
+ if flashcart.PulseResetAfterWrite():
4243
+ if bank == 0:
4244
+ if self.FW["fw_ver"] < 2:
4245
+ self._write(self.DEVICE_CMD["OFW_GB_CART_MODE"])
4246
+ else:
4247
+ self._write(self.DEVICE_CMD["SET_MODE_DMG"], wait=self.FW["fw_ver"] >= 12)
4135
4248
  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
4249
+ self._set_fw_variable("DMG_ROM_BANK", bank)
4250
+
4251
+ buffer_len = min(buffer_len, bank_size)
4252
+ if "start_addr" in flashcart.CONFIG and bank == 0: start_address = flashcart.CONFIG["start_addr"]
4253
+ end_address = start_address + bank_size
4254
+ start_address += (buffer_pos % rom_bank_size)
4255
+ if end_address > start_address + sector[1]:
4256
+ end_address = start_address + sector[1]
4165
4257
 
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
4258
+ elif self.MODE == "AGB":
4259
+ if "flash_bank_select_type" in cart_type and cart_type["flash_bank_select_type"] > 0:
4260
+ if bank != current_bank:
4261
+ flashcart.Reset(full_reset=True)
4262
+ flashcart.SelectBankROM(bank)
4263
+ temp = end_address - start_address
4264
+ start_address %= cart_type["flash_bank_size"]
4265
+ end_address = min(cart_type["flash_bank_size"], start_address + temp)
4266
+ current_bank = bank
4267
+ # ↑↑↑ Switch ROM bank
4268
+
4269
+ pos = start_address
4270
+ #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))
4271
+ verified = self.CompareCRC32(buffer=data_import, offset=buffer_pos_matchcheck, length=end_address - pos, address=pos, flashcart=flashcart, reset=True, mbc=_mbc, bank=bank)
4272
+ self.SetProgress({"action":"UPDATE_POS", "pos":buffer_pos_matchcheck})
4273
+ if verified is not True:
4274
+ break
4275
+ buffer_pos_matchcheck += (end_address - pos)
4276
+ bank += 1
4174
4277
 
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
4278
+ if verified is True:
4279
+ dprint("Skipping sector #{:d}, because the CRC32 matched".format(sector_pos))
4280
+ if flashcart.FlashCommandsOnBank1(): _mbc.SelectBankROM(bank)
4281
+ self.NO_PROG_UPDATE = True
4282
+ se_ret = flashcart.SectorErase(pos=pos, buffer_pos=buffer_pos, skip=verified)
4283
+ self.NO_PROG_UPDATE = False
4284
+
4285
+ if self.CANCEL:
4286
+ cancel_args = {"action":"ABORT", "abortable":False}
4287
+ cancel_args.update(self.CANCEL_ARGS)
4288
+ self.CANCEL_ARGS = {}
4289
+ self.ERROR_ARGS = {}
4290
+ self.SetProgress(cancel_args)
4291
+ if self.CanPowerCycleCart(): self.CartPowerCycle()
4292
+ return
4293
+
4294
+ ts_se_elapsed = time.time() - ts_se_start
4295
+ if se_ret:
4296
+ sector_size = se_ret
4297
+ dprint("Next sector size: 0x{:X}".format(sector_size))
4298
+ buffer_pos += sector_size
4299
+ continue
4300
+ else:
4301
+ verified = False
4302
+ bank = start_bank
4200
4303
  # ↑↑↑ Check if data matches already
4201
4304
 
4202
4305
  while bank < end_bank:
@@ -4210,7 +4313,6 @@ class LK_Device(ABC):
4210
4313
  return
4211
4314
 
4212
4315
  status = None
4213
- #print("Bank:", bank, "...")
4214
4316
  # ↓↓↓ Switch ROM bank
4215
4317
  if self.MODE == "DMG":
4216
4318
  if _mbc.ResetBeforeBankChange(bank) is True:
@@ -4224,8 +4326,6 @@ class LK_Device(ABC):
4224
4326
  else:
4225
4327
  self._write(self.DEVICE_CMD["SET_MODE_DMG"], wait=self.FW["fw_ver"] >= 12)
4226
4328
  self._write(self.DEVICE_CMD["DMG_MBC_RESET"], wait=True)
4227
- # else:
4228
- # self._write(self.DEVICE_CMD["OFW_GB_FLASH_BANK_1_COMMAND_WRITES"])
4229
4329
  self._set_fw_variable("DMG_ROM_BANK", bank)
4230
4330
 
4231
4331
  buffer_len = min(buffer_len, bank_size)
@@ -4296,8 +4396,6 @@ class LK_Device(ABC):
4296
4396
  status = self.WriteROM(address=pos, buffer=data_import[buffer_pos:buffer_pos+buffer_len], flash_buffer_size=flash_buffer_size, skip_init=(skip_init and not self.SKIPPING))
4297
4397
  elif command_set_type == "DMG-MBC5-32M-FLASH" and self.FW["fw_ver"] < 12:
4298
4398
  status = self.WriteROM_DMG_MBC5_32M_FLASH(address=pos, buffer=data_import[buffer_pos:buffer_pos+buffer_len], bank=bank)
4299
- #elif command_set_type == "DMG-MBC5-32M-FLASH" and self.FW["fw_ver"] >= 12:
4300
- # status = self.WriteROM(address=pos, buffer=data_import[buffer_pos:buffer_pos+buffer_len], flash_buffer_size=flash_buffer_size, skip_init=(skip_init and not self.SKIPPING))
4301
4399
  elif command_set_type == "EEPROM":
4302
4400
  status = self.WriteROM_DMG_EEPROM(address=pos, buffer=data_import[buffer_pos:buffer_pos+buffer_len], bank=bank, eeprom_buffer_size=256)
4303
4401
  elif command_set_type == "BLAZE_XPLODER":
@@ -4348,21 +4446,22 @@ class LK_Device(ABC):
4348
4446
  if "from_user" in self.CANCEL_ARGS and self.CANCEL_ARGS["from_user"]:
4349
4447
  break
4350
4448
  elif not self.DEVICE.is_open or self.DEVICE is None:
4351
- self.CANCEL_ARGS.update({"info_type":"msgbox_critical", "info_msg":"An error occured while writing 0x{:X} bytes at position 0x{:X} ({:s}). Please re-connect the device and try again from the beginning.\n\nTroubleshooting advice:\n- Clean cartridge contacts\n- Avoid passive USB hubs and try different USB ports/cables\n- Check cartridge type selection{:s}\n\nStatus Register: {:s}".format(buffer_len, buffer_pos, Util.formatFileSize(size=buffer_pos, asInt=False), errmsg_mbc_selection, sr)})
4449
+ self.CANCEL_ARGS.update({"info_type":"msgbox_critical", "info_msg":"An error occured while writing 0x{:X} bytes at position 0x{:X} ({:s}). Please re-connect the device and try again from the beginning.\n\nTroubleshooting advice:\n- Clean cartridge contacts\n- Check soldering if it’s a DIY cartridge\n- Avoid passive USB hubs and try different USB ports/cables\n- Check cartridge type selection{:s}\n\nStatus Register: {:s}".format(buffer_len, buffer_pos, Util.formatFileSize(size=buffer_pos, asInt=False), errmsg_mbc_selection, sr)})
4352
4450
  break
4353
4451
  else:
4354
4452
  if chip_erase: retry_hp = 0
4355
4453
  if "iteration" in self.ERROR_ARGS and self.ERROR_ARGS["iteration"] > 0:
4356
4454
  retry_hp -= 5
4357
4455
  if retry_hp <= 0:
4358
- self.CANCEL_ARGS.update({"info_type":"msgbox_critical", "info_msg":"Unstable connection detected while writing 0x{:X} bytes in iteration {:d} at position 0x{:X} ({:s}). Please re-connect the device and try again from the beginning.\n\nTroubleshooting advice:\n- Clean cartridge contacts\n- Avoid passive USB hubs and try different USB ports/cables\n\nStatus Register: {:s}".format(buffer_len, self.ERROR_ARGS["iteration"], buffer_pos, Util.formatFileSize(size=buffer_pos, asInt=False), sr)})
4456
+ self.CANCEL_ARGS.update({"info_type":"msgbox_critical", "info_msg":"Unstable connection detected while writing 0x{:X} bytes in iteration {:d} at position 0x{:X} ({:s}). Please re-connect the device and try again from the beginning.\n\nTroubleshooting advice:\n- Clean cartridge contacts\n- Check soldering if it’s a DIY cartridge\n- Avoid passive USB hubs and try different USB ports/cables\n\nStatus Register: {:s}".format(buffer_len, self.ERROR_ARGS["iteration"], buffer_pos, Util.formatFileSize(size=buffer_pos, asInt=False), sr)})
4359
4457
  continue
4360
4458
  else:
4361
4459
  retry_hp -= 10
4362
4460
  if retry_hp <= 0:
4363
- self.CANCEL_ARGS.update({"info_type":"msgbox_critical", "info_msg":"An error occured while writing 0x{:X} bytes at position 0x{:X} ({:s}). Please re-connect the device and try again from the beginning.\n\nTroubleshooting advice:\n- Clean cartridge contacts\n- Avoid passive USB hubs and try different USB ports/cables\n- Check cartridge type selection\n- Check cartridge ROM storage size (at least {:s} is required){:s}\n- Your {:s} may also be incompatible with this cartridge\n\nStatus Register: {:s}".format(buffer_len, buffer_pos, Util.formatFileSize(size=buffer_pos, asInt=False), Util.formatFileSize(size=len(data_import), asInt=False), errmsg_mbc_selection, self.DEVICE_NAME, sr), "abortable":False})
4461
+ enable_pullup_wr_str = " (+ WR pullup)" if enable_pullup_wr == 2 else ""
4462
+ self.CANCEL_ARGS.update({"info_type":"msgbox_critical", "info_msg":"An error occured while writing 0x{:X} bytes at position 0x{:X} ({:s}). Please re-connect the device and try again from the beginning.\n\nTroubleshooting advice:\n- Clean cartridge contacts\n- Check soldering if it’s a DIY cartridge\n- Avoid passive USB hubs and try different USB ports/cables\n- Check cartridge type selection\n- Check cartridge ROM storage size (at least {:s} is required){:s}\n- Check cartridge profile used: {:s}{:s}\n- The cartridge may also be incompatible with your “{:s}” device\n\nStatus Register: {:s}".format(buffer_len, buffer_pos, Util.formatFileSize(size=buffer_pos, asInt=False), Util.formatFileSize(size=len(data_import), asInt=False), errmsg_mbc_selection, cart_name, enable_pullup_wr_str, self.GetFullNameLabel(), sr), "abortable":False})
4364
4463
  continue
4365
-
4464
+
4366
4465
  rev_buffer_pos = sector_offsets[sector_pos - 1][0]
4367
4466
  buffer_pos = rev_buffer_pos
4368
4467
  bank = start_bank
@@ -4396,10 +4495,6 @@ class LK_Device(ABC):
4396
4495
  self._cart_write(pos, 0xFF)
4397
4496
  if flashcart.Unlock() is False: return False
4398
4497
  continue
4399
-
4400
- self.CANCEL = True
4401
- self.ERROR = True
4402
- continue
4403
4498
 
4404
4499
  skip_init = True
4405
4500
 
@@ -4425,6 +4520,8 @@ class LK_Device(ABC):
4425
4520
 
4426
4521
  # ↓↓↓ Reset flash
4427
4522
  flashcart.Reset(full_reset=True)
4523
+ if self.FW["fw_ver"] >= 14 and "set_audio_high" in cart_type:
4524
+ self._set_fw_variable("DMG_AUDIO_ENABLED", 0)
4428
4525
  # ↑↑↑ Reset flash
4429
4526
 
4430
4527
  # ↓↓↓ Flash verify
@@ -4490,8 +4587,6 @@ class LK_Device(ABC):
4490
4587
  else:
4491
4588
  self._write(self.DEVICE_CMD["SET_MODE_DMG"], wait=self.FW["fw_ver"] >= 12)
4492
4589
  self._write(self.DEVICE_CMD["DMG_MBC_RESET"], wait=True)
4493
- # else:
4494
- # self._write(self.DEVICE_CMD["OFW_GB_FLASH_BANK_1_COMMAND_WRITES"])
4495
4590
  self._set_fw_variable("DMG_ROM_BANK", bank)
4496
4591
 
4497
4592
  buffer_len = min(buffer_len, bank_size)
@@ -4501,7 +4596,6 @@ class LK_Device(ABC):
4501
4596
  if end_address > start_address + sector[1]:
4502
4597
  end_address = start_address + sector[1]
4503
4598
  pos_from = (bank * start_address)
4504
- # pos_to = (bank * start_address) + verify_len
4505
4599
 
4506
4600
  elif self.MODE == "AGB":
4507
4601
  if "flash_bank_select_type" in cart_type and cart_type["flash_bank_select_type"] > 0:
@@ -4514,14 +4608,13 @@ class LK_Device(ABC):
4514
4608
  current_bank = bank
4515
4609
  verify_len = sector[1]
4516
4610
  pos_from = sector[0]
4517
- # pos_to = pos_from + verify_len
4518
4611
  # ↑↑↑ Switch ROM bank
4519
4612
 
4520
4613
  dprint(f"Verifying ROM bank #{bank} at 0x{pos_from:x} (physical 0x{start_address:X}, 0x{verify_len:X} bytes)")
4521
4614
 
4522
4615
  verified = False
4523
4616
  if self.FW["fw_ver"] >= 12 and sector[1] >= verify_len and crc32_errors < 5:
4524
- verified = self.CompareCRC32(buffer=data_import, offset=pos_from, length=verify_len, address=start_address, flashcart=flashcart, reset=False)
4617
+ verified = self.CompareCRC32(buffer=data_import, offset=pos_from, length=verify_len, address=start_address, flashcart=flashcart, reset=False, mbc=_mbc, bank=bank)
4525
4618
  if verified is True:
4526
4619
  dprint("CRC32 verification successful between 0x{:X} and 0x{:X}".format(pos_from, verify_len))
4527
4620
  self.SetProgress({"action":"UPDATE_POS", "pos":pos_from + verify_len})
@@ -4610,9 +4703,10 @@ class LK_Device(ABC):
4610
4703
 
4611
4704
  self.SetMode(self.MODE)
4612
4705
 
4613
- self.INFO["last_action"] = self.INFO["action"]
4614
- self.INFO["action"] = None
4615
- self.SetProgress({"action":"FINISHED", "verified":verified})
4706
+ if not "photo_mode" in args:
4707
+ self.INFO["last_action"] = self.INFO["action"]
4708
+ self.INFO["action"] = None
4709
+ self.SetProgress({"action":"FINISHED", "verified":verified})
4616
4710
  return True
4617
4711
 
4618
4712
  #################################################################
@@ -4639,7 +4733,7 @@ class LK_Device(ABC):
4639
4733
  self.SIGNAL = signal
4640
4734
  try:
4641
4735
  temp = copy.copy(args)
4642
- if "buffer" in temp: temp["buffer"] = "(data)"
4736
+ if "buffer" in temp: temp["buffer"] = "(0x{:x} bytes of data)".format(len(temp["buffer"]))
4643
4737
  dprint("args:", temp)
4644
4738
  del(temp)
4645
4739
  self.NO_PROG_UPDATE = False