FlashGBX 4.2__py3-none-any.whl → 4.4__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 -2
- FlashGBX/FlashGBX.py +2 -2
- FlashGBX/FlashGBX_CLI.py +40 -29
- FlashGBX/FlashGBX_GUI.py +484 -191
- FlashGBX/Flashcart.py +3 -1
- FlashGBX/GBMemory.py +3 -1
- FlashGBX/LK_Device.py +408 -199
- FlashGBX/Mapper.py +46 -7
- FlashGBX/PocketCamera.py +2 -2
- FlashGBX/PocketCameraWindow.py +35 -5
- FlashGBX/RomFileAGB.py +4 -1
- FlashGBX/RomFileDMG.py +13 -2
- FlashGBX/Util.py +86 -16
- FlashGBX/fw_GBFlash.py +0 -5
- FlashGBX/fw_GBxCartRW_v1_4.py +2 -5
- FlashGBX/fw_JoeyJr.py +23 -8
- FlashGBX/hw_GBFlash.py +16 -7
- FlashGBX/hw_GBxCartRW.py +18 -16
- FlashGBX/hw_JoeyJr.py +2 -2
- FlashGBX/res/Third Party Notices.md +21 -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.2.dist-info → FlashGBX-4.4.dist-info}/METADATA +101 -52
- FlashGBX-4.4.dist-info/RECORD +43 -0
- {FlashGBX-4.2.dist-info → FlashGBX-4.4.dist-info}/WHEEL +1 -1
- FlashGBX-4.2.dist-info/RECORD +0 -43
- {FlashGBX-4.2.dist-info → FlashGBX-4.4.dist-info}/LICENSE +0 -0
- {FlashGBX-4.2.dist-info → FlashGBX-4.4.dist-info}/entry_points.txt +0 -0
- {FlashGBX-4.2.dist-info → FlashGBX-4.4.dist-info}/top_level.txt +0 -0
FlashGBX/LK_Device.py
CHANGED
|
@@ -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,9 +114,10 @@ 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
|
-
ACTIONS = {"ROM_READ":1, "SAVE_READ":2, "SAVE_WRITE":3, "ROM_WRITE":4, "ROM_WRITE_VERIFY":4, "SAVE_WRITE_VERIFY":3, "RTC_WRITE":5}
|
|
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}
|
|
120
121
|
SUPPORTED_CARTS = {}
|
|
121
122
|
|
|
122
123
|
FW = {}
|
|
@@ -229,8 +230,14 @@ class LK_Device(ABC):
|
|
|
229
230
|
#################################################################
|
|
230
231
|
|
|
231
232
|
def IsSupportedMbc(self, mbc):
|
|
232
|
-
return mbc in ( 0x00, 0x01, 0x02, 0x03, 0x05, 0x06, 0x08, 0x09, 0x0B, 0x0D, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x20, 0x22, 0xFC, 0xFD, 0xFE, 0xFF, 0x101, 0x103, 0x104, 0x105, 0x110, 0x201, 0x202, 0x203, 0x204, 0x205 )
|
|
233
|
+
return mbc in ( 0x00, 0x01, 0x02, 0x03, 0x05, 0x06, 0x08, 0x09, 0x0B, 0x0D, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x20, 0x22, 0xFC, 0xFD, 0xFE, 0xFF, 0x101, 0x103, 0x104, 0x105, 0x110, 0x201, 0x202, 0x203, 0x204, 0x205, 0x206 )
|
|
233
234
|
|
|
235
|
+
def IsUnregistered(self):
|
|
236
|
+
if "unregistered" in self.FW:
|
|
237
|
+
return self.FW["unregistered"]
|
|
238
|
+
else:
|
|
239
|
+
return False
|
|
240
|
+
|
|
234
241
|
def TryConnect(self, port, baudrate):
|
|
235
242
|
dprint("Trying to connect to {:s} at baud rate {:d} ({:s})".format(port, baudrate, type(self).__module__))
|
|
236
243
|
try:
|
|
@@ -299,7 +306,7 @@ class LK_Device(ABC):
|
|
|
299
306
|
for mode in flashcarts.keys():
|
|
300
307
|
for key in sorted(flashcarts[mode].keys(), key=str.casefold):
|
|
301
308
|
self.SUPPORTED_CARTS[mode][key] = flashcarts[mode][key]
|
|
302
|
-
|
|
309
|
+
|
|
303
310
|
def IsConnected(self):
|
|
304
311
|
if self.DEVICE is None: return False
|
|
305
312
|
if not self.DEVICE.isOpen(): return False
|
|
@@ -635,11 +642,11 @@ class LK_Device(ABC):
|
|
|
635
642
|
ret = self._read(1)
|
|
636
643
|
if ret != 0x01:
|
|
637
644
|
if ret is False:
|
|
638
|
-
msg = "Error: No response while trying to
|
|
645
|
+
msg = "Error: No response while trying to communicate with the device."
|
|
639
646
|
time.sleep(0.5)
|
|
640
647
|
self.DEVICE.reset_input_buffer()
|
|
641
648
|
else:
|
|
642
|
-
msg = "Error: Bad response “{:s}” while trying to
|
|
649
|
+
msg = "Error: Bad response “{:s}” while trying to communicate with the device.".format(str(ret))
|
|
643
650
|
print(f"{ANSI.RED}{msg}{ANSI.RESET}")
|
|
644
651
|
dprint(msg)
|
|
645
652
|
#self.CANCEL_ARGS.update({"info_type":"msgbox_critical", "info_msg":"A critical communication error occured during a write. Please avoid passive USB hubs, try different USB ports/cables and re-connect the device."})
|
|
@@ -673,6 +680,12 @@ class LK_Device(ABC):
|
|
|
673
680
|
self.CartPowerCycle(delay=delay)
|
|
674
681
|
return
|
|
675
682
|
|
|
683
|
+
if self.FW["fw_ver"] < 12:
|
|
684
|
+
self.CANCEL_ARGS.update({"info_type":"msgbox_critical", "info_msg":"This cartridge type requires at least firmware version L12."})
|
|
685
|
+
self.CANCEL = True
|
|
686
|
+
self.USER_ANSWER = None
|
|
687
|
+
return False
|
|
688
|
+
|
|
676
689
|
mode = self.GetMode()
|
|
677
690
|
var_state = self.GetVarState()
|
|
678
691
|
|
|
@@ -741,7 +754,7 @@ class LK_Device(ABC):
|
|
|
741
754
|
if self.DEVICE.in_waiting == 0:
|
|
742
755
|
dprint("Waiting for ACK...")
|
|
743
756
|
hp -= 1
|
|
744
|
-
time.sleep(0.
|
|
757
|
+
time.sleep(0.1)
|
|
745
758
|
continue
|
|
746
759
|
temp = self.DEVICE.read(self.DEVICE.in_waiting)
|
|
747
760
|
if len(temp) >= 1: temp = temp[len(temp) - 1]
|
|
@@ -751,6 +764,13 @@ class LK_Device(ABC):
|
|
|
751
764
|
self._write(self.DEVICE_CMD["QUERY_CART_PWR"])
|
|
752
765
|
time.sleep(0.05)
|
|
753
766
|
hp -= 1
|
|
767
|
+
|
|
768
|
+
if hp == 0:
|
|
769
|
+
self.DEVICE.close()
|
|
770
|
+
self.DEVICE = None
|
|
771
|
+
self.ERROR = True
|
|
772
|
+
raise BrokenPipeError("Couldn’t power on the cartridge.")
|
|
773
|
+
|
|
754
774
|
self.DEVICE.timeout = self.DEVICE_TIMEOUT
|
|
755
775
|
|
|
756
776
|
self._write(self.DEVICE_CMD["QUERY_CART_PWR"])
|
|
@@ -823,6 +843,7 @@ class LK_Device(ABC):
|
|
|
823
843
|
self._write(self.DEVICE_CMD["SET_VOLTAGE_5V"], wait=self.FW["fw_ver"] >= 12)
|
|
824
844
|
self._set_fw_variable("DMG_READ_METHOD", self.DMG_READ_METHOD)
|
|
825
845
|
self._set_fw_variable("CART_MODE", 1)
|
|
846
|
+
#if self.FW["fw_ver"] >= 14: self._set_fw_variable("DMG_AUDIO_ENABLED", 0)
|
|
826
847
|
self.MODE = "DMG"
|
|
827
848
|
elif mode == "AGB":
|
|
828
849
|
self._write(self.DEVICE_CMD["SET_MODE_AGB"], wait=self.FW["fw_ver"] >= 12)
|
|
@@ -854,31 +875,31 @@ class LK_Device(ABC):
|
|
|
854
875
|
def GetSupportedCartridgesAGB(self):
|
|
855
876
|
return (list(self.SUPPORTED_CARTS['AGB'].keys()), list(self.SUPPORTED_CARTS['AGB'].values()))
|
|
856
877
|
|
|
857
|
-
def SetProgress(self, args):
|
|
878
|
+
def SetProgress(self, args, signal=None):
|
|
858
879
|
if self.CANCEL and args["action"] not in ("ABORT", "FINISHED", "ERROR"): return
|
|
859
880
|
if "pos" in args: self.POS = args["pos"]
|
|
860
881
|
if args["action"] == "UPDATE_POS": self.INFO["transferred"] = args["pos"]
|
|
882
|
+
if signal is None:
|
|
883
|
+
signal = self.SIGNAL
|
|
884
|
+
|
|
861
885
|
try:
|
|
862
|
-
|
|
886
|
+
signal.emit(args)
|
|
863
887
|
except AttributeError:
|
|
864
|
-
if
|
|
865
|
-
|
|
888
|
+
if signal is not None:
|
|
889
|
+
signal(args)
|
|
866
890
|
|
|
867
891
|
if args["action"] == "INITIALIZE":
|
|
868
892
|
if self.CanPowerCycleCart(): self.CartPowerOn() # Ensure cart is powered
|
|
869
893
|
self.POS = 0
|
|
870
894
|
elif args["action"] == "FINISHED":
|
|
871
895
|
self.POS = 0
|
|
896
|
+
signal = None
|
|
872
897
|
self.SIGNAL = None
|
|
873
898
|
|
|
874
899
|
def Debug(self):
|
|
875
|
-
# for i in range(0, 0x100000):
|
|
876
|
-
# print(hex(i), self._set_fw_variable("ADDRESS", i), end="\r", flush=True)
|
|
877
900
|
return
|
|
878
901
|
|
|
879
902
|
def ReadInfo(self, setPinsAsInputs=False, checkRtc=True):
|
|
880
|
-
self.Debug()
|
|
881
|
-
|
|
882
903
|
if not self.IsConnected(): raise ConnectionError("Couldn’t access the the device.")
|
|
883
904
|
data = {}
|
|
884
905
|
self.SIGNAL = None
|
|
@@ -905,7 +926,7 @@ class LK_Device(ABC):
|
|
|
905
926
|
header = self.ReadROM(0, 0x180)
|
|
906
927
|
|
|
907
928
|
if ".dev" in Util.VERSION_PEP440 or Util.DEBUG:
|
|
908
|
-
with open("debug_header.bin", "wb") as f: f.write(header)
|
|
929
|
+
with open(Util.CONFIG_PATH + "/debug_header.bin", "wb") as f: f.write(header)
|
|
909
930
|
|
|
910
931
|
# Parse ROM header
|
|
911
932
|
if self.MODE == "DMG":
|
|
@@ -942,6 +963,7 @@ class LK_Device(ABC):
|
|
|
942
963
|
data["rtc_string"] = _mbc.GetRTCString()
|
|
943
964
|
except:
|
|
944
965
|
data["rtc_string"] = "Invalid data"
|
|
966
|
+
|
|
945
967
|
if _mbc.GetName() == "G-MMC1":
|
|
946
968
|
try:
|
|
947
969
|
temp = bytearray([0] * 0x100000)
|
|
@@ -959,6 +981,21 @@ class LK_Device(ABC):
|
|
|
959
981
|
print(traceback.format_exc())
|
|
960
982
|
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))
|
|
961
983
|
|
|
984
|
+
elif _mbc.GetName() == "MAC-GBD":
|
|
985
|
+
dprint("Reading Game Boy Camera calibration data...")
|
|
986
|
+
_mbc.EnableRAM(True)
|
|
987
|
+
_mbc.SelectBankRAM(2)
|
|
988
|
+
temp = self.ReadRAM(address=0xFF2, length=0xE)
|
|
989
|
+
if temp != bytearray(temp[0] * len(temp)):
|
|
990
|
+
data["gbcamera_calibration1"] = temp
|
|
991
|
+
dprint("Game Boy Camera calibration data 1:", ''.join(format(x, '02X') for x in temp))
|
|
992
|
+
_mbc.SelectBankRAM(8)
|
|
993
|
+
temp = self.ReadRAM(address=0x1FF2, length=0xE)
|
|
994
|
+
if temp != bytearray(temp[0] * len(temp)):
|
|
995
|
+
data["gbcamera_calibration2"] = temp
|
|
996
|
+
dprint("Game Boy Camera calibration data 2:", ''.join(format(x, '02X') for x in temp))
|
|
997
|
+
_mbc.EnableRAM(False)
|
|
998
|
+
|
|
962
999
|
elif self.MODE == "AGB":
|
|
963
1000
|
# Unlock DACS carts on older firmware
|
|
964
1001
|
if not self.CanPowerCycleCart() or self.FW["fw_ver"] == 1:
|
|
@@ -1067,9 +1104,22 @@ class LK_Device(ABC):
|
|
|
1067
1104
|
if self.MODE == "DMG": #and setPinsAsInputs:
|
|
1068
1105
|
self._write(self.DEVICE_CMD["SET_ADDR_AS_INPUTS"], wait=self.FW["fw_ver"] >= 12)
|
|
1069
1106
|
|
|
1107
|
+
self.Debug()
|
|
1070
1108
|
return data
|
|
1071
1109
|
|
|
1072
|
-
def
|
|
1110
|
+
def _DetectCartridge(self, args): # Wrapper for thread call
|
|
1111
|
+
self.SetProgress({"action":"INITIALIZE", "abortable":False, "method":"DETECT_CART"})
|
|
1112
|
+
signal = self.SIGNAL
|
|
1113
|
+
self.SIGNAL = None
|
|
1114
|
+
ret = self.DoDetectCartridge(mbc=None, limitVoltage=args["limitVoltage"], checkSaveType=args["checkSaveType"], signal=signal)
|
|
1115
|
+
self.INFO["detect_cart"] = ret
|
|
1116
|
+
self.INFO["last_action"] = self.ACTIONS["DETECT_CART"]
|
|
1117
|
+
self.INFO["action"] = None
|
|
1118
|
+
self.SIGNAL = signal
|
|
1119
|
+
self.SetProgress({"action":"FINISHED"})
|
|
1120
|
+
return True
|
|
1121
|
+
|
|
1122
|
+
def DoDetectCartridge(self, mbc=None, limitVoltage=False, checkSaveType=True, signal=None):
|
|
1073
1123
|
self.SIGNAL = None
|
|
1074
1124
|
self.CANCEL = False
|
|
1075
1125
|
self.ERROR = False
|
|
@@ -1079,8 +1129,10 @@ class LK_Device(ABC):
|
|
|
1079
1129
|
sram_unstable = None
|
|
1080
1130
|
save_size = None
|
|
1081
1131
|
checkBatterylessSRAM = False
|
|
1132
|
+
_apot = 0
|
|
1082
1133
|
|
|
1083
1134
|
# Header
|
|
1135
|
+
if signal is not None: self.SetProgress({"action":"UPDATE_INFO", "text":"Detecting ROM..."}, signal=signal)
|
|
1084
1136
|
info = self.ReadInfo(checkRtc=True)
|
|
1085
1137
|
if self.MODE == "DMG" and mbc is None:
|
|
1086
1138
|
mbc = info["mapper_raw"]
|
|
@@ -1088,23 +1140,27 @@ class LK_Device(ABC):
|
|
|
1088
1140
|
|
|
1089
1141
|
# Disable Auto Power Off
|
|
1090
1142
|
_apoe = False
|
|
1091
|
-
if self.
|
|
1092
|
-
self.
|
|
1093
|
-
|
|
1143
|
+
if self.FW["fw_ver"] >= 12:
|
|
1144
|
+
if self.CanPowerCycleCart():
|
|
1145
|
+
self.CartPowerCycle()
|
|
1094
1146
|
_apoe = self._get_fw_variable("AUTO_POWEROFF_ENABLED") == 1
|
|
1095
1147
|
if _apoe is True:
|
|
1096
1148
|
_apot = self._get_fw_variable("AUTO_POWEROFF_TIME")
|
|
1097
1149
|
self._set_fw_variable("AUTO_POWEROFF_TIME", 5000)
|
|
1098
1150
|
|
|
1099
1151
|
# Detect Flash Cart
|
|
1152
|
+
if signal is not None: self.SetProgress({"action":"UPDATE_INFO", "text":"Detecting Flash..."}, signal=signal)
|
|
1100
1153
|
ret = self.DetectFlash(limitVoltage=limitVoltage)
|
|
1101
1154
|
if ret is False: return False
|
|
1102
1155
|
(cart_types, cart_type_id, flash_id, cfi_s, cfi, detected_size) = ret
|
|
1103
1156
|
supported_carts = list(self.SUPPORTED_CARTS[self.MODE].values())
|
|
1104
1157
|
cart_type = supported_carts[cart_type_id]
|
|
1105
1158
|
|
|
1159
|
+
# Skip DMG save type detection
|
|
1160
|
+
if self.MODE == "DMG" and cart_type_id == 0: checkSaveType = False
|
|
1161
|
+
|
|
1106
1162
|
# Preparations
|
|
1107
|
-
if "command_set" in cart_type and cart_type["command_set"] in ("DMG-MBC5-32M-FLASH", "GBAMP"):
|
|
1163
|
+
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):
|
|
1108
1164
|
checkSaveType = False
|
|
1109
1165
|
elif self.MODE == "AGB" and "flash_bank_select_type" in cart_type and cart_type["flash_bank_select_type"] == 1:
|
|
1110
1166
|
save_size = 65536
|
|
@@ -1113,6 +1169,7 @@ class LK_Device(ABC):
|
|
|
1113
1169
|
elif self.MODE == "AGB" and "flash_bank_select_type" in cart_type and cart_type["flash_bank_select_type"] > 1:
|
|
1114
1170
|
checkSaveType = False
|
|
1115
1171
|
elif self.MODE == "DMG" and "mbc" in cart_type and cart_type["mbc"] == 0x105: # G-MMC1
|
|
1172
|
+
if signal is not None: self.SetProgress({"action":"UPDATE_INFO", "text":"Detecting GB-Memory..."}, signal=signal)
|
|
1116
1173
|
header = self.ReadROM(0, 0x180)
|
|
1117
1174
|
data = RomFileDMG(header).GetHeader()
|
|
1118
1175
|
_mbc = DMG_MBC().GetInstance(args={"mbc":cart_type["mbc"]}, cart_write_fncptr=self._cart_write, cart_read_fncptr=self._cart_read, cart_powercycle_fncptr=self.CartPowerCycleOrAskReconnect, clk_toggle_fncptr=self._clk_toggle)
|
|
@@ -1131,6 +1188,7 @@ class LK_Device(ABC):
|
|
|
1131
1188
|
|
|
1132
1189
|
# Save Type and Size
|
|
1133
1190
|
if checkSaveType:
|
|
1191
|
+
if signal is not None: self.SetProgress({"action":"UPDATE_INFO", "text":"Detecting save type..."}, signal=signal)
|
|
1134
1192
|
if self.MODE == "DMG":
|
|
1135
1193
|
save_size = 131072
|
|
1136
1194
|
save_type = 0x04
|
|
@@ -1148,6 +1206,8 @@ class LK_Device(ABC):
|
|
|
1148
1206
|
args = { 'mode':2, 'path':None, 'mbc':mbc, 'save_type':save_type, 'rtc':False, 'detect':True }
|
|
1149
1207
|
elif self.MODE == "AGB":
|
|
1150
1208
|
args = { 'mode':2, 'path':None, 'mbc':mbc, 'save_type':8, 'rtc':False, 'detect':True }
|
|
1209
|
+
else:
|
|
1210
|
+
return
|
|
1151
1211
|
|
|
1152
1212
|
ret = self._BackupRestoreRAM(args=args)
|
|
1153
1213
|
|
|
@@ -1175,6 +1235,10 @@ class LK_Device(ABC):
|
|
|
1175
1235
|
if self.INFO["data"][i:i+3] != bytearray([self.INFO["data"][i]] * 3):
|
|
1176
1236
|
check = False
|
|
1177
1237
|
break
|
|
1238
|
+
|
|
1239
|
+
if self.INFO["data"][0:0x8000] == self.INFO["data"][0x8000:0x10000]: # MBCX
|
|
1240
|
+
check = True
|
|
1241
|
+
|
|
1178
1242
|
if check:
|
|
1179
1243
|
save_size = 32768
|
|
1180
1244
|
save_type = 0x03
|
|
@@ -1201,13 +1265,21 @@ class LK_Device(ABC):
|
|
|
1201
1265
|
if flash_save_id != 0 and flash_save_id in Util.AGB_Flash_Save_Chips:
|
|
1202
1266
|
save_size = Util.AGB_Flash_Save_Chips_Sizes[list(Util.AGB_Flash_Save_Chips).index(flash_save_id)]
|
|
1203
1267
|
save_chip = Util.AGB_Flash_Save_Chips[flash_save_id]
|
|
1204
|
-
|
|
1268
|
+
|
|
1269
|
+
if flash_save_id in (0xBF5B, 0xFFFF): # Bootlegs
|
|
1270
|
+
if self.INFO["data"][0:0x20000] == bytearray([0xFF] * 0x20000):
|
|
1271
|
+
save_type = 5
|
|
1272
|
+
elif self.INFO["data"][0:0x10000] == self.INFO["data"][0x10000:0x20000]:
|
|
1273
|
+
save_type = 4
|
|
1274
|
+
else:
|
|
1275
|
+
save_type = 5
|
|
1276
|
+
elif save_size == 131072:
|
|
1205
1277
|
save_type = 5
|
|
1206
1278
|
elif save_size == 65536:
|
|
1207
1279
|
save_type = 4
|
|
1208
1280
|
except:
|
|
1209
1281
|
pass
|
|
1210
|
-
|
|
1282
|
+
|
|
1211
1283
|
if save_type is None:
|
|
1212
1284
|
checkBatterylessSRAM = True
|
|
1213
1285
|
if info["dacs_8m"] is True:
|
|
@@ -1238,8 +1310,8 @@ class LK_Device(ABC):
|
|
|
1238
1310
|
save_size = Util.find_size(self.INFO["data"], len(self.INFO["data"]))
|
|
1239
1311
|
eeprom_64k = self.INFO["data"]
|
|
1240
1312
|
if eeprom_64k in (bytearray([0xFF] * len(eeprom_64k)), bytearray([0] * len(eeprom_64k))):
|
|
1241
|
-
save_type = None
|
|
1242
1313
|
save_size = 0
|
|
1314
|
+
save_type = 0
|
|
1243
1315
|
elif (eeprom_4k == eeprom_64k[:len(eeprom_4k)]):
|
|
1244
1316
|
save_type = 2
|
|
1245
1317
|
save_size = 8192
|
|
@@ -1332,6 +1404,7 @@ class LK_Device(ABC):
|
|
|
1332
1404
|
|
|
1333
1405
|
def ReadFlashSaveID(self):
|
|
1334
1406
|
# Check if actually SRAM/FRAM
|
|
1407
|
+
dprint("Checking Flash ID of Save Memory")
|
|
1335
1408
|
test1 = self._cart_read(0, 0x10, agb_save_flash=True)[4]
|
|
1336
1409
|
self._cart_write_flash([[ 0x0004, test1 ^ 0xFF ]])
|
|
1337
1410
|
test2 = self._cart_read(0, 0x10, agb_save_flash=True)[4]
|
|
@@ -1395,6 +1468,8 @@ class LK_Device(ABC):
|
|
|
1395
1468
|
command = "DMG_CART_READ"
|
|
1396
1469
|
elif self.MODE == "AGB":
|
|
1397
1470
|
command = "AGB_CART_READ"
|
|
1471
|
+
else:
|
|
1472
|
+
raise NotImplementedError
|
|
1398
1473
|
|
|
1399
1474
|
for n in range(0, num):
|
|
1400
1475
|
self._write(self.DEVICE_CMD[command])
|
|
@@ -1687,7 +1762,6 @@ class LK_Device(ABC):
|
|
|
1687
1762
|
self._set_fw_variable("ADDRESS", address)
|
|
1688
1763
|
elif self.MODE == "AGB":
|
|
1689
1764
|
self._set_fw_variable("ADDRESS", address >> 1)
|
|
1690
|
-
# print("==>", hex(self._get_fw_variable("ADDRESS")), hex(self._get_fw_variable("TRANSFER_SIZE")), hex(self._get_fw_variable("BUFFER_SIZE")))
|
|
1691
1765
|
|
|
1692
1766
|
skip_init = True
|
|
1693
1767
|
|
|
@@ -1791,9 +1865,6 @@ class LK_Device(ABC):
|
|
|
1791
1865
|
self._write(buffer[i*length:i*length+length])
|
|
1792
1866
|
ret = self._read(1)
|
|
1793
1867
|
if ret not in (0x01, 0x03):
|
|
1794
|
-
#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)})
|
|
1795
|
-
#self.CANCEL = True
|
|
1796
|
-
#self.ERROR = True
|
|
1797
1868
|
return False
|
|
1798
1869
|
|
|
1799
1870
|
self._cart_write(address + length - 1, 0xFF)
|
|
@@ -1936,7 +2007,7 @@ class LK_Device(ABC):
|
|
|
1936
2007
|
buffer2 = self.ReadROM(0x80, 0x40)
|
|
1937
2008
|
return buffer1 == buffer2
|
|
1938
2009
|
|
|
1939
|
-
def CompareCRC32(self, buffer, offset, length, address, flashcart=None, max_length=0x20000, reset=False):
|
|
2010
|
+
def CompareCRC32(self, buffer, offset, length, address, flashcart=None, max_length=0x20000, reset=False, mbc=None, bank=0):
|
|
1940
2011
|
left = length
|
|
1941
2012
|
chunk_pos = 0
|
|
1942
2013
|
verified = False
|
|
@@ -1944,7 +2015,7 @@ class LK_Device(ABC):
|
|
|
1944
2015
|
chunk_len = max_length if left > max_length else left
|
|
1945
2016
|
chunk_from = offset + chunk_pos
|
|
1946
2017
|
chunk_to = offset + chunk_pos + chunk_len
|
|
1947
|
-
dprint(f"Running CRC32 verification, comparing between source 0x{chunk_from:
|
|
2018
|
+
dprint(f"Running CRC32 verification, comparing between source 0x{chunk_from:X}~0x{chunk_to:X} and target 0x{address+chunk_pos:X}~0x{address+chunk_pos+chunk_len:X}")
|
|
1948
2019
|
crc32_expected = zlib.crc32(buffer[chunk_from:chunk_to])
|
|
1949
2020
|
|
|
1950
2021
|
for i in range(0, 2 if (reset is True and flashcart is not None) else 1): # for retrying with reset
|
|
@@ -1962,6 +2033,8 @@ class LK_Device(ABC):
|
|
|
1962
2033
|
if crc32_expected != crc32_calculated:
|
|
1963
2034
|
if i == 0 and flashcart is not None:
|
|
1964
2035
|
flashcart.Reset(full_reset=True)
|
|
2036
|
+
if mbc is not None:
|
|
2037
|
+
mbc.SelectBankROM(bank)
|
|
1965
2038
|
verified = (crc32_expected, crc32_calculated)
|
|
1966
2039
|
continue
|
|
1967
2040
|
else:
|
|
@@ -2008,17 +2081,33 @@ class LK_Device(ABC):
|
|
|
2008
2081
|
self.SetAGBReadMethod(0)
|
|
2009
2082
|
self._write(self.DEVICE_CMD["SET_MODE_AGB"], wait=self.FW["fw_ver"] >= 12)
|
|
2010
2083
|
|
|
2084
|
+
else:
|
|
2085
|
+
raise NotImplementedError
|
|
2086
|
+
|
|
2011
2087
|
rom = self._cart_read(0, 8)
|
|
2012
2088
|
|
|
2013
2089
|
dprint("Resetting and unlocking all cart types")
|
|
2014
2090
|
cmds = []
|
|
2015
2091
|
cmds_reset = []
|
|
2016
2092
|
cmds_unlock_read = []
|
|
2017
|
-
|
|
2018
|
-
|
|
2093
|
+
|
|
2094
|
+
for cart_type in sorted(supported_carts, key=lambda c: 'm29w640' not in c): # m29w640 first because of corruption risk
|
|
2095
|
+
f = supported_carts.index(cart_type)
|
|
2019
2096
|
if "command_set" not in cart_type: continue
|
|
2020
2097
|
if "manual_select" in cart_type and cart_type["manual_select"] is True: continue
|
|
2021
|
-
if self.MODE == "DMG" and
|
|
2098
|
+
if self.MODE == "DMG" and "m29w640" in cart_type:
|
|
2099
|
+
self._cart_write_flash(cart_type["commands"]["reset"])
|
|
2100
|
+
rom1 = self._cart_read(0, 8)
|
|
2101
|
+
self._cart_write_flash(cart_type["commands"]["read_identifier"])
|
|
2102
|
+
rom2 = self._cart_read(0, 8)
|
|
2103
|
+
if rom1 != rom2 and list(rom2[:len(cart_type["flash_ids"][0])]) == cart_type["flash_ids"][0]:
|
|
2104
|
+
found = True
|
|
2105
|
+
flash_types.append(f)
|
|
2106
|
+
dprint("Found a M29W640 cartridge")
|
|
2107
|
+
self._cart_write_flash(cart_type["commands"]["reset"])
|
|
2108
|
+
break
|
|
2109
|
+
continue
|
|
2110
|
+
elif self.MODE == "DMG" and cart_type["command_set"] == "BLAZE_XPLODER":
|
|
2022
2111
|
self._cart_read(0x102, 1)
|
|
2023
2112
|
self._cart_write(6, 1)
|
|
2024
2113
|
self._cart_write_flash(cart_type["commands"]["reset"])
|
|
@@ -2059,7 +2148,7 @@ class LK_Device(ABC):
|
|
|
2059
2148
|
self._cart_write_flash(cart_type["commands"]["reset"])
|
|
2060
2149
|
break
|
|
2061
2150
|
continue
|
|
2062
|
-
elif self.MODE == "DMG" and
|
|
2151
|
+
elif self.MODE == "DMG" and "dmg-mbc5-32m-flash" in cart_type:
|
|
2063
2152
|
self._set_we_pin_audio()
|
|
2064
2153
|
self._cart_write_flash(cart_type["commands"]["unlock"], flashcart=False)
|
|
2065
2154
|
self._cart_write_flash(cart_type["commands"]["reset"])
|
|
@@ -2149,6 +2238,7 @@ class LK_Device(ABC):
|
|
|
2149
2238
|
self._cart_write(cmd[0], cmd[1], flashcart=True)
|
|
2150
2239
|
|
|
2151
2240
|
flash_id_cmds = sorted(cmds, key=lambda x: x['read_identifier'][0][0])
|
|
2241
|
+
read_cfi_cmds = []
|
|
2152
2242
|
|
|
2153
2243
|
rom_s = " ".join(format(x, '02X') for x in rom)
|
|
2154
2244
|
if self.MODE == "DMG":
|
|
@@ -2174,41 +2264,13 @@ class LK_Device(ABC):
|
|
|
2174
2264
|
cmp = self._cart_read(0, 8)
|
|
2175
2265
|
self._cart_write_flash(flash_id_cmds[i]["reset"], flashcart=True)
|
|
2176
2266
|
if rom != cmp: # ROM data changed
|
|
2177
|
-
if "read_cfi" not in flash_id_cmds[i]:
|
|
2178
|
-
flash_id_cmds[i]["read_cfi"] = [[ flash_id_cmds[i]["read_identifier"][0][0], 0x98 ]]
|
|
2179
|
-
self._cart_write_flash(flash_id_cmds[i]["read_cfi"], flashcart=True)
|
|
2180
|
-
cfi_buffer = self._cart_read(0, 0x400)
|
|
2181
|
-
self._cart_write_flash(flash_id_cmds[i]["reset"], flashcart=True)
|
|
2182
2267
|
flash_id_methods.append([we - 1, i, list(cmp), cfi_buffer, flash_id_cmds[i]["read_identifier"]])
|
|
2183
|
-
|
|
2184
|
-
if ".dev" in Util.VERSION_PEP440 or Util.DEBUG:
|
|
2185
|
-
with open("debug_cfi.bin", "wb") as f: f.write(cfi_buffer)
|
|
2186
|
-
try:
|
|
2187
|
-
magic = "{:s}{:s}{:s}".format(chr(cfi_buffer[0x20]), chr(cfi_buffer[0x22]), chr(cfi_buffer[0x24]))
|
|
2188
|
-
d_swap = (0, 0)
|
|
2189
|
-
if magic == "QRY": # D0D1 not swapped
|
|
2190
|
-
pass
|
|
2191
|
-
elif magic == "RQZ": # D0D1 swapped
|
|
2192
|
-
d_swap = [(0, 1)]
|
|
2193
|
-
for j2 in range(0, len(d_swap)):
|
|
2194
|
-
for j in range(0, len(cfi_buffer)):
|
|
2195
|
-
cfi_buffer[j] = bitswap(cfi_buffer[j], d_swap[j2])
|
|
2196
|
-
elif magic == "\x92\x91\x9A": # D0D1+D6D7 swapped
|
|
2197
|
-
d_swap = [( 0, 1 ), ( 6, 7 )]
|
|
2198
|
-
for j2 in range(0, len(d_swap)):
|
|
2199
|
-
for j in range(0, len(cfi_buffer)):
|
|
2200
|
-
cfi_buffer[j] = bitswap(cfi_buffer[j], d_swap[j2])
|
|
2201
|
-
if ".dev" in Util.VERSION_PEP440 or Util.DEBUG:
|
|
2202
|
-
with open("debug_cfi_d0d1+d6d7.bin", "wb") as f: f.write(cfi_buffer)
|
|
2203
|
-
else:
|
|
2204
|
-
cfi_buffer = None
|
|
2205
|
-
except:
|
|
2206
|
-
cfi_buffer = None
|
|
2207
|
-
|
|
2208
2268
|
if self.MODE == "DMG":
|
|
2209
2269
|
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))
|
|
2210
2270
|
else:
|
|
2211
2271
|
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))
|
|
2272
|
+
flash_id_cmds[i]["read_cfi"] = [ flash_id_cmds[i]["read_identifier"][0][0], 0x98 ]
|
|
2273
|
+
read_cfi_cmds.append(flash_id_cmds[i]["read_cfi"])
|
|
2212
2274
|
|
|
2213
2275
|
dprint(f"Found {len(flash_id_methods):d} result(s)")
|
|
2214
2276
|
self._cart_write_flash([[0, 0xFF]], True)
|
|
@@ -2242,10 +2304,55 @@ class LK_Device(ABC):
|
|
|
2242
2304
|
|
|
2243
2305
|
dprint("Compatible flash types:", [(index, supported_carts[index]["names"][0]) for index in flash_types])
|
|
2244
2306
|
|
|
2307
|
+
try:
|
|
2308
|
+
if len(flash_types) > 0 and "read_cfi" in supported_carts[flash_types[0]]["commands"]:
|
|
2309
|
+
read_cfi_cmd = supported_carts[flash_types[0]]["commands"]["read_cfi"]
|
|
2310
|
+
reset_cmd = supported_carts[flash_types[0]]["commands"]["reset"]
|
|
2311
|
+
else:
|
|
2312
|
+
if len(read_cfi_cmds) == 0:
|
|
2313
|
+
read_cfi_cmd = [ [0, 0x98] ]
|
|
2314
|
+
else:
|
|
2315
|
+
read_cfi_cmd = [ read_cfi_cmds[0] ]
|
|
2316
|
+
reset_cmd = flash_id_cmds[0]["reset"]
|
|
2317
|
+
self._cart_write_flash(read_cfi_cmd, flashcart=(self.MODE == "AGB"))
|
|
2318
|
+
cfi_buffer = self._cart_read(0, 0x400)
|
|
2319
|
+
self._cart_write_flash(reset_cmd, flashcart=(self.MODE == "AGB"))
|
|
2320
|
+
|
|
2321
|
+
if ".dev" in Util.VERSION_PEP440 or Util.DEBUG:
|
|
2322
|
+
with open(Util.CONFIG_PATH + "/debug_cfi.bin", "wb") as f: f.write(cfi_buffer)
|
|
2323
|
+
|
|
2324
|
+
found = False
|
|
2325
|
+
for o in ((0x20, 2), (0x10, 1)):
|
|
2326
|
+
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])]))
|
|
2327
|
+
dprint("CFI magic:", hex(o[0]), hex(o[0] + (1 * o[1])), hex(o[0] + (2 * o[1])), "=", str(magic))
|
|
2328
|
+
d_swap = (0, 0)
|
|
2329
|
+
if magic == "QRY": # D0D1 not swapped
|
|
2330
|
+
found = True
|
|
2331
|
+
elif magic == "RQZ": # D0D1 swapped
|
|
2332
|
+
d_swap = [(0, 1)]
|
|
2333
|
+
for j2 in range(0, len(d_swap)):
|
|
2334
|
+
for j in range(0, len(cfi_buffer)):
|
|
2335
|
+
cfi_buffer[j] = bitswap(cfi_buffer[j], d_swap[j2])
|
|
2336
|
+
found = True
|
|
2337
|
+
elif magic == "\x92\x91\x9A": # D0D1+D6D7 swapped
|
|
2338
|
+
d_swap = [( 0, 1 ), ( 6, 7 )]
|
|
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
|
+
if ".dev" in Util.VERSION_PEP440 or Util.DEBUG:
|
|
2343
|
+
with open(Util.CONFIG_PATH + "/debug_cfi_d0d1+d6d7.bin", "wb") as f: f.write(cfi_buffer)
|
|
2344
|
+
found = True
|
|
2345
|
+
if found: break
|
|
2346
|
+
if found is False:
|
|
2347
|
+
cfi_buffer = None
|
|
2348
|
+
except:
|
|
2349
|
+
cfi_buffer = None
|
|
2350
|
+
|
|
2245
2351
|
if cfi_buffer is None or len(cfi_buffer) < 0x400:
|
|
2246
2352
|
cfi = False
|
|
2247
2353
|
else:
|
|
2248
2354
|
cfi = ParseCFI(cfi_buffer)
|
|
2355
|
+
|
|
2249
2356
|
if cfi is not False:
|
|
2250
2357
|
cfi["raw"] = cfi_buffer
|
|
2251
2358
|
s = ""
|
|
@@ -2281,6 +2388,8 @@ class LK_Device(ABC):
|
|
|
2281
2388
|
supp_flash_types = self.GetSupportedCartridgesDMG()
|
|
2282
2389
|
elif self.MODE == "AGB":
|
|
2283
2390
|
supp_flash_types = self.GetSupportedCartridgesAGB()
|
|
2391
|
+
else:
|
|
2392
|
+
raise NotImplementedError
|
|
2284
2393
|
|
|
2285
2394
|
if "flash_size" in supp_flash_types[1][flash_types[0]]:
|
|
2286
2395
|
size = supp_flash_types[1][flash_types[0]]["flash_size"]
|
|
@@ -2381,6 +2490,9 @@ class LK_Device(ABC):
|
|
|
2381
2490
|
def FlashROM(self, fncSetProgress=None, args=None):
|
|
2382
2491
|
self.DoTransfer(4, fncSetProgress, args)
|
|
2383
2492
|
|
|
2493
|
+
def DetectCartridge(self, fncSetProgress=None, args=None):
|
|
2494
|
+
self.DoTransfer(5, fncSetProgress, args)
|
|
2495
|
+
|
|
2384
2496
|
#################################################################
|
|
2385
2497
|
|
|
2386
2498
|
def _BackupROM(self, args):
|
|
@@ -2416,8 +2528,8 @@ class LK_Device(ABC):
|
|
|
2416
2528
|
|
|
2417
2529
|
# Firmware check L8
|
|
2418
2530
|
if self.FW["fw_ver"] < 8 and flashcart and "enable_pullups" in cart_type:
|
|
2419
|
-
|
|
2420
|
-
|
|
2531
|
+
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))
|
|
2532
|
+
del(cart_type["enable_pullups"])
|
|
2421
2533
|
# Firmware check L8
|
|
2422
2534
|
|
|
2423
2535
|
buffer_len = 0x4000
|
|
@@ -2477,9 +2589,6 @@ class LK_Device(ABC):
|
|
|
2477
2589
|
self.INFO["dump_info"]["agb_read_method"] = "3D Memory"
|
|
2478
2590
|
|
|
2479
2591
|
elif flashcart and "command_set" in cart_type and cart_type["command_set"] == "GBAMP":
|
|
2480
|
-
# if not self.CanPowerCycleCart():
|
|
2481
|
-
# 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})
|
|
2482
|
-
# return False
|
|
2483
2592
|
self.INFO["dump_info"]["agb_read_method"] = "GBA Movie Player"
|
|
2484
2593
|
if not "verify_write" in args: self.CartPowerCycleOrAskReconnect()
|
|
2485
2594
|
flashcart.Unlock()
|
|
@@ -2550,9 +2659,6 @@ class LK_Device(ABC):
|
|
|
2550
2659
|
else:
|
|
2551
2660
|
rom_banks = 1
|
|
2552
2661
|
rom_bank_size = 0x2000000
|
|
2553
|
-
|
|
2554
|
-
#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:
|
|
2555
|
-
# self.SetAGBReadMethod(0)
|
|
2556
2662
|
|
|
2557
2663
|
if self.ERROR: return
|
|
2558
2664
|
|
|
@@ -2577,9 +2683,12 @@ class LK_Device(ABC):
|
|
|
2577
2683
|
else:
|
|
2578
2684
|
self._write(self.DEVICE_CMD["DISABLE_PULLUPS"], wait=True)
|
|
2579
2685
|
dprint("Pullups disabled")
|
|
2686
|
+
|
|
2580
2687
|
if self.FW["fw_ver"] >= 12:
|
|
2581
|
-
if "
|
|
2582
|
-
|
|
2688
|
+
if self.MODE == "DMG":
|
|
2689
|
+
# Joey Jr bug workaround
|
|
2690
|
+
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
|
|
2691
|
+
self._set_fw_variable("PULLUPS_ENABLED", enable_pullup_wr)
|
|
2583
2692
|
|
|
2584
2693
|
buffer = bytearray(size)
|
|
2585
2694
|
max_length = self.MAX_BUFFER_READ
|
|
@@ -2603,6 +2712,8 @@ class LK_Device(ABC):
|
|
|
2603
2712
|
end_bank = math.ceil((buffer_pos + args["verify_len"]) / rom_bank_size)
|
|
2604
2713
|
rom_banks = end_bank
|
|
2605
2714
|
elif "bl_offset" in args:
|
|
2715
|
+
if "bl_layout" in args and args["bl_layout"] in (1, 2):
|
|
2716
|
+
args["bl_size"] <<= 1
|
|
2606
2717
|
buffer_pos = args["bl_offset"]
|
|
2607
2718
|
start_address = buffer_pos
|
|
2608
2719
|
end_address = args["bl_offset"] + args["bl_size"]
|
|
@@ -2707,17 +2818,22 @@ class LK_Device(ABC):
|
|
|
2707
2818
|
elif lives < 20:
|
|
2708
2819
|
lives = 20
|
|
2709
2820
|
|
|
2710
|
-
if file is not None:
|
|
2821
|
+
if file is not None:
|
|
2822
|
+
if "bl_layout" in args and args["bl_layout"] == 1:
|
|
2823
|
+
file.write(temp[0x0000:0x2000])
|
|
2824
|
+
elif "bl_layout" in args and args["bl_layout"] == 2:
|
|
2825
|
+
file.write(temp[0x2000:0x4000])
|
|
2826
|
+
else:
|
|
2827
|
+
file.write(temp)
|
|
2711
2828
|
buffer[pos_total:pos_total+len(temp)] = temp
|
|
2712
2829
|
pos_total += len(temp)
|
|
2713
2830
|
|
|
2714
2831
|
if "verify_write" in args:
|
|
2715
|
-
#if pos_total >= len(args["verify_write"]): break
|
|
2716
2832
|
check = args["verify_write"][pos_total-len(temp):pos_total]
|
|
2717
2833
|
if temp[:len(check)] != check:
|
|
2718
2834
|
if ".dev" in Util.VERSION_PEP440 or Util.DEBUG:
|
|
2719
2835
|
dprint("Writing 0x{:X} bytes to debug_verify_0x{:X}.bin".format(len(temp), pos_total-len(temp)))
|
|
2720
|
-
with open("debug_verify_0x{:X}.bin".format(pos_total-len(temp)), "ab") as f: f.write(temp)
|
|
2836
|
+
with open(Util.CONFIG_PATH + "/debug_verify_0x{:X}.bin".format(pos_total-len(temp)), "ab") as f: f.write(temp)
|
|
2721
2837
|
|
|
2722
2838
|
for i in range(0, pos_total):
|
|
2723
2839
|
if (i < len(args["verify_write"]) - 1) and (i < pos_total - 1) and args["verify_write"][i] != buffer[i]:
|
|
@@ -2818,7 +2934,7 @@ class LK_Device(ABC):
|
|
|
2818
2934
|
|
|
2819
2935
|
# Check for ROM loops
|
|
2820
2936
|
self.INFO["loop_detected"] = False
|
|
2821
|
-
temp =
|
|
2937
|
+
temp = len(buffer)
|
|
2822
2938
|
while temp > 0x4000:
|
|
2823
2939
|
temp = temp >> 1
|
|
2824
2940
|
if (buffer[0:0x4000] == buffer[temp:temp+0x4000]):
|
|
@@ -2861,6 +2977,8 @@ class LK_Device(ABC):
|
|
|
2861
2977
|
_agb_gpio = AGB_GPIO(args={"rtc":True}, cart_write_fncptr=self._cart_write, cart_read_fncptr=self._cart_read, cart_powercycle_fncptr=self.CartPowerCycleOrAskReconnect, clk_toggle_fncptr=self._clk_toggle)
|
|
2862
2978
|
if _agb_gpio.HasRTC() is not True: return False
|
|
2863
2979
|
ret = _agb_gpio.WriteRTCDict(args["rtc_dict"])
|
|
2980
|
+
else:
|
|
2981
|
+
raise NotImplementedError
|
|
2864
2982
|
return ret
|
|
2865
2983
|
|
|
2866
2984
|
def _BackupRestoreRAM(self, args):
|
|
@@ -2872,14 +2990,23 @@ class LK_Device(ABC):
|
|
|
2872
2990
|
empty_data_byte = 0x00
|
|
2873
2991
|
extra_size = 0
|
|
2874
2992
|
audio_low = False
|
|
2993
|
+
|
|
2994
|
+
# Initialization
|
|
2995
|
+
ram_banks = 0
|
|
2996
|
+
buffer_len = 0
|
|
2997
|
+
sram_5 = 0
|
|
2998
|
+
temp = None
|
|
2875
2999
|
|
|
2876
3000
|
cart_type = None
|
|
2877
3001
|
if "cart_type" in args and args["cart_type"] >= 0:
|
|
2878
3002
|
supported_carts = list(self.SUPPORTED_CARTS[self.MODE].values())
|
|
2879
3003
|
cart_type = copy.deepcopy(supported_carts[args["cart_type"]])
|
|
3004
|
+
|
|
2880
3005
|
if self.FW["fw_ver"] >= 12:
|
|
2881
|
-
if "
|
|
2882
|
-
|
|
3006
|
+
if self.MODE == "DMG":
|
|
3007
|
+
# Joey Jr bug workaround
|
|
3008
|
+
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
|
|
3009
|
+
self._set_fw_variable("PULLUPS_ENABLED", enable_pullup_wr)
|
|
2883
3010
|
|
|
2884
3011
|
self._set_fw_variable("STATUS_REGISTER_MASK", 0x80)
|
|
2885
3012
|
self._set_fw_variable("STATUS_REGISTER_VALUE", 0x80)
|
|
@@ -2895,7 +3022,9 @@ class LK_Device(ABC):
|
|
|
2895
3022
|
save_size = args["save_size"]
|
|
2896
3023
|
else:
|
|
2897
3024
|
save_size = Util.DMG_Header_RAM_Sizes_Flasher_Map[Util.DMG_Header_RAM_Sizes_Map.index(args["save_type"])]
|
|
3025
|
+
|
|
2898
3026
|
ram_banks = _mbc.GetRAMBanks(save_size)
|
|
3027
|
+
|
|
2899
3028
|
buffer_len = min(0x200, _mbc.GetRAMBankSize())
|
|
2900
3029
|
self._write(self.DEVICE_CMD["SET_MODE_DMG"], wait=self.FW["fw_ver"] >= 12)
|
|
2901
3030
|
self._set_fw_variable("DMG_WRITE_CS_PULSE", 0)
|
|
@@ -3052,9 +3181,13 @@ class LK_Device(ABC):
|
|
|
3052
3181
|
if args["rtc"] is True:
|
|
3053
3182
|
extra_size = 0x10
|
|
3054
3183
|
|
|
3184
|
+
action = None
|
|
3055
3185
|
if args["mode"] == 2: # Backup
|
|
3056
3186
|
action = "SAVE_READ"
|
|
3057
3187
|
buffer = bytearray()
|
|
3188
|
+
if self.MODE == "DMG" and args["save_type"] == 0x204: # Unlicensed PHOTO!
|
|
3189
|
+
ram_banks = 16
|
|
3190
|
+
|
|
3058
3191
|
elif args["mode"] == 3: # Restore
|
|
3059
3192
|
action = "SAVE_WRITE"
|
|
3060
3193
|
self.INFO["save_erase"] = args["erase"]
|
|
@@ -3062,6 +3195,9 @@ class LK_Device(ABC):
|
|
|
3062
3195
|
buffer = bytearray([ empty_data_byte ] * save_size)
|
|
3063
3196
|
if self.MODE == "DMG" and _mbc.GetName() == "Xploder GB":
|
|
3064
3197
|
buffer[0] = 0x00
|
|
3198
|
+
elif self.MODE == "DMG" and _mbc.GetName() == "MAC-GBD":
|
|
3199
|
+
buffer[0x11B2:0x11D7] = bytearray.fromhex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D616769631115")
|
|
3200
|
+
buffer[0x11D7:0x11FC] = buffer[0x11B2:0x11D7]
|
|
3065
3201
|
else:
|
|
3066
3202
|
if args["path"] is None:
|
|
3067
3203
|
if "buffer" in args:
|
|
@@ -3072,16 +3208,18 @@ class LK_Device(ABC):
|
|
|
3072
3208
|
with open(args["path"], "rb") as f:
|
|
3073
3209
|
buffer = bytearray(f.read())
|
|
3074
3210
|
|
|
3211
|
+
if self.MODE == "DMG" and args["save_type"] == 0x204: # Unlicensed PHOTO!
|
|
3212
|
+
ram_banks = 16
|
|
3213
|
+
if len(buffer) <= 0x20000:
|
|
3214
|
+
save_size = len(buffer)
|
|
3215
|
+
args["save_type"] = 0x04
|
|
3216
|
+
|
|
3075
3217
|
# Fill too small file
|
|
3076
3218
|
if not (self.MODE == "AGB" and args["save_type"] == 6): # Not DACS
|
|
3077
3219
|
if args["mode"] == 3:
|
|
3078
3220
|
while len(buffer) < save_size:
|
|
3079
3221
|
buffer += bytearray(buffer)
|
|
3080
3222
|
|
|
3081
|
-
#if self.MODE == "AGB" and "ereader" in self.INFO and self.INFO["ereader"] is True: # e-Reader
|
|
3082
|
-
# buffer[0xFF80:0x10000] = bytearray([0] * 0x80)
|
|
3083
|
-
# buffer[0x1FF80:0x20000] = bytearray([0] * 0x80)
|
|
3084
|
-
|
|
3085
3223
|
# Main loop
|
|
3086
3224
|
if not (args["mode"] == 2 and "verify_write" in args and args["verify_write"]):
|
|
3087
3225
|
self.INFO["action"] = self.ACTIONS[action]
|
|
@@ -3132,10 +3270,6 @@ class LK_Device(ABC):
|
|
|
3132
3270
|
else:
|
|
3133
3271
|
dprint("Unknown bank switching method")
|
|
3134
3272
|
time.sleep(0.05)
|
|
3135
|
-
|
|
3136
|
-
# if "detect" in args and args["detect"] is True:
|
|
3137
|
-
# start_address = end_address - 64
|
|
3138
|
-
# buffer_len = 64
|
|
3139
3273
|
|
|
3140
3274
|
max_length = 64
|
|
3141
3275
|
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))
|
|
@@ -3193,7 +3327,6 @@ class LK_Device(ABC):
|
|
|
3193
3327
|
continue
|
|
3194
3328
|
|
|
3195
3329
|
if xe == 2 and in_temp[0] != in_temp[1]:
|
|
3196
|
-
# print(in_temp[0], in_temp[1], sep="\n")
|
|
3197
3330
|
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})
|
|
3198
3331
|
return False
|
|
3199
3332
|
|
|
@@ -3315,11 +3448,6 @@ class LK_Device(ABC):
|
|
|
3315
3448
|
|
|
3316
3449
|
pos += buffer_len
|
|
3317
3450
|
buffer_offset += buffer_len
|
|
3318
|
-
|
|
3319
|
-
# if "detect" in args and args["detect"] is True:
|
|
3320
|
-
# buffer += bytearray(end_address - 64)
|
|
3321
|
-
# pos += end_address - 64
|
|
3322
|
-
# buffer_offset += end_address - 64
|
|
3323
3451
|
|
|
3324
3452
|
verified = False
|
|
3325
3453
|
if args["mode"] == 2: # Backup
|
|
@@ -3355,6 +3483,13 @@ class LK_Device(ABC):
|
|
|
3355
3483
|
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:
|
|
3356
3484
|
buffer[5] = sram_5
|
|
3357
3485
|
|
|
3486
|
+
# PHOTO! rolls
|
|
3487
|
+
if self.MODE == "DMG" and args["save_type"] == 0x204:
|
|
3488
|
+
for i in range(8, 64):
|
|
3489
|
+
_mbc.SelectBankROM(i)
|
|
3490
|
+
buffer += self.ReadROM(0x4000, 0x4000)
|
|
3491
|
+
self.SetProgress({"action":"UPDATE_POS", "pos":len(buffer)})
|
|
3492
|
+
|
|
3358
3493
|
if args["path"] is not None:
|
|
3359
3494
|
if self.MODE == "DMG" and _mbc.GetName() == "MBC2":
|
|
3360
3495
|
for i in range(0, len(buffer)):
|
|
@@ -3381,11 +3516,21 @@ class LK_Device(ABC):
|
|
|
3381
3516
|
advance = "rtc_advance" in args and args["rtc_advance"]
|
|
3382
3517
|
self.SetProgress({"action":"UPDATE_RTC", "method":"write"})
|
|
3383
3518
|
if self.MODE == "DMG" and args["rtc"] is True:
|
|
3519
|
+
if "erase" in args and args["erase"] is True:
|
|
3520
|
+
buffer += bytearray([0] * _mbc.GetRTCBufferSize())
|
|
3384
3521
|
_mbc.WriteRTC(buffer[-_mbc.GetRTCBufferSize():], advance=advance)
|
|
3385
3522
|
elif self.MODE == "AGB":
|
|
3523
|
+
if "erase" in args and args["erase"] is True:
|
|
3524
|
+
buffer += bytearray([0xFF] * 0x10)
|
|
3386
3525
|
_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)
|
|
3387
3526
|
_agb_gpio.WriteRTC(buffer[-0x10:], advance=advance)
|
|
3388
3527
|
|
|
3528
|
+
# PHOTO! rolls
|
|
3529
|
+
if self.MODE == "DMG" and args["save_type"] == 0x204 and "cart_type" in args and args["cart_type"] != -1:
|
|
3530
|
+
if len(buffer) > 0x20000:
|
|
3531
|
+
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})
|
|
3532
|
+
args["verify_write"] = False
|
|
3533
|
+
|
|
3389
3534
|
self.SetProgress({"action":"UPDATE_POS", "pos":len(buffer), "force_update":True})
|
|
3390
3535
|
|
|
3391
3536
|
# ↓↓↓ Write verify
|
|
@@ -3467,7 +3612,15 @@ class LK_Device(ABC):
|
|
|
3467
3612
|
return True
|
|
3468
3613
|
|
|
3469
3614
|
def _FlashROM(self, args):
|
|
3615
|
+
# Initialization
|
|
3470
3616
|
self.FAST_READ = True
|
|
3617
|
+
temp = None
|
|
3618
|
+
rom_bank_size = 0
|
|
3619
|
+
end_bank = 0
|
|
3620
|
+
pos_from = 0
|
|
3621
|
+
verify_len = 0
|
|
3622
|
+
enable_pullup_wr = False
|
|
3623
|
+
|
|
3471
3624
|
if "buffer" in args:
|
|
3472
3625
|
data_import = args["buffer"]
|
|
3473
3626
|
else:
|
|
@@ -3479,6 +3632,20 @@ class LK_Device(ABC):
|
|
|
3479
3632
|
if "start_addr" in args and args["start_addr"] > 0:
|
|
3480
3633
|
data_import = bytearray(b'\xFF' * args["start_addr"]) + data_import
|
|
3481
3634
|
|
|
3635
|
+
# Batteryless SRAM
|
|
3636
|
+
if "bl_layout" in args and args["bl_layout"] in (1, 2):
|
|
3637
|
+
args["bl_size"] <<= 1
|
|
3638
|
+
args["flash_size"] <<= 1
|
|
3639
|
+
bl_data_import = bytearray(b'\xFF' * args["bl_size"])
|
|
3640
|
+
|
|
3641
|
+
if args["bl_layout"] == 1:
|
|
3642
|
+
for i in range(0, args["bl_size"] // 0x4000):
|
|
3643
|
+
bl_data_import[i*0x4000:i*0x4000+0x2000] = data_import[i*0x2000:i*0x2000+0x2000]
|
|
3644
|
+
elif args["bl_layout"] == 2:
|
|
3645
|
+
for i in range(0, args["bl_size"] // 0x4000):
|
|
3646
|
+
bl_data_import[i*0x4000+0x2000:i*0x4000+0x2000+0x2000] = data_import[i*0x2000:i*0x2000+0x2000]
|
|
3647
|
+
data_import = bl_data_import
|
|
3648
|
+
|
|
3482
3649
|
# Pad data
|
|
3483
3650
|
if len(data_import) > 0:
|
|
3484
3651
|
if len(data_import) < 0x400:
|
|
@@ -3521,24 +3688,23 @@ class LK_Device(ABC):
|
|
|
3521
3688
|
|
|
3522
3689
|
supported_carts = list(self.SUPPORTED_CARTS[self.MODE].values())
|
|
3523
3690
|
cart_type = copy.deepcopy(supported_carts[args["cart_type"]])
|
|
3691
|
+
try:
|
|
3692
|
+
cart_name = cart_type["names"][0]
|
|
3693
|
+
except:
|
|
3694
|
+
cart_name = "Unknown"
|
|
3695
|
+
|
|
3524
3696
|
if cart_type == "RETAIL": return False # Generic ROM Cartridge is not flashable
|
|
3525
3697
|
|
|
3526
|
-
#
|
|
3527
|
-
# if "power_cycle" in cart_type and cart_type["power_cycle"] is True and not self.CanPowerCycleCart():
|
|
3528
|
-
# 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})
|
|
3529
|
-
# return False
|
|
3530
|
-
# Special carts
|
|
3531
|
-
# Firmware check L1
|
|
3698
|
+
# Firmware check L2
|
|
3532
3699
|
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)):
|
|
3533
|
-
#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})
|
|
3534
3700
|
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type requires at least firmware version L2.", "abortable":False})
|
|
3535
3701
|
return False
|
|
3536
|
-
# Firmware check L1
|
|
3537
3702
|
# Firmware check L2
|
|
3703
|
+
# Firmware check L3
|
|
3538
3704
|
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"])):
|
|
3539
3705
|
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))
|
|
3540
3706
|
del(cart_type["commands"]["buffer_write"])
|
|
3541
|
-
# Firmware check
|
|
3707
|
+
# Firmware check L3
|
|
3542
3708
|
# Firmware check L5
|
|
3543
3709
|
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)):
|
|
3544
3710
|
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type requires at least firmware version L5.", "abortable":False})
|
|
@@ -3549,17 +3715,25 @@ class LK_Device(ABC):
|
|
|
3549
3715
|
# Firmware check L5
|
|
3550
3716
|
# Firmware check L8
|
|
3551
3717
|
if (self.FW["fw_ver"] < 8 and "enable_pullups" in cart_type and cart_type["enable_pullups"] is True):
|
|
3552
|
-
|
|
3553
|
-
|
|
3718
|
+
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))
|
|
3719
|
+
del(cart_type["enable_pullups"])
|
|
3554
3720
|
# Firmware check L8
|
|
3555
3721
|
# Firmware check L12
|
|
3556
3722
|
if (self.FW["fw_ver"] < 12 and "set_irq_high" in cart_type and cart_type["set_irq_high"] is True):
|
|
3557
|
-
|
|
3558
|
-
|
|
3723
|
+
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))
|
|
3724
|
+
del(cart_type["set_irq_high"])
|
|
3559
3725
|
if (self.FW["fw_ver"] < 12 and "status_register_mask" in cart_type):
|
|
3560
|
-
self.
|
|
3726
|
+
if self.FW["pcb_name"] in ("GBxCart RW", ""):
|
|
3727
|
+
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})
|
|
3728
|
+
else:
|
|
3729
|
+
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type requires at least firmware version L12.", "abortable":False})
|
|
3561
3730
|
return False
|
|
3562
3731
|
# Firmware check L12
|
|
3732
|
+
# Firmware check L14
|
|
3733
|
+
if (self.FW["fw_ver"] < 14 and "set_audio_high" in cart_type and cart_type["set_audio_high"] is True):
|
|
3734
|
+
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type requires at least firmware version L14.", "abortable":False})
|
|
3735
|
+
return False
|
|
3736
|
+
# Firmware check L14
|
|
3563
3737
|
|
|
3564
3738
|
# Ensure cart is powered
|
|
3565
3739
|
if self.CanPowerCycleCart(): self.CartPowerOn()
|
|
@@ -3591,7 +3765,7 @@ class LK_Device(ABC):
|
|
|
3591
3765
|
flashcart = Flashcart(config=cart_type, fncptr=fc_fncptr)
|
|
3592
3766
|
|
|
3593
3767
|
rumble = "rumble" in flashcart.CONFIG and flashcart.CONFIG["rumble"] is True
|
|
3594
|
-
|
|
3768
|
+
|
|
3595
3769
|
# ↓↓↓ Set Voltage
|
|
3596
3770
|
if args["override_voltage"] is not False:
|
|
3597
3771
|
if args["override_voltage"] == 5:
|
|
@@ -3603,20 +3777,22 @@ class LK_Device(ABC):
|
|
|
3603
3777
|
elif flashcart.GetVoltage() == 5:
|
|
3604
3778
|
self._write(self.DEVICE_CMD["SET_VOLTAGE_5V"], wait=self.FW["fw_ver"] >= 12)
|
|
3605
3779
|
# ↑↑↑ Set Voltage
|
|
3606
|
-
|
|
3780
|
+
|
|
3607
3781
|
# ↓↓↓ Pad data for full chip erase on sector erase mode
|
|
3608
3782
|
if not flashcart.SupportsChipErase() and flashcart.SupportsSectorErase() and args["prefer_chip_erase"]:
|
|
3609
3783
|
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))
|
|
3610
|
-
|
|
3611
|
-
if
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
pad_len
|
|
3617
|
-
|
|
3784
|
+
# Pad data if the user wants to erase the entire cartridge
|
|
3785
|
+
if data_import == bytearray([0xFF] * len(data_import)):
|
|
3786
|
+
flash_size = flashcart.GetFlashSize()
|
|
3787
|
+
if flash_size is not False and len(data_import) < flash_size:
|
|
3788
|
+
# Pad with FF till the end (with MemoryError fix)
|
|
3789
|
+
pad_len = flash_size - len(data_import)
|
|
3790
|
+
while pad_len > 0x2000000:
|
|
3791
|
+
data_import += bytearray([0xFF] * 0x2000000)
|
|
3792
|
+
pad_len -= 0x2000000
|
|
3793
|
+
data_import += bytearray([0xFF] * (flash_size - len(data_import)))
|
|
3618
3794
|
# ↑↑↑ Pad data for full chip erase on sector erase mode
|
|
3619
|
-
|
|
3795
|
+
|
|
3620
3796
|
# ↓↓↓ Flashcart configuration
|
|
3621
3797
|
if self.FW["fw_ver"] >= 8:
|
|
3622
3798
|
if "enable_pullups" in cart_type:
|
|
@@ -3627,9 +3803,11 @@ class LK_Device(ABC):
|
|
|
3627
3803
|
self._write(self.DEVICE_CMD["DISABLE_PULLUPS"], wait=True)
|
|
3628
3804
|
dprint("Pullups disabled")
|
|
3629
3805
|
if self.FW["fw_ver"] >= 12:
|
|
3630
|
-
if "
|
|
3631
|
-
|
|
3632
|
-
|
|
3806
|
+
if self.MODE == "DMG":
|
|
3807
|
+
# Joey Jr bug workaround
|
|
3808
|
+
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
|
|
3809
|
+
self._set_fw_variable("PULLUPS_ENABLED", enable_pullup_wr)
|
|
3810
|
+
elif self.MODE == "AGB":
|
|
3633
3811
|
self._set_fw_variable("AGB_IRQ_ENABLED", 1 if "set_irq_high" in cart_type else 0)
|
|
3634
3812
|
|
|
3635
3813
|
_mbc = None
|
|
@@ -3704,7 +3882,7 @@ class LK_Device(ABC):
|
|
|
3704
3882
|
else:
|
|
3705
3883
|
dprint("Hidden sector data:", args["buffer_map"])
|
|
3706
3884
|
if ".dev" in Util.VERSION_PEP440 or Util.DEBUG:
|
|
3707
|
-
with open("debug_mmsa_map.bin", "wb") as f: f.write(args["buffer_map"])
|
|
3885
|
+
with open(Util.CONFIG_PATH + "/debug_mmsa_map.bin", "wb") as f: f.write(args["buffer_map"])
|
|
3708
3886
|
data_map_import = copy.copy(args["buffer_map"])
|
|
3709
3887
|
data_map_import = bytearray(data_map_import)
|
|
3710
3888
|
dprint("Hidden sector data loaded")
|
|
@@ -3716,17 +3894,13 @@ class LK_Device(ABC):
|
|
|
3716
3894
|
temp = 0
|
|
3717
3895
|
if command_set_type == "AMD":
|
|
3718
3896
|
temp = 0x01
|
|
3719
|
-
#self._write(0x01) # FLASH_COMMAND_SET_AMD
|
|
3720
|
-
#self._set_fw_variable("FLASH_SHARP_VERIFY_SR", 0)
|
|
3721
3897
|
dprint("Using AMD command set")
|
|
3722
3898
|
elif command_set_type == "INTEL":
|
|
3723
3899
|
temp = 0x02
|
|
3724
|
-
#self._write(0x02) # FLASH_COMMAND_SET_INTEL
|
|
3725
3900
|
self._set_fw_variable("FLASH_SHARP_VERIFY_SR", 0)
|
|
3726
3901
|
dprint("Using Intel command set")
|
|
3727
3902
|
elif command_set_type == "SHARP":
|
|
3728
3903
|
temp = 0x02
|
|
3729
|
-
#self._write(0x02) # FLASH_COMMAND_SET_INTEL
|
|
3730
3904
|
self._set_fw_variable("FLASH_SHARP_VERIFY_SR", 1)
|
|
3731
3905
|
dprint("Using Sharp/Intel command set")
|
|
3732
3906
|
elif command_set_type in ("GBMEMORY", "DMG-MBC5-32M-FLASH"):
|
|
@@ -3867,6 +4041,8 @@ class LK_Device(ABC):
|
|
|
3867
4041
|
_mbc.SelectBankROM(1)
|
|
3868
4042
|
if we != 0x00:
|
|
3869
4043
|
self._set_fw_variable("FLASH_WE_PIN", we)
|
|
4044
|
+
if self.FW["fw_ver"] >= 14 and "set_audio_high" in cart_type:
|
|
4045
|
+
self._set_fw_variable("DMG_AUDIO_ENABLED", 1 if "set_audio_high" in cart_type else 0)
|
|
3870
4046
|
# ↑↑↑ Preparations
|
|
3871
4047
|
|
|
3872
4048
|
# ↓↓↓ Read Flash ID
|
|
@@ -3893,8 +4069,6 @@ class LK_Device(ABC):
|
|
|
3893
4069
|
if len(sector_offsets) > 0:
|
|
3894
4070
|
flash_capacity = sector_offsets[-1][0] + sector_offsets[-1][1]
|
|
3895
4071
|
if flash_capacity < len(data_import) and not (flashcart.SupportsChipErase() and args["prefer_chip_erase"]):
|
|
3896
|
-
#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})
|
|
3897
|
-
#return False
|
|
3898
4072
|
sector_offsets = flashcart.GetSectorOffsets(rom_size=len(data_import), rom_bank_size=rom_bank_size)
|
|
3899
4073
|
|
|
3900
4074
|
sector_offsets_hash = base64.urlsafe_b64encode(hashlib.sha1(str(sector_offsets).encode("UTF-8")).digest()).decode("ASCII", "ignore")[:4]
|
|
@@ -3949,7 +4123,6 @@ class LK_Device(ABC):
|
|
|
3949
4123
|
bl_sectors = []
|
|
3950
4124
|
for sector in sector_offsets:
|
|
3951
4125
|
if flash_offset > sector[0]: continue
|
|
3952
|
-
#if len(bl_sectors) > 0 and (flash_offset + flash_size) < (sector[0] + sector[1]): break
|
|
3953
4126
|
if (flash_offset + flash_size) < sector[0]: break
|
|
3954
4127
|
bl_sectors.append(sector)
|
|
3955
4128
|
write_sectors = bl_sectors
|
|
@@ -3963,7 +4136,7 @@ class LK_Device(ABC):
|
|
|
3963
4136
|
|
|
3964
4137
|
dprint("Sectors to update:", write_sectors)
|
|
3965
4138
|
# ↑↑↑ Read Sector Map
|
|
3966
|
-
|
|
4139
|
+
|
|
3967
4140
|
# ↓↓↓ Chip erase
|
|
3968
4141
|
chip_erase = False
|
|
3969
4142
|
if flashcart.SupportsChipErase() and not flash_offset > 0:
|
|
@@ -3978,7 +4151,7 @@ class LK_Device(ABC):
|
|
|
3978
4151
|
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"No erase method available.", "abortable":False})
|
|
3979
4152
|
return False
|
|
3980
4153
|
# ↑↑↑ Chip erase
|
|
3981
|
-
|
|
4154
|
+
|
|
3982
4155
|
# ↓↓↓ Flash Write
|
|
3983
4156
|
if chip_erase:
|
|
3984
4157
|
write_sectors = [[ 0, len(data_import) ]]
|
|
@@ -3987,9 +4160,10 @@ class LK_Device(ABC):
|
|
|
3987
4160
|
elif len(write_sectors) == 0:
|
|
3988
4161
|
write_sectors = sector_offsets
|
|
3989
4162
|
|
|
3990
|
-
|
|
4163
|
+
if not "photo_mode" in args:
|
|
4164
|
+
self.SetProgress({"action":"INITIALIZE", "method":"ROM_WRITE", "size":len(data_import), "flash_offset":flash_offset, "sector_count":len(write_sectors)})
|
|
4165
|
+
self.INFO["action"] = self.ACTIONS["ROM_WRITE"]
|
|
3991
4166
|
self.SetProgress({"action":"UPDATE_POS", "pos":flash_offset})
|
|
3992
|
-
self.INFO["action"] = self.ACTIONS["ROM_WRITE"]
|
|
3993
4167
|
|
|
3994
4168
|
if smallest_sector_size is not False:
|
|
3995
4169
|
buffer_len = smallest_sector_size
|
|
@@ -4030,9 +4204,6 @@ class LK_Device(ABC):
|
|
|
4030
4204
|
sector_pos = sector_offsets.index(sector[:2])
|
|
4031
4205
|
start_bank = math.floor(buffer_pos / rom_bank_size)
|
|
4032
4206
|
end_bank = math.ceil((buffer_pos + sector[1]) / rom_bank_size)
|
|
4033
|
-
# print(hex(start_address), hex(end_address), start_bank, end_bank)
|
|
4034
|
-
# print(hex(sector_offsets[sector_pos][0]), sector_pos)
|
|
4035
|
-
# print("")
|
|
4036
4207
|
elif self.MODE == "DMG":
|
|
4037
4208
|
dprint("Writing sector:", hex(sector[0]), hex(sector[1]))
|
|
4038
4209
|
buffer_pos = sector[0]
|
|
@@ -4043,12 +4214,85 @@ class LK_Device(ABC):
|
|
|
4043
4214
|
sector_pos = sector_offsets.index(sector[:2])
|
|
4044
4215
|
start_bank = math.floor(buffer_pos / rom_bank_size)
|
|
4045
4216
|
end_bank = math.ceil((buffer_pos + sector[1]) / rom_bank_size)
|
|
4046
|
-
# print(hex(start_address), hex(end_address), start_bank, end_bank)
|
|
4047
|
-
# print(hex(sector_offsets[sector_pos][0]), sector_pos)
|
|
4048
|
-
# print("")
|
|
4049
4217
|
|
|
4050
|
-
#for bank in range(start_bank, end_bank):
|
|
4051
4218
|
bank = start_bank
|
|
4219
|
+
|
|
4220
|
+
# ↓↓↓ Check if data matches already
|
|
4221
|
+
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"):
|
|
4222
|
+
buffer_pos_matchcheck = buffer_pos
|
|
4223
|
+
verified = False
|
|
4224
|
+
ts_se_start = time.time()
|
|
4225
|
+
while bank < end_bank:
|
|
4226
|
+
status = None
|
|
4227
|
+
# ↓↓↓ Switch ROM bank
|
|
4228
|
+
if self.MODE == "DMG":
|
|
4229
|
+
if _mbc.ResetBeforeBankChange(bank) is True:
|
|
4230
|
+
dprint("Resetting the MBC")
|
|
4231
|
+
self._write(self.DEVICE_CMD["DMG_MBC_RESET"], wait=True)
|
|
4232
|
+
(start_address, bank_size) = _mbc.SelectBankROM(bank)
|
|
4233
|
+
if flashcart.PulseResetAfterWrite():
|
|
4234
|
+
if bank == 0:
|
|
4235
|
+
if self.FW["fw_ver"] < 2:
|
|
4236
|
+
self._write(self.DEVICE_CMD["OFW_GB_CART_MODE"])
|
|
4237
|
+
else:
|
|
4238
|
+
self._write(self.DEVICE_CMD["SET_MODE_DMG"], wait=self.FW["fw_ver"] >= 12)
|
|
4239
|
+
self._write(self.DEVICE_CMD["DMG_MBC_RESET"], wait=True)
|
|
4240
|
+
self._set_fw_variable("DMG_ROM_BANK", bank)
|
|
4241
|
+
|
|
4242
|
+
buffer_len = min(buffer_len, bank_size)
|
|
4243
|
+
if "start_addr" in flashcart.CONFIG and bank == 0: start_address = flashcart.CONFIG["start_addr"]
|
|
4244
|
+
end_address = start_address + bank_size
|
|
4245
|
+
start_address += (buffer_pos % rom_bank_size)
|
|
4246
|
+
if end_address > start_address + sector[1]:
|
|
4247
|
+
end_address = start_address + sector[1]
|
|
4248
|
+
|
|
4249
|
+
elif self.MODE == "AGB":
|
|
4250
|
+
if "flash_bank_select_type" in cart_type and cart_type["flash_bank_select_type"] > 0:
|
|
4251
|
+
if bank != current_bank:
|
|
4252
|
+
flashcart.Reset(full_reset=True)
|
|
4253
|
+
flashcart.SelectBankROM(bank)
|
|
4254
|
+
temp = end_address - start_address
|
|
4255
|
+
start_address %= cart_type["flash_bank_size"]
|
|
4256
|
+
end_address = min(cart_type["flash_bank_size"], start_address + temp)
|
|
4257
|
+
current_bank = bank
|
|
4258
|
+
# ↑↑↑ Switch ROM bank
|
|
4259
|
+
|
|
4260
|
+
pos = start_address
|
|
4261
|
+
#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))
|
|
4262
|
+
verified = self.CompareCRC32(buffer=data_import, offset=buffer_pos_matchcheck, length=end_address - pos, address=pos, flashcart=flashcart, reset=True, mbc=_mbc, bank=bank)
|
|
4263
|
+
self.SetProgress({"action":"UPDATE_POS", "pos":buffer_pos_matchcheck})
|
|
4264
|
+
if verified is not True:
|
|
4265
|
+
break
|
|
4266
|
+
buffer_pos_matchcheck += (end_address - pos)
|
|
4267
|
+
bank += 1
|
|
4268
|
+
|
|
4269
|
+
if verified is True:
|
|
4270
|
+
dprint("Skipping sector #{:d}, because the CRC32 matched".format(sector_pos))
|
|
4271
|
+
if flashcart.FlashCommandsOnBank1(): _mbc.SelectBankROM(bank)
|
|
4272
|
+
self.NO_PROG_UPDATE = True
|
|
4273
|
+
se_ret = flashcart.SectorErase(pos=pos, buffer_pos=buffer_pos, skip=verified)
|
|
4274
|
+
self.NO_PROG_UPDATE = False
|
|
4275
|
+
|
|
4276
|
+
if self.CANCEL:
|
|
4277
|
+
cancel_args = {"action":"ABORT", "abortable":False}
|
|
4278
|
+
cancel_args.update(self.CANCEL_ARGS)
|
|
4279
|
+
self.CANCEL_ARGS = {}
|
|
4280
|
+
self.ERROR_ARGS = {}
|
|
4281
|
+
self.SetProgress(cancel_args)
|
|
4282
|
+
if self.CanPowerCycleCart(): self.CartPowerCycle()
|
|
4283
|
+
return
|
|
4284
|
+
|
|
4285
|
+
ts_se_elapsed = time.time() - ts_se_start
|
|
4286
|
+
if se_ret:
|
|
4287
|
+
sector_size = se_ret
|
|
4288
|
+
dprint("Next sector size: 0x{:X}".format(sector_size))
|
|
4289
|
+
buffer_pos += sector_size
|
|
4290
|
+
continue
|
|
4291
|
+
else:
|
|
4292
|
+
verified = False
|
|
4293
|
+
bank = start_bank
|
|
4294
|
+
# ↑↑↑ Check if data matches already
|
|
4295
|
+
|
|
4052
4296
|
while bank < end_bank:
|
|
4053
4297
|
if self.CANCEL:
|
|
4054
4298
|
cancel_args = {"action":"ABORT", "abortable":False}
|
|
@@ -4060,7 +4304,6 @@ class LK_Device(ABC):
|
|
|
4060
4304
|
return
|
|
4061
4305
|
|
|
4062
4306
|
status = None
|
|
4063
|
-
#print("Bank:", bank, "...")
|
|
4064
4307
|
# ↓↓↓ Switch ROM bank
|
|
4065
4308
|
if self.MODE == "DMG":
|
|
4066
4309
|
if _mbc.ResetBeforeBankChange(bank) is True:
|
|
@@ -4074,8 +4317,6 @@ class LK_Device(ABC):
|
|
|
4074
4317
|
else:
|
|
4075
4318
|
self._write(self.DEVICE_CMD["SET_MODE_DMG"], wait=self.FW["fw_ver"] >= 12)
|
|
4076
4319
|
self._write(self.DEVICE_CMD["DMG_MBC_RESET"], wait=True)
|
|
4077
|
-
# else:
|
|
4078
|
-
# self._write(self.DEVICE_CMD["OFW_GB_FLASH_BANK_1_COMMAND_WRITES"])
|
|
4079
4320
|
self._set_fw_variable("DMG_ROM_BANK", bank)
|
|
4080
4321
|
|
|
4081
4322
|
buffer_len = min(buffer_len, bank_size)
|
|
@@ -4116,44 +4357,20 @@ class LK_Device(ABC):
|
|
|
4116
4357
|
se_ret = None
|
|
4117
4358
|
if chip_erase is False:
|
|
4118
4359
|
if sector_pos < len(sector_offsets) and buffer_pos == sector_offsets[sector_pos][0]:
|
|
4119
|
-
len_rest = end_address - pos
|
|
4120
|
-
skip_se = False
|
|
4121
4360
|
ts_se_start = time.time()
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
skip_se = True
|
|
4126
|
-
elif verified is not True and len(verified) == 2:
|
|
4127
|
-
dprint("Writing sector #{:d}, because the CRC32 didn’t match: 0x{:X} ≠ 0x{:X}".format(sector_pos, verified[0], verified[1]))
|
|
4128
|
-
verified = False
|
|
4129
|
-
skip_se = False
|
|
4130
|
-
|
|
4131
|
-
if self.CANCEL:
|
|
4132
|
-
cancel_args = {"action":"ABORT", "abortable":False}
|
|
4133
|
-
cancel_args.update(self.CANCEL_ARGS)
|
|
4134
|
-
self.CANCEL_ARGS = {}
|
|
4135
|
-
self.ERROR_ARGS = {}
|
|
4136
|
-
self.SetProgress(cancel_args)
|
|
4137
|
-
if self.CanPowerCycleCart(): self.CartPowerCycle()
|
|
4138
|
-
return
|
|
4139
|
-
|
|
4140
|
-
if skip_se is True:
|
|
4141
|
-
dprint("Skipping sector #{:d}, because the CRC32 matched".format(sector_pos))
|
|
4142
|
-
self.SetProgress({"action":"UPDATE_POS", "pos":buffer_pos, "sector_pos":sector_pos, "force_update":True})
|
|
4143
|
-
else:
|
|
4144
|
-
if sector not in verify_sectors:
|
|
4145
|
-
verify_sectors.append(sector)
|
|
4146
|
-
dprint("Erasing sector #{:d} at position 0x{:X} (0x{:X})".format(sector_pos, buffer_pos, pos))
|
|
4147
|
-
self.SetProgress({"action":"UPDATE_POS", "pos":buffer_pos, "force_update":True})
|
|
4148
|
-
if self.CanPowerCycleCart(): self.CartPowerOn()
|
|
4361
|
+
dprint("Erasing sector #{:d} at position 0x{:X} (0x{:X})".format(sector_pos, buffer_pos, pos))
|
|
4362
|
+
self.SetProgress({"action":"UPDATE_POS", "pos":buffer_pos, "force_update":True})
|
|
4363
|
+
if self.CanPowerCycleCart(): self.CartPowerOn()
|
|
4149
4364
|
|
|
4150
4365
|
sector_pos += 1
|
|
4151
4366
|
if flashcart.FlashCommandsOnBank1(): _mbc.SelectBankROM(bank)
|
|
4152
4367
|
self.NO_PROG_UPDATE = True
|
|
4153
|
-
se_ret = flashcart.SectorErase(pos=pos, buffer_pos=buffer_pos, skip=
|
|
4368
|
+
se_ret = flashcart.SectorErase(pos=pos, buffer_pos=buffer_pos, skip=False)
|
|
4154
4369
|
self.NO_PROG_UPDATE = False
|
|
4155
4370
|
if "from_user" in self.CANCEL_ARGS and self.CANCEL_ARGS["from_user"]:
|
|
4156
4371
|
continue
|
|
4372
|
+
if sector not in verify_sectors:
|
|
4373
|
+
verify_sectors.append(sector)
|
|
4157
4374
|
|
|
4158
4375
|
ts_se_elapsed = time.time() - ts_se_start
|
|
4159
4376
|
if se_ret:
|
|
@@ -4161,11 +4378,6 @@ class LK_Device(ABC):
|
|
|
4161
4378
|
sector_size = se_ret
|
|
4162
4379
|
dprint("Next sector size: 0x{:X}".format(sector_size))
|
|
4163
4380
|
skip_init = False
|
|
4164
|
-
|
|
4165
|
-
if skip_se:
|
|
4166
|
-
buffer_pos += sector_size
|
|
4167
|
-
pos += sector_size
|
|
4168
|
-
continue
|
|
4169
4381
|
# ↑↑↑ Sector erase
|
|
4170
4382
|
|
|
4171
4383
|
if se_ret is not False:
|
|
@@ -4175,8 +4387,6 @@ class LK_Device(ABC):
|
|
|
4175
4387
|
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))
|
|
4176
4388
|
elif command_set_type == "DMG-MBC5-32M-FLASH" and self.FW["fw_ver"] < 12:
|
|
4177
4389
|
status = self.WriteROM_DMG_MBC5_32M_FLASH(address=pos, buffer=data_import[buffer_pos:buffer_pos+buffer_len], bank=bank)
|
|
4178
|
-
#elif command_set_type == "DMG-MBC5-32M-FLASH" and self.FW["fw_ver"] >= 12:
|
|
4179
|
-
# 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))
|
|
4180
4390
|
elif command_set_type == "EEPROM":
|
|
4181
4391
|
status = self.WriteROM_DMG_EEPROM(address=pos, buffer=data_import[buffer_pos:buffer_pos+buffer_len], bank=bank, eeprom_buffer_size=256)
|
|
4182
4392
|
elif command_set_type == "BLAZE_XPLODER":
|
|
@@ -4227,21 +4437,22 @@ class LK_Device(ABC):
|
|
|
4227
4437
|
if "from_user" in self.CANCEL_ARGS and self.CANCEL_ARGS["from_user"]:
|
|
4228
4438
|
break
|
|
4229
4439
|
elif not self.DEVICE.is_open or self.DEVICE is None:
|
|
4230
|
-
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)})
|
|
4440
|
+
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)})
|
|
4231
4441
|
break
|
|
4232
4442
|
else:
|
|
4233
4443
|
if chip_erase: retry_hp = 0
|
|
4234
4444
|
if "iteration" in self.ERROR_ARGS and self.ERROR_ARGS["iteration"] > 0:
|
|
4235
4445
|
retry_hp -= 5
|
|
4236
4446
|
if retry_hp <= 0:
|
|
4237
|
-
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)})
|
|
4447
|
+
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)})
|
|
4238
4448
|
continue
|
|
4239
4449
|
else:
|
|
4240
4450
|
retry_hp -= 10
|
|
4241
4451
|
if retry_hp <= 0:
|
|
4242
|
-
|
|
4452
|
+
enable_pullup_wr_str = " (+ WR pullup)" if enable_pullup_wr == 2 else ""
|
|
4453
|
+
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})
|
|
4243
4454
|
continue
|
|
4244
|
-
|
|
4455
|
+
|
|
4245
4456
|
rev_buffer_pos = sector_offsets[sector_pos - 1][0]
|
|
4246
4457
|
buffer_pos = rev_buffer_pos
|
|
4247
4458
|
bank = start_bank
|
|
@@ -4275,10 +4486,6 @@ class LK_Device(ABC):
|
|
|
4275
4486
|
self._cart_write(pos, 0xFF)
|
|
4276
4487
|
if flashcart.Unlock() is False: return False
|
|
4277
4488
|
continue
|
|
4278
|
-
|
|
4279
|
-
self.CANCEL = True
|
|
4280
|
-
self.ERROR = True
|
|
4281
|
-
continue
|
|
4282
4489
|
|
|
4283
4490
|
skip_init = True
|
|
4284
4491
|
|
|
@@ -4304,6 +4511,8 @@ class LK_Device(ABC):
|
|
|
4304
4511
|
|
|
4305
4512
|
# ↓↓↓ Reset flash
|
|
4306
4513
|
flashcart.Reset(full_reset=True)
|
|
4514
|
+
if self.FW["fw_ver"] >= 14 and "set_audio_high" in cart_type:
|
|
4515
|
+
self._set_fw_variable("DMG_AUDIO_ENABLED", 0)
|
|
4307
4516
|
# ↑↑↑ Reset flash
|
|
4308
4517
|
|
|
4309
4518
|
# ↓↓↓ Flash verify
|
|
@@ -4313,7 +4522,7 @@ class LK_Device(ABC):
|
|
|
4313
4522
|
if "verify_write" in args and args["verify_write"] is True:
|
|
4314
4523
|
self.SetProgress({"action":"INITIALIZE", "method":"ROM_WRITE_VERIFY", "size":len(data_import), "flash_offset":flash_offset})
|
|
4315
4524
|
if ".dev" in Util.VERSION_PEP440 or Util.DEBUG:
|
|
4316
|
-
with open("debug_verify.bin", "wb") as f: pass
|
|
4525
|
+
with open(Util.CONFIG_PATH + "/debug_verify.bin", "wb") as f: pass
|
|
4317
4526
|
|
|
4318
4527
|
current_bank = None
|
|
4319
4528
|
broken_sectors = []
|
|
@@ -4369,8 +4578,6 @@ class LK_Device(ABC):
|
|
|
4369
4578
|
else:
|
|
4370
4579
|
self._write(self.DEVICE_CMD["SET_MODE_DMG"], wait=self.FW["fw_ver"] >= 12)
|
|
4371
4580
|
self._write(self.DEVICE_CMD["DMG_MBC_RESET"], wait=True)
|
|
4372
|
-
# else:
|
|
4373
|
-
# self._write(self.DEVICE_CMD["OFW_GB_FLASH_BANK_1_COMMAND_WRITES"])
|
|
4374
4581
|
self._set_fw_variable("DMG_ROM_BANK", bank)
|
|
4375
4582
|
|
|
4376
4583
|
buffer_len = min(buffer_len, bank_size)
|
|
@@ -4380,7 +4587,6 @@ class LK_Device(ABC):
|
|
|
4380
4587
|
if end_address > start_address + sector[1]:
|
|
4381
4588
|
end_address = start_address + sector[1]
|
|
4382
4589
|
pos_from = (bank * start_address)
|
|
4383
|
-
# pos_to = (bank * start_address) + verify_len
|
|
4384
4590
|
|
|
4385
4591
|
elif self.MODE == "AGB":
|
|
4386
4592
|
if "flash_bank_select_type" in cart_type and cart_type["flash_bank_select_type"] > 0:
|
|
@@ -4393,14 +4599,13 @@ class LK_Device(ABC):
|
|
|
4393
4599
|
current_bank = bank
|
|
4394
4600
|
verify_len = sector[1]
|
|
4395
4601
|
pos_from = sector[0]
|
|
4396
|
-
# pos_to = pos_from + verify_len
|
|
4397
4602
|
# ↑↑↑ Switch ROM bank
|
|
4398
4603
|
|
|
4399
4604
|
dprint(f"Verifying ROM bank #{bank} at 0x{pos_from:x} (physical 0x{start_address:X}, 0x{verify_len:X} bytes)")
|
|
4400
4605
|
|
|
4401
4606
|
verified = False
|
|
4402
4607
|
if self.FW["fw_ver"] >= 12 and sector[1] >= verify_len and crc32_errors < 5:
|
|
4403
|
-
verified = self.CompareCRC32(buffer=data_import, offset=pos_from, length=verify_len, address=start_address, flashcart=flashcart, reset=False)
|
|
4608
|
+
verified = self.CompareCRC32(buffer=data_import, offset=pos_from, length=verify_len, address=start_address, flashcart=flashcart, reset=False, mbc=_mbc, bank=bank)
|
|
4404
4609
|
if verified is True:
|
|
4405
4610
|
dprint("CRC32 verification successful between 0x{:X} and 0x{:X}".format(pos_from, verify_len))
|
|
4406
4611
|
self.SetProgress({"action":"UPDATE_POS", "pos":pos_from + verify_len})
|
|
@@ -4489,9 +4694,10 @@ class LK_Device(ABC):
|
|
|
4489
4694
|
|
|
4490
4695
|
self.SetMode(self.MODE)
|
|
4491
4696
|
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4697
|
+
if not "photo_mode" in args:
|
|
4698
|
+
self.INFO["last_action"] = self.INFO["action"]
|
|
4699
|
+
self.INFO["action"] = None
|
|
4700
|
+
self.SetProgress({"action":"FINISHED", "verified":verified})
|
|
4495
4701
|
return True
|
|
4496
4702
|
|
|
4497
4703
|
#################################################################
|
|
@@ -4502,6 +4708,8 @@ class LK_Device(ABC):
|
|
|
4502
4708
|
self.CANCEL_ARGS = {}
|
|
4503
4709
|
self.READ_ERRORS = 0
|
|
4504
4710
|
self.WRITE_ERRORS = 0
|
|
4711
|
+
_apot = 0
|
|
4712
|
+
|
|
4505
4713
|
if self.IsConnected():
|
|
4506
4714
|
_apoe = False
|
|
4507
4715
|
if self.CanPowerCycleCart():
|
|
@@ -4516,7 +4724,7 @@ class LK_Device(ABC):
|
|
|
4516
4724
|
self.SIGNAL = signal
|
|
4517
4725
|
try:
|
|
4518
4726
|
temp = copy.copy(args)
|
|
4519
|
-
if "buffer" in temp: temp["buffer"] = "(data)"
|
|
4727
|
+
if "buffer" in temp: temp["buffer"] = "(0x{:x} bytes of data)".format(len(temp["buffer"]))
|
|
4520
4728
|
dprint("args:", temp)
|
|
4521
4729
|
del(temp)
|
|
4522
4730
|
self.NO_PROG_UPDATE = False
|
|
@@ -4524,6 +4732,7 @@ class LK_Device(ABC):
|
|
|
4524
4732
|
elif args['mode'] == 2: ret = self._BackupRestoreRAM(args)
|
|
4525
4733
|
elif args['mode'] == 3: ret = self._BackupRestoreRAM(args)
|
|
4526
4734
|
elif args['mode'] == 4: ret = self._FlashROM(args)
|
|
4735
|
+
elif args['mode'] == 5: ret = self._DetectCartridge(args)
|
|
4527
4736
|
elif args['mode'] == 0xFF: self.Debug()
|
|
4528
4737
|
if self.FW is None: return False
|
|
4529
4738
|
if self.FW["fw_ver"] >= 2 and self.FW["pcb_name"] == "GBxCart RW":
|