From 7f9989cab69ac782667153bc046aae6f18239308 Mon Sep 17 00:00:00 2001 From: Polprzewodnikowy Date: Sun, 23 Jan 2022 19:56:28 +0100 Subject: [PATCH] fsd write, rtc, isv and reset fixes --- sw/n64/src/fatfs/diskio.c | 20 ++++++ sw/n64/src/fatfs/ffconf.h | 2 +- sw/n64/src/sc64.c | 20 ++++++ sw/n64/src/sc64.h | 16 +++++ sw/n64/src/storage.c | 1 + sw/pc/helpers.py | 23 +++++++ sw/pc/requirements.txt | 1 + sw/pc/sc64.py | 54 +++++++++++---- sw/riscv/src/cfg.c | 139 +++++++++++++++++++++++--------------- sw/riscv/src/cfg.h | 4 +- sw/riscv/src/isv.c | 1 + sw/riscv/src/usb.c | 28 ++++++-- 12 files changed, 235 insertions(+), 74 deletions(-) create mode 100644 sw/pc/helpers.py diff --git a/sw/n64/src/fatfs/diskio.c b/sw/n64/src/fatfs/diskio.c index 594c9f8..32bee80 100644 --- a/sw/n64/src/fatfs/diskio.c +++ b/sw/n64/src/fatfs/diskio.c @@ -46,5 +46,25 @@ DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count) { #endif DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void *buff) { + if (cmd == CTRL_SYNC) { + return RES_OK; + } return RES_PARERR; } + +static uint8_t from_bcd (uint8_t bcd) { + return ((((bcd >> 4) & 0x0F) * 10) + (bcd & 0x0F)); +} + +DWORD get_fattime(void) { + rtc_time_t t; + sc64_get_time(&t); + return ( + ((from_bcd(t.year) + 20) << 25) | + (from_bcd(t.month) << 21) | + (from_bcd(t.day) << 16) | + (from_bcd(t.hour) << 11) | + (from_bcd(t.minute) << 5) | + (from_bcd(t.second) >> 1) + ); +} diff --git a/sw/n64/src/fatfs/ffconf.h b/sw/n64/src/fatfs/ffconf.h index 28460b5..33c16b4 100644 --- a/sw/n64/src/fatfs/ffconf.h +++ b/sw/n64/src/fatfs/ffconf.h @@ -237,7 +237,7 @@ / Note that enabling exFAT discards ANSI C (C89) compatibility. */ -#define FF_FS_NORTC 1 +#define FF_FS_NORTC 0 #define FF_NORTC_MON 1 #define FF_NORTC_MDAY 1 #define FF_NORTC_YEAR 2020 diff --git a/sw/n64/src/sc64.c b/sw/n64/src/sc64.c index 34761cb..d4316f4 100644 --- a/sw/n64/src/sc64.c +++ b/sw/n64/src/sc64.c @@ -62,6 +62,26 @@ void sc64_init (void) { sc64_change_config(CFG_ID_SDRAM_SWITCH, true); } +void sc64_get_time (rtc_time_t *t) { + uint32_t result[2]; + sc64_perform_cmd(SC64_CMD_GET_TIME, NULL, result); + t->second = (result[0] & 0xFF); + t->minute = ((result[0] >> 8) & 0xFF); + t->hour = ((result[0] >> 16) & 0xFF); + t->weekday = ((result[1] >> 24) & 0xFF); + t->day = (result[1] & 0xFF); + t->month = ((result[1] >> 8) & 0xFF); + t->year = ((result[1] >> 16) & 0xFF); +} + +void sc64_set_time (rtc_time_t *t) { + uint32_t args[2] = { + ((t->hour << 16) | (t->minute << 8) | t->second), + ((t->weekday << 24) | (t->year << 16) | (t->month << 8) | t->day), + }; + sc64_perform_cmd(SC64_CMD_SET_TIME, args, NULL); +} + static uint32_t sc64_wait_drive_ready (drive_id_t drive) { uint32_t args[2] = { (drive & 0xFF), 0 }; uint32_t result[2]; diff --git a/sw/n64/src/sc64.h b/sw/n64/src/sc64.h index b43197c..8a56cb5 100644 --- a/sw/n64/src/sc64.h +++ b/sw/n64/src/sc64.h @@ -9,10 +9,14 @@ #define SC64_CMD_QUERY ('Q') #define SC64_CMD_CONFIG ('C') +#define SC64_CMD_GET_TIME (0xEE) +#define SC64_CMD_SET_TIME (0xEF) #define SC64_CMD_DRIVE_INIT (0xF0) #define SC64_CMD_DRIVE_BUSY (0xF1) #define SC64_CMD_DRIVE_READ (0xF2) #define SC64_CMD_DRIVE_WRITE (0xF3) +#define SC64_CMD_DRIVE_LOAD (0xF4) +#define SC64_CMD_DRIVE_STORE (0xF5) #define SC64_CMD_UART_PUT (0xFF) #define SC64_VERSION_2 (0x53437632) @@ -64,6 +68,16 @@ typedef struct { tv_type_t tv_type; } sc64_info_t; +typedef struct { + uint8_t second; + uint8_t minute; + uint8_t hour; + uint8_t weekday; + uint8_t day; + uint8_t month; + uint8_t year; +} rtc_time_t; + typedef enum { DRIVE_SD = 0, DRIVE_USB = 1, @@ -76,6 +90,8 @@ uint32_t sc64_query_config (cfg_id_t id); void sc64_change_config (cfg_id_t id, uint32_t value); void sc64_get_info (sc64_info_t *info); void sc64_init (void); +void sc64_get_time (rtc_time_t *t); +void sc64_set_time (rtc_time_t *t); bool sc64_storage_init (drive_id_t drive); bool sc64_storage_read (drive_id_t drive, void *buffer, uint32_t sector, uint32_t count); bool sc64_storage_write (drive_id_t drive, const void *buffer, uint32_t sector, uint32_t count); diff --git a/sw/n64/src/storage.c b/sw/n64/src/storage.c index 220c8ca..1edd9da 100644 --- a/sw/n64/src/storage.c +++ b/sw/n64/src/storage.c @@ -70,6 +70,7 @@ void storage_run_menu (storage_backend_t storage_backend) { FF_CHECK(f_read(&fil, menu, size, &br), "Couldn't read menu file"); FF_CHECK(br != size, "Read size is different than expected"); FF_CHECK(f_close(&fil), "Couldn't close menu file"); + FF_CHECK(f_unmount(path), "Couldn't unmount drive"); deinit(); diff --git a/sw/pc/helpers.py b/sw/pc/helpers.py new file mode 100644 index 0000000..09d9718 --- /dev/null +++ b/sw/pc/helpers.py @@ -0,0 +1,23 @@ +from io import TextIOWrapper +import contextlib +import os.path +import platform + + + +@contextlib.contextmanager +def lock_volume(volume: TextIOWrapper): + if (os.path.ismount(volume.name)): + if (platform.system().startswith("Windows")): + import msvcrt + import win32file + import winioctlcon + handle = msvcrt.get_osfhandle(volume.fileno()) + win32file.DeviceIoControl(handle, winioctlcon.FSCTL_LOCK_VOLUME, None, None) + try: + yield volume + finally: + try: + volume.flush() + finally: + win32file.DeviceIoControl(handle, winioctlcon.FSCTL_UNLOCK_VOLUME, None, None) diff --git a/sw/pc/requirements.txt b/sw/pc/requirements.txt index 884889c..a9dad9b 100644 --- a/sw/pc/requirements.txt +++ b/sw/pc/requirements.txt @@ -1,2 +1,3 @@ progressbar2==3.55.0 pyft232==0.12 +pywin32==303; sys_platform == 'win32' diff --git a/sw/pc/sc64.py b/sw/pc/sc64.py index 9e5ebbf..8354b9d 100644 --- a/sw/pc/sc64.py +++ b/sw/pc/sc64.py @@ -1,9 +1,12 @@ #!/usr/bin/env python3 +from datetime import datetime from ft232 import Ft232, Ft232Exception from io import TextIOWrapper +from typing import Union import argparse import filecmp +import helpers import os import progressbar import re @@ -73,6 +76,7 @@ class SC64: def __del__(self) -> None: if (self.__usb): + self.__reset_n64("release") self.__usb.close() if (self.__fsd_file): self.__fsd_file.close() @@ -134,21 +138,26 @@ class SC64: self.__write(value.to_bytes(4, byteorder="big")) - def __read_cmd_status(self, cmd: str) -> None: - if (self.__read(4) != f"CMP{cmd[0]}".encode(encoding="ascii")): + def __read_cmd_status(self, cmd: Union[str, int]) -> None: + token = b"CMP" + (cmd.encode() if isinstance(cmd, str) else int.to_bytes(cmd, 1, byteorder="big")) + if (self.__read(4) != token): raise SC64Exception("Wrong command response") - def __write_cmd(self, cmd: str, arg1: int, arg2: int) -> None: - self.__write(f"CMD{cmd[0]}".encode()) + def __write_cmd(self, cmd: Union[str, int], arg1: int, arg2: int) -> None: + token = b"CMD" + (cmd.encode() if isinstance(cmd, str) else int.to_bytes(cmd, 1, byteorder="big")) + self.__write(token) self.__write_int(arg1) self.__write_int(arg2) - def reset_n64(self) -> None: - self.__usb.cbus_setup(mask=1, init=0) - time.sleep(0.1) - self.__usb.cbus_setup(mask=0) + def __reset_n64(self, type: str) -> None: + if (self.__usb): + if (type == "hold"): + self.__usb.cbus_setup(mask=1, init=0) + time.sleep(0.6) + elif (type == "release"): + self.__usb.cbus_setup(mask=0) def __find_sc64(self) -> None: @@ -157,6 +166,7 @@ class SC64: try: self.__usb = Ft232(description="SummerCart64") + self.__reset_n64("hold") self.__usb.flushOutput() self.reset_link() self.__probe_device() @@ -252,6 +262,16 @@ class SC64: self.__find_sc64() + def set_rtc(self, t: datetime) -> None: + to_bcd = lambda v : ((int((v / 10) % 10) << 4) | int(int(v) % 10)) + args = [ + (to_bcd(t.weekday() + 1) << 24) | (to_bcd(t.hour) << 16) | (to_bcd(t.minute) << 8) | to_bcd(t.second), + (to_bcd(t.year) << 16) | (to_bcd(t.month) << 8) | to_bcd(t.day), + ] + self.__write_cmd(0xEF, args[0], args[1]) + self.__read_cmd_status(0xEF) + + def set_boot_mode(self, mode: int) -> None: if (mode >= 0 and mode <= 4): self.__change_config(self.__CFG_ID_BOOT_MODE, mode) @@ -555,9 +575,10 @@ class SC64: offset = int.from_bytes(data[4:8], byteorder="little") if (self.__fsd_file): - self.__fsd_file.seek(sector * 512) - self.__write_cmd("F", offset, 512) - self.__fsd_file.write(self.__read(512)) + with helpers.lock_volume(self.__fsd_file): + self.__fsd_file.seek(sector * 512) + self.__write_cmd("F", offset, 512) + self.__fsd_file.write(self.__read(512)) else: self.__write_cmd("F", offset, 0) @@ -609,6 +630,8 @@ class SC64: start_indicator = bytearray() dropped_bytes = 0 + self.__reset_n64("release") + while (True): while (start_indicator != b"DMA@"): start_indicator.append(self.__read_long(1)[0]) @@ -705,6 +728,7 @@ class SC64ProgressBar: if __name__ == "__main__": parser = argparse.ArgumentParser(description="SummerCart64 one stop control center") + parser.add_argument("-rtc", default=False, action="store_true", required=False, help="update RTC to system time") parser.add_argument("-b", metavar="boot_mode", default="2", required=False, help="set boot mode (0 - 4)") parser.add_argument("-t", metavar="tv_type", default="3", required=False, help="set TV type (0 - 2)") parser.add_argument("-c", metavar="cic_seed", default="0xFFFF", required=False, help="set CIC seed") @@ -731,6 +755,7 @@ if __name__ == "__main__": try: sc64 = SC64() + rtc = args.rtc boot_mode = int(args.b) save_type = int(args.s) tv_type = int(args.t) @@ -751,6 +776,11 @@ if __name__ == "__main__": firmware_backup_file = "sc64firmware.bin.bak" with SC64ProgressBar(sc64): + if (rtc): + now = datetime.now() + print(f"Setting RTC to [{now}]") + sc64.set_rtc(now) + if (update_file): if (is_read): sc64.backup_firmware(update_file) @@ -804,8 +834,6 @@ if __name__ == "__main__": sc64.download_save(save_file) else: sc64.upload_save(save_file) - - sc64.reset_n64() if (debug_server): sc64.debug_init(sd_file, disk_file, dd_turbo) diff --git a/sw/riscv/src/cfg.c b/sw/riscv/src/cfg.c index afb635c..ba05a48 100644 --- a/sw/riscv/src/cfg.c +++ b/sw/riscv/src/cfg.c @@ -3,8 +3,9 @@ #include "flash.h" #include "isv.h" #include "joybus.h" -#include "usb.h" +#include "rtc.h" #include "uart.h" +#include "usb.h" #define SAVE_SIZE_EEPROM_4K (512) @@ -132,6 +133,59 @@ uint32_t cfg_get_version (void) { return CFG->VERSION; } +void cfg_query (uint32_t *args) { + switch (args[0]) { + case CFG_ID_SCR: + args[1] = CFG->SCR; + break; + case CFG_ID_SDRAM_SWITCH: + args[1] = CFG->SCR & CFG_SCR_SDRAM_SWITCH; + break; + case CFG_ID_SDRAM_WRITABLE: + args[1] = CFG->SCR & CFG_SCR_SDRAM_WRITABLE; + break; + case CFG_ID_DD_ENABLE: + args[1] = CFG->SCR & CFG_SCR_DD_EN; + break; + case CFG_ID_SAVE_TYPE: + args[1] = (uint32_t) (p.save_type); + break; + case CFG_ID_CIC_SEED: + args[1] = (uint32_t) (p.cic_seed); + break; + case CFG_ID_TV_TYPE: + args[1] = (uint32_t) (p.tv_type); + break; + case CFG_ID_SAVE_OFFEST: + args[1] = CFG->SAVE_OFFSET; + break; + case CFG_ID_DDIPL_OFFEST: + args[1] = CFG->DDIPL_OFFSET; + break; + case CFG_ID_BOOT_MODE: + args[1] = p.boot_mode; + break; + case CFG_ID_FLASH_SIZE: + args[1] = flash_size(); + break; + case CFG_ID_RECONFIGURE: + args[1] = CFG->RECONFIGURE; + break; + case CFG_ID_DD_DISK_STATE: + args[1] = dd_get_disk_state(); + break; + case CFG_ID_DD_DRIVE_ID: + args[1] = dd_get_drive_id(); + break; + case CFG_ID_DD_THB_TABLE_OFFSET: + args[1] = dd_get_thb_table_offset(); + break; + case CFG_ID_IS_VIEWER_ENABLE: + args[1] = isv_get_enabled(); + break; + } +} + void cfg_update (uint32_t *args) { switch (args[0]) { case CFG_ID_SCR: @@ -194,57 +248,22 @@ void cfg_update (uint32_t *args) { } } -void cfg_query (uint32_t *args) { - switch (args[0]) { - case CFG_ID_SCR: - args[1] = CFG->SCR; - break; - case CFG_ID_SDRAM_SWITCH: - args[1] = CFG->SCR & CFG_SCR_SDRAM_SWITCH; - break; - case CFG_ID_SDRAM_WRITABLE: - args[1] = CFG->SCR & CFG_SCR_SDRAM_WRITABLE; - break; - case CFG_ID_DD_ENABLE: - args[1] = CFG->SCR & CFG_SCR_DD_EN; - break; - case CFG_ID_SAVE_TYPE: - args[1] = (uint32_t) (p.save_type); - break; - case CFG_ID_CIC_SEED: - args[1] = (uint32_t) (p.cic_seed); - break; - case CFG_ID_TV_TYPE: - args[1] = (uint32_t) (p.tv_type); - break; - case CFG_ID_SAVE_OFFEST: - args[1] = CFG->SAVE_OFFSET; - break; - case CFG_ID_DDIPL_OFFEST: - args[1] = CFG->DDIPL_OFFSET; - break; - case CFG_ID_BOOT_MODE: - args[1] = p.boot_mode; - break; - case CFG_ID_FLASH_SIZE: - args[1] = flash_size(); - break; - case CFG_ID_RECONFIGURE: - args[1] = CFG->RECONFIGURE; - break; - case CFG_ID_DD_DISK_STATE: - args[1] = dd_get_disk_state(); - break; - case CFG_ID_DD_DRIVE_ID: - args[1] = dd_get_drive_id(); - break; - case CFG_ID_DD_THB_TABLE_OFFSET: - args[1] = dd_get_thb_table_offset(); - break; - case CFG_ID_IS_VIEWER_ENABLE: - args[1] = isv_get_enabled(); - break; - } +void cfg_get_time (uint32_t *args) { + rtc_time_t *t = rtc_get_time(); + args[0] = ((t->hour << 16) | (t->minute << 8) | t->second); + args[1] = ((t->weekday << 24) | (t->year << 16) | (t->month << 8) | t->day); +} + +void cfg_set_time (uint32_t *args) { + rtc_time_t t; + t.second = (args[0] & 0xFF); + t.minute = ((args[0] >> 8) & 0xFF); + t.hour = ((args[0] >> 16) & 0xFF); + t.weekday = ((args[1] >> 24) & 0xFF); + t.day = (args[1] & 0xFF); + t.month = ((args[1] >> 8) & 0xFF); + t.year = ((args[1] >> 16) & 0xFF); + rtc_set_time(&t); } @@ -271,14 +290,26 @@ void process_cfg (void) { args[1] = CFG->DATA[1]; switch (CFG->CMD) { - case 'C': - cfg_update(args); + case 'V': + args[0] = cfg_get_version(); break; case 'Q': cfg_query(args); break; + case 'C': + cfg_update(args); + break; + + case 0xEE: + cfg_get_time(args); + break; + + case 0xEF: + cfg_set_time(args); + break; + case 0xF0: if (args[0] == 0) { change_scr_bits(CFG_SCR_CMD_ERROR, true); diff --git a/sw/riscv/src/cfg.h b/sw/riscv/src/cfg.h index 1312835..3a20cbf 100644 --- a/sw/riscv/src/cfg.h +++ b/sw/riscv/src/cfg.h @@ -6,8 +6,10 @@ uint32_t cfg_get_version (void); -void cfg_update (uint32_t *args); void cfg_query (uint32_t *args); +void cfg_update (uint32_t *args); +void cfg_get_time (uint32_t *args); +void cfg_set_time (uint32_t *args); void cfg_init (void); void process_cfg (void); diff --git a/sw/riscv/src/isv.c b/sw/riscv/src/isv.c index d6c1d97..1a48951 100644 --- a/sw/riscv/src/isv.c +++ b/sw/riscv/src/isv.c @@ -21,6 +21,7 @@ static void isv_set_ready (void) { void isv_set_enabled (bool enabled) { if (enabled) { CFG->SCR |= CFG_SCR_ISV_EN; + CFG->ISV_CURRENT_RD_PTR = CFG->ISV_RD_PTR; p.ready = true; } else { CFG->SCR &= ~(CFG_SCR_ISV_EN); diff --git a/sw/riscv/src/usb.c b/sw/riscv/src/usb.c index fbff580..5b33572 100644 --- a/sw/riscv/src/usb.c +++ b/sw/riscv/src/usb.c @@ -210,11 +210,6 @@ void process_usb (void) { } break; - case 'C': - cfg_update(p.args); - p.state = STATE_RESPONSE; - break; - case 'Q': if (p.counter == 0) { cfg_query(p.args); @@ -225,6 +220,29 @@ void process_usb (void) { } break; + case 'C': + cfg_update(p.args); + p.state = STATE_RESPONSE; + break; + + case 0xEE: + if (p.counter == 0) { + cfg_get_time(p.args); + p.counter += 1; + } + if ((p.counter == 1) && tx_word(p.args[0])) { + p.counter += 1; + } + if ((p.counter == 2) && tx_word(p.args[1])) { + p.state = STATE_RESPONSE; + } + break; + + case 0xEF: + cfg_set_time(p.args); + p.state = STATE_RESPONSE; + break; + case 'R': case 'W': case 'L':