mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-25 15:16:53 +01:00
pc software done
This commit is contained in:
parent
0e79411740
commit
9373fcfe44
@ -846,7 +846,7 @@
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
(tstamp 14a13283-4e54-4226-a07c-af565889337c)
|
||||
)
|
||||
(fp_text value "12k" (at 0 1.43) (layer "F.Fab")
|
||||
(fp_text value "10k" (at 0 1.43) (layer "F.Fab")
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
(tstamp 818ee031-0985-4f05-ac35-c39f534af651)
|
||||
)
|
||||
@ -1303,7 +1303,7 @@
|
||||
(tags "TQFP QFP")
|
||||
(property "Sheetfile" "sc64v2.kicad_sch")
|
||||
(property "Sheetname" "")
|
||||
(path "/f5284160-b8bd-4591-b634-bcdefecda6c2")
|
||||
(path "/7adce0b2-9540-4d77-8cf1-4df964c29563")
|
||||
(attr smd)
|
||||
(fp_text reference "U8" (at 0 -12.35) (layer "F.SilkS")
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
|
@ -10854,7 +10854,7 @@
|
||||
(property "Reference" "R8" (id 0) (at 196.85 383.5399 0)
|
||||
(effects (font (size 1.27 1.27)) (justify right))
|
||||
)
|
||||
(property "Value" "12k" (id 1) (at 196.85 386.0799 0)
|
||||
(property "Value" "10k" (id 1) (at 196.85 386.0799 0)
|
||||
(effects (font (size 1.27 1.27)) (justify right))
|
||||
)
|
||||
(property "Footprint" "Resistor_SMD:R_0603_1608Metric" (id 2) (at 196.088 384.81 90)
|
||||
@ -11649,7 +11649,7 @@
|
||||
(reference "R7") (unit 1) (value "12k") (footprint "Resistor_SMD:R_0603_1608Metric")
|
||||
)
|
||||
(path "/d1984805-4314-4f1c-9ab1-479802945b94"
|
||||
(reference "R8") (unit 1) (value "12k") (footprint "Resistor_SMD:R_0603_1608Metric")
|
||||
(reference "R8") (unit 1) (value "10k") (footprint "Resistor_SMD:R_0603_1608Metric")
|
||||
)
|
||||
(path "/38f041d3-336d-4c45-9e25-efeece1e2340"
|
||||
(reference "R9") (unit 1) (value "5.1k") (footprint "Resistor_SMD:R_0603_1608Metric")
|
||||
|
274
sw/pc/sc64.py
274
sw/pc/sc64.py
@ -1,8 +1,12 @@
|
||||
import argparse
|
||||
import os
|
||||
import queue
|
||||
import serial
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
from dd64 import BadBlockError, DD64Image
|
||||
from enum import IntEnum
|
||||
from enum import Enum, IntEnum
|
||||
from serial.tools import list_ports
|
||||
from threading import Thread
|
||||
from typing import Optional
|
||||
@ -15,13 +19,16 @@ class ConnectionException(Exception):
|
||||
|
||||
class SC64Serial:
|
||||
__disconnect = False
|
||||
__serial = None
|
||||
__serial: Optional[serial.Serial] = None
|
||||
__thread_read = None
|
||||
__thread_write = None
|
||||
__queue_output = queue.Queue()
|
||||
__queue_input = queue.Queue()
|
||||
__queue_packet = queue.Queue()
|
||||
|
||||
__VID = 0x0403
|
||||
__PID = 0x6014
|
||||
|
||||
def __init__(self) -> None:
|
||||
ports = list_ports.comports()
|
||||
device_found = False
|
||||
@ -30,7 +37,7 @@ class SC64Serial:
|
||||
raise ConnectionException('Serial port is already open')
|
||||
|
||||
for p in ports:
|
||||
if (p.vid == 0x0403 and p.pid == 0x6014 and p.serial_number.startswith('SC64')):
|
||||
if (p.vid == self.__VID and p.pid == self.__PID and p.serial_number.startswith('SC64')):
|
||||
try:
|
||||
self.__serial = serial.Serial(p.device, timeout=0.1, write_timeout=5.0)
|
||||
self.__reset_link()
|
||||
@ -180,22 +187,23 @@ class SC64Serial:
|
||||
|
||||
class SC64:
|
||||
class __Address(IntEnum):
|
||||
ROM = 0x0000_0000
|
||||
SDRAM = 0x0000_0000
|
||||
FLASH = 0x0400_0000
|
||||
BUFFER = 0x0500_0000
|
||||
EEPROM = 0x0500_2000
|
||||
FIRMWARE = 0x0200_0000
|
||||
DDIPL = 0x03BC_0000
|
||||
SAVE = 0x03FE_0000
|
||||
SHADOW = 0x04FE_0000
|
||||
BUFFER = 0x0500_0000
|
||||
EEPROM = 0x0500_2000
|
||||
|
||||
class __Length(IntEnum):
|
||||
ROM = (64 * 1024 * 1024)
|
||||
FIRMWARE = (2 * 1024 * 1024)
|
||||
SDRAM = (64 * 1024 * 1024)
|
||||
FLASH = (16 * 1024 * 1024)
|
||||
BUFFER = (8 * 1024)
|
||||
EEPROM = (2 * 1024)
|
||||
DDIPL = (4 * 1024 * 1024)
|
||||
SAVE = (128 * 1024)
|
||||
SHADOW = (128 * 1024)
|
||||
BUFFER = (8 * 1024)
|
||||
EEPROM = (2 * 1024)
|
||||
|
||||
class __SaveLength(IntEnum):
|
||||
NONE = 0
|
||||
@ -203,7 +211,7 @@ class SC64:
|
||||
EEPROM_16K = (2 * 1024)
|
||||
SRAM = (32 * 1024)
|
||||
FLASHRAM = (128 * 1024)
|
||||
SRAM_X3 = (3 * 32 * 1024)
|
||||
SRAM_3X = (3 * 32 * 1024)
|
||||
|
||||
class __CfgId(IntEnum):
|
||||
BOOTLOADER_SWITCH = 0
|
||||
@ -306,13 +314,26 @@ class SC64:
|
||||
return self.__get_int(data)
|
||||
|
||||
def __write_memory(self, address: int, data: bytes) -> None:
|
||||
self.__link.execute_cmd(cmd=b'M', args=[address, len(data)], data=data)
|
||||
if (len(data) > 0):
|
||||
self.__link.execute_cmd(cmd=b'M', args=[address, len(data)], data=data, timeout=10.0)
|
||||
|
||||
def __read_memory(self, address: int, length: int) -> bytes:
|
||||
return self.__link.execute_cmd(cmd=b'm', args=[address, length])
|
||||
if (length > 0):
|
||||
return self.__link.execute_cmd(cmd=b'm', args=[address, length], timeout=10.0)
|
||||
return bytes([])
|
||||
|
||||
def __erase_flash_region(self, address: int, length: int) -> None:
|
||||
if (address < self.__Address.FLASH):
|
||||
raise ValueError('Flash erase address or length outside of possible range')
|
||||
if ((address + length) > (self.__Address.FLASH + self.__Length.FLASH)):
|
||||
raise ValueError('Flash erase address or length outside of possible range')
|
||||
erase_block_size = self.__get_config(self.__CfgId.FLASH_ERASE_BLOCK)
|
||||
if ((address % erase_block_size != 0) or (length % erase_block_size != 0)):
|
||||
raise ValueError('Flash erase address or length not aligned to block size')
|
||||
for offset in range(address, address + length, erase_block_size):
|
||||
self.__set_config(self.__CfgId.FLASH_ERASE_BLOCK, offset)
|
||||
|
||||
def reset_state(self) -> None:
|
||||
self.__set_config(self.__CfgId.BOOTLOADER_SWITCH, False)
|
||||
self.__set_config(self.__CfgId.ROM_WRITE_ENABLE, False)
|
||||
self.__set_config(self.__CfgId.ROM_SHADOW_ENABLE, False)
|
||||
self.__set_config(self.__CfgId.DD_MODE, self.__DDMode.NONE)
|
||||
@ -326,10 +347,22 @@ class SC64:
|
||||
self.__set_config(self.__CfgId.BUTTON_MODE, self.__ButtonMode.NONE)
|
||||
self.set_cic_parameters()
|
||||
|
||||
def upload_rom(self, data: bytes):
|
||||
if (len(data) > self.__Length.ROM):
|
||||
def upload_rom(self, data: bytes, use_shadow: bool=True):
|
||||
rom_length = len(data)
|
||||
if (rom_length > self.__Length.SDRAM):
|
||||
raise ValueError('ROM size too big')
|
||||
self.__write_memory(self.__Address.ROM, data)
|
||||
sdram_length = rom_length
|
||||
shadow_enabled = use_shadow and rom_length > (self.__Length.SDRAM - self.__Length.SHADOW)
|
||||
if (shadow_enabled):
|
||||
sdram_length = (self.__Length.SDRAM - self.__Length.SHADOW)
|
||||
shadow_length = rom_length - sdram_length
|
||||
if (self.__read_memory(self.__Address.SHADOW, shadow_length) != data[sdram_length:]):
|
||||
self.__erase_flash_region(self.__Address.SHADOW, self.__Length.SHADOW)
|
||||
self.__write_memory(self.__Address.SHADOW, data[sdram_length:])
|
||||
if (self.__read_memory(self.__Address.SHADOW, shadow_length) != data[sdram_length:]):
|
||||
raise ConnectionException('Shadow ROM program failure')
|
||||
self.__write_memory(self.__Address.SDRAM, data[:sdram_length])
|
||||
self.__set_config(self.__CfgId.ROM_SHADOW_ENABLE, shadow_enabled)
|
||||
|
||||
def upload_ddipl(self, data: bytes) -> None:
|
||||
if (len(data) > self.__Length.DDIPL):
|
||||
@ -340,6 +373,8 @@ class SC64:
|
||||
save_type = self.SaveType(self.__get_config(self.__CfgId.SAVE_TYPE))
|
||||
if (save_type not in self.SaveType):
|
||||
raise ConnectionError('Unknown save type fetched from SC64 device')
|
||||
if (save_type == self.SaveType.NONE):
|
||||
raise ValueError('No save type set inside SC64 device')
|
||||
if (len(data) != self.__SaveLength[save_type.name]):
|
||||
raise ValueError('Wrong save data length')
|
||||
address = self.__Address.SAVE
|
||||
@ -347,6 +382,32 @@ class SC64:
|
||||
address = self.__Address.EEPROM
|
||||
self.__write_memory(address, data)
|
||||
|
||||
def download_save(self) -> bytes:
|
||||
save_type = self.SaveType(self.__get_config(self.__CfgId.SAVE_TYPE))
|
||||
if (save_type not in self.SaveType):
|
||||
raise ConnectionError('Unknown save type fetched from SC64 device')
|
||||
if (save_type == self.SaveType.NONE):
|
||||
raise ValueError('No save type set inside SC64 device')
|
||||
address = self.__Address.SAVE
|
||||
length = self.__SaveLength[save_type.name]
|
||||
if (save_type == self.SaveType.EEPROM_4K or save_type == self.SaveType.EEPROM_16K):
|
||||
address = self.__Address.EEPROM
|
||||
return self.__read_memory(address, length)
|
||||
|
||||
def set_rtc(self, t: datetime) -> None:
|
||||
to_bcd = lambda v: ((int((v / 10) % 10) << 4) | int(int(v) % 10))
|
||||
data = bytes([
|
||||
to_bcd(t.weekday() + 1),
|
||||
to_bcd(t.hour),
|
||||
to_bcd(t.minute),
|
||||
to_bcd(t.second),
|
||||
0,
|
||||
to_bcd(t.year),
|
||||
to_bcd(t.month),
|
||||
to_bcd(t.day),
|
||||
])
|
||||
self.__link.execute_cmd(cmd=b'T', args=[self.__get_int(data[0:4]), self.__get_int(data[4:8])])
|
||||
|
||||
def set_boot_mode(self, mode: BootMode) -> None:
|
||||
if (mode not in self.BootMode):
|
||||
raise ValueError('Boot mode outside of allowed values')
|
||||
@ -368,23 +429,14 @@ class SC64:
|
||||
raise ValueError('Save type outside of allowed values')
|
||||
self.__set_config(self.__CfgId.SAVE_TYPE, type)
|
||||
|
||||
def set_cic_parameters(self, dd_mode: bool=False, seed: int=0x3F, checksum: bytes=[0xA5, 0x36, 0xC0, 0xF1, 0xD8, 0x59]) -> None:
|
||||
def set_cic_parameters(self, dd_mode: bool=False, seed: int=0x3F, checksum: bytes=bytes([0xA5, 0x36, 0xC0, 0xF1, 0xD8, 0x59])) -> None:
|
||||
if (seed < 0 or seed > 0xFF):
|
||||
raise ValueError('CIC seed outside of allowed values')
|
||||
if (len(checksum) != 6):
|
||||
raise ValueError('CIC checksum length outside of allowed values')
|
||||
args = [0, 0]
|
||||
if (dd_mode):
|
||||
args[0] |= (1 << 24)
|
||||
args[0] |= (seed << 16)
|
||||
args[0] |= (checksum[0] << 8) | checksum[1]
|
||||
args[1] |= (
|
||||
(checksum[2] << 24) |
|
||||
(checksum[3] << 16) |
|
||||
(checksum[4] << 8) |
|
||||
(checksum[5])
|
||||
)
|
||||
self.__link.execute_cmd(cmd=b'B', args=args)
|
||||
data = bytes([1 if dd_mode else 0, seed])
|
||||
data = [*data, *checksum]
|
||||
self.__link.execute_cmd(cmd=b'B', args=[self.__get_int(data[0:4]), self.__get_int(data[4:8])])
|
||||
|
||||
def update_firmware(self, data: bytes) -> None:
|
||||
address = self.__Address.FIRMWARE
|
||||
@ -399,9 +451,9 @@ class SC64:
|
||||
if (packet == None):
|
||||
raise ConnectionException('Update timeout')
|
||||
(cmd, data) = packet
|
||||
status = self.__UpdateStatus(self.__get_int(data))
|
||||
if (cmd != b'F'):
|
||||
raise ConnectionException('Wrong update status packet')
|
||||
status = self.__UpdateStatus(self.__get_int(data))
|
||||
print(f'Update status [{status.name}]')
|
||||
if (status == self.__UpdateStatus.ERROR):
|
||||
raise ConnectionException('Update error, device is most likely bricked')
|
||||
@ -417,7 +469,7 @@ class SC64:
|
||||
raise ConnectionException('Error while getting firmware backup')
|
||||
return self.__read_memory(address, length)
|
||||
|
||||
def __handle_dd_packet(self, dd: DD64Image, data: bytes) -> None:
|
||||
def __handle_dd_packet(self, dd: Optional[DD64Image], data: bytes) -> None:
|
||||
CMD_READ_BLOCK = 1
|
||||
CMD_WRITE_BLOCK = 2
|
||||
cmd = self.__get_int(data[0:])
|
||||
@ -427,7 +479,7 @@ class SC64:
|
||||
head = (track_head_block >> 1) & 0x1
|
||||
block = track_head_block & 0x1
|
||||
try:
|
||||
if (not dd.loaded):
|
||||
if (not dd or not dd.loaded):
|
||||
raise BadBlockError
|
||||
if (cmd == CMD_READ_BLOCK):
|
||||
block_data = dd.read_block(track, head, block)
|
||||
@ -448,15 +500,19 @@ class SC64:
|
||||
|
||||
def debug_loop(self, isv: bool=False, disks: Optional[list[str]]=None) -> None:
|
||||
dd = None
|
||||
drive_type = None
|
||||
current_image = 0
|
||||
next_image = 0
|
||||
|
||||
self.__set_config(self.__CfgId.ROM_WRITE_ENABLE, isv)
|
||||
self.__set_config(self.__CfgId.ISV_ENABLE, isv)
|
||||
if (isv):
|
||||
print('IS-Viewer64 support set to [ENABLED]')
|
||||
if (self.__get_config(self.__CfgId.ROM_SHADOW_ENABLE)):
|
||||
print('ROM shadow enabled - ISV support will NOT work (use --no-shadow option to disable it)')
|
||||
|
||||
if (disks):
|
||||
dd = DD64Image()
|
||||
drive_type = None
|
||||
for path in disks:
|
||||
try:
|
||||
dd.load(path)
|
||||
@ -469,15 +525,22 @@ class SC64:
|
||||
dd = None
|
||||
print(f'64DD disabled, incorrect disk images provided: {e}')
|
||||
break
|
||||
|
||||
drive_type = self.__DDDriveType.RETAIL if drive_type == 'retail' else self.__DDDriveType.DEVELOPMENT
|
||||
|
||||
if (dd):
|
||||
self.__set_config(self.__CfgId.DD_MODE, self.__DDMode.FULL)
|
||||
self.__set_config(self.__CfgId.DD_DRIVE_TYPE, drive_type)
|
||||
self.__set_config(self.__CfgId.DD_DRIVE_TYPE, {
|
||||
'retail': self.__DDDriveType.RETAIL,
|
||||
'development': self.__DDDriveType.DEVELOPMENT
|
||||
}[drive_type])
|
||||
self.__set_config(self.__CfgId.DD_DISK_STATE, self.__DDDiskState.EJECTED)
|
||||
self.__set_config(self.__CfgId.BUTTON_MODE, self.__ButtonMode.USB_PACKET)
|
||||
print('64DD enabled, loaded disks:')
|
||||
for disk in disks:
|
||||
print(f' - {os.path.basename(disk)}')
|
||||
print('Press button on SC64 device to cycle through provided disks')
|
||||
|
||||
print('Debug loop started, use Ctrl-C to exit')
|
||||
|
||||
try:
|
||||
while (True):
|
||||
packet = self.__link.get_packet()
|
||||
if (packet != None):
|
||||
@ -489,44 +552,131 @@ class SC64:
|
||||
if (cmd == b'U'):
|
||||
self.__handle_usb_packet(data)
|
||||
if (cmd == b'B'):
|
||||
if (dd.loaded):
|
||||
self.__set_config(self.__CfgId.DD_DISK_STATE, self.__DDDiskState.EJECTED)
|
||||
dd.unload()
|
||||
print(f'64DD disk ejected [{disks[current_image]}]')
|
||||
else:
|
||||
if (not dd.loaded):
|
||||
dd.load(disks[next_image])
|
||||
self.__set_config(self.__CfgId.DD_DISK_STATE, self.__DDDiskState.INSERTED)
|
||||
current_image = next_image
|
||||
next_image += 1
|
||||
if (next_image >= len(disks)):
|
||||
next_image = 0
|
||||
print(f'64DD disk inserted [{disks[current_image]}]')
|
||||
print(f'64DD disk inserted - {os.path.basename(disks[current_image])}')
|
||||
else:
|
||||
self.__set_config(self.__CfgId.DD_DISK_STATE, self.__DDDiskState.EJECTED)
|
||||
dd.unload()
|
||||
print(f'64DD disk ejected - {os.path.basename(disks[current_image])}')
|
||||
except KeyboardInterrupt:
|
||||
if (dd and dd.loaded):
|
||||
self.__set_config(self.__CfgId.DD_DISK_STATE, self.__DDDiskState.EJECTED)
|
||||
|
||||
|
||||
class EnumAction(argparse.Action):
|
||||
def __init__(self, **kwargs):
|
||||
type = kwargs.pop('type', None)
|
||||
if type is None:
|
||||
raise ValueError('No type was provided')
|
||||
if not issubclass(type, Enum):
|
||||
raise TypeError('Provided type is not an Enum subclass')
|
||||
items = (choice.lower().replace('_', '-') for (choice, _) in type.__members__.items())
|
||||
kwargs.setdefault('choices', tuple(items))
|
||||
super(EnumAction, self).__init__(**kwargs)
|
||||
self.__enum = type
|
||||
|
||||
def __call__(self, parser, namespace, values, option_string):
|
||||
key = str(values).upper().replace('-', '_')
|
||||
value = self.__enum[key]
|
||||
setattr(namespace, self.dest, value)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='SC64 control software')
|
||||
parser.add_argument('--backup', help='backup SC64 firmware and write it to specified file')
|
||||
parser.add_argument('--update', help='update SC64 firmware from specified file')
|
||||
parser.add_argument('--reset-state', action='store_true', help='reset SC64 internal state')
|
||||
parser.add_argument('--boot', type=SC64.BootMode, action=EnumAction, help='set boot mode')
|
||||
parser.add_argument('--tv', type=SC64.TVType, action=EnumAction, help='force TV type to set value')
|
||||
parser.add_argument('--cic', type=SC64.CICSeed, action=EnumAction, help='force CIC seed to set value')
|
||||
parser.add_argument('--rtc', action='store_true', help='update clock in SC64 to system time')
|
||||
parser.add_argument('--rom', help='upload ROM from specified file')
|
||||
parser.add_argument('--no-shadow', action='store_false', help='do not put last 128 kB of ROM inside flash memory (can corrupt non EEPROM saves)')
|
||||
parser.add_argument('--save-type', type=SC64.SaveType, action=EnumAction, help='set save type')
|
||||
parser.add_argument('--save', help='upload save from specified file')
|
||||
parser.add_argument('--backup-save', help='download save and write it to specified file')
|
||||
parser.add_argument('--ddipl', help='upload 64DD IPL from specified file')
|
||||
parser.add_argument('--disk', action='append', help='path to 64DD disk (.ndd format), can be specified multiple times')
|
||||
parser.add_argument('--isv', action='store_true', help='enable IS-Viewer64 support')
|
||||
parser.add_argument('--debug', action='store_true', help='run debug loop (required for IS-Viewer64 and 64DD)')
|
||||
|
||||
if (len(sys.argv) <= 1):
|
||||
parser.print_help()
|
||||
parser.exit()
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
sc64 = SC64()
|
||||
|
||||
if (args.backup):
|
||||
with open(args.backup, 'wb+') as f:
|
||||
print('Generating backup, this might take a while... ', end='', flush=True)
|
||||
f.write(sc64.backup_firmware())
|
||||
print('done')
|
||||
|
||||
if (args.update):
|
||||
with open(args.update, 'rb+') as f:
|
||||
print('Updating firmware, this might take a while... ', end='', flush=True)
|
||||
sc64.update_firmware(f.read())
|
||||
print('done')
|
||||
|
||||
if (args.reset_state):
|
||||
sc64.reset_state()
|
||||
|
||||
# sc64.set_save_type(SC64.SaveType.EEPROM_4K)
|
||||
# with open('S:/n64/saves/SM64.eep', 'rb+') as f:
|
||||
# sc64.upload_save(f.read())
|
||||
# with open('S:/n64/roms/baserom.us.z64', 'rb+') as f:
|
||||
# sc64.upload_rom(f.read())
|
||||
# sc64.set_boot_mode(SC64.BootMode.ROM)
|
||||
if (args.boot != None):
|
||||
sc64.set_boot_mode(args.boot)
|
||||
print(f'Boot mode set to [{args.boot.name}]')
|
||||
|
||||
# with open('S:/n64/64dd/ipl/NDDJ2.n64', 'rb+') as f:
|
||||
# sc64.upload_ddipl(f.read())
|
||||
# sc64.set_boot_mode(SC64.BootMode.DDIPL)
|
||||
if (args.tv != None):
|
||||
sc64.set_tv_type(args.tv)
|
||||
print(f'TV type set to [{args.tv.name}]')
|
||||
|
||||
# try:
|
||||
# disks = [
|
||||
# 'S:/n64/64dd/rtl/NUD-DMPJ-JPN (sealed).ndd',
|
||||
# 'S:/n64/64dd/rtl/NUD-DMBJ-JPN.ndd'
|
||||
# ]
|
||||
# sc64.debug_loop(disks=disks)
|
||||
# except KeyboardInterrupt:
|
||||
# pass
|
||||
if (args.cic != None):
|
||||
sc64.set_cic_seed(args.cic)
|
||||
print(f'CIC seed set to [0x{args.cic:X}]')
|
||||
|
||||
if (args.rtc):
|
||||
sc64.set_rtc(datetime.now())
|
||||
|
||||
if (args.rom):
|
||||
with open(args.rom, 'rb+') as f:
|
||||
print('Uploading ROM... ', end='', flush=True)
|
||||
sc64.upload_rom(f.read(), use_shadow=args.no_shadow)
|
||||
print('done')
|
||||
|
||||
if (args.save_type != None):
|
||||
sc64.set_save_type(args.save_type)
|
||||
print(f'Save type set to [{args.save_type.name}]')
|
||||
|
||||
if (args.save):
|
||||
with open(args.save, 'rb+') as f:
|
||||
print('Uploading save... ', end='', flush=True)
|
||||
sc64.upload_save(f.read())
|
||||
print('done')
|
||||
|
||||
if (args.ddipl):
|
||||
with open(args.ddipl, 'rb+') as f:
|
||||
print('Uploading 64DD IPL... ', end='', flush=True)
|
||||
sc64.upload_ddipl(f.read())
|
||||
print('done')
|
||||
|
||||
if (args.debug):
|
||||
sc64.debug_loop(isv=args.isv, disks=args.disk)
|
||||
|
||||
if (args.backup_save):
|
||||
with open(args.backup_save, 'wb+') as f:
|
||||
print('Downloading save... ', end='', flush=True)
|
||||
f.write(sc64.download_save())
|
||||
print('done')
|
||||
except ValueError as e:
|
||||
print(f'\nValue error: {e}')
|
||||
except ConnectionException as e:
|
||||
print(f'SC64 error: {e}')
|
||||
print(f'\nSC64 error: {e}')
|
||||
|
Loading…
Reference in New Issue
Block a user