FlashGBX 3.36__py3-none-any.whl → 4.0__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.
@@ -1,2599 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- # FlashGBX
3
- # Author: Lesserkuma (github.com/lesserkuma)
4
- # Partly based on work from Alex from insideGadgets (www.insidegadgets.com), code used with permission
5
- # This code is used for official firmware of GBxCart v1.3 only and this code is pure chaos, sorry
6
- # Refer to hw_GBxCartRW.py for the much cleaner rewrite (used for GBxCart RW v1.4 and firmware L1 on v1.3)
7
-
8
- import time, math, struct, traceback, zlib, copy, hashlib, os, datetime, platform
9
- import serial, serial.tools.list_ports
10
- from serial import SerialException
11
- from .RomFileDMG import RomFileDMG
12
- from .RomFileAGB import RomFileAGB
13
- from .Util import APPNAME, ANSI, dprint, bitswap, ParseCFI
14
- from . import Util
15
-
16
- class GbxDevice:
17
- DEVICE_NAME = "GBxCart RW"
18
- DEVICE_MIN_FW = 26
19
- DEVICE_MAX_FW = 31
20
-
21
- DEVICE_CMD = {
22
- "CART_MODE":'C',
23
- "GB_MODE":1,
24
- "GBA_MODE":2,
25
- # GB/GBC defines/commands
26
- "SET_START_ADDRESS":'A',
27
- "READ_ROM_RAM":'R',
28
- "READ_ROM_4000H":'Q',
29
- "WRITE_RAM":'W',
30
- "SET_BANK":'B',
31
- "SET_BANK_WITH_CS":'H',
32
- "RESET_MBC":'-',
33
- "GB_CART_MODE":'G',
34
- "READ_EEPROM_MBC7":'~',
35
- "WRITE_EEPROM_MBC7":'#',
36
- # GBA defines/commands
37
- "EEPROM_NONE":0,
38
- "EEPROM_4KBIT":1,
39
- "EEPROM_64KBIT":2,
40
- "SRAM_FLASH_NONE":0,
41
- "SRAM_FLASH_256KBIT":1,
42
- "SRAM_FLASH_512KBIT":2,
43
- "SRAM_FLASH_1MBIT":3,
44
- "NOT_CHECKED":0,
45
- "NO_FLASH":1,
46
- "FLASH_FOUND":2,
47
- "FLASH_FOUND_ATMEL":3,
48
- "GBA_READ_ROM":'r',
49
- "GBA_READ_ROM_256BYTE":'j',
50
- "GBA_READ_ROM_8000H":'Z',
51
- "GBA_READ_3DMEMORY":'}',
52
- "GBA_READ_3DMEMORY_1000H":']',
53
- "GBA_READ_SRAM":'m',
54
- "GBA_WRITE_SRAM":'w',
55
- "GBA_WRITE_ONE_BYTE_SRAM":'o',
56
- "GBA_CART_MODE":'g',
57
- "GBA_SET_EEPROM_SIZE":'S',
58
- "GBA_READ_EEPROM":'e',
59
- "GBA_WRITE_EEPROM":'p',
60
- "GBA_FLASH_READ_ID":'i',
61
- "GBA_FLASH_SET_BANK":'k',
62
- "GBA_FLASH_4K_SECTOR_ERASE":'s',
63
- "GBA_FLASH_WRITE_BYTE":'b',
64
- "GBA_FLASH_WRITE_ATMEL":'a',
65
- # Flash Cart commands
66
- "GB_FLASH_WE_PIN":'P',
67
- "WE_AS_AUDIO_PIN":'A',
68
- "WE_AS_WR_PIN":'W',
69
- "GB_FLASH_PROGRAM_METHOD":'E',
70
- "GB_FLASH_PROGRAM_555":0,
71
- "GB_FLASH_PROGRAM_AAA":1,
72
- "GB_FLASH_PROGRAM_555_BIT01_SWAPPED":2,
73
- "GB_FLASH_PROGRAM_AAA_BIT01_SWAPPED":3,
74
- "GB_FLASH_PROGRAM_5555":4,
75
- "GB_FLASH_PROGRAM_7AAA_BIT01_SWAPPED":5,
76
- "GB_FLASH_WRITE_BYTE":'F',
77
- "GB_FLASH_WRITE_64BYTE":'T',
78
- "GB_FLASH_WRITE_256BYTE":'X',
79
- "GB_FLASH_WRITE_UNBUFFERED_256BYTE":'{',
80
- "GB_FLASH_WRITE_BUFFERED_32BYTE":'Y',
81
- "GB_FLASH_BANK_1_COMMAND_WRITES":'N',
82
- "GB_FLASH_WRITE_64BYTE_PULSE_RESET":'J',
83
- "GB_FLASH_WRITE_INTEL_BUFFERED_32BYTE":'y',
84
- "GBA_FLASH_CART_WRITE_BYTE":'n',
85
- "GBA_FLASH_WRITE_64BYTE_SWAPPED_D0D1":'q',
86
- "GBA_FLASH_WRITE_256BYTE_SWAPPED_D0D1":'t',
87
- "GBA_FLASH_WRITE_256BYTE":'f',
88
- "GBA_FLASH_WRITE_BUFFERED_256BYTE":'c',
89
- "GBA_FLASH_WRITE_BUFFERED_256BYTE_SWAPPED_D0D1":'d',
90
- "GBA_FLASH_WRITE_INTEL_64BYTE":'l',
91
- "GBA_FLASH_WRITE_INTEL_1024BYTE_4050":'K',
92
- "GBA_FLASH_WRITE_INTEL_256BYTE":';',
93
- "GBA_FLASH_WRITE_INTEL_64BYTE_WORD":'u',
94
- "GBA_FLASH_WRITE_INTEL_INTERLEAVED_256BYTE":'v',
95
- "GBA_FLASH_WRITE_SHARP_64BYTE":'x',
96
- # General commands
97
- "SET_INPUT":'I',
98
- "SET_OUTPUT":'O',
99
- "SET_OUTPUT_LOW":'L',
100
- "SET_OUTPUT_HIGH":'H',
101
- "READ_INPUT":'D',
102
- "RESET_COMMON_LINES":'M',
103
- "READ_FIRMWARE_VERSION":'V',
104
- "READ_PCB_VERSION":'h',
105
- "VOLTAGE_3_3V":'3',
106
- "VOLTAGE_5V":'5',
107
- "SET_PINS_AS_INPUTS":':',
108
- "RESET_AVR":'*',
109
- "RESET_VALUE":0x7E5E1,
110
- "XMAS_LEDS":'#',
111
- "XMAS_VALUE":0x7690FCD,
112
- "READ_BUFFER":0,
113
- "USART_1_7M_SPEED":'>',
114
- "CLK_HIGH":'K',
115
- "CLK_LOW":'[',
116
- "CART_PWR_ON":'/',
117
- "CART_PWR_OFF":'.',
118
- "QUERY_CART_PWR":']',
119
- "QUERY_ADDR":'@',
120
- "AUDIO_HIGH":'8',
121
- "AUDIO_LOW":'9',
122
- }
123
- PCB_VERSIONS = {2:'v1.1/v1.2', 4:'v1.3', 90:'XMAS v1.0', 100:'Mini v1.0', 101:'Mini v1.0d'}
124
- SUPPORTED_CARTS = {}
125
-
126
- FW = []
127
- FW_UPDATE_REQ = False
128
- QBL = None
129
- MODE = None
130
- PORT = ''
131
- DEVICE = None
132
- WORKER = None
133
- INFO = { "last_action":None, "dump_info":{} }
134
- CANCEL = False
135
- ERROR = False
136
- CANCEL_ARGS = {}
137
- SIGNAL = None
138
- POS = 0
139
- NO_PROG_UPDATE = False
140
- FAST_READ = False
141
- BAUDRATE = 1000000
142
- WRITE_DELAY = False
143
- READ_ERRORS = 0
144
-
145
- def __init__(self):
146
- pass
147
-
148
- def Initialize(self, flashcarts, port=None, max_baud=1000000):
149
- if self.IsConnected(): self.DEVICE.close()
150
-
151
- dev = None
152
- conn_msg = []
153
- ports = []
154
- if port is not None:
155
- ports = [ port ]
156
- else:
157
- comports = serial.tools.list_ports.comports()
158
- for i in range(0, len(comports)):
159
- if comports[i].vid == 0x1A86 and comports[i].pid == 0x7523:
160
- ports.append(comports[i].device)
161
- #break
162
- if len(ports) == 0: return False
163
-
164
- for i in range(0, len(ports)):
165
- try:
166
- dev = serial.Serial(ports[i], self.BAUDRATE, timeout=0.1)
167
- self.DEVICE = dev
168
- if not self.LoadFirmwareVersion() and max_baud >= 1700000:
169
- dev.close()
170
- self.BAUDRATE = 1700000
171
- dev = serial.Serial(ports[i], self.BAUDRATE, timeout=0.1)
172
- self.DEVICE = dev
173
- if not self.LoadFirmwareVersion():
174
- dev.close()
175
- self.DEVICE = None
176
- self.BAUDRATE = 1000000
177
- return False
178
-
179
- elif len(self.FW) > 0 and self.FW[1] == 5 and self.BAUDRATE < 1700000 and max_baud >= 1700000:
180
- pass
181
-
182
- if self.DEVICE is None or not self.IsConnected() or self.FW == [] or self.FW[0] == b'' or self.QBL is False:
183
- dev.close()
184
- self.DEVICE = None
185
- conn_msg.append([0, "Couldn’t communicate with the GBxCart RW device on port " + ports[i] + ". Please disconnect and reconnect the device, then try again."])
186
- continue
187
-
188
- if self.FW[0] == 0:
189
- dev.close()
190
- self.DEVICE = None
191
- return False
192
- elif (self.FW[1] == 100 and self.FW[0] < 26 and self.FW[0] != 20):
193
- self.FW_UPDATE_REQ = True
194
- elif (self.FW[1] == 90 and self.FW[0] < 30):
195
- self.FW_UPDATE_REQ = True
196
- elif (self.FW[1] in (2, 4, 90) and self.FW[0] < self.DEVICE_MAX_FW) or (self.FW[0] < self.DEVICE_MIN_FW):
197
- self.FW_UPDATE_REQ = True
198
- elif self.FW[0] < self.DEVICE_MAX_FW:
199
- #conn_msg.append([1, "The GBxCart RW device on port " + ports[i] + " is running an older firmware version. Please consider updating to version R" + str(self.DEVICE_MAX_FW) + " to make use of the latest features.<br><br>Firmware updates are available at <a href=\"https://www.gbxcart.com/\">https://www.gbxcart.com/</a>."])
200
- pass
201
- elif self.FW[0] > self.DEVICE_MAX_FW:
202
- #conn_msg.append([0, "NOTE: The GBxCart RW device on port " + ports[i] + " is running a firmware version that is newer than what this version of FlashGBX was developed to work with."])
203
- pass
204
-
205
- if self.FW[1] not in self.PCB_VERSIONS.keys():
206
- dev.close()
207
- self.DEVICE = None
208
- continue
209
-
210
- if self.FW[1] not in (4, 5):
211
- conn_msg.append([0, "{:s}Now running in Legacy Mode.\nNote that FlashGBX works with insideGadgets GBxCart RW v1.3 and newer.\nOlder revisions are not fully compatible! More info: https://www.gbxcart.com/{:s}".format(ANSI.YELLOW, ANSI.RESET)])
212
- elif self.FW[1] == 4:
213
- conn_msg.append([0, "{:s}Now running in Legacy Mode.\nFor full support install firmware version L1 from the “Tools” menu in GUI mode.{:s}".format(ANSI.YELLOW, ANSI.RESET)])
214
-
215
- self.PORT = ports[i]
216
- self.DEVICE.timeout = 1
217
-
218
- # Load Flash Cartridge Handlers
219
- self.UpdateFlashCarts(flashcarts)
220
-
221
- # Stop after first found device
222
- break
223
-
224
- except SerialException as e:
225
- if "Permission" in str(e):
226
- conn_msg.append([3, "The GBxCart RW device on port " + ports[i] + " couldn’t be accessed. Make sure your user account has permission to use it and it’s not already in use by another application."])
227
- else:
228
- conn_msg.append([3, "A critical error occured while trying to access the GBxCart RW device on port " + ports[i] + ".\n\n" + str(e)])
229
- continue
230
-
231
- return conn_msg
232
-
233
- def UpdateFlashCarts(self, flashcarts):
234
- self.SUPPORTED_CARTS = {
235
- "DMG":{ "Generic ROM Cartridge":"RETAIL" },
236
- "AGB":{ "Generic ROM Cartridge":"RETAIL" }
237
- }
238
- for mode in flashcarts.keys():
239
- for key in sorted(flashcarts[mode].keys(), key=str.casefold):
240
- self.SUPPORTED_CARTS[mode][key] = flashcarts[mode][key]
241
-
242
- def IsConnected(self):
243
- if self.DEVICE is None: return False
244
- if not self.DEVICE.isOpen(): return False
245
- try:
246
- while self.DEVICE.in_waiting > 0:
247
- print("Clearing input buffer... ({:d})".format(self.DEVICE.in_waiting))
248
- self.DEVICE.reset_input_buffer()
249
- time.sleep(1)
250
- self.DEVICE.reset_output_buffer()
251
- self.LoadFirmwareVersion()
252
- return True
253
- except SerialException:
254
- return False
255
-
256
- def Close(self, cartPowerOff=False):
257
- if self.IsConnected():
258
- try:
259
- if cartPowerOff:
260
- self.set_mode(self.DEVICE_CMD["SET_PINS_AS_INPUTS"])
261
- self.DEVICE.close()
262
- except:
263
- self.DEVICE = None
264
- self.MODE = None
265
-
266
- def GetName(self):
267
- return "GBxCart RW"
268
-
269
- def GetFirmwareVersion(self, more=False):
270
- fw, _ = self.FW
271
- return "R{:s}".format(str(fw))
272
-
273
- def GetBaudRate(self):
274
- return self.BAUDRATE
275
-
276
- def ChangeBaudRate(self, _):
277
- return
278
-
279
- def GetPCBVersion(self):
280
- _, pcb = self.FW
281
- if pcb in self.PCB_VERSIONS:
282
- return self.PCB_VERSIONS[pcb]
283
- else:
284
- return "(unknown revision)"
285
-
286
- def GetFullName(self):
287
- self.DEVICE_NAME = "{:s} {:s}".format(self.GetName(), self.GetPCBVersion())
288
- return self.DEVICE_NAME
289
-
290
- def GetFullNameExtended(self, more=False):
291
- if more:
292
- return "{:s} – Firmware {:s} on {:s}".format(self.GetFullName(), self.GetFirmwareVersion(), str(self.PORT))
293
- else:
294
- return "{:s} – Firmware {:s}".format(self.GetFullName(), self.GetFirmwareVersion())
295
-
296
- def GetOfficialWebsite(self):
297
- return "https://www.gbxcart.com/"
298
-
299
- def SupportsFirmwareUpdates(self):
300
- fw, pcb = self.FW
301
- #return pcb == 4
302
- return (pcb in (2, 4, 90, 100) and fw > 3)
303
-
304
- def FirmwareUpdateAvailable(self):
305
- fw, pcb = self.FW
306
- #if pcb != 4: return False
307
- if pcb not in (2, 4, 90, 100) and fw <= 3: return False
308
- if (self.FW[1] == 100 and self.FW[0] >= 26): return False
309
- if (self.FW[1] == 90 and self.FW[0] >= 30): return False
310
- return fw < self.DEVICE_MAX_FW
311
-
312
- def GetFirmwareUpdaterClass(self):
313
- _, pcb = self.FW
314
- if pcb in (2, 4, 90, 100):
315
- try:
316
- from . import fw_GBxCartRW_v1_3
317
- return (None, fw_GBxCartRW_v1_3.FirmwareUpdaterWindow)
318
- except:
319
- return False
320
- else:
321
- return False
322
-
323
- def GetPort(self):
324
- return self.PORT
325
-
326
- def GetFWBuildDate(self):
327
- return ""
328
-
329
- def LoadFirmwareVersion(self):
330
- try:
331
- self.DEVICE.reset_input_buffer()
332
- self.DEVICE.reset_output_buffer()
333
- self.write("0")
334
- self.write(self.DEVICE_CMD["READ_PCB_VERSION"])
335
- pcb = self.DEVICE.read(1)
336
- if pcb == b'': return False
337
- self.write(self.DEVICE_CMD["READ_FIRMWARE_VERSION"])
338
- fw = self.DEVICE.read(1)
339
- self.FW = [fw[0], pcb[0]]
340
- if self.FW[1] in (2, 4) and self.FW[0] > 30: # check fw memory
341
- self.set_number(0x21FF0, self.DEVICE_CMD["QUERY_ADDR"])
342
- self.QBL = self.DEVICE.read(1)[0] == 84
343
- return True
344
- except:
345
- self.FW = False
346
- return False
347
-
348
- def CanSetVoltageManually(self):
349
- _, pcb = self.FW
350
- if not pcb in (4, 100):
351
- return True
352
- else:
353
- return False
354
-
355
- def CanSetVoltageAutomatically(self):
356
- _, pcb = self.FW
357
- if pcb in (1, 2, 100):
358
- return False
359
- else:
360
- return True
361
-
362
- def CanPowerCycleCart(self):
363
- _, pcb = self.FW
364
- return pcb in (5, 6)
365
-
366
- def GetSupprtedModes(self):
367
- _, pcb = self.FW
368
- if pcb in (100, 101):
369
- return ["DMG"]
370
- else:
371
- return ["DMG", "AGB"]
372
-
373
- def IsSupportedMbc(self, mbc):
374
- return mbc in ( 0x00, 0x01, 0x02, 0x03, 0x10, 0x12, 0x13, 0x19, 0x1A, 0x1B, 0x1C, 0x1E, 0xFC, 0xFE, 0xFF, 0x101, 0x103, 0x110 )
375
-
376
- def IsSupported3dMemory(self):
377
- return False
378
-
379
- def IsClkConnected(self):
380
- return False
381
-
382
- def GetMode(self):
383
- return self.MODE
384
-
385
- def GetSupportedCartridgesDMG(self):
386
- return (list(self.SUPPORTED_CARTS['DMG'].keys()), list(self.SUPPORTED_CARTS['DMG'].values()))
387
-
388
- def GetSupportedCartridgesAGB(self):
389
- return (list(self.SUPPORTED_CARTS['AGB'].keys()), list(self.SUPPORTED_CARTS['AGB'].values()))
390
-
391
- def SetProgress(self, args):
392
- if self.CANCEL and args["action"] not in ("ABORT", "FINISHED"): return
393
- if "pos" in args: self.POS = args["pos"]
394
- if args["action"] == "UPDATE_POS": self.INFO["transferred"] = args["pos"]
395
- try:
396
- self.SIGNAL.emit(args)
397
- except AttributeError:
398
- if self.SIGNAL is not None:
399
- self.SIGNAL(args)
400
-
401
- if args["action"] == "INITIALIZE":
402
- self.POS = 0
403
- elif args["action"] == "FINISHED":
404
- self.POS = 0
405
- self.SIGNAL = None
406
-
407
- def SetWriteDelay(self, enable=True):
408
- self.WRITE_DELAY = enable
409
-
410
- def SetTimeout(self, seconds=1):
411
- self.DEVICE.timeout = seconds
412
-
413
- def wait_for_ack(self):
414
- buffer = self.read(1)
415
- if buffer == False:
416
- stack = traceback.extract_stack()
417
- stack = stack[len(stack)-2] # caller only
418
- print("{:s}Waiting for confirmation from the device has timed out. (Called from {:s}(), line {:d}){:s}\n".format(ANSI.RED, stack.name, stack.lineno, ANSI.RESET))
419
- self.CANCEL = True
420
- self.ERROR = True
421
- self.CANCEL_ARGS = {"info_type":"msgbox_critical", "info_msg":"A timeout error occured while waiting for confirmation from the device. Please make sure that the cartridge contacts are clean, re-connect the device and try again from the beginning."}
422
- return False
423
-
424
- lives = 2
425
- while buffer != b'1':
426
- print("{:s}Waiting for confirmation from the device (buffer={:s})... {:s}".format(ANSI.YELLOW, str(buffer), ANSI.RESET))
427
- lives -= 1
428
- if lives < 1:
429
- stack = traceback.extract_stack()
430
- stack = stack[len(stack)-2] # caller only
431
- print("{:s}Waiting for confirmation from the device has failed. (Called from {:s}(), line {:d}){:s}\n".format(ANSI.RED, stack.name, stack.lineno, ANSI.RESET))
432
- self.CANCEL = True
433
- self.ERROR = True
434
- self.CANCEL_ARGS = {"info_type":"msgbox_critical", "info_msg":"A critical error occured while waiting for confirmation from the device. Please make sure that the cartridge contacts are clean, re-connect the device and try again from the beginning."}
435
- return False
436
- else:
437
- time.sleep(0.05)
438
- buffer = self.read(1)
439
-
440
- return True
441
-
442
- def read(self, length=64, last=False, ask_next_bytes=True, max_bytes=64):
443
- readlen = length
444
- if readlen > 64: readlen = max_bytes
445
- mbuffer = bytearray()
446
- #dprint("read(length={:d}, last={:s}, ask_next_bytes={:s}, max_bytes={:d})".format(length, str(last), str(ask_next_bytes), max_bytes))
447
- for i in range(0, length, readlen):
448
- if self.DEVICE.in_waiting > 1000: dprint("Recv buffer used: {:d} bytes".format(self.DEVICE.in_waiting))
449
- buffer = self.DEVICE.read(readlen)
450
- if len(buffer) != readlen:
451
- self.READ_ERRORS += 1
452
- dprint("Received {:d} byte(s) instead of the expected {:d} bytes during iteration {:d}.".format(len(buffer), readlen, i))
453
- self.write('0') # end
454
- time.sleep(0.5)
455
- while self.DEVICE.in_waiting > 0:
456
- self.DEVICE.reset_input_buffer()
457
- time.sleep(0.5)
458
- self.DEVICE.reset_output_buffer()
459
- return False
460
-
461
- mbuffer += buffer
462
- if not self.NO_PROG_UPDATE:
463
- self.SetProgress({"action":"READ", "bytes_added":len(buffer)})
464
-
465
- if ask_next_bytes and not (i + readlen >= length):
466
- self.write('1') # ask for next bytes (continue message)
467
- if (i + readlen) > length:
468
- readlen = length - i
469
-
470
- if (ask_next_bytes and last) or not ask_next_bytes:
471
- self.write('0')
472
-
473
- return mbuffer[:length]
474
-
475
- def write(self, data, wait_for_ack=False):
476
- if not isinstance(data, bytearray):
477
- data = bytearray(data, 'ascii')
478
- self.DEVICE.write(data)
479
- self.DEVICE.flush()
480
- if platform.system() == "Darwin" or self.WRITE_DELAY is True:
481
- time.sleep(0.00125)
482
- if wait_for_ack: return self.wait_for_ack()
483
-
484
- def DetectCartridge(self, mbc=None, limitVoltage=False, checkSaveType=False):
485
- self.SIGNAL = None
486
- cart_type_id = 0
487
- save_type = False
488
- save_chip = None
489
- sram_unstable = None
490
- save_size = None
491
-
492
- # Header
493
- info = self.ReadInfo()
494
-
495
- self.INFO["last_action"] = 0
496
- self.INFO["action"] = None
497
-
498
- (cart_types, cart_type_id, flash_id, cfi_s, cfi) = self.AutoDetectFlash(limitVoltage=limitVoltage)
499
- return (info, save_size, save_type, save_chip, sram_unstable, cart_types, cart_type_id, cfi_s, cfi, flash_id)
500
-
501
- def ReadRAM_TAMA5(self, rtc=False):
502
- buffer = bytearray()
503
- self.NO_PROG_UPDATE = True
504
-
505
- # Read save state
506
- for i in range(0, 0x20):
507
- self.cart_write(0xA001, 0x06, cs=True) # register select and address (high)
508
- self.cart_write(0xA000, i >> 4 | 0x01 << 1, cs=True) # bit 0 = higher ram address, rest = command
509
- self.cart_write(0xA001, 0x07, cs=True) # address (low)
510
- self.cart_write(0xA000, i & 0x0F, cs=True) # bits 0-3 = lower ram address
511
- self.cart_write(0xA001, 0x0D, cs=True) # data out (high)
512
- data_h = self.ReadROM(0xA000, 64)[0]
513
- self.cart_write(0xA001, 0x0C, cs=True) # data out (low)
514
- data_l = self.ReadROM(0xA000, 64)[0]
515
- data = ((data_h & 0xF) << 4) | (data_l & 0xF)
516
- buffer.append(data)
517
- self.SetProgress({"action":"UPDATE_POS", "abortable":False, "pos":i+1})
518
-
519
- # Read RTC state
520
- if rtc:
521
- for r in range(0, 0x10):
522
- self.cart_write(0xA001, 0x04, cs=True) # set address
523
- self.cart_write(0xA000, r, cs=True) # address
524
- self.cart_write(0xA001, 0x06, cs=True) # register select
525
- self.cart_write(0xA000, 0x04 << 1, cs=True) # rtc mode
526
- self.cart_write(0xA001, 0x07, cs=True) # set access mode
527
- self.cart_write(0xA000, 1, cs=True) # 1 = read
528
- self.cart_write(0xA001, 0x0C, cs=True) # data out
529
- data = self.ReadROM(0xA000, 64)[0]
530
- buffer.append(data)
531
- self.SetProgress({"action":"UPDATE_POS", "abortable":False, "pos":0x21+r})
532
-
533
- # Add timestamp of backup time (a future version may offer to auto-advance or edit the values)
534
- ts = int(time.time())
535
- buffer.extend(struct.pack("<Q", ts))
536
-
537
- self.NO_PROG_UPDATE = False
538
- return buffer
539
-
540
- def WriteRAM_TAMA5(self, data, rtc=False):
541
- self.NO_PROG_UPDATE = True
542
-
543
- for i in range(0, 0x20):
544
- self.cart_write(0xA001, 0x05, cs=True) # data in (high)
545
- self.cart_write(0xA000, data[i] >> 4, cs=True)
546
- self.cart_write(0xA001, 0x04, cs=True) # data in (low)
547
- self.cart_write(0xA000, data[i] & 0xF, cs=True)
548
- self.cart_write(0xA001, 0x06, cs=True) # register select and address (high)
549
- self.cart_write(0xA000, i >> 4 | 0x00 << 1, cs=True) # bit 0 = higher ram address, rest = command
550
- self.cart_write(0xA001, 0x07, cs=True) # address (low)
551
- self.cart_write(0xA000, i & 0x0F, cs=True) # bits 0-3 = lower ram address
552
- self.SetProgress({"action":"UPDATE_POS", "abortable":False, "pos":i+1})
553
-
554
- if rtc and bytearray(data[0x20:0x30]) != bytearray([0xFF] * 0x10):
555
- for r in range(0, 0x10):
556
- self.cart_write(0xA001, 0x04, cs=True) # set address
557
- self.cart_write(0xA000, r, cs=True) # address
558
- self.cart_write(0xA001, 0x05, cs=True) # set value to write
559
- self.cart_write(0xA000, data[0x20+r], cs=True) # value
560
- self.cart_write(0xA001, 0x06, cs=True) # register select
561
- self.cart_write(0xA000, 0x04 << 1, cs=True) # rtc mode
562
- self.cart_write(0xA001, 0x07, cs=True) # set access mode
563
- self.cart_write(0xA000, 0, cs=True) # 0 = write
564
- self.SetProgress({"action":"UPDATE_POS", "abortable":False, "pos":0x21+r})
565
-
566
- self.SetProgress({"action":"UPDATE_POS", "pos":0x30})
567
- self.NO_PROG_UPDATE = False
568
-
569
- def ReadROM(self, offset, length, set_address=True, agb_3dmemory=False):
570
- reqlen = length
571
- if length < 64: length = 64
572
- buffer = False
573
- lives = 5
574
- dprint("ReadROM(offset=0x{:X}, length=0x{:X}, set_address={:s}) fast_read_mode={:s}".format(offset, length, str(set_address), str(self.FAST_READ)))
575
- while buffer == False:
576
- ask_next_bytes = True
577
- max_bytes = 64
578
- if self.MODE == "DMG":
579
- if self.FAST_READ and length == 0x4000:
580
- ask_next_bytes = False
581
- max_bytes = 0x80
582
- if set_address:
583
- self.set_number(offset, self.DEVICE_CMD["SET_START_ADDRESS"])
584
- self.set_mode(self.DEVICE_CMD["READ_ROM_4000H"])
585
- else:
586
- if set_address:
587
- self.set_number(offset, self.DEVICE_CMD["SET_START_ADDRESS"])
588
- self.set_mode(self.DEVICE_CMD["READ_ROM_RAM"])
589
- buffer = self.read(length, last=True, ask_next_bytes=ask_next_bytes)
590
- elif self.MODE == "AGB":
591
- if agb_3dmemory and self.FAST_READ and length == 0x1000:
592
- ask_next_bytes = False
593
- max_bytes = 0x80
594
- if set_address:
595
- self.set_number(math.floor(offset / 2), self.DEVICE_CMD["SET_START_ADDRESS"])
596
- self.set_mode(self.DEVICE_CMD["GBA_READ_3DMEMORY_1000H"])
597
- elif agb_3dmemory and length == 0x200:
598
- if set_address:
599
- self.set_number(math.floor(offset / 2), self.DEVICE_CMD["SET_START_ADDRESS"])
600
- self.set_mode(self.DEVICE_CMD["GBA_READ_3DMEMORY"])
601
- elif self.FAST_READ and length == 0x10000:
602
- ask_next_bytes = False
603
- max_bytes = 0x80
604
- if set_address:
605
- self.set_number(math.floor(offset / 2), self.DEVICE_CMD["SET_START_ADDRESS"])
606
- self.set_mode(self.DEVICE_CMD["GBA_READ_ROM_8000H"])
607
- else:
608
- if set_address:
609
- self.set_number(math.floor(offset / 2), self.DEVICE_CMD["SET_START_ADDRESS"])
610
- self.set_mode(self.DEVICE_CMD["GBA_READ_ROM"])
611
- buffer = self.read(length, last=True, ask_next_bytes=ask_next_bytes, max_bytes=max_bytes)
612
-
613
- if buffer == False:
614
- if lives == 0:
615
- self.CANCEL = True
616
- self.ERROR = True
617
- if self.FAST_READ:
618
- self.CANCEL_ARGS = {"info_type":"msgbox_critical", "info_msg":"An error occured while receiving data from the device. Please disable Fast Read Mode, re-connect the device and try again."}
619
- else:
620
- self.CANCEL_ARGS = {"info_type":"msgbox_critical", "info_msg":"An error occured while receiving data from the device. Please re-connect the device and try again."}
621
- print("{:s}{:s}Couldn’t recover from the read error.{:s}".format(ANSI.CLEAR_LINE, ANSI.RED, ANSI.RESET), flush=True)
622
- return False
623
- elif lives != 5:
624
- print("", flush=True)
625
- print("{:s}{:s}Failed to receive 0x{:X} bytes at 0x{:X}. Retrying...{:s}".format(ANSI.CLEAR_LINE, ANSI.YELLOW, length, self.POS, ANSI.RESET), flush=True)
626
- set_address = True
627
- lives -= 1
628
-
629
- if lives < 5:
630
- print("{:s}└ The retry was successful!".format(ANSI.CLEAR_LINE), flush=True)
631
-
632
- return bytearray(buffer[:reqlen])
633
-
634
- def gbx_flash_write_address_byte(self, address, data):
635
- dprint("gbx_flash_write_address_byte(address=0x{:X}, data=0x{:X})".format(address, data))
636
- if self.MODE == "DMG":
637
- return self.gb_flash_write_address_byte(address, data)
638
- elif self.MODE == "AGB":
639
- return self.gba_flash_write_address_byte(address, data)
640
-
641
- def gba_flash_write_address_byte(self, address, data):
642
- address = int(address / 2)
643
- address = format(address, 'x')
644
- buffer = self.DEVICE_CMD["GBA_FLASH_CART_WRITE_BYTE"] + address + '\x00'
645
- self.write(buffer)
646
- time.sleep(0.001)
647
- data = format(data, 'x')
648
- buffer = self.DEVICE_CMD["GBA_FLASH_CART_WRITE_BYTE"] + data + '\x00'
649
- self.write(buffer)
650
- time.sleep(0.001)
651
-
652
- ack = self.wait_for_ack()
653
- if ack == False:
654
- self.CANCEL = True
655
- self.ERROR = True
656
- self.CANCEL_ARGS = {"info_type":"msgbox_critical", "info_msg":"A critical error occured while trying to write the ROM. Please re-connect the device and try again from the beginning."}
657
- return False
658
-
659
- def gb_flash_write_address_byte(self, address, data):
660
- address = format(address, 'x')
661
- buffer = self.DEVICE_CMD["GB_FLASH_WRITE_BYTE"] + address + '\x00'
662
- self.write(buffer)
663
- buffer = format(data, 'x') + '\x00'
664
- self.write(buffer)
665
-
666
- ack = self.wait_for_ack()
667
- if ack == False:
668
- self.CANCEL = True
669
- self.ERROR = True
670
- self.CANCEL_ARGS = {"info_type":"msgbox_critical", "info_msg":"A critical error occured while trying to write a byte. Please re-connect the device and try again from the beginning."}
671
- return False
672
-
673
- def gbx_flash_write_data_bytes(self, command, data):
674
- buffer = bytearray(command, "ascii") + bytearray(data)
675
- self.write(buffer)
676
-
677
- def cart_write(self, address, bank, cs=False):
678
- dprint("cart_write(address={:s}, data={:s})".format(format(address, 'x'), format(bank, 'x')))
679
- # Firmware check R26+
680
- if cs and self.FW[0] >= 26:
681
- cmd = self.DEVICE_CMD["SET_BANK_WITH_CS"]
682
- else:
683
- cmd = self.DEVICE_CMD["SET_BANK"]
684
-
685
- address = format(address, 'x')
686
- buffer = cmd + address + '\x00'
687
- self.write(buffer)
688
- time.sleep(0.005)
689
- bank = format(bank, 'd')
690
- buffer = cmd + bank + '\x00'
691
- self.write(buffer)
692
- time.sleep(0.005)
693
-
694
- def set_mode(self, command):
695
- dprint("set_mode(command={:s})".format(str(command)))
696
- buffer = format(command, 's')
697
- self.write(buffer)
698
-
699
- def set_number(self, number, command):
700
- number = int(number)
701
- buffer = format(command, 's') + format(number, 'x') + '\x00'
702
- self.write(buffer)
703
- time.sleep(0.005)
704
-
705
- def EnableRAM(self, mbc=1, enable=True):
706
- if enable:
707
- if mbc in (0x01, 0x02, 0x03, 0x101, 0x103, 0x10, 0x13, 0x110): # MBC1, MBC1M, MBC3, MBC30
708
- self.cart_write(0x6000, 1)
709
- self.cart_write(0x0000, 0x0A, cs=(mbc == 0xFD))
710
- else:
711
- if mbc == 0xFF: # HuC-1
712
- self.cart_write(0x0000, 0x0E) # enabling IR disables RAM
713
- else:
714
- self.cart_write(0x0000, 0x00, cs=(mbc == 0xFD))
715
- if mbc <= 4: self.cart_write(0x6000, 0)
716
- time.sleep(0.2)
717
-
718
- def SetBankROM(self, bank, mbc=0, bank_count=0):
719
- dprint("SetBankROM(bank={:d}, mbc=0x{:X}, bank_count={:d})".format(bank, int(mbc), bank_count))
720
- if mbc == 0 and bank_count == 0:
721
- mbc = 0x19 # MBC5
722
-
723
- if mbc in (0x01, 0x02, 0x03): # MBC1
724
- dprint("└[MBC1] 0x6000=0x00, 0x4000=0x{:X}, 0x2000=0x{:X}".format(bank >> 5, bank & 0x1F))
725
- #self.cart_write(0x6000, 0)
726
- #self.cart_write(0x4000, bank >> 5)
727
- #self.cart_write(0x2000, bank & 0x1F)
728
- self.cart_write(0x6000, 1)
729
- self.cart_write(0x2000, bank)
730
- self.cart_write(0x4000, bank >> 5)
731
- elif mbc in (0x101, 0x103): # MBC1M
732
- self.cart_write(0x4000, bank >> 4)
733
- if (bank < 10):
734
- dprint("└[MBC1M] 0x4000=0x{:X}, 0x2000=0x{:X}".format(bank >> 4, bank & 0x1F))
735
- self.cart_write(0x2000, bank & 0x1F)
736
- else:
737
- dprint("└[MBC1M] 0x4000=0x{:X}, 0x2000=0x{:X}".format(bank >> 4, 0x10 | (bank & 0x1F)))
738
- self.cart_write(0x2000, 0x10 | (bank & 0x1F))
739
- elif (mbc == 0 and bank_count > 256) or mbc in (0x19, 0x1A, 0x1B, 0x1C, 0x1E): # MBC5
740
- dprint("└[MBC5] 0x2100=0x{:X}".format(bank & 0xFF))
741
- self.cart_write(0x2100, (bank & 0xFF))
742
- if bank == 0 or bank >= 256:
743
- dprint("└[MBC5] 0x3000=0x{:X}".format((bank >> 8) & 0xFF))
744
- self.cart_write(0x3000, ((bank >> 8) & 0xFF))
745
- elif mbc in (0x0B, 0x0D): # MMM01
746
- if bank % 0x20 == 0:
747
- dprint("└[MMM01] RESET_MBC, 0x2000=0x{:X}".format(bank))
748
- self.set_mode(self.DEVICE_CMD['RESET_MBC'])
749
- self.wait_for_ack()
750
- self.cart_write(0x2000, bank) # start from this ROM bank
751
- self.cart_write(0x6000, 0x00) # 0x00 = 512 KB, 0x04 = 32 KB, 0x08 = 64 KB, 0x10 = 128 KB, 0x20 = 256 KB
752
- self.cart_write(0x4000, 0x40) # RAM bank?
753
- self.cart_write(0x0000, 0x00)
754
- self.cart_write(0x0000, 0x40) # Enable mapping
755
- dprint("└[MMM01] 0x2100=0x{:X}".format(((bank % 0x20) & 0xFF)))
756
- self.cart_write(0x2100, ((bank % 0x20) & 0xFF))
757
- elif mbc == 0xFD: # TAMA5
758
- dprint("└[TAMA5] 0xA001=0x00, 0xA000=0x{:X}, 0xA001=0x01, 0xA000=0x{:X}".format(bank & 0x0F, bank >> 4))
759
- self.cart_write(0xA001, 0x00, cs=True) # ROM bank (low)
760
- self.cart_write(0xA000, bank & 0x0F, cs=True)
761
- self.cart_write(0xA001, 0x01, cs=True) # ROM bank (high)
762
- self.cart_write(0xA000, (bank >> 4) & 0x0F, cs=True)
763
- elif mbc == 0xFF: # HuC-1
764
- dprint("└[HuC-1] 0x2000=0x{:X}".format(bank & 0x3F))
765
- self.cart_write(0x2000, (bank & 0x3F))
766
- elif mbc == 0x104: # M161
767
- dprint("└[M161] RESET_MBC, 0x4000=0x{:X}".format(bank & 0x7))
768
- self.set_mode(self.DEVICE_CMD['RESET_MBC'])
769
- self.wait_for_ack()
770
- self.cart_write(0x4000, (bank & 0x7))
771
- else: # MBC2, MBC3 and others
772
- dprint("└[MBCx] 0x2100=0x{:X}".format(bank & 0xFF))
773
- self.cart_write(0x2100, (bank & 0xFF))
774
-
775
- def SetBankRAM(self, bank, mbc=0x19):
776
- if mbc in (0x06, 0xFD): return # MBC2 or TAMA5
777
- dprint("SetBankRAM(bank={:d}, mbc={:d})".format(bank, mbc))
778
- dprint("└[MBC] 0x4000=0x{:X}".format(bank & 0xFF))
779
- self.cart_write(0x4000, (bank & 0xFF))
780
-
781
- def ReadFlashSaveMakerID(self):
782
- makers = { 0x1F:"ATMEL", 0xBF:"SST/SANYO", 0xC2:"MACRONIX", 0x32:"PANASONIC", 0x62:"SANYO" }
783
- self.set_mode(self.DEVICE_CMD["GBA_FLASH_READ_ID"])
784
- time.sleep(0.02)
785
- buffer = self.DEVICE.read(2)
786
- if buffer[0] in makers.keys():
787
- return makers[buffer[0]]
788
- else:
789
- return buffer[0]
790
-
791
- def CartPowerOff(self):
792
- return
793
-
794
- def CartPowerOn(self):
795
- return
796
-
797
- def SetMode(self, mode):
798
- if mode == "DMG":
799
- self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
800
- self.MODE = "DMG"
801
- elif mode == "AGB":
802
- self.set_mode(self.DEVICE_CMD["VOLTAGE_3_3V"])
803
- self.MODE = "AGB"
804
- self.set_number(0, self.DEVICE_CMD["SET_START_ADDRESS"])
805
- self.CartPowerOn()
806
-
807
- def AutoDetectFlash(self, limitVoltage=False):
808
- flash_types = []
809
- flash_type = 0
810
- flash_id = None
811
-
812
- if self.MODE == "DMG":
813
- if limitVoltage:
814
- self.set_mode(self.DEVICE_CMD["VOLTAGE_3_3V"])
815
- else:
816
- self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
817
-
818
- supported_carts = list(self.SUPPORTED_CARTS['DMG'].values())
819
- for f in range(2, len(supported_carts)):
820
- flashcart_meta = supported_carts[f]
821
- if flash_id is not None:
822
- if ("flash_ids" not in flashcart_meta) or (flash_id not in flashcart_meta["flash_ids"]):
823
- continue
824
-
825
- self.set_mode(self.DEVICE_CMD["GB_CART_MODE"])
826
- if "flash_commands_on_bank_1" in flashcart_meta:
827
- self.set_mode(self.DEVICE_CMD["GB_FLASH_BANK_1_COMMAND_WRITES"])
828
-
829
- if flashcart_meta["write_pin"] == "WR":
830
- self.set_mode(self.DEVICE_CMD["GB_FLASH_WE_PIN"])
831
- self.set_mode(self.DEVICE_CMD["WE_AS_WR_PIN"])
832
- elif flashcart_meta["write_pin"] in ("AUDIO", "VIN"):
833
- self.set_mode(self.DEVICE_CMD["GB_FLASH_WE_PIN"])
834
- self.set_mode(self.DEVICE_CMD["WE_AS_AUDIO_PIN"])
835
-
836
- # Reset Flash
837
- if "reset" in flashcart_meta["commands"]:
838
- for i in range(0, len(flashcart_meta["commands"]["reset"])):
839
- self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
840
-
841
- # Unlock Flash
842
- if "unlock" in flashcart_meta["commands"]:
843
- for i in range(0, len(flashcart_meta["commands"]["unlock"])):
844
- addr = flashcart_meta["commands"]["unlock"][i][0]
845
- data = flashcart_meta["commands"]["unlock"][i][1]
846
- count = flashcart_meta["commands"]["unlock"][i][2]
847
- for _ in range(0, count):
848
- self.gbx_flash_write_address_byte(addr, data)
849
-
850
- # Read Flash ID / Electronic Signature
851
- if "flash_ids" in flashcart_meta:
852
- if "read_identifier" in flashcart_meta["commands"]:
853
- for i in range(0, len(flashcart_meta["commands"]["read_identifier"])):
854
- self.gbx_flash_write_address_byte(flashcart_meta["commands"]["read_identifier"][i][0], flashcart_meta["commands"]["read_identifier"][i][1])
855
- buffer = self.ReadROM(0, 64)
856
- flash_id_found = False
857
- for i in range(0, len(flashcart_meta["flash_ids"])):
858
- id = list(buffer[0:len(flashcart_meta["flash_ids"][i])])
859
- if id in flashcart_meta["flash_ids"]:
860
- flash_id = id
861
- flash_id_found = True
862
- if not flash_id_found and len(flashcart_meta["flash_ids"]) > 0:
863
- pass
864
-
865
- # Reset Flash
866
- if "reset" in flashcart_meta["commands"]:
867
- for i in range(0, len(flashcart_meta["commands"]["reset"])):
868
- self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
869
-
870
- if flash_id_found:
871
- flash_type = f
872
- flash_types.append(flash_type)
873
-
874
- elif self.MODE == "AGB":
875
- supported_carts = list(self.SUPPORTED_CARTS['AGB'].values())
876
- for f in range(2, len(supported_carts)):
877
- flashcart_meta = supported_carts[f]
878
- if flash_id is not None:
879
- if ("flash_ids" not in flashcart_meta) or (flash_id not in flashcart_meta["flash_ids"]):
880
- continue
881
-
882
- # Unlock Flash
883
- if "unlock" in flashcart_meta["commands"]:
884
- for i in range(0, len(flashcart_meta["commands"]["unlock"])):
885
- addr = flashcart_meta["commands"]["unlock"][i][0]
886
- data_ = flashcart_meta["commands"]["unlock"][i][1]
887
- count = flashcart_meta["commands"]["unlock"][i][2]
888
- for _ in range(0, count):
889
- self.gbx_flash_write_address_byte(addr, data_)
890
-
891
- # Reset Flash
892
- if "reset" in flashcart_meta["commands"]:
893
- for i in range(0, len(flashcart_meta["commands"]["reset"])):
894
- self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
895
-
896
- # Read Flash ID / Electronic Signature
897
- if "flash_ids" in flashcart_meta:
898
- if "read_identifier" in flashcart_meta["commands"]:
899
- for i in range(0, len(flashcart_meta["commands"]["read_identifier"])):
900
- self.gbx_flash_write_address_byte(flashcart_meta["commands"]["read_identifier"][i][0], flashcart_meta["commands"]["read_identifier"][i][1])
901
- buffer = self.ReadROM(0, 64)
902
- flash_id_found = False
903
- for i in range(0, len(flashcart_meta["flash_ids"])):
904
- id = list(buffer[0:len(flashcart_meta["flash_ids"][i])])
905
- if id in flashcart_meta["flash_ids"]:
906
- flash_id = id
907
- flash_id_found = True
908
- if not flash_id_found and len(flashcart_meta["flash_ids"]) > 0:
909
- pass
910
-
911
- # Reset Flash
912
- if "reset" in flashcart_meta["commands"]:
913
- for i in range(0, len(flashcart_meta["commands"]["reset"])):
914
- self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
915
-
916
- if flash_id_found:
917
- flash_type = f
918
- flash_types.append(flash_type)
919
-
920
- # Check flash size
921
- flash_type_id = 0
922
- cfi_s = ""
923
- cfi = None
924
- if len(flash_types) > 0:
925
- flash_type_id = flash_types[0]
926
- if self.MODE == "DMG":
927
- supp_flash_types = self.GetSupportedCartridgesDMG()
928
- elif self.MODE == "AGB":
929
- supp_flash_types = self.GetSupportedCartridgesAGB()
930
-
931
- (flash_id, cfi_s, cfi) = self.CheckFlashChip(limitVoltage=limitVoltage, cart_type=supp_flash_types[1][flash_type_id])
932
- if "flash_size" in supp_flash_types[1][flash_types[0]]:
933
- size = supp_flash_types[1][flash_types[0]]["flash_size"]
934
- size_undetected = False
935
- for i in range(0, len(flash_types)):
936
- if "flash_size" in supp_flash_types[1][flash_types[i]]:
937
- if size != supp_flash_types[1][flash_types[i]]["flash_size"]:
938
- size_undetected = True
939
-
940
- if size_undetected:
941
- if isinstance(cfi, dict) and "device_size" in cfi:
942
- for i in range(0, len(flash_types)):
943
- if cfi['device_size'] == supp_flash_types[1][flash_types[i]]["flash_size"]:
944
- flash_type_id = flash_types[i]
945
- size_undetected = False
946
- break
947
-
948
- else:
949
- (flash_id, cfi_s, cfi) = self.CheckFlashChip(limitVoltage=limitVoltage)
950
-
951
- if self.MODE == "DMG" and not flash_id_found:
952
- self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
953
-
954
- return (flash_types, flash_type_id, flash_id, cfi_s, cfi)
955
- #return flash_types
956
-
957
- def CheckFlashChip(self, limitVoltage=False, cart_type=None):
958
- flash_id_lines = []
959
- flash_commands = [
960
- { 'read_cfi':[[0x555, 0x98]], 'read_identifier':[[ 0x555, 0xAA ], [ 0x2AA, 0x55 ], [ 0x555, 0x90 ]], 'reset':[[ 0x0, 0xF0 ]] },
961
- { 'read_cfi':[[0x5555, 0x98]], 'read_identifier':[[ 0x5555, 0xAA ], [ 0x2AAA, 0x55 ], [ 0x5555, 0x90 ]], 'reset':[[ 0x0, 0xF0 ]] },
962
- { 'read_cfi':[[0xAA, 0x98]], 'read_identifier':[[ 0xAAA, 0xAA ], [ 0x555, 0x55 ], [ 0xAAA, 0x90 ]], 'reset':[[ 0x0, 0xF0 ]] },
963
- { 'read_cfi':[[0xAAA, 0x98]], 'read_identifier':[[ 0xAAA, 0xAA ], [ 0x555, 0x55 ], [ 0xAAA, 0x90 ]], 'reset':[[ 0x0, 0xF0 ]] },
964
- { 'read_cfi':[[0xAAAA, 0x98]], 'read_identifier':[[ 0xAAAA, 0xAA ], [ 0x5555, 0x55 ], [ 0xAAAA, 0x90 ]], 'reset':[[ 0x0, 0xF0 ]] },
965
- { 'read_cfi':[[0x4555, 0x98]], 'read_identifier':[[ 0x4555, 0xAA ], [ 0x4AAA, 0x55 ], [ 0x4555, 0x90 ]], 'reset':[[ 0x4000, 0xF0 ]] },
966
- { 'read_cfi':[[0x7555, 0x98]], 'read_identifier':[[ 0x7555, 0xAA ], [ 0x7AAA, 0x55 ], [ 0x7555, 0x90 ]], 'reset':[[ 0x7000, 0xF0 ]] },
967
- { 'read_cfi':[[0x4AAA, 0x98]], 'read_identifier':[[ 0x4AAA, 0xAA ], [ 0x4555, 0x55 ], [ 0x4AAA, 0x90 ]], 'reset':[[ 0x4000, 0xF0 ]] },
968
- { 'read_cfi':[[0x7AAA, 0x98]], 'read_identifier':[[ 0x7AAA, 0xAA ], [ 0x7555, 0x55 ], [ 0x7AAA, 0x90 ]], 'reset':[[ 0x7000, 0xF0 ]] },
969
- { 'read_cfi':[[0, 0x98]], 'read_identifier':[[ 0, 0x90 ]], 'reset':[[ 0, 0xFF ]] },
970
- ]
971
-
972
- check_buffer = self.ReadROM(0, 0x200)
973
- d_swap = None
974
- cfi_info = ""
975
- rom_string = ""
976
- for j in range(0, 8):
977
- rom_string += "{:02X} ".format(check_buffer[j])
978
- rom_string += "\n"
979
- cfi = {'raw':b''}
980
-
981
- if self.MODE == "DMG":
982
- if limitVoltage:
983
- self.set_mode(self.DEVICE_CMD["VOLTAGE_3_3V"])
984
- else:
985
- self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
986
- rom_string = "[ ROM ] " + rom_string
987
- we_pins = [ "WR", "AUDIO" ]
988
- else:
989
- rom_string = "[ ROM ] " + rom_string
990
- we_pins = [ None ]
991
-
992
- for we in we_pins:
993
- if "method" in cfi: break
994
- for method in flash_commands:
995
- if self.MODE == "DMG":
996
- self.set_mode(self.DEVICE_CMD["GB_FLASH_WE_PIN"])
997
- self.set_mode(self.DEVICE_CMD["WE_AS_" + we + "_PIN"])
998
-
999
- for i in range(0, len(method['reset'])):
1000
- self.gbx_flash_write_address_byte(method['reset'][i][0], method['reset'][i][1])
1001
- for i in range(0, len(method['read_cfi'])):
1002
- self.gbx_flash_write_address_byte(method['read_cfi'][i][0], method["read_cfi"][i][1])
1003
- buffer = self.ReadROM(0, 0x400)
1004
- for i in range(0, len(method['reset'])):
1005
- self.gbx_flash_write_address_byte(method['reset'][i][0], method['reset'][i][1])
1006
- if buffer == check_buffer: continue
1007
-
1008
- magic = "{:s}{:s}{:s}".format(chr(buffer[0x20]), chr(buffer[0x22]), chr(buffer[0x24]))
1009
- if magic == "QRY": # nothing swapped
1010
- d_swap = ( 0, 0 )
1011
- elif magic == "RQZ": # D0D1 swapped
1012
- d_swap = ( 0, 1 )
1013
- if d_swap is not None:
1014
- for i in range(0, len(buffer)):
1015
- buffer[i] = bitswap(buffer[i], d_swap)
1016
-
1017
- cfi_parsed = ParseCFI(buffer)
1018
- try:
1019
- if d_swap is not None:
1020
- dprint("CFI @ {:s}/{:X}/{:X}/{:s}".format(str(we), method['read_identifier'][0][0], bitswap(method['read_identifier'][0][1], d_swap), str(d_swap)))
1021
- else:
1022
- dprint("CFI @ {:s}/{:X}/{:X}/{:s}".format(str(we), method['read_identifier'][0][0], method['read_identifier'][0][1], str(d_swap)))
1023
- dprint("└", cfi_parsed)
1024
- except:
1025
- pass
1026
-
1027
- if cfi_parsed != False:
1028
- cfi = cfi_parsed
1029
- cfi["raw"] = buffer
1030
- if Util.DEBUG:
1031
- with open("debug_cfi.bin", "wb") as f: f.write(buffer)
1032
-
1033
- #cfi["sha1"] = hashlib.sha1(buffer).hexdigest()
1034
- cfi["bytes"] = ""
1035
- for i in range(0, 0x400):
1036
- cfi["bytes"] += "{:02X}".format(buffer[i])
1037
- if self.MODE == "DMG": cfi["we"] = we
1038
- cfi["method_id"] = flash_commands.index(method)
1039
-
1040
- if d_swap is not None:
1041
- for k in method.keys():
1042
- for c in range(0, len(method[k])):
1043
- if isinstance(method[k][c][1], int):
1044
- method[k][c][1] = bitswap(method[k][c][1], d_swap)
1045
-
1046
- # Flash ID
1047
- for i in range(0, len(method['read_identifier'])):
1048
- self.gbx_flash_write_address_byte(method['read_identifier'][i][0], method["read_identifier"][i][1])
1049
- flash_id = self.ReadROM(0, 64)[0:8]
1050
- if self.MODE == "DMG":
1051
- method_string = "[" + we.ljust(5) + "/{:4X}/{:2X}]".format(method['read_identifier'][0][0], method['read_identifier'][0][1])
1052
- else:
1053
- method_string = "[{:6X}/{:2X}]".format(method['read_identifier'][0][0], method['read_identifier'][0][1])
1054
- line_exists = False
1055
- for i in range(0, len(flash_id_lines)):
1056
- if method_string == flash_id_lines[i][0]: line_exists = True
1057
- if not line_exists: flash_id_lines.append([method_string, flash_id])
1058
- for i in range(0, len(method['reset'])):
1059
- self.gbx_flash_write_address_byte(method['reset'][i][0], method['reset'][i][1])
1060
-
1061
- cfi["method"] = method
1062
-
1063
- if cart_type is not None: # reset cartridge if method is known
1064
- flashcart_meta = copy.deepcopy(cart_type)
1065
- if "reset" in flashcart_meta["commands"]:
1066
- for i in range(0, len(flashcart_meta["commands"]["reset"])):
1067
- self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
1068
-
1069
- if "method" in cfi:
1070
- s = ""
1071
- if d_swap is not None and d_swap != ( 0, 0 ): s += "Swapped pins: {:s}\n".format(str(d_swap))
1072
- s += "Device size: 0x{:07X} ({:.2f} MB)\n".format(cfi["device_size"], cfi["device_size"] / 1024 / 1024)
1073
- s += "Voltage: {:.1f}–{:.1f} V\n".format(cfi["vdd_min"], cfi["vdd_max"])
1074
- s += "Single write: {:s}\n".format(str(cfi["single_write"]))
1075
- if "buffer_size" in cfi:
1076
- s += "Buffered write: {:s} ({:d} Bytes)\n".format(str(cfi["buffer_write"]), cfi["buffer_size"])
1077
- else:
1078
- s += "Buffered write: {:s}\n".format(str(cfi["buffer_write"]))
1079
- if cfi["chip_erase"]: s += "Chip erase: {:d}–{:d} ms\n".format(cfi["chip_erase_time_avg"], cfi["chip_erase_time_max"])
1080
- if cfi["sector_erase"]: s += "Sector erase: {:d}–{:d} ms\n".format(cfi["sector_erase_time_avg"], cfi["sector_erase_time_max"])
1081
- if cfi["tb_boot_sector"] is not False: s += "Sector flags: {:s}\n".format(str(cfi["tb_boot_sector"]))
1082
- pos = 0
1083
- oversize = False
1084
- s = s[:-1]
1085
- for i in range(0, cfi['erase_sector_regions']):
1086
- esb = cfi['erase_sector_blocks'][i]
1087
- s += "\nRegion {:d}: 0x{:07X}–0x{:07X} @ 0x{:X} Bytes × {:d}".format(i+1, pos, pos+esb[2]-1, esb[0], esb[1])
1088
- if oversize: s += " (alt)"
1089
- pos += esb[2]
1090
- if pos >= cfi['device_size']:
1091
- pos = 0
1092
- oversize = True
1093
- #s += "\nSHA-1: {:s}".format(cfi["sha1"])
1094
- cfi_info = s
1095
-
1096
- if cfi['raw'] == b'':
1097
- for we in we_pins:
1098
- for method in flash_commands:
1099
- for i in range(0, len(method['reset'])):
1100
- self.gbx_flash_write_address_byte(method['reset'][i][0], method["reset"][i][1])
1101
- for i in range(0, len(method['read_identifier'])):
1102
- self.gbx_flash_write_address_byte(method['read_identifier'][i][0], method["read_identifier"][i][1])
1103
- flash_id = self.ReadROM(0, 64)[0:8]
1104
- for i in range(0, len(method['reset'])):
1105
- self.gbx_flash_write_address_byte(method['reset'][i][0], method["reset"][i][1])
1106
-
1107
- if flash_id != check_buffer[0:8]:
1108
- if self.MODE == "DMG":
1109
- method_string = "[" + we.ljust(5) + "/{:4X}/{:2X}]".format(method['read_identifier'][0][0], method['read_identifier'][0][1])
1110
- else:
1111
- method_string = "[{:6X}/{:2X}]".format(method['read_identifier'][0][0], method['read_identifier'][0][1])
1112
- line_exists = False
1113
- for i in range(0, len(flash_id_lines)):
1114
- if method_string == flash_id_lines[i][0]: line_exists = True
1115
- if not line_exists: flash_id_lines.append([method_string, flash_id])
1116
- for i in range(0, len(method['reset'])):
1117
- self.gbx_flash_write_address_byte(method['reset'][i][0], method['reset'][i][1])
1118
-
1119
- if self.MODE == "DMG":
1120
- self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
1121
-
1122
- if cart_type is not None: # reset cartridge if method is known
1123
- flashcart_meta = copy.deepcopy(cart_type)
1124
- if "reset_every" in flashcart_meta and "flash_size" in flashcart_meta:
1125
- for j in range(0, flashcart_meta["flash_size"], flashcart_meta["reset_every"]):
1126
- if j >= 0x2000000: break
1127
- dprint("reset_every @ 0x{:X}".format(j))
1128
- for command in flashcart_meta["commands"]["reset"]:
1129
- self.gbx_flash_write_address_byte(j, command[1])
1130
- time.sleep(0.01)
1131
- elif "reset" in flashcart_meta["commands"]:
1132
- for i in range(0, len(flashcart_meta["commands"]["reset"])):
1133
- self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
1134
-
1135
- flash_id = ""
1136
- for i in range(0, len(flash_id_lines)):
1137
- flash_id += flash_id_lines[i][0] + " "
1138
- for j in range(0, 8):
1139
- flash_id += "{:02X} ".format(flash_id_lines[i][1][j])
1140
- flash_id += "\n"
1141
-
1142
- flash_id = rom_string + flash_id
1143
-
1144
- return (flash_id, cfi_info, cfi)
1145
-
1146
- def CheckROMStable(self):
1147
- if not self.IsConnected(): raise ConnectionError("Couldn’t access the the device.")
1148
- self.ReadROM(0, 64)
1149
- buffer = self.ReadROM(0, 0x180)
1150
- time.sleep(0.1)
1151
- if buffer != self.ReadROM(0, 0x180):
1152
- return False
1153
- return True
1154
-
1155
- def ReadInfo(self, setPinsAsInputs=False, checkRtc=False):
1156
- if not self.IsConnected(): raise ConnectionError("Couldn’t access the the device.")
1157
- data = {}
1158
- if self.MODE == "DMG":
1159
- self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
1160
- time.sleep(0.1)
1161
- # Firmware check R26+
1162
- if (int(self.FW[0]) >= 26):
1163
- self.set_mode(self.DEVICE_CMD['RESET_MBC'])
1164
- self.wait_for_ack()
1165
- # Firmware check R26+
1166
-
1167
- header = self.ReadROM(0, 0x180)
1168
- if header is False or len(header) != 0x180: raise ConnectionError("Couldn’t read the cartridge information. Please try again.")
1169
- if Util.DEBUG:
1170
- with open("debug_header.bin", "wb") as f: f.write(header)
1171
-
1172
- # Check for DACS
1173
- dacs_8m = False
1174
- if header[0x04:0x04+0x9C] == bytearray([0x00] * 0x9C):
1175
- self.ReadROM(0x1FFFFE0, 20) # Unlock DACS
1176
- header = self.ReadROM(0, 0x180)
1177
- temp = self.ReadROM(0x1FFE000, 0x0C)
1178
- if temp == b"AGBFLASHDACS":
1179
- dacs_8m = True
1180
-
1181
- # Parse ROM header
1182
- if self.MODE == "DMG":
1183
- data = RomFileDMG(header).GetHeader()
1184
-
1185
- elif self.MODE == "AGB":
1186
- data = RomFileAGB(header).GetHeader()
1187
- # Check where the ROM data repeats (for unlicensed carts)
1188
- size_check = header[0xA0:0xA0+16]
1189
- currAddr = 0x10000
1190
- while currAddr < 0x2000000:
1191
- buffer = self.ReadROM(currAddr + 0xA0, 64)[:16]
1192
- if buffer == size_check: break
1193
- currAddr *= 2
1194
- data["rom_size"] = currAddr
1195
- if (data["3d_memory"] == True):
1196
- data["rom_size"] = 0x4000000
1197
- elif dacs_8m:
1198
- data["dacs_8m"] = True
1199
-
1200
- data["raw"] = header
1201
- self.INFO = data
1202
- self.INFO["flash_type"] = 0
1203
- self.INFO["last_action"] = 0
1204
- self.INFO["has_rtc"] = False
1205
- self.INFO["no_rtc_reason"] = -1
1206
- self.INFO["rtc_string"] = "(Unsupported in Legacy Mode)"
1207
- self.INFO["dump_info"] = {}
1208
- self.INFO["dump_info"]["header"] = data
1209
-
1210
- if self.MODE == "DMG" and setPinsAsInputs: self.set_mode(self.DEVICE_CMD["SET_PINS_AS_INPUTS"])
1211
- return data
1212
-
1213
- def GetDumpReport(self):
1214
- return Util.GetDumpReport(self.INFO["dump_info"], self)
1215
-
1216
- def GetReadErrors(self):
1217
- return self.READ_ERRORS
1218
-
1219
- #################################################################
1220
-
1221
- def BackupROM(self, fncSetProgress=None, args=None):
1222
- from . import DataTransfer
1223
- args['mode'] = 1
1224
- args['port'] = self
1225
- if self.WORKER is None:
1226
- self.WORKER = DataTransfer.DataTransfer(args)
1227
- self.WORKER.updateProgress.connect(fncSetProgress)
1228
- else:
1229
- self.WORKER.setConfig(args)
1230
- self.WORKER.start()
1231
-
1232
- def BackupRAM(self, fncSetProgress=None, args=None):
1233
- from . import DataTransfer
1234
- args['mode'] = 2
1235
- args['port'] = self
1236
- if fncSetProgress is False:
1237
- self.TransferData(args=args, signal=None)
1238
- else:
1239
- if self.WORKER is None:
1240
- self.WORKER = DataTransfer.DataTransfer(args)
1241
- self.WORKER.updateProgress.connect(fncSetProgress)
1242
- else:
1243
- self.WORKER.setConfig(args)
1244
- self.WORKER.start()
1245
-
1246
- def RestoreRAM(self, fncSetProgress=None, args=None):
1247
- from . import DataTransfer
1248
- args['mode'] = 3
1249
- args['port'] = self
1250
- if self.WORKER is None:
1251
- self.WORKER = DataTransfer.DataTransfer(args)
1252
- self.WORKER.updateProgress.connect(fncSetProgress)
1253
- else:
1254
- self.WORKER.setConfig(args)
1255
- self.WORKER.start()
1256
-
1257
- def FlashROM(self, fncSetProgress=None, args=None):
1258
- from . import DataTransfer
1259
- args['mode'] = 4
1260
- args['port'] = self
1261
- if self.WORKER is None:
1262
- self.WORKER = DataTransfer.DataTransfer(args)
1263
- self.WORKER.updateProgress.connect(fncSetProgress)
1264
- else:
1265
- self.WORKER.setConfig(args)
1266
- self.WORKER.start()
1267
-
1268
- def TransferData(self, args, signal):
1269
- if not self.IsConnected(): raise ConnectionError("Couldn’t access the the device.")
1270
- self.SIGNAL = signal
1271
- mode = args["mode"]
1272
- path = args["path"]
1273
- if "rtc" not in args: args["rtc"] = False
1274
- self.INFO["last_path"] = path
1275
- bank_size = 0x4000
1276
- agb_3dmemory = False
1277
- self.CANCEL_ARGS = {}
1278
- self.POS = 0
1279
- if self.INFO == None: self.ReadInfo()
1280
-
1281
- # Firmware check R26+
1282
- if (int(self.FW[0]) < 26) and self.MODE == "DMG" and "mbc" in args and args["mbc"] in (0x0B, 0x0D, 0xFD):
1283
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"A firmware update is required to access this cartridge. Please update the firmware of your GBxCart RW device to version R26 or higher.", "abortable":False})
1284
- return False
1285
- # Firmware check R26+
1286
- # Firmware check CFW
1287
- if ("agb_rom_size" in args and args["agb_rom_size"] > 32 * 1024 * 1024) or (self.MODE == "DMG" and "mbc" in args and not self.IsSupportedMbc(args["mbc"])) or (self.MODE == "AGB" and "dacs_8m" in self.INFO and self.INFO["dacs_8m"] is True): # 3D Memory
1288
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge is currently not supported by {:s} using the current firmware version of the {:s} device. Please try the dedicated insideGadgets software programs, try updating the firmware or upgrade to a new hardware revision.".format(APPNAME, self.GetFullName()), "abortable":False})
1289
- return False
1290
- # Firmware check CFW
1291
-
1292
- # Enable TAMA5
1293
- if self.MODE == "DMG" and "mbc" in args and args["mbc"] == 0xFD:
1294
- self.ReadInfo()
1295
- tama5_check = int.from_bytes(self.ReadROM(0xA000, 64)[:1], byteorder="little")
1296
- dprint("Enabling TAMA5")
1297
- lives = 20
1298
- while (tama5_check & 3) != 1:
1299
- dprint("└Current value is 0x{:X}, now writing 0xA001=0x{:X}".format(tama5_check, 0x0A))
1300
- self.cart_write(0xA001, 0x0A, cs=True)
1301
- tama5_check = int.from_bytes(self.ReadROM(0xA000, 64)[:1], byteorder="little")
1302
- time.sleep(0.1)
1303
- lives -= 1
1304
- if lives < 0:
1305
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"The TAMA5 cartridge doesn’t seem to respond. Please try again.", "abortable":False})
1306
- return False
1307
-
1308
- # main work starts here
1309
- self.INFO["last_action"] = mode
1310
- self.FAST_READ = False
1311
- if mode == 1: # Backup ROM
1312
- self.INFO["dump_info"]["timestamp"] = datetime.datetime.now().astimezone().replace(microsecond=0).isoformat()
1313
- self.INFO["dump_info"]["file_name"] = args["path"]
1314
- self.INFO["dump_info"]["file_size"] = args["rom_size"]
1315
- self.INFO["dump_info"]["cart_type"] = args["cart_type"]
1316
- self.INFO["dump_info"]["system"] = self.MODE
1317
- self.INFO["dump_info"]["transfer_size"] = 64
1318
- fast_read_mode = False #args["fast_read_mode"]
1319
- buffer_len = 0x1000
1320
- if self.MODE == "DMG":
1321
- self.INFO["dump_info"]["rom_size"] = args["rom_size"]
1322
- self.INFO["dump_info"]["mapper_type"] = args["mbc"]
1323
- supported_carts = list(self.SUPPORTED_CARTS['DMG'].values())
1324
- mbc = args["mbc"]
1325
- bank_count = int(args["rom_size"] / 0x4000)
1326
-
1327
- if mbc == 0x104: # M161
1328
- bank_count = 8
1329
- bank_size = 0x8000
1330
-
1331
- if fast_read_mode:
1332
- buffer_len = 0x4000
1333
- self.FAST_READ = True
1334
- rom_size = bank_count * bank_size
1335
-
1336
- elif self.MODE == "AGB":
1337
- self.INFO["dump_info"]["mapper_type"] = None
1338
- supported_carts = list(self.SUPPORTED_CARTS['AGB'].values())
1339
- rom_size = args["agb_rom_size"]
1340
- self.INFO["dump_info"]["rom_size"] = rom_size
1341
- bank_count = 1
1342
- endAddr = rom_size
1343
- if rom_size == 64 * 1024 * 1024: # 3D Memory
1344
- agb_3dmemory = True
1345
- if fast_read_mode:
1346
- buffer_len = 0x1000
1347
- self.FAST_READ = True
1348
- else:
1349
- buffer_len = 0x200
1350
-
1351
- elif fast_read_mode:
1352
- buffer_len = 0x10000
1353
- self.FAST_READ = True
1354
-
1355
- if rom_size == 0:
1356
- rom_size = 32 * 1024 * 1024
1357
-
1358
- # Read a bit before actually dumping (fixes some carts that don’t like SET_PINS_AS_INPUTS)
1359
- self.ReadROM(0, 64)
1360
-
1361
- # Cart type check (GB Memory)
1362
- flashcart_meta = False
1363
- if not isinstance(args["cart_type"], dict):
1364
- for i in range(0, len(supported_carts)):
1365
- if i == args["cart_type"]: flashcart_meta = supported_carts[i]
1366
- if flashcart_meta == "RETAIL": flashcart_meta = False
1367
- else:
1368
- flashcart_meta = args["cart_type"]
1369
-
1370
- if flashcart_meta is not False and "unlock_before_rom_dump" in flashcart_meta and flashcart_meta["unlock_before_rom_dump"] is True:
1371
- # Unlock Flash
1372
- if "unlock" in flashcart_meta["commands"]:
1373
- for i in range(0, len(flashcart_meta["commands"]["unlock"])):
1374
- addr = flashcart_meta["commands"]["unlock"][i][0]
1375
- data = flashcart_meta["commands"]["unlock"][i][1]
1376
- count = flashcart_meta["commands"]["unlock"][i][2]
1377
- for _ in range(0, count):
1378
- self.gbx_flash_write_address_byte(addr, data)
1379
-
1380
- # Reset Flash
1381
- if "reset" in flashcart_meta["commands"]:
1382
- for i in range(0, len(flashcart_meta["commands"]["reset"])):
1383
- self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
1384
-
1385
- data_dump = bytearray()
1386
-
1387
- startAddr = 0
1388
- currAddr = 0
1389
- recvBytes = 0
1390
-
1391
- try:
1392
- file = open(path, "wb")
1393
- except PermissionError:
1394
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"FlashGBX doesn’t have permission to access this file for writing:\n" + path, "abortable":False})
1395
- return False
1396
-
1397
- if self.MODE == "DMG":
1398
- endAddr = bank_size
1399
-
1400
- dprint("bank_count: {:d}".format(bank_count))
1401
-
1402
- self.SetProgress({"action":"INITIALIZE", "method":"ROM_READ", "size":rom_size})
1403
-
1404
- for bank in range(0, bank_count):
1405
- if self.MODE == "DMG":
1406
- if bank > 0:
1407
- startAddr = bank_size
1408
- endAddr = startAddr + bank_size
1409
-
1410
- if mbc in (0x0B, 0x0D) and bank % 0x20 == 0: # MMM01
1411
- startAddr = 0
1412
- endAddr = bank_size
1413
- elif mbc == 0x104: # M161
1414
- startAddr = 0
1415
- endAddr = 0x8000
1416
- elif mbc in (0x01, 0x02, 0x03): # MBC1
1417
- if bank & 0x1F:
1418
- startAddr = 0x4000
1419
- endAddr = 0x8000
1420
- else:
1421
- startAddr = 0
1422
- endAddr = 0x4000
1423
-
1424
- self.SetBankROM(bank, mbc)
1425
-
1426
- for currAddr in range(startAddr, endAddr, buffer_len):
1427
- if self.CANCEL:
1428
- cancel_args = {"action":"ABORT", "abortable":False}
1429
- cancel_args.update(self.CANCEL_ARGS)
1430
- self.CANCEL_ARGS = {}
1431
- self.SetProgress(cancel_args)
1432
- try:
1433
- file.close()
1434
- except:
1435
- pass
1436
- return
1437
-
1438
- if currAddr == startAddr:
1439
- buffer = self.ReadROM(currAddr, buffer_len, True, agb_3dmemory=agb_3dmemory)
1440
- else:
1441
- buffer = self.ReadROM(currAddr, buffer_len, False, agb_3dmemory=agb_3dmemory)
1442
-
1443
- if buffer == False:
1444
- self.CANCEL = True
1445
- self.ERROR = True
1446
- continue
1447
-
1448
- data_dump.extend(buffer)
1449
- file.write(buffer)
1450
- recvBytes += buffer_len
1451
- self.SetProgress({"action":"UPDATE_POS", "pos":recvBytes})
1452
-
1453
- file.close()
1454
-
1455
- # Read hidden sector (GB Memory)
1456
- if flashcart_meta is not False and "read_hidden_sector" in flashcart_meta["commands"] and "hidden_sector_size" in flashcart_meta:
1457
- # Unlock Flash
1458
- if "unlock" in flashcart_meta["commands"]:
1459
- for i in range(0, len(flashcart_meta["commands"]["unlock"])):
1460
- addr = flashcart_meta["commands"]["unlock"][i][0]
1461
- data = flashcart_meta["commands"]["unlock"][i][1]
1462
- count = flashcart_meta["commands"]["unlock"][i][2]
1463
- for _ in range(0, count):
1464
- self.gbx_flash_write_address_byte(addr, data)
1465
-
1466
- # Request hidden sector
1467
- for i in range(0, len(flashcart_meta["commands"]["read_hidden_sector"])):
1468
- self.gbx_flash_write_address_byte(flashcart_meta["commands"]["read_hidden_sector"][i][0], flashcart_meta["commands"]["read_hidden_sector"][i][1])
1469
-
1470
- # Read data
1471
- buffer = self.ReadROM(0, flashcart_meta["hidden_sector_size"], True)
1472
- path2 = os.path.splitext(path)[0] + ".map"
1473
- try:
1474
- file = open(path2, "wb")
1475
- except PermissionError:
1476
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"FlashGBX doesn’t have permission to access this file for writing:\n" + path2, "abortable":False})
1477
- return False
1478
- file.write(buffer)
1479
- file.close()
1480
-
1481
- # Calculate Global Checksum
1482
- buffer = data_dump
1483
- self.INFO["file_crc32"] = zlib.crc32(buffer) & 0xFFFFFFFF
1484
- self.INFO["file_sha1"] = hashlib.sha1(buffer).hexdigest()
1485
- self.INFO["file_sha256"] = hashlib.sha256(buffer).hexdigest()
1486
- self.INFO["file_md5"] = hashlib.md5(buffer).hexdigest()
1487
- self.INFO["dump_info"]["hash_crc32"] = self.INFO["file_crc32"]
1488
- self.INFO["dump_info"]["hash_sha1"] = self.INFO["file_sha1"]
1489
- self.INFO["dump_info"]["hash_sha256"] = self.INFO["file_sha256"]
1490
- self.INFO["dump_info"]["hash_md5"] = self.INFO["file_md5"]
1491
- chk = 0
1492
- if self.MODE == "DMG":
1493
- self.INFO["dump_info"]["header"] = RomFileDMG(buffer[:0x180]).GetHeader(unchanged=True)
1494
- if mbc in (0x0B, 0x0D): # MMM01
1495
- self.set_mode(self.DEVICE_CMD['RESET_MBC'])
1496
- self.wait_for_ack()
1497
- temp_data = data_dump[0:-0x8000]
1498
- temp_menu = data_dump[-0x8000:]
1499
- temp_dump = temp_menu + temp_data
1500
- for i in range(0, len(temp_dump), 2):
1501
- if i != 0x14E:
1502
- chk = chk + temp_dump[i + 1]
1503
- chk = chk + temp_dump[i]
1504
- chk = chk & 0xFFFF
1505
-
1506
- else:
1507
- for i in range(0, len(data_dump), 2):
1508
- if i != 0x14E:
1509
- chk = chk + data_dump[i + 1]
1510
- chk = chk + data_dump[i]
1511
- chk = chk & 0xFFFF
1512
-
1513
- elif self.MODE == "AGB":
1514
- self.INFO["dump_info"]["header"] = RomFileAGB(buffer[:0x180]).GetHeader(unchanged=True)
1515
- chk = self.INFO["file_crc32"]
1516
-
1517
- temp_ver = "N/A"
1518
- ids = [ b"SRAM_", b"EEPROM_V", b"FLASH_V", b"FLASH512_V", b"FLASH1M_V", b"AGB_8MDACS_DL_V" ]
1519
- for id in ids:
1520
- temp_pos = buffer.find(id)
1521
- if temp_pos > 0:
1522
- temp_ver = buffer[temp_pos:temp_pos+0x20]
1523
- temp_ver = temp_ver[:temp_ver.index(0x00)].decode("ascii", "replace")
1524
- break
1525
- self.INFO["dump_info"]["agb_savelib"] = temp_ver
1526
- self.INFO["dump_info"]["agb_save_flash_id"] = None
1527
-
1528
- self.INFO["rom_checksum_calc"] = chk
1529
-
1530
- # Check for ROM loops
1531
- self.INFO["loop_detected"] = False
1532
- temp = min(0x2000000, len(data_dump))
1533
- while temp > 0x4000:
1534
- temp = temp >> 1
1535
- if (data_dump[0:0x4000] == data_dump[temp:temp+0x4000]):
1536
- if data_dump[0:temp] == data_dump[temp:temp*2]:
1537
- self.INFO["loop_detected"] = temp
1538
- else:
1539
- break
1540
-
1541
- self.SetProgress({"action":"FINISHED"})
1542
-
1543
- #########################################
1544
-
1545
- elif mode == 2 or mode == 3: # Backup or Restore RAM
1546
- data_dump = bytearray()
1547
- data_import = bytearray()
1548
- self.ReadROM(0, 64) # fix
1549
- audio_low = False
1550
-
1551
- startAddr = 0
1552
- if self.MODE == "DMG":
1553
- bank_size = 0x2000
1554
- mbc = args["mbc"]
1555
- #save_size = args["save_type"]
1556
- save_size = Util.DMG_Header_RAM_Sizes_Flasher_Map[Util.DMG_Header_RAM_Sizes_Map.index(args["save_type"])]
1557
- bank_count = int(max(save_size, bank_size) / bank_size)
1558
- self.EnableRAM(mbc=mbc, enable=True)
1559
- startAddr = 0xA000
1560
- if mode == 2: # Backup
1561
- transfer_size = 512
1562
- else: # Restore
1563
- transfer_size = 64
1564
-
1565
- if mbc == 0xFD: # TAMA5
1566
- if args["rtc"]: save_size += 0x10
1567
- elif mbc == 0x22: # MBC7 EEPROM
1568
- transfer_size = 32
1569
- self.cart_write(0x4000, 0x40)
1570
- if mode == 3: # Restore
1571
- self.cart_write(0xA080, 0x00) # init eeprom
1572
- self.cart_write(0xA080, 0x80)
1573
-
1574
- self.cart_write(0xA080, 0x80) # init command
1575
- self.cart_write(0xA080, 0xC0)
1576
- self.cart_write(0xA080, 0x82)
1577
- self.cart_write(0xA080, 0xC2)
1578
-
1579
- self.cart_write(0xA080, 0x80) # write enable command
1580
- self.cart_write(0xA080, 0xC0)
1581
- self.cart_write(0xA080, 0x80)
1582
- self.cart_write(0xA080, 0xC0)
1583
- self.cart_write(0xA080, 0x82)
1584
- self.cart_write(0xA080, 0xC2)
1585
- self.cart_write(0xA080, 0x82)
1586
- self.cart_write(0xA080, 0xC2)
1587
- for _ in range(0, 6):
1588
- self.cart_write(0xA080, 0x80)
1589
- self.cart_write(0xA080, 0xC0)
1590
-
1591
- if transfer_size >= save_size:
1592
- transfer_size = save_size
1593
- bank_size = save_size
1594
-
1595
- # Check for DMG-MBC5-32M-FLASH
1596
- self.cart_write(0x2000, 0x00)
1597
- self.cart_write(0x4000, 0x90)
1598
- flash_id = self.ReadROM(0x4000, 2)
1599
- if flash_id == bytearray([0xB0, 0x88]): audio_low = True
1600
- self.cart_write(0x4000, 0xF0)
1601
- self.cart_write(0x4000, 0xFF)
1602
- self.cart_write(0x2000, 0x01)
1603
- if audio_low:
1604
- dprint("DMG-MBC5-32M-FLASH Development Cartridge detected")
1605
- self.set_mode(self.DEVICE_CMD["AUDIO_LOW"])
1606
- self.cart_write(0x4000, 0x00)
1607
-
1608
- elif self.MODE == "AGB":
1609
- bank_size = 0x10000
1610
- save_type = args["save_type"]
1611
- bank_count = 1
1612
- eeprom_size = 0
1613
- transfer_size = 64
1614
-
1615
- if save_type == 0:
1616
- return
1617
- elif save_type == 1: # EEPROM 512 Byte
1618
- save_size = 512
1619
- read_command = 'GBA_READ_EEPROM'
1620
- write_command = 'GBA_WRITE_EEPROM'
1621
- transfer_size = 8
1622
- eeprom_size = 1
1623
- elif save_type == 2: # EEPROM 8 KB
1624
- save_size = 8 * 1024
1625
- read_command = 'GBA_READ_EEPROM'
1626
- write_command = 'GBA_WRITE_EEPROM'
1627
- transfer_size = 8
1628
- eeprom_size = 2
1629
- elif save_type == 3: # SRAM 32 KB
1630
- save_size = 32 * 1024
1631
- read_command = 'GBA_READ_SRAM'
1632
- write_command = 'GBA_WRITE_SRAM'
1633
- elif save_type == 7: # SRAM 64 KB
1634
- save_size = 64 * 1024
1635
- read_command = 'GBA_READ_SRAM'
1636
- write_command = 'GBA_WRITE_SRAM'
1637
- elif save_type == 8: # SRAM 128 KB
1638
- save_size = 128 * 1024
1639
- read_command = 'GBA_READ_SRAM'
1640
- write_command = 'GBA_WRITE_SRAM'
1641
- bank_count = 2
1642
- elif save_type == 4: # FLASH 64 KB
1643
- save_size = 64 * 1024
1644
- read_command = 'GBA_READ_SRAM'
1645
- elif save_type == 5: # FLASH 128 KB
1646
- save_size = 128 * 1024
1647
- read_command = 'GBA_READ_SRAM'
1648
- bank_count = 2
1649
- else:
1650
- return
1651
-
1652
- # Get Save Flash Manufacturer
1653
- maker_id = None
1654
- if save_type == 4 or save_type == 5:
1655
- maker_id = self.ReadFlashSaveMakerID()
1656
- if maker_id == "ATMEL" and mode == 3:
1657
- transfer_size = 128
1658
- elif maker_id == "SANYO":
1659
- if int(self.FW[0]) < 24:
1660
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"A firmware update is required to access this cartridge. Please update the firmware of your GBxCart RW device to version R24 or higher.", "abortable":False})
1661
- return False
1662
-
1663
- # Prepare some stuff
1664
- if mode == 2: # Backup
1665
- self.SetProgress({"action":"INITIALIZE", "method":"SAVE_READ", "size":save_size})
1666
-
1667
- elif mode == 3: # Restore
1668
- if args["erase"]: # Erase
1669
- if args["mbc"] == 0xFD: # TAMA5
1670
- data_import = save_size * b'\x00'
1671
- else:
1672
- data_import = save_size * b'\xFF'
1673
- self.INFO["save_erase"] = True
1674
- else:
1675
- with open(path, "rb") as file: data_import = file.read()
1676
-
1677
- while len(data_import) < save_size:
1678
- data_import += bytearray(data_import)
1679
- data_import = data_import[:save_size]
1680
-
1681
- self.SetProgress({"action":"INITIALIZE", "method":"SAVE_WRITE", "size":save_size})
1682
-
1683
- currAddr = 0
1684
- pos = 0
1685
-
1686
- for bank in range(0, bank_count):
1687
- if self.MODE == "DMG":
1688
- endAddr = startAddr + bank_size
1689
- if endAddr > (startAddr + save_size): endAddr = startAddr + save_size
1690
- if mbc != 0x22: # exclude MBC7
1691
- self.SetBankRAM(bank, mbc)
1692
-
1693
- elif self.MODE == "AGB":
1694
- endAddr = startAddr + min(save_size, bank_size)
1695
- if endAddr > (startAddr + save_size): endAddr = startAddr + save_size
1696
- if save_type == 1 or save_type == 2: # EEPROM
1697
- self.set_number(eeprom_size, self.DEVICE_CMD["GBA_SET_EEPROM_SIZE"])
1698
- elif save_type == 8: # 1M SRAM
1699
- self.gbx_flash_write_address_byte(0x1000000, bank)
1700
- elif (save_type == 4 or save_type == 5) and bank > 0: # FLASH
1701
- self.set_number(bank, self.DEVICE_CMD["GBA_FLASH_SET_BANK"])
1702
-
1703
- self.set_number(startAddr, self.DEVICE_CMD["SET_START_ADDRESS"])
1704
-
1705
- buffer_len = transfer_size
1706
- sector = 0
1707
- for currAddr in range(startAddr, endAddr, buffer_len):
1708
- if self.CANCEL:
1709
- if self.MODE == "DMG":
1710
- self.EnableRAM(mbc=mbc, enable=False)
1711
- elif self.MODE == "AGB":
1712
- if bank > 0: self.set_number(0, self.DEVICE_CMD["GBA_FLASH_SET_BANK"])
1713
- self.ReadInfo()
1714
- cancel_args = {"action":"ABORT", "abortable":False}
1715
- cancel_args.update(self.CANCEL_ARGS)
1716
- self.CANCEL_ARGS = {}
1717
- self.SetProgress(cancel_args)
1718
- return
1719
-
1720
- if mode == 2: # Backup
1721
- if self.MODE == "DMG":
1722
- if mbc == 0xFD: # TAMA5
1723
- buffer = self.ReadRAM_TAMA5(rtc=args["rtc"])
1724
- elif mbc == 0x22: # MBC7 EEPROM
1725
- self.set_mode(self.DEVICE_CMD["READ_EEPROM_MBC7"])
1726
- buffer = self.read(length=buffer_len, last=True, ask_next_bytes=False)
1727
- if buffer == False:
1728
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Backup failed, please try again.", "abortable":False})
1729
- return False
1730
- else:
1731
- buffer = self.ReadROM(currAddr, buffer_len)
1732
- elif self.MODE == "AGB":
1733
- self.set_mode(self.DEVICE_CMD[read_command])
1734
- buffer = self.read(length=buffer_len, last=True, ask_next_bytes=False)
1735
- if buffer == False:
1736
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Backup failed, please try again.", "abortable":False})
1737
- return False
1738
-
1739
- data_dump.extend(buffer)
1740
- #file.write(buffer)
1741
-
1742
- elif mode == 3: # Restore
1743
- data = data_import[pos:pos+buffer_len]
1744
- if self.MODE == "DMG":
1745
- if mbc == 0xFD: # TAMA5
1746
- self.WriteRAM_TAMA5(data, rtc=args["rtc"])
1747
- elif mbc == 0x22: # MBC7 EEPROM
1748
- self.gbx_flash_write_data_bytes(self.DEVICE_CMD["WRITE_EEPROM_MBC7"], data)
1749
- self.wait_for_ack()
1750
- else:
1751
- self.gbx_flash_write_data_bytes(self.DEVICE_CMD["WRITE_RAM"], data)
1752
- self.wait_for_ack()
1753
-
1754
- elif self.MODE == "AGB":
1755
- if save_type == 4 or save_type == 5: # FLASH
1756
- if maker_id == "ATMEL":
1757
- self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_ATMEL"], data)
1758
- self.wait_for_ack()
1759
- else:
1760
- if (currAddr % 4096 == 0):
1761
- self.set_number(sector, self.DEVICE_CMD["GBA_FLASH_4K_SECTOR_ERASE"])
1762
- self.wait_for_ack()
1763
- sector += 1
1764
- lives = 50
1765
- while True: # wait for 0xFF (= erase done)
1766
- self.set_number(currAddr, self.DEVICE_CMD["SET_START_ADDRESS"])
1767
- self.set_mode(self.DEVICE_CMD[read_command])
1768
- buffer = self.read(buffer_len, last=True)
1769
- if buffer[0] == 0xFF: break
1770
- time.sleep(0.01)
1771
- lives -= 1
1772
- if lives == 0:
1773
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Accessing the save data flash chip failed. Please make sure you selected the correct save type. If you are using a reproduction cartridge, check if it really is equipped with a flash chip for save data, or if it uses SRAM for save data instead.", "abortable":False})
1774
- return False
1775
- self.set_number(currAddr, self.DEVICE_CMD["SET_START_ADDRESS"])
1776
-
1777
- self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_BYTE"], data)
1778
- self.wait_for_ack()
1779
-
1780
- else: # EEPROM / SRAM
1781
- self.gbx_flash_write_data_bytes(self.DEVICE_CMD[write_command], data)
1782
- self.wait_for_ack()
1783
-
1784
- self.SetProgress({"action":"WRITE", "bytes_added":len(data)})
1785
-
1786
- pos += buffer_len
1787
- self.SetProgress({"action":"UPDATE_POS", "pos":pos})
1788
-
1789
- self.INFO["transferred"] = pos
1790
-
1791
- if self.MODE == "DMG":
1792
- # MBC7 EEPROM write end
1793
- if mode == 3 and mbc == 0x22:
1794
- self.cart_write(0xA080, 0x00) # init eeprom
1795
- self.cart_write(0xA080, 0x80)
1796
-
1797
- self.cart_write(0xA080, 0x80) # init command
1798
- self.cart_write(0xA080, 0xC0)
1799
- self.cart_write(0xA080, 0x82)
1800
- self.cart_write(0xA080, 0xC2)
1801
-
1802
- self.cart_write(0xA080, 0x80) # disable write command
1803
- self.cart_write(0xA080, 0xC0)
1804
- self.cart_write(0xA080, 0x80)
1805
- self.cart_write(0xA080, 0xC0)
1806
- self.cart_write(0xA080, 0x80)
1807
- self.cart_write(0xA080, 0xC0)
1808
- self.cart_write(0xA080, 0x80)
1809
- self.cart_write(0xA080, 0xC0)
1810
- for _ in range(0, 6):
1811
- self.cart_write(0xA080, 0x80)
1812
- self.cart_write(0xA080, 0xC0)
1813
-
1814
- # RTC for MBC3+RTC+SRAM+BATTERY
1815
- elif mbc in (0x10, 0x110) and args["rtc"]:
1816
- buffer = bytearray()
1817
- self.cart_write(0x6000, 0)
1818
- self.cart_write(0x6000, 1)
1819
-
1820
- if mode == 2: # Backup
1821
- for i in range(0x8, 0xD):
1822
- self.cart_write(0x4000, i)
1823
- buffer.extend(struct.pack("<I", ord(self.ReadROM(0xA000, 1))))
1824
- buffer.extend(buffer)
1825
- ts = int(time.time())
1826
- buffer.extend(struct.pack("<Q", ts))
1827
- #file.write(buffer)
1828
-
1829
- # RTC for HuC-3+RTC+SRAM+BATTERY
1830
- elif mbc == 0xFE and args["rtc"]:
1831
- buffer = bytearray()
1832
-
1833
- self.cart_write(0x0000, 0x0B)
1834
- self.cart_write(0xA000, 0x60)
1835
- self.cart_write(0x0000, 0x0D)
1836
- self.cart_write(0xA000, 0xFE)
1837
- self.cart_write(0x0000, 0x0C)
1838
- self.cart_write(0x0000, 0x00)
1839
-
1840
- self.cart_write(0x0000, 0x0B)
1841
- self.cart_write(0xA000, 0x40)
1842
- self.cart_write(0x0000, 0x0D)
1843
- self.cart_write(0xA000, 0xFE)
1844
- self.cart_write(0x0000, 0x0C)
1845
- self.cart_write(0x0000, 0x00)
1846
-
1847
- if mode == 2: # Backup
1848
- rtc = 0
1849
- for i in range(0, 6):
1850
- self.cart_write(0x0000, 0x0B)
1851
- self.cart_write(0xA000, 0x10)
1852
- self.cart_write(0x0000, 0x0D)
1853
- self.cart_write(0xA000, 0xFE)
1854
- self.cart_write(0x0000, 0x0C)
1855
- rtc |= (self.ReadROM(0xA000, 64)[0] & 0xF) << (i * 4)
1856
- self.cart_write(0x0000, 0x00)
1857
-
1858
- buffer.extend(struct.pack("<L", rtc))
1859
- ts = int(time.time())
1860
- buffer.extend(struct.pack("<Q", ts))
1861
-
1862
- elif mode == 3 and len(data_import) == save_size + 0x0C: # Restore
1863
- buffer = data_import[-0x0C:-0x08]
1864
-
1865
- for i in range(0, 3):
1866
- self.cart_write(0x0000, 0x0B)
1867
- self.cart_write(0xA000, 0x30 | (buffer[i] & 0xF))
1868
- self.cart_write(0x0000, 0x0D)
1869
- self.cart_write(0xA000, 0xFE)
1870
- self.cart_write(0x0000, 0x00)
1871
- self.cart_write(0x0000, 0x0D)
1872
-
1873
- self.cart_write(0x0000, 0x0B)
1874
- self.cart_write(0xA000, 0x30 | ((buffer[i] >> 4) & 0xF))
1875
- self.cart_write(0x0000, 0x0D)
1876
- self.cart_write(0xA000, 0xFE)
1877
- self.cart_write(0x0000, 0x00)
1878
- self.cart_write(0x0000, 0x0D)
1879
-
1880
- self.cart_write(0x0000, 0x0B)
1881
- self.cart_write(0xA000, 0x31)
1882
- self.cart_write(0x0000, 0x0D)
1883
- self.cart_write(0xA000, 0xFE)
1884
- self.cart_write(0x0000, 0x00)
1885
- self.cart_write(0x0000, 0x0D)
1886
-
1887
- self.cart_write(0x0000, 0x0B)
1888
- self.cart_write(0xA000, 0x61)
1889
- self.cart_write(0x0000, 0x0D)
1890
- self.cart_write(0xA000, 0xFE)
1891
- self.cart_write(0x0000, 0x00)
1892
-
1893
- elif self.MODE == "AGB":
1894
- if bank > 0:
1895
- if (save_type == 8) and bank > 0: # 1M SRAM
1896
- self.gbx_flash_write_address_byte(0x1000000, 0)
1897
- elif (save_type == 4 or save_type == 5) and bank > 0: # FLASH
1898
- self.set_number(0, self.DEVICE_CMD["GBA_FLASH_SET_BANK"])
1899
-
1900
- if mode == 2:
1901
- if args["path"] is not None:
1902
- try:
1903
- file = open(args["path"], "wb")
1904
- except PermissionError:
1905
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"FlashGBX doesn’t have permission to access this file for writing:\n" + path, "abortable":False})
1906
- return False
1907
- file.write(data_dump)
1908
- file.close()
1909
- else:
1910
- self.INFO["data"] = data_dump
1911
- #file.close()
1912
- self.INFO["file_crc32"] = zlib.crc32(data_dump) & 0xFFFFFFFF
1913
- self.INFO["file_sha1"] = hashlib.sha1(data_dump).hexdigest()
1914
-
1915
- if audio_low: self.set_mode(self.DEVICE_CMD["AUDIO_HIGH"])
1916
- self.INFO["last_action"] = mode
1917
- self.SetProgress({"action":"FINISHED"})
1918
-
1919
- #########################################
1920
-
1921
- elif mode == 4: # Flash ROM
1922
- if self.MODE == "DMG":
1923
- supported_carts = list(self.SUPPORTED_CARTS['DMG'].values())
1924
- i_size = 0x4000
1925
- elif self.MODE == "AGB":
1926
- supported_carts = list(self.SUPPORTED_CARTS['AGB'].values())
1927
- i_size = 0x10000
1928
-
1929
- if not isinstance(args["cart_type"], dict):
1930
- cart_type = "RETAIL"
1931
- for i in range(0, len(supported_carts)):
1932
- if i == args["cart_type"]: cart_type = supported_carts[i]
1933
- if cart_type == "RETAIL": return False # Generic ROM Cartridge is not flashable
1934
- else:
1935
- cart_type = args["cart_type"]
1936
-
1937
- if path != "":
1938
- with open(path, "rb") as file: data_import = file.read()
1939
- else:
1940
- data_import = args["buffer"]
1941
-
1942
- # pad to next possible size
1943
- i = i_size
1944
- while len(data_import) > i: i += i_size
1945
- i = i - len(data_import)
1946
- if i > 0: data_import += bytearray([0xFF] * i)
1947
-
1948
- self._FlashROM(buffer=data_import, cart_type=cart_type, voltage=args["override_voltage"], start_addr=0, signal=signal, prefer_chip_erase=args["prefer_chip_erase"], fast_read_mode=False, verify_write=args["verify_write"], fix_header=args["fix_header"], manual_mbc=args["mbc"])
1949
-
1950
- # Reset pins to avoid save data loss
1951
- self.set_mode(self.DEVICE_CMD["SET_PINS_AS_INPUTS"])
1952
- return True
1953
-
1954
- #######################################################################################################################################
1955
-
1956
- def _FlashROM(self, buffer=bytearray(), start_addr=0, cart_type=None, voltage=3.3, signal=None, prefer_chip_erase=False, fast_read_mode=False, verify_write=False, fix_header=False, manual_mbc=0):
1957
- if not self.IsConnected(): raise ConnectionError("Couldn’t access the the device.")
1958
- if self.INFO == None: self.ReadInfo()
1959
- self.INFO["last_action"] = 4
1960
- bank_size = 0x4000
1961
- time_start = time.time()
1962
-
1963
- data_import = copy.copy(buffer)
1964
- if start_addr > 0:
1965
- data_import = (b'\xFF' * start_addr) + data_import
1966
- data_import = bytearray(data_import)
1967
-
1968
- if cart_type == "RETAIL": return False # Generic ROM Cartridge is not flashable
1969
- flashcart_meta = copy.deepcopy(cart_type)
1970
-
1971
- # Fix header
1972
- if fix_header:
1973
- if self.MODE == "DMG":
1974
- temp = RomFileDMG(data_import[0:0x200]).FixHeader()
1975
- elif self.MODE == "AGB":
1976
- temp = RomFileAGB(data_import[0:0x200]).FixHeader()
1977
- data_import[0:0x200] = temp
1978
-
1979
- # Special carts
1980
- if "Retrostage GameBoy Blaster" in cart_type["names"]:
1981
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"The Retrostage GameBoy Blaster cartridge is currently not fully supported by FlashGBX. However, you can use the insideGadgets “Flasher” software available from <a href=\"https://www.gbxcart.com/\">https://www.gbxcart.com/</a> to flash this cartridge.", "abortable":False})
1982
- return False
1983
- elif "insideGadgets Power Cart 1 MB, 128 KB SRAM" in cart_type["names"]:
1984
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"The insideGadgets Power Cart is currently not fully supported by FlashGBX. However, you can use the dedicated insideGadgets “iG Power Cart Programs” software available from <a href=\"https://www.gbxcart.com/\">https://www.gbxcart.com/</a> to flash this cartridge.", "abortable":False})
1985
- return False
1986
- elif "power_cycle" in cart_type and cart_type["power_cycle"] is True and not self.CanPowerCycleCart():
1987
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type is not flashable using FlashGBX and your GBxCart RW hardware revision due to missing cartridge power cycling support.", "abortable":False})
1988
- return False
1989
- # Special carts
1990
- # Firmware check R20+
1991
- if (int(self.FW[0]) < 20) and self.MODE == "AGB" and "buffer_write" in flashcart_meta["commands"] and flashcart_meta["commands"]["buffer_write"] == [[0xAAA, 0xAA], [0x555, 0x55], ['SA', 0x25], ['SA', 'BS'], ['PA', 'PD'], ['SA', 0x29]]:
1992
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"A firmware update is required to access this cartridge. Please update the firmware of your GBxCart RW device to version R20 or higher.", "abortable":False})
1993
- return False
1994
- # Firmware check R20+
1995
- # Firmware check R23+
1996
- if (int(self.FW[0]) < 23) and self.MODE == "AGB" and "buffer_write" in flashcart_meta["commands"] and flashcart_meta["commands"]["buffer_write"] == [[0xAAA, 0xA9], [0x555, 0x56], ['SA', 0x26], ['SA', 'BS'], ['PA', 'PD'], ['SA', 0x2A]]:
1997
- print("NOTE: Update your GBxCart RW firmware to version R23 or higher for a better transfer rate with this cartridge.")
1998
- del flashcart_meta["commands"]["buffer_write"]
1999
- # Firmware check R23+
2000
- # Firmware check R25+
2001
- if self.MODE == "AGB" and "single_write" in flashcart_meta["commands"] and flashcart_meta["commands"]["single_write"] == [['PA', 0x70], ['PA', 0x10], ['PA', 'PD']] and (([ 0xB0, 0x00, 0xE2, 0x00 ] in flashcart_meta["flash_ids"]) or ([ 0xB0, 0x00, 0xB0, 0x00 ] in flashcart_meta["flash_ids"])): # Dev
2002
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge is currently not supported by {:s} using the current firmware version of the {:s} device. Please check for firmware updates in the “Tools” menu or the maker’s website.".format(APPNAME, self.GetFullName()), "abortable":False})
2003
- return False
2004
- # Firmware check R25+
2005
- # Firmware check R28+
2006
- if (int(self.FW[0]) >= 28) and self.MODE == "AGB" and ("flash_ids" in flashcart_meta and ([ 0x89, 0x00, 0x89, 0x00, 0x18, 0x00, 0x18, 0x00 ] in flashcart_meta["flash_ids"])): # Flash2Advance
2007
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge is currently not supported by {:s} using the current firmware version of the {:s} device. Please check for firmware updates in the “Tools” menu or the maker’s website.".format(APPNAME, self.GetFullName()), "abortable":False})
2008
- return False
2009
- # Firmware check R25+
2010
- # Firmware check
2011
- if self.MODE == "AGB" and "buffer_write" in flashcart_meta["commands"] and flashcart_meta["commands"]["buffer_write"] == [['SA', 0xEA], ['SA', 'BS'], ['PA', 'PD'], ['SA', 0xD0], ['SA', 0xFF]]:
2012
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge is currently not supported by {:s} using the current firmware version of the {:s} device. Please check for firmware updates in the “Tools” menu or the maker’s website.".format(APPNAME, self.GetFullName()), "abortable":False})
2013
- return False
2014
- if self.MODE == "AGB" and "buffer_size" in flashcart_meta and flashcart_meta["buffer_size"] > 256:
2015
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge is currently not supported by {:s} using the current firmware version of the {:s} device. Please check for firmware updates in the “Tools” menu or the maker’s website.".format(APPNAME, self.GetFullName()), "abortable":False})
2016
- return False
2017
- if self.MODE == "DMG" and "single_write" in flashcart_meta["commands"] and "buffer_write" in flashcart_meta["commands"] and flashcart_meta["commands"]["buffer_write"] != [['SA', 0xE8], ['SA', 'BS'], ['PA', 'PD'], ['SA', 0xD0], ['SA', 0xFF]]:
2018
- print("NOTE: Update your GBxCart RW firmware to version L1 or higher for a better transfer rate with this cartridge.")
2019
- del flashcart_meta["commands"]["buffer_write"]
2020
- elif self.MODE == "AGB" and "single_write" in flashcart_meta["commands"] and "buffer_write" in flashcart_meta["commands"] and flashcart_meta["commands"]["buffer_write"] != [['SA', 0xE8], ['SA', 'BS'], ['PA', 'PD'], ['SA', 0xD0], ['SA', 0xFF]]:
2021
- print("NOTE: Update your GBxCart RW firmware to version L1 or higher for a better transfer rate with this cartridge.")
2022
- del flashcart_meta["commands"]["buffer_write"]
2023
-
2024
- if "flash_commands_on_bank_1" in cart_type:
2025
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type is currently not supported by FlashGBX. Please try the official GBxCart RW firmware and interface software instead.", "abortable":False})
2026
- return False
2027
-
2028
- # Set Voltage
2029
- if voltage == 3.3:
2030
- self.set_mode(self.DEVICE_CMD["VOLTAGE_3_3V"])
2031
- elif voltage == 5:
2032
- self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
2033
- elif flashcart_meta["voltage"] == 3.3:
2034
- self.set_mode(self.DEVICE_CMD["VOLTAGE_3_3V"])
2035
- elif flashcart_meta["voltage"] == 5:
2036
- self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
2037
-
2038
- if self.MODE == "DMG":
2039
- # MBC
2040
- if "mbc" in flashcart_meta:
2041
- mbc = flashcart_meta["mbc"]
2042
- if mbc is not False and isinstance(mbc, int):
2043
- dprint("Using forced mapper type 0x{:02X} for flashing".format(mbc))
2044
- elif mbc == "manual":
2045
- mbc = manual_mbc
2046
- dprint("Using manually selected mapper type 0x{:02X} for flashing".format(mbc))
2047
- if mbc == 0:
2048
- mbc = 0x19 # MBC5 default
2049
- dprint("Using default mapper type 0x{:02X} for flashing".format(mbc))
2050
- else:
2051
- mbc = 0x19 # MBC5 default
2052
-
2053
- self.set_mode(self.DEVICE_CMD["GB_CART_MODE"])
2054
- if "flash_commands_on_bank_1" in flashcart_meta and flashcart_meta["flash_commands_on_bank_1"]:
2055
- dprint("Setting GB_FLASH_BANK_1_COMMAND_WRITES")
2056
- self.set_mode(self.DEVICE_CMD["GB_FLASH_BANK_1_COMMAND_WRITES"])
2057
-
2058
- self.set_mode(self.DEVICE_CMD["GB_FLASH_WE_PIN"])
2059
- if flashcart_meta["write_pin"] == "WR":
2060
- dprint("Setting WE_AS_WR_PIN")
2061
- self.set_mode(self.DEVICE_CMD["WE_AS_WR_PIN"])
2062
- elif flashcart_meta["write_pin"] in ("AUDIO", "VIN"):
2063
- dprint("Setting WE_AS_AUDIO_PIN")
2064
- self.set_mode(self.DEVICE_CMD["WE_AS_AUDIO_PIN"])
2065
-
2066
- if "single_write" in flashcart_meta["commands"] and len(flashcart_meta["commands"]["single_write"]) == 4:
2067
- # Submit flash program commands to firmware
2068
- dprint("Setting GB_FLASH_PROGRAM_METHOD")
2069
- self.set_mode(self.DEVICE_CMD["GB_FLASH_PROGRAM_METHOD"])
2070
- for i in range(0, 3):
2071
- dprint("single_write_command(",i,"):", hex(flashcart_meta["commands"]["single_write"][i][0]), "=", hex(flashcart_meta["commands"]["single_write"][i][1]))
2072
- self.write(bytearray(format(flashcart_meta["commands"]["single_write"][i][0], "x"), "ascii") + b'\x00', True)
2073
- self.write(bytearray(format(flashcart_meta["commands"]["single_write"][i][1], "x"), "ascii") + b'\x00', True)
2074
-
2075
- elif self.MODE == "AGB":
2076
- # Read a bit of ROM before starting
2077
- self.ReadROM(0, 64)
2078
-
2079
- # Unlock Flash
2080
- if "unlock" in flashcart_meta["commands"]:
2081
- for i in range(0, len(flashcart_meta["commands"]["unlock"])):
2082
- addr = flashcart_meta["commands"]["unlock"][i][0]
2083
- data = flashcart_meta["commands"]["unlock"][i][1]
2084
- count = flashcart_meta["commands"]["unlock"][i][2]
2085
- for j in range(0, count):
2086
- self.gbx_flash_write_address_byte(addr, data)
2087
-
2088
- # Reset Flash
2089
- if "reset" in flashcart_meta["commands"]:
2090
- for i in range(0, len(flashcart_meta["commands"]["reset"])):
2091
- self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
2092
-
2093
- # Read sector size from CFI if necessary
2094
- if "sector_size_from_cfi" in flashcart_meta and flashcart_meta["sector_size_from_cfi"] is True:
2095
- (_, cfi_s, cfi) = self.CheckFlashChip(limitVoltage=(voltage == 3.3), cart_type=cart_type)
2096
- if cfi_s == "":
2097
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Couldn’t read the Common Flash Interface (CFI) data from the flash chip in order to determine the correct sector size map. Please make sure that the cartridge contacts are clean, and that the selected cartridge type and settings are correct.", "abortable":False})
2098
- return False
2099
- flashcart_meta["sector_size"] = cfi["erase_sector_blocks"]
2100
- if cfi["tb_boot_sector_raw"] == 0x03: flashcart_meta['sector_size'].reverse()
2101
- dprint("Sector map was read from Common Flash Interface (CFI) data:", cfi["erase_sector_blocks"], cfi["erase_sector_blocks"])
2102
- self.set_number(0, self.DEVICE_CMD["SET_START_ADDRESS"])
2103
-
2104
- # Check if write command exists and quit if not
2105
- if "single_write" not in flashcart_meta["commands"] and "buffer_write" not in flashcart_meta["commands"]:
2106
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type is currently not supported for ROM writing using the current firmware version. However, a new firmware version might work which may be available in GUI mode from the “Tools” menu.", "abortable":False})
2107
- return False
2108
-
2109
- # Chip Erase
2110
- chip_erase = False
2111
- if "chip_erase" in flashcart_meta["commands"]:
2112
- if "sector_erase" in flashcart_meta["commands"] and prefer_chip_erase is False:
2113
- chip_erase = False
2114
- elif "chip_erase_treshold" in flashcart_meta:
2115
- if len(data_import) > flashcart_meta["chip_erase_treshold"] or "sector_erase" not in flashcart_meta["commands"]:
2116
- chip_erase = True
2117
- else:
2118
- chip_erase = True
2119
- self.SetProgress({"action":"ERASE", "time_start":time_start, "abortable":False})
2120
- for i in range(0, len(flashcart_meta["commands"]["chip_erase"])):
2121
- addr = flashcart_meta["commands"]["chip_erase"][i][0]
2122
- data = flashcart_meta["commands"]["chip_erase"][i][1]
2123
- if not addr == None:
2124
- self.gbx_flash_write_address_byte(addr, data)
2125
- if flashcart_meta["commands"]["chip_erase_wait_for"][i][0] != None:
2126
- addr = flashcart_meta["commands"]["chip_erase_wait_for"][i][0]
2127
- data = flashcart_meta["commands"]["chip_erase_wait_for"][i][1]
2128
- timeout = flashcart_meta["chip_erase_timeout"]
2129
- while True:
2130
- self.SetProgress({"action":"ERASE", "time_start":time_start, "abortable":False})
2131
- if "wait_read_status_register" in flashcart_meta and flashcart_meta["wait_read_status_register"]:
2132
- for j in range(0, len(flashcart_meta["commands"]["read_status_register"])):
2133
- sr_addr = flashcart_meta["commands"]["read_status_register"][j][0]
2134
- sr_data = flashcart_meta["commands"]["read_status_register"][j][1]
2135
- self.gbx_flash_write_address_byte(sr_addr, sr_data)
2136
- wait_for = self.ReadROM(addr, 64)
2137
- wait_for = ((wait_for[1] << 8 | wait_for[0]) & flashcart_meta["commands"]["chip_erase_wait_for"][i][2])
2138
- dprint("CE_SR {:X}=={:X}?".format(wait_for, data))
2139
- if wait_for == data: break
2140
- time.sleep(0.5)
2141
- timeout -= 0.5
2142
- if timeout <= 0:
2143
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Erasing the flash chip timed out. Please make sure that the cartridge contacts are clean, and that the selected cartridge type and settings are correct.", "abortable":False})
2144
- return False
2145
-
2146
- # Reset Flash
2147
- if "reset" in flashcart_meta["commands"]:
2148
- for i in range(0, len(flashcart_meta["commands"]["reset"])):
2149
- self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
2150
-
2151
- dprint("Chip erase took {:d} seconds".format(math.ceil(time.time() - time_start)))
2152
-
2153
- elif "sector_erase" in flashcart_meta["commands"] and "flash_size" in flashcart_meta and prefer_chip_erase is True:
2154
- flash_size = flashcart_meta["flash_size"]
2155
- if flash_size is not False and len(data_import) < flash_size:
2156
- # Pad with FF till the end
2157
- data_import += bytearray([0xFF] * (flash_size - len(data_import)))
2158
-
2159
- self.set_number(0, self.DEVICE_CMD["SET_START_ADDRESS"])
2160
-
2161
- # Write Flash
2162
- pos = 0
2163
- currAddr = 0
2164
- skipping = False # skips if block is full of 0xFF
2165
- if self.MODE == "DMG":
2166
- if "first_bank" in flashcart_meta: first_bank = flashcart_meta["first_bank"]
2167
- if "start_addr" in flashcart_meta: currAddr = flashcart_meta["start_addr"]
2168
- endAddr = 0x7FFF
2169
- bank_count = math.ceil(len(data_import) / bank_size)
2170
- if start_addr == 0: self.SetBankROM(0, mbc=mbc, bank_count=bank_count)
2171
- elif self.MODE == "AGB":
2172
- currAddr = 0
2173
- endAddr = len(data_import)
2174
- first_bank = 0
2175
- bank_count = 1
2176
-
2177
- self.SetProgress({"action":"INITIALIZE", "time_start":time.time(), "method":"ROM_WRITE", "size":len(data_import)})
2178
-
2179
- currSect = 0
2180
-
2181
- # Fast Forward
2182
- if start_addr > 0:
2183
- first_bank = math.floor(start_addr / bank_size)
2184
- self.SetBankROM(first_bank, mbc=mbc, bank_count=bank_count)
2185
- offset = start_addr % bank_size
2186
- currAddr = bank_size + offset
2187
- if "sector_erase" in flashcart_meta["commands"]:
2188
- while pos < start_addr:
2189
- dprint("* currSect:",currSect)
2190
- dprint("sector_size:", hex(flashcart_meta["sector_size"][currSect][0]))
2191
- dprint("start_addr:",hex(start_addr),", pos:",hex(pos))
2192
- pos += flashcart_meta["sector_size"][currSect][0]
2193
- flashcart_meta["sector_size"][currSect][1] -= 1
2194
- if flashcart_meta["sector_size"][currSect][1] == 0:
2195
- currSect += 1
2196
- dprint("currSect:", currSect, end=", ")
2197
- dprint(flashcart_meta["sector_size"])
2198
- dprint(flashcart_meta["sector_size"][currSect][1])
2199
-
2200
- sector_count = None
2201
- sector_size = 0
2202
- if "sector_erase" in flashcart_meta["commands"]:
2203
- if isinstance(flashcart_meta["sector_size"], list):
2204
- sector_size = flashcart_meta["sector_size"][currSect][0]
2205
- else:
2206
- sector_size = flashcart_meta["sector_size"]
2207
- dprint("sector_size:", sector_size)
2208
-
2209
- dprint("start_addr:", hex(start_addr))
2210
- dprint("first_bank:", first_bank, ", bank_count:", bank_count)
2211
- dprint("currAddr:", hex(currAddr), ", endAddr:", hex(endAddr))
2212
- dprint("pos:", hex(pos))
2213
-
2214
- ack = True
2215
- if first_bank == bank_count: first_bank -= 1 # dirty hack so that <32 KB works too
2216
- for bank in range(first_bank, bank_count):
2217
- if self.MODE == "DMG":
2218
- if bank > first_bank: currAddr = bank_size
2219
- self.set_number(currAddr, self.DEVICE_CMD["SET_START_ADDRESS"])
2220
-
2221
- while (currAddr < endAddr):
2222
- if pos >= len(data_import): break
2223
- if self.CANCEL:
2224
- # Reset Flash
2225
- if "reset" in flashcart_meta["commands"]:
2226
- for i in range(0, len(flashcart_meta["commands"]["reset"])):
2227
- self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
2228
- cancel_args = {"action":"ABORT", "abortable":False}
2229
- cancel_args.update(self.CANCEL_ARGS)
2230
- self.CANCEL_ARGS = {}
2231
- self.SetProgress(cancel_args)
2232
- return
2233
-
2234
- if self.MODE == "DMG":
2235
- # Change Bank
2236
- if (currAddr == bank_size):
2237
- # Reset Flash
2238
- if "reset" in flashcart_meta["commands"]:
2239
- for i in range(0, len(flashcart_meta["commands"]["reset"])):
2240
- self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
2241
- self.SetBankROM(bank, mbc=mbc, bank_count=bank_count)
2242
- time.sleep(0.05)
2243
-
2244
- # Sector Erase (if supported)
2245
- if "sector_erase" in flashcart_meta["commands"] and not chip_erase:
2246
- if isinstance(flashcart_meta["sector_size"], list):
2247
- if sector_count == None:
2248
- sector_count = flashcart_meta["sector_size"][currSect][1]
2249
- if sector_count == 0:
2250
- if ((currSect+1) != len(flashcart_meta["sector_size"])):
2251
- currSect += 1
2252
- sector_count = flashcart_meta["sector_size"][currSect][1]
2253
-
2254
- if pos % sector_size == 0:
2255
- self.SetProgress({"action":"UPDATE_POS", "pos":pos})
2256
- self.SetProgress({"action":"SECTOR_ERASE", "sector_size":sector_size, "sector_pos":pos, "time_start":time.time(), "abortable":True})
2257
-
2258
- # Update sector size if changed
2259
- if "sector_erase" in flashcart_meta["commands"]:
2260
- if isinstance(flashcart_meta["sector_size"], list):
2261
- sector_size = flashcart_meta["sector_size"][currSect][0]
2262
- dprint("* sector_count:", sector_count, "sector_size:", hex(sector_size), "pos:",hex(pos))
2263
-
2264
- for i in range(0, len(flashcart_meta["commands"]["sector_erase"])):
2265
- addr = flashcart_meta["commands"]["sector_erase"][i][0]
2266
- data = flashcart_meta["commands"]["sector_erase"][i][1]
2267
- if addr == "SA": addr = currAddr
2268
- if addr == "SA+1": addr = currAddr + 1
2269
- if addr == "SA+2": addr = currAddr + 2
2270
- if addr == "SA+0x4000": addr = currAddr + 0x4000
2271
- if addr == "SA+0x7000": addr = currAddr + 0x7000
2272
- if not addr == None:
2273
- self.gbx_flash_write_address_byte(addr, data)
2274
- dprint("SE {:08X}={:X}".format(addr, data))
2275
- if flashcart_meta["commands"]["sector_erase_wait_for"][i][0] != None:
2276
- addr = flashcart_meta["commands"]["sector_erase_wait_for"][i][0]
2277
- data = flashcart_meta["commands"]["sector_erase_wait_for"][i][1]
2278
- if addr == "SA": addr = currAddr
2279
- if addr == "SA+1": addr = currAddr + 1
2280
- if addr == "SA+2": addr = currAddr + 2
2281
- if addr == "SA+0x4000": addr = currAddr + 0x4000
2282
- if addr == "SA+0x7000": addr = currAddr + 0x7000
2283
- time.sleep(0.05)
2284
- timeout = 100
2285
- while True:
2286
- if "wait_read_status_register" in flashcart_meta and flashcart_meta["wait_read_status_register"] == True:
2287
- for j in range(0, len(flashcart_meta["commands"]["read_status_register"])):
2288
- sr_addr = flashcart_meta["commands"]["read_status_register"][j][0]
2289
- sr_data = flashcart_meta["commands"]["read_status_register"][j][1]
2290
- self.gbx_flash_write_address_byte(sr_addr, sr_data)
2291
- dprint("SE_SR {:08X}={:X}".format(addr, data))
2292
- wait_for = self.ReadROM(currAddr, 64)
2293
- wait_for = ((wait_for[1] << 8 | wait_for[0]) & flashcart_meta["commands"]["sector_erase_wait_for"][i][2])
2294
- dprint("SE_SR {:X}=={:X}?".format(wait_for, data))
2295
- time.sleep(0.1)
2296
- timeout -= 1
2297
- if timeout < 1:
2298
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Erasing a flash chip sector timed out. Please make sure that the cartridge contacts are clean, and that the selected cartridge type and settings are correct.", "abortable":False})
2299
- return False
2300
- if wait_for == data: break
2301
- self.SetProgress({"action":"SECTOR_ERASE", "sector_size":sector_size, "sector_pos":pos, "time_start":time.time(), "abortable":True})
2302
-
2303
- # Reset Flash
2304
- if "reset" in flashcart_meta["commands"]:
2305
- for i in range(0, len(flashcart_meta["commands"]["reset"])):
2306
- self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
2307
-
2308
- if self.MODE == "DMG":
2309
- self.set_number(currAddr, self.DEVICE_CMD["SET_START_ADDRESS"])
2310
- elif self.MODE == "AGB":
2311
- self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
2312
-
2313
- if sector_count is not None:
2314
- sector_count -= 1
2315
-
2316
- # Write data (with special firmware acceleration if available)
2317
- if "buffer_write" in flashcart_meta["commands"]:
2318
- if self.MODE == "DMG":
2319
- # BUNG Doctor GB Card 64M
2320
- if flashcart_meta["commands"]["buffer_write"] == [['SA', 0xE8], ['SA', 'BS'], ['PA', 'PD'], ['SA', 0xD0], ['SA', 0xFF]]:
2321
- data = data_import[pos:pos+32]
2322
- if data == bytearray([0xFF] * len(data)):
2323
- skipping = True
2324
- else:
2325
- if skipping:
2326
- self.set_number(currAddr, self.DEVICE_CMD["SET_START_ADDRESS"])
2327
- skipping = False
2328
- self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GB_FLASH_WRITE_INTEL_BUFFERED_32BYTE"], data)
2329
- ack = self.wait_for_ack()
2330
- currAddr += 32
2331
- pos += 32
2332
-
2333
- else:
2334
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Buffer writing for this flash chip is not supported with your device’s firmware version. You can a newer firmware version which is available through the firmware updater in the “Tools” menu.\n\n{:s}".format(str(flashcart_meta["commands"]["buffer_write"])), "abortable":False})
2335
- return False
2336
-
2337
- elif self.MODE == "AGB":
2338
- # Flash2Advance 256M
2339
- if flashcart_meta["commands"]["buffer_write"] == [['SA', 0xE8], ['SA+2', 0xE8], ['SA', 'BS'], ['SA+2', 'BS'], ['PA', 'PD'], ['SA', 0xD0], ['SA+2', 0xD0], [None, None], [None, None]]:
2340
- data = data_import[pos:pos+256]
2341
- if data == bytearray([0xFF] * len(data)):
2342
- skipping = True
2343
- else:
2344
- if skipping:
2345
- self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
2346
- skipping = False
2347
- self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_INTEL_INTERLEAVED_256BYTE"], data)
2348
- ack = self.wait_for_ack()
2349
- currAddr += 256
2350
- pos += 256
2351
-
2352
- # 256L30B, M36L0R etc.
2353
- elif flashcart_meta["commands"]["buffer_write"] == [['SA', 0xE8], ['SA', 'BS'], ['PA', 'PD'], ['SA', 0xD0], ['SA', 0xFF]]:
2354
- if "single_write_7FC0_to_7FFF" in flashcart_meta and flashcart_meta["single_write_7FC0_to_7FFF"] and int(currAddr % 0x8000) in range(0x7FC0, 0x7FFF):
2355
- for i in range(0, len(flashcart_meta["commands"]["single_write"])):
2356
- addr = flashcart_meta["commands"]["single_write"][i][0]
2357
- data = flashcart_meta["commands"]["single_write"][i][1]
2358
- if addr == "PA": addr = int(currAddr)
2359
- if data == "PD": data = struct.unpack('H', data_import[pos:pos+2])[0]
2360
- self.gbx_flash_write_address_byte(addr, data)
2361
- currAddr += 2
2362
- pos += 2
2363
- data = data_import[pos:pos+2]
2364
-
2365
- if int(currAddr % 0x8000) == 0:
2366
- self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
2367
-
2368
- # Firmware check R24+
2369
- elif (int(self.FW[0]) >= 24) and "single_write_7FC0_to_7FFF" not in flashcart_meta:
2370
- data = data_import[pos:pos+256]
2371
- if data == bytearray([0xFF] * len(data)):
2372
- skipping = True
2373
- else:
2374
- if skipping:
2375
- self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
2376
- skipping = False
2377
- self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_INTEL_256BYTE"], data)
2378
- ack = self.wait_for_ack()
2379
-
2380
- currAddr += 256
2381
- pos += 256
2382
-
2383
- else:
2384
- data = data_import[pos:pos+64]
2385
- if data == bytearray([0xFF] * len(data)):
2386
- skipping = True
2387
- else:
2388
- if skipping:
2389
- self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
2390
- skipping = False
2391
- self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_INTEL_64BYTE"], data)
2392
- ack = self.wait_for_ack()
2393
-
2394
- currAddr += 64
2395
- pos += 64
2396
-
2397
- # MSP55LV128M etc.
2398
- elif flashcart_meta["commands"]["buffer_write"] == [[0xAAA, 0xA9], [0x555, 0x56], ['SA', 0x26], ['SA', 'BS'], ['PA', 'PD'], ['SA', 0x2A]]:
2399
- data = data_import[pos:pos+256]
2400
- if data == bytearray([0xFF] * len(data)):
2401
- skipping = True
2402
- else:
2403
- if skipping:
2404
- self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
2405
- skipping = False
2406
- self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_BUFFERED_256BYTE_SWAPPED_D0D1"], data)
2407
- ack = self.wait_for_ack()
2408
- currAddr += 256
2409
- pos += 256
2410
-
2411
- # insideGadgets flash carts etc.
2412
- elif flashcart_meta["commands"]["buffer_write"] == [[0xAAA, 0xAA], [0x555, 0x55], ['SA', 0x25], ['SA', 'BS'], ['PA', 'PD'], ['SA', 0x29]]:
2413
- if "single_write_first_256_bytes" in flashcart_meta and flashcart_meta["single_write_first_256_bytes"] and currAddr < 256:
2414
- for i in range(0, len(flashcart_meta["commands"]["single_write"])):
2415
- addr = flashcart_meta["commands"]["single_write"][i][0]
2416
- data = flashcart_meta["commands"]["single_write"][i][1]
2417
- if addr == "PA": addr = int(currAddr)
2418
- if data == "PD": data = struct.unpack('H', data_import[pos:pos+2])[0]
2419
- self.gbx_flash_write_address_byte(addr, data)
2420
- currAddr += 2
2421
- pos += 2
2422
- data = data_import[pos:pos+2]
2423
-
2424
- if currAddr == 256:
2425
- self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
2426
-
2427
- else:
2428
- data = data_import[pos:pos+256]
2429
- if data == bytearray([0xFF] * len(data)):
2430
- skipping = True
2431
- else:
2432
- if skipping:
2433
- self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
2434
- skipping = False
2435
- self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_BUFFERED_256BYTE"], data)
2436
- ack = self.wait_for_ack()
2437
- currAddr += 256
2438
- pos += 256
2439
-
2440
- else:
2441
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Buffer writing for this flash chip is not supported with your device’s firmware version. You can try a newer firmware version which is available through the firmware updater in the “Tools” menu.\n\n{:s}".format(str(flashcart_meta["commands"]["buffer_write"])), "abortable":False})
2442
- return False
2443
-
2444
- elif "single_write" in flashcart_meta["commands"]:
2445
- if self.MODE == "DMG":
2446
- # Firmware check R24+
2447
- if (int(self.FW[0]) < 24) or ("pulse_reset_after_write" in flashcart_meta and flashcart_meta["pulse_reset_after_write"]):
2448
- data = data_import[pos:pos+64]
2449
- else:
2450
- data = data_import[pos:pos+256]
2451
-
2452
- if data == bytearray([0xFF] * len(data)):
2453
- skipping = True
2454
- else:
2455
- if skipping:
2456
- self.set_number(currAddr, self.DEVICE_CMD["SET_START_ADDRESS"])
2457
- skipping = False
2458
- if "pulse_reset_after_write" in flashcart_meta and flashcart_meta["pulse_reset_after_write"]:
2459
- self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GB_FLASH_WRITE_64BYTE_PULSE_RESET"], data)
2460
- elif len(data) == 64:
2461
- self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GB_FLASH_WRITE_64BYTE"], data)
2462
- elif len(data) == 256:
2463
- self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GB_FLASH_WRITE_UNBUFFERED_256BYTE"], data)
2464
- ack = self.wait_for_ack()
2465
-
2466
- currAddr += len(data)
2467
- pos += len(data)
2468
-
2469
- elif self.MODE == "AGB":
2470
- # MSP55LV128 etc.
2471
- if flashcart_meta["commands"]["single_write"] == [[0xAAA, 0xA9], [0x555, 0x56], [0xAAA, 0xA0], ['PA', 'PD']]:
2472
- data = data_import[pos:pos+256]
2473
- if data == bytearray([0xFF] * len(data)):
2474
- skipping = True
2475
- else:
2476
- if skipping:
2477
- self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
2478
- skipping = False
2479
- self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_256BYTE_SWAPPED_D0D1"], data)
2480
- ack = self.wait_for_ack()
2481
- currAddr += 256
2482
- pos += 256
2483
-
2484
- # 128W30B0 etc.
2485
- elif flashcart_meta["commands"]["single_write"] == [[ 0, 0x70 ], [ 0, 0x10 ], [ 'PA', 'PD' ]]:
2486
- data = data_import[pos:pos+64]
2487
- if data == bytearray([0xFF] * len(data)):
2488
- skipping = True
2489
- else:
2490
- if skipping:
2491
- self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
2492
- skipping = False
2493
- self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_INTEL_64BYTE_WORD"], data)
2494
- ack = self.wait_for_ack()
2495
- currAddr += 64
2496
- pos += 64
2497
-
2498
- else: # super slow -- for testing purposes only!
2499
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge is currently not supported by {:s} using the current firmware version of the {:s} device. Please try a differnt firmware version or newer hardware revision.".format(APPNAME, self.GetFullName()), "abortable":False})
2500
- return False
2501
-
2502
- if ack == False:
2503
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Couldn’t write {:d} bytes to flash at position 0x{:X}. Please make sure that the cartridge contacts are clean, and that the selected cartridge type and settings are correct.".format(len(data), pos-len(data)), "abortable":False})
2504
- return False
2505
- else:
2506
- if (skipping is False) and (isinstance(data, int) or data is None or data == b''):
2507
- print(skipping, data)
2508
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"No flash commands available for this cartridge type. Please make sure that the selected cartridge type and settings are correct. ({:s})".format(str(data)), "abortable":False})
2509
- return False
2510
- else:
2511
- self.SetProgress({"action":"WRITE", "bytes_added":len(data), "skipping":skipping})
2512
-
2513
- self.SetProgress({"action":"UPDATE_POS", "pos":pos})
2514
- time.sleep(0.5)
2515
-
2516
- # Reset Flash
2517
- if "reset_every" in flashcart_meta:
2518
- for j in range(0, pos, flashcart_meta["reset_every"]):
2519
- for i in range(0, len(flashcart_meta["commands"]["reset"])):
2520
- self.gbx_flash_write_address_byte(j, flashcart_meta["commands"]["reset"][i][1])
2521
- elif "reset" in flashcart_meta["commands"]:
2522
- for i in range(0, len(flashcart_meta["commands"]["reset"])):
2523
- self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
2524
-
2525
- # Verify Flash
2526
- verified = False
2527
- if verify_write:
2528
- rom_size = len(data_import)
2529
- buffer_len = 0x1000
2530
- if self.MODE == "DMG":
2531
- self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
2532
- if fast_read_mode:
2533
- buffer_len = 0x4000
2534
- self.FAST_READ = True
2535
- elif self.MODE == "AGB":
2536
- if fast_read_mode:
2537
- buffer_len = 0x10000
2538
- self.FAST_READ = True
2539
-
2540
- startAddr = 0
2541
- currAddr = 0
2542
- pos = 0
2543
-
2544
- if self.MODE == "DMG":
2545
- endAddr = bank_size
2546
- else:
2547
- endAddr = rom_size
2548
- bank_count = 1
2549
-
2550
- # Read a bit before actually dumping (fixes some bootlegs)
2551
- self.ReadROM(0, 64)
2552
-
2553
- self.SetProgress({"action":"INITIALIZE", "method":"ROM_WRITE_VERIFY", "size":rom_size})
2554
-
2555
- for bank in range(0, bank_count):
2556
- if self.MODE == "DMG":
2557
- if bank > 0:
2558
- startAddr = bank_size
2559
- endAddr = startAddr + bank_size
2560
- self.SetBankROM(bank, mbc=mbc, bank_count=bank_count)
2561
-
2562
- for currAddr in range(startAddr, endAddr, buffer_len):
2563
- if self.CANCEL:
2564
- cancel_args = {"action":"ABORT", "abortable":False}
2565
- cancel_args.update(self.CANCEL_ARGS)
2566
- self.CANCEL_ARGS = {}
2567
- self.SetProgress(cancel_args)
2568
- return
2569
-
2570
- if currAddr == startAddr:
2571
- buffer = self.ReadROM(currAddr, buffer_len, True)
2572
- else:
2573
- buffer = self.ReadROM(currAddr, buffer_len, False)
2574
-
2575
- if buffer == False:
2576
- self.CANCEL = True
2577
- self.ERROR = True
2578
- continue
2579
-
2580
- if not buffer == data_import[pos:pos+buffer_len]:
2581
- err_pos = 0
2582
- for i in range(0, buffer_len):
2583
- if buffer[i] != data_import[pos+i]:
2584
- err_pos = pos+i
2585
- break
2586
- self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"The ROM was flashed completely, but verification of written data failed at address 0x{:X}.".format(err_pos), "abortable":False})
2587
- self.CANCEL = True
2588
- self.ERROR = True
2589
- return False
2590
-
2591
- pos += buffer_len
2592
- self.SetProgress({"action":"UPDATE_POS", "pos":pos})
2593
- verified = True
2594
-
2595
- self.POS = 0
2596
- if self.MODE == "DMG":
2597
- self.SetBankROM(0, mbc=mbc, bank_count=bank_count)
2598
-
2599
- self.SetProgress({"action":"FINISHED", "verified":verified})