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/DataTransfer.py +1 -1
- FlashGBX/FlashGBX.py +4 -3
- FlashGBX/FlashGBX_CLI.py +36 -20
- FlashGBX/FlashGBX_GUI.py +359 -148
- FlashGBX/Flashcart.py +3 -2
- FlashGBX/GBMemory.py +4 -2
- FlashGBX/LK_Device.py +327 -233
- FlashGBX/Mapper.py +6 -27
- FlashGBX/PocketCamera.py +1 -1
- FlashGBX/PocketCameraWindow.py +32 -2
- FlashGBX/RomFileAGB.py +5 -2
- FlashGBX/RomFileDMG.py +8 -3
- FlashGBX/UserInputDialog.py +1 -1
- FlashGBX/Util.py +33 -11
- FlashGBX/__main__.py +1 -1
- FlashGBX/fw_GBFlash.py +20 -3
- FlashGBX/fw_GBxCartRW_v1_3.py +1 -1
- FlashGBX/fw_GBxCartRW_v1_4.py +1 -1
- FlashGBX/fw_JoeyJr.py +10 -3
- FlashGBX/hw_GBFlash.py +3 -3
- FlashGBX/hw_GBxCartRW.py +16 -16
- FlashGBX/hw_JoeyJr.py +3 -3
- FlashGBX/pyside.py +1 -1
- FlashGBX/res/config.zip +0 -0
- FlashGBX/res/fw_GBFlash.zip +0 -0
- FlashGBX/res/fw_GBxCart_RW_v1_4.zip +0 -0
- FlashGBX/res/fw_GBxCart_RW_v1_4a.zip +0 -0
- FlashGBX/res/fw_JoeyJr.zip +0 -0
- {FlashGBX-4.3.dist-info → flashgbx-4.6.dist-info}/METADATA +103 -57
- flashgbx-4.6.dist-info/RECORD +43 -0
- {FlashGBX-4.3.dist-info → flashgbx-4.6.dist-info}/WHEEL +1 -1
- FlashGBX-4.3.dist-info/RECORD +0 -43
- {FlashGBX-4.3.dist-info → flashgbx-4.6.dist-info}/entry_points.txt +0 -0
- {FlashGBX-4.3.dist-info → flashgbx-4.6.dist-info/licenses}/LICENSE +0 -0
- {FlashGBX-4.3.dist-info → flashgbx-4.6.dist-info}/top_level.txt +0 -0
FlashGBX/LK_Device.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
# FlashGBX
|
|
3
|
-
# Author: Lesserkuma (github.com/
|
|
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
|
-
"
|
|
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.
|
|
1123
|
-
self.
|
|
1124
|
-
|
|
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
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
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
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
save_type =
|
|
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
|
-
|
|
2069
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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 "
|
|
2640
|
-
|
|
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:
|
|
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 "
|
|
2947
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
3688
|
-
if
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
pad_len
|
|
3694
|
-
|
|
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 "
|
|
3708
|
-
|
|
3709
|
-
|
|
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
|
-
|
|
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"] >=
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
if
|
|
4133
|
-
|
|
4134
|
-
|
|
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
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
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
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
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
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
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
|