mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-22 14:09:16 +01:00
Added save writeback through USB
This commit is contained in:
parent
b3891f2c75
commit
009f41d87f
@ -20,6 +20,7 @@
|
|||||||
| `M` | **MEMORY_WRITE** | address | length | data | --- | Write data to specified memory address |
|
| `M` | **MEMORY_WRITE** | address | length | data | --- | Write data to specified memory address |
|
||||||
| `U` | **USB_WRITE** | type | length | data | N/A | Send data to be received by app running on N64 (no response!) |
|
| `U` | **USB_WRITE** | type | length | data | N/A | Send data to be received by app running on N64 (no response!) |
|
||||||
| `D` | **DD_SET_BLOCK_READY** | success | --- | --- | --- | Notify flashcart about 64DD block readiness |
|
| `D` | **DD_SET_BLOCK_READY** | success | --- | --- | --- | Notify flashcart about 64DD block readiness |
|
||||||
|
| `W` | **WRITEBACK_ENABLE** | --- | --- | --- | --- | Enable save writeback through USB packet |
|
||||||
| `p` | **FLASH_WAIT_BUSY** | wait | --- | --- | erase_block_size | Wait until flash ready / Get flash block erase size |
|
| `p` | **FLASH_WAIT_BUSY** | wait | --- | --- | erase_block_size | Wait until flash ready / Get flash block erase size |
|
||||||
| `P` | **FLASH_ERASE_BLOCK** | address | --- | --- | --- | Start flash block erase |
|
| `P` | **FLASH_ERASE_BLOCK** | address | --- | --- | --- | Start flash block erase |
|
||||||
| `f` | **FIRMWARE_BACKUP** | address | --- | --- | status/length | Backup firmware to specified memory address |
|
| `f` | **FIRMWARE_BACKUP** | address | --- | --- | status/length | Backup firmware to specified memory address |
|
||||||
|
@ -628,7 +628,7 @@ void cfg_process (void) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
writeback_load_sector_table(args[0]);
|
writeback_load_sector_table(args[0]);
|
||||||
writeback_enable();
|
writeback_enable(WRITEBACK_SD);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'K':
|
case 'K':
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "update.h"
|
#include "update.h"
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
#include "writeback.h"
|
||||||
|
|
||||||
|
|
||||||
#define BOOTLOADER_ADDRESS (0x04E00000UL)
|
#define BOOTLOADER_ADDRESS (0x04E00000UL)
|
||||||
@ -307,6 +308,12 @@ static void usb_rx_process (void) {
|
|||||||
p.response_pending = true;
|
p.response_pending = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'W':
|
||||||
|
writeback_enable(WRITEBACK_USB);
|
||||||
|
p.rx_state = RX_STATE_IDLE;
|
||||||
|
p.response_pending = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
if (p.rx_args[0]) {
|
if (p.rx_args[0]) {
|
||||||
flash_wait_busy();
|
flash_wait_busy();
|
||||||
|
@ -11,6 +11,7 @@ typedef enum packet_cmd {
|
|||||||
PACKET_CMD_DD_REQUEST = 'D',
|
PACKET_CMD_DD_REQUEST = 'D',
|
||||||
PACKET_CMD_DEBUG_OUTPUT = 'U',
|
PACKET_CMD_DEBUG_OUTPUT = 'U',
|
||||||
PACKET_CMD_ISV_OUTPUT = 'I',
|
PACKET_CMD_ISV_OUTPUT = 'I',
|
||||||
|
PACKET_CMD_SAVE_WRITEBACK = 'S',
|
||||||
PACKET_CMD_UPDATE_STATUS = 'F',
|
PACKET_CMD_UPDATE_STATUS = 'F',
|
||||||
} usb_packet_cmd_e;
|
} usb_packet_cmd_e;
|
||||||
|
|
||||||
|
@ -2,23 +2,25 @@
|
|||||||
#include "fpga.h"
|
#include "fpga.h"
|
||||||
#include "sd.h"
|
#include "sd.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
#include "usb.h"
|
||||||
#include "writeback.h"
|
#include "writeback.h"
|
||||||
|
|
||||||
|
|
||||||
#define SAVE_MAX_SECTOR_COUNT (256)
|
#define SAVE_MAX_SECTOR_COUNT (256)
|
||||||
#define EEPROM_ADDRESS (0x05002000)
|
#define EEPROM_ADDRESS (0x05002000)
|
||||||
#define SRAM_FLASHRAM_ADDRESS (0x03FE0000)
|
#define SRAM_FLASHRAM_ADDRESS (0x03FE0000)
|
||||||
#define EEPROM_4K_SECTOR_COUNT (1)
|
#define EEPROM_4K_LENGTH (512)
|
||||||
#define EEPROM_16K_SECTOR_COUNT (4)
|
#define EEPROM_16K_LENGTH (2048)
|
||||||
#define SRAM_SECTOR_COUNT (64)
|
#define SRAM_LENGTH (32 * 1024)
|
||||||
#define FLASHRAM_SECTOR_COUNT (256)
|
#define FLASHRAM_LENGTH (128 * 1024)
|
||||||
#define SRAM_BANKED_SECTOR_COUNT (192)
|
#define SRAM_BANKED_LENGTH (3 * 32 * 1024)
|
||||||
#define WRITEBACK_DELAY_TICKS (100)
|
#define WRITEBACK_DELAY_TICKS (100)
|
||||||
|
|
||||||
|
|
||||||
struct process {
|
struct process {
|
||||||
bool enabled;
|
bool enabled;
|
||||||
bool pending;
|
bool pending;
|
||||||
|
writeback_mode_t mode;
|
||||||
uint16_t last_save_count;
|
uint16_t last_save_count;
|
||||||
uint32_t sectors[SAVE_MAX_SECTOR_COUNT];
|
uint32_t sectors[SAVE_MAX_SECTOR_COUNT];
|
||||||
};
|
};
|
||||||
@ -27,41 +29,75 @@ struct process {
|
|||||||
static struct process p;
|
static struct process p;
|
||||||
|
|
||||||
|
|
||||||
static void writeback_save_to_sd (void) {
|
static save_type_t writeback_get_address_length (uint32_t *address, uint32_t *length) {
|
||||||
uint32_t address;
|
save_type_t save = cfg_get_save_type();
|
||||||
uint32_t count;
|
|
||||||
|
|
||||||
switch (cfg_get_save_type()) {
|
switch (save) {
|
||||||
case SAVE_TYPE_EEPROM_4K:
|
case SAVE_TYPE_EEPROM_4K:
|
||||||
address = EEPROM_ADDRESS;
|
*address = EEPROM_ADDRESS;
|
||||||
count = EEPROM_4K_SECTOR_COUNT;
|
*length = EEPROM_4K_LENGTH;
|
||||||
break;
|
break;
|
||||||
case SAVE_TYPE_EEPROM_16K:
|
case SAVE_TYPE_EEPROM_16K:
|
||||||
address = EEPROM_ADDRESS;
|
*address = EEPROM_ADDRESS;
|
||||||
count = EEPROM_16K_SECTOR_COUNT;
|
*length = EEPROM_16K_LENGTH;
|
||||||
break;
|
break;
|
||||||
case SAVE_TYPE_SRAM:
|
case SAVE_TYPE_SRAM:
|
||||||
address = SRAM_FLASHRAM_ADDRESS;
|
*address = SRAM_FLASHRAM_ADDRESS;
|
||||||
count = SRAM_SECTOR_COUNT;
|
*length = SRAM_LENGTH;
|
||||||
break;
|
break;
|
||||||
case SAVE_TYPE_FLASHRAM:
|
case SAVE_TYPE_FLASHRAM:
|
||||||
address = SRAM_FLASHRAM_ADDRESS;
|
*address = SRAM_FLASHRAM_ADDRESS;
|
||||||
count = FLASHRAM_SECTOR_COUNT;
|
*length = FLASHRAM_LENGTH;
|
||||||
break;
|
break;
|
||||||
case SAVE_TYPE_SRAM_BANKED:
|
case SAVE_TYPE_SRAM_BANKED:
|
||||||
address = SRAM_FLASHRAM_ADDRESS;
|
*address = SRAM_FLASHRAM_ADDRESS;
|
||||||
count = SRAM_BANKED_SECTOR_COUNT;
|
*length = SRAM_BANKED_LENGTH;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
*address = 0;
|
||||||
|
*length = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return save;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeback_save_to_sd (void) {
|
||||||
|
save_type_t save;
|
||||||
|
uint32_t address;
|
||||||
|
uint32_t length;
|
||||||
|
|
||||||
|
save = writeback_get_address_length(&address, &length);
|
||||||
|
if (save == SAVE_TYPE_NONE) {
|
||||||
writeback_disable();
|
writeback_disable();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sd_optimize_sectors(address, p.sectors, count, sd_write_sectors)) {
|
if(sd_optimize_sectors(address, p.sectors, length / SD_SECTOR_SIZE, sd_write_sectors)) {
|
||||||
writeback_disable();
|
writeback_disable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool writeback_save_to_usb (void) {
|
||||||
|
save_type_t save;
|
||||||
|
uint32_t address;
|
||||||
|
uint32_t length;
|
||||||
|
|
||||||
|
save = writeback_get_address_length(&address, &length);
|
||||||
|
if (save == SAVE_TYPE_NONE) {
|
||||||
|
writeback_disable();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_tx_info_t packet_info;
|
||||||
|
usb_create_packet(&packet_info, PACKET_CMD_SAVE_WRITEBACK);
|
||||||
|
packet_info.data_length = 4;
|
||||||
|
packet_info.data[0] = save;
|
||||||
|
packet_info.dma_length = length;
|
||||||
|
packet_info.dma_address = address;
|
||||||
|
return usb_enqueue_packet(&packet_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void writeback_load_sector_table (uint32_t address) {
|
void writeback_load_sector_table (uint32_t address) {
|
||||||
fpga_mem_read(address, sizeof(p.sectors), (uint8_t *) (p.sectors));
|
fpga_mem_read(address, sizeof(p.sectors), (uint8_t *) (p.sectors));
|
||||||
@ -70,9 +106,10 @@ void writeback_load_sector_table (uint32_t address) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeback_enable (void) {
|
void writeback_enable (writeback_mode_t mode) {
|
||||||
p.enabled = true;
|
p.enabled = true;
|
||||||
p.pending = false;
|
p.pending = false;
|
||||||
|
p.mode = mode;
|
||||||
p.last_save_count = fpga_reg_get(REG_SAVE_COUNT);
|
p.last_save_count = fpga_reg_get(REG_SAVE_COUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,13 +122,14 @@ void writeback_disable (void) {
|
|||||||
void writeback_init (void) {
|
void writeback_init (void) {
|
||||||
p.enabled = false;
|
p.enabled = false;
|
||||||
p.pending = false;
|
p.pending = false;
|
||||||
|
p.mode = WRITEBACK_SD;
|
||||||
for (int i = 0; i < SAVE_MAX_SECTOR_COUNT; i++) {
|
for (int i = 0; i < SAVE_MAX_SECTOR_COUNT; i++) {
|
||||||
p.sectors[i] = 0;
|
p.sectors[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeback_process (void) {
|
void writeback_process (void) {
|
||||||
if (p.enabled && !sd_card_is_inserted()) {
|
if (p.enabled && (p.mode == WRITEBACK_SD) && !sd_card_is_inserted()) {
|
||||||
writeback_disable();
|
writeback_disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +143,19 @@ void writeback_process (void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (p.pending && (timer_get(TIMER_ID_WRITEBACK) == 0)) {
|
if (p.pending && (timer_get(TIMER_ID_WRITEBACK) == 0)) {
|
||||||
p.pending = false;
|
switch (p.mode) {
|
||||||
|
case WRITEBACK_SD:
|
||||||
writeback_save_to_sd();
|
writeback_save_to_sd();
|
||||||
|
p.pending = false;
|
||||||
|
break;
|
||||||
|
case WRITEBACK_USB:
|
||||||
|
if (writeback_save_to_usb()) {
|
||||||
|
p.pending = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
writeback_disable();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,14 @@
|
|||||||
#define WRITEBACK_SECTOR_TABLE_SIZE (1024)
|
#define WRITEBACK_SECTOR_TABLE_SIZE (1024)
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
WRITEBACK_SD,
|
||||||
|
WRITEBACK_USB,
|
||||||
|
} writeback_mode_t;
|
||||||
|
|
||||||
|
|
||||||
void writeback_load_sector_table (uint32_t address);
|
void writeback_load_sector_table (uint32_t address);
|
||||||
void writeback_enable (void);
|
void writeback_enable (writeback_mode_t mode);
|
||||||
void writeback_disable (void);
|
void writeback_disable (void);
|
||||||
void writeback_init (void);
|
void writeback_init (void);
|
||||||
void writeback_process (void);
|
void writeback_process (void);
|
||||||
|
@ -115,6 +115,8 @@ impl TryFrom<Vec<u8>> for ScreenshotMetadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MAX_FILE_LENGTH: u64 = 8 * 1024 * 1024;
|
||||||
|
|
||||||
impl Handler {
|
impl Handler {
|
||||||
pub fn process_user_input(&self) -> Option<sc64::DebugPacket> {
|
pub fn process_user_input(&self) -> Option<sc64::DebugPacket> {
|
||||||
if let Ok(line) = self.line_rx.try_recv() {
|
if let Ok(line) = self.line_rx.try_recv() {
|
||||||
@ -151,6 +153,10 @@ impl Handler {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
if length > MAX_FILE_LENGTH {
|
||||||
|
println!("File too big ({length} bytes), exceeding max size of {MAX_FILE_LENGTH} bytes");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
let mut data = vec![0u8; length as usize];
|
let mut data = vec![0u8; length as usize];
|
||||||
if let Err(error) = file.read_exact(&mut data) {
|
if let Err(error) = file.read_exact(&mut data) {
|
||||||
println!("Couldn't read file contents: {error}");
|
println!("Couldn't read file contents: {error}");
|
||||||
@ -202,9 +208,9 @@ impl Handler {
|
|||||||
match File::create(filename) {
|
match File::create(filename) {
|
||||||
Ok(mut file) => {
|
Ok(mut file) => {
|
||||||
if let Err(error) = file.write_all(data) {
|
if let Err(error) = file.write_all(data) {
|
||||||
println!("Error during raw binary save: {error}");
|
println!("Error during raw binary write: {error}");
|
||||||
}
|
}
|
||||||
println!("Wrote {} bytes to [{}]", data.len(), filename);
|
println!("Wrote [{}] bytes to [{}]", data.len(), filename);
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
println!("Error during raw binary file creation: {error}");
|
println!("Error during raw binary file creation: {error}");
|
||||||
@ -267,6 +273,37 @@ impl Handler {
|
|||||||
self.gdb_tx.send(data.to_vec()).ok();
|
self.gdb_tx.send(data.to_vec()).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn handle_save_writeback(
|
||||||
|
&self,
|
||||||
|
save_writeback: sc64::SaveWriteback,
|
||||||
|
path: &Option<PathBuf>,
|
||||||
|
) {
|
||||||
|
let filename = &if let Some(path) = path {
|
||||||
|
path.to_string_lossy().to_string()
|
||||||
|
} else {
|
||||||
|
self.generate_filename(
|
||||||
|
"save",
|
||||||
|
match save_writeback.save {
|
||||||
|
sc64::SaveType::Eeprom4k | sc64::SaveType::Eeprom16k => "eep",
|
||||||
|
sc64::SaveType::Sram | sc64::SaveType::SramBanked => "srm",
|
||||||
|
sc64::SaveType::Flashram => "fla",
|
||||||
|
_ => "sav",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
};
|
||||||
|
match File::create(filename) {
|
||||||
|
Ok(mut file) => {
|
||||||
|
if let Err(error) = file.write_all(&save_writeback.data) {
|
||||||
|
println!("Error during save write: {error}");
|
||||||
|
}
|
||||||
|
println!("Wrote [{}] save to [{}]", save_writeback.save, filename);
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
println!("Error during save writeback file creation: {error}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn generate_filename(&self, prefix: &str, extension: &str) -> String {
|
fn generate_filename(&self, prefix: &str, extension: &str) -> String {
|
||||||
format!(
|
format!(
|
||||||
"{prefix}-{}.{extension}",
|
"{prefix}-{}.{extension}",
|
||||||
@ -314,7 +351,7 @@ fn stdin_thread(line_tx: Sender<String>) {
|
|||||||
loop {
|
loop {
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
if stdin().read_line(&mut line).is_ok() {
|
if stdin().read_line(&mut line).is_ok() {
|
||||||
if line_tx.send(line).is_err() {
|
if line_tx.send(line.trim_end().to_string()).is_err() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,6 +146,10 @@ struct _64DDArgs {
|
|||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
struct DebugArgs {
|
struct DebugArgs {
|
||||||
|
/// Path to the save file to use by the save writeback mechanism
|
||||||
|
#[arg(short, long)]
|
||||||
|
save: Option<PathBuf>,
|
||||||
|
|
||||||
/// Enable IS-Viewer64 and set listening address at ROM offset (in most cases it's fixed at 0x03FF0000)
|
/// Enable IS-Viewer64 and set listening address at ROM offset (in most cases it's fixed at 0x03FF0000)
|
||||||
#[arg(long, value_name = "offset", value_parser = |s: &str| maybe_hex_range::<u32>(s, 0x00000004, 0x03FF0000))]
|
#[arg(long, value_name = "offset", value_parser = |s: &str| maybe_hex_range::<u32>(s, 0x00000004, 0x03FF0000))]
|
||||||
isv: Option<u32>,
|
isv: Option<u32>,
|
||||||
@ -581,6 +585,7 @@ fn handle_debug_command(connection: Connection, args: &DebugArgs) -> Result<(),
|
|||||||
.bright_blue()
|
.bright_blue()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
sc64.set_save_writeback(true)?;
|
||||||
|
|
||||||
println!("{}: Started", "[Debug]".bold());
|
println!("{}: Started", "[Debug]".bold());
|
||||||
|
|
||||||
@ -594,6 +599,9 @@ fn handle_debug_command(connection: Connection, args: &DebugArgs) -> Result<(),
|
|||||||
sc64::DataPacket::Debug(debug_packet) => {
|
sc64::DataPacket::Debug(debug_packet) => {
|
||||||
debug_handler.handle_debug_packet(debug_packet)
|
debug_handler.handle_debug_packet(debug_packet)
|
||||||
}
|
}
|
||||||
|
sc64::DataPacket::SaveWriteback(save_writeback) => {
|
||||||
|
debug_handler.handle_save_writeback(save_writeback, &args.save);
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
} else if let Some(gdb_packet) = debug_handler.receive_gdb_packet() {
|
} else if let Some(gdb_packet) = debug_handler.receive_gdb_packet() {
|
||||||
@ -603,6 +611,7 @@ fn handle_debug_command(connection: Connection, args: &DebugArgs) -> Result<(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sc64.set_save_writeback(false)?;
|
||||||
if args.isv.is_some() {
|
if args.isv.is_some() {
|
||||||
sc64.configure_is_viewer_64(None)?;
|
sc64.configure_is_viewer_64(None)?;
|
||||||
println!("{}: Stopped listening", "[IS-Viewer 64]".bold());
|
println!("{}: Stopped listening", "[IS-Viewer 64]".bold());
|
||||||
|
@ -12,8 +12,8 @@ pub use self::{
|
|||||||
server::ServerEvent,
|
server::ServerEvent,
|
||||||
types::{
|
types::{
|
||||||
BootMode, ButtonMode, ButtonState, CicSeed, DataPacket, DdDiskState, DdDriveType, DdMode,
|
BootMode, ButtonMode, ButtonState, CicSeed, DataPacket, DdDiskState, DdDriveType, DdMode,
|
||||||
DebugPacket, DiskPacket, DiskPacketKind, FpgaDebugData, McuStackUsage, SaveType, Switch,
|
DebugPacket, DiskPacket, DiskPacketKind, FpgaDebugData, McuStackUsage, SaveType,
|
||||||
TvType,
|
SaveWriteback, Switch, TvType,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -272,6 +272,15 @@ impl SC64 {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn command_writeback_enable(&mut self) -> Result<(), Error> {
|
||||||
|
self.link.execute_command(&Command {
|
||||||
|
id: b'W',
|
||||||
|
args: [0, 0],
|
||||||
|
data: &[],
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn command_flash_wait_busy(&mut self, wait: bool) -> Result<u32, Error> {
|
fn command_flash_wait_busy(&mut self, wait: bool) -> Result<u32, Error> {
|
||||||
let data = self.link.execute_command(&Command {
|
let data = self.link.execute_command(&Command {
|
||||||
id: b'p',
|
id: b'p',
|
||||||
@ -582,6 +591,16 @@ impl SC64 {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_save_writeback(&mut self, enabled: bool) -> Result<(), Error> {
|
||||||
|
if enabled {
|
||||||
|
self.command_writeback_enable()?;
|
||||||
|
} else {
|
||||||
|
let save_type = get_config!(self, SaveType)?;
|
||||||
|
self.set_save_type(save_type)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn receive_data_packet(&mut self) -> Result<Option<DataPacket>, Error> {
|
pub fn receive_data_packet(&mut self) -> Result<Option<DataPacket>, Error> {
|
||||||
if let Some(packet) = self.link.receive_packet()? {
|
if let Some(packet) = self.link.receive_packet()? {
|
||||||
return Ok(Some(packet.try_into()?));
|
return Ok(Some(packet.try_into()?));
|
||||||
|
@ -580,6 +580,7 @@ pub enum DataPacket {
|
|||||||
Debug(DebugPacket),
|
Debug(DebugPacket),
|
||||||
Disk(DiskPacket),
|
Disk(DiskPacket),
|
||||||
IsViewer64(String),
|
IsViewer64(String),
|
||||||
|
SaveWriteback(SaveWriteback),
|
||||||
UpdateStatus(UpdateStatus),
|
UpdateStatus(UpdateStatus),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -591,6 +592,7 @@ impl TryFrom<Packet> for DataPacket {
|
|||||||
b'U' => Self::Debug(value.data.try_into()?),
|
b'U' => Self::Debug(value.data.try_into()?),
|
||||||
b'D' => Self::Disk(value.data.try_into()?),
|
b'D' => Self::Disk(value.data.try_into()?),
|
||||||
b'I' => Self::IsViewer64(EUC_JP.decode(&value.data).0.into()),
|
b'I' => Self::IsViewer64(EUC_JP.decode(&value.data).0.into()),
|
||||||
|
b'S' => Self::SaveWriteback(value.data.try_into()?),
|
||||||
b'F' => {
|
b'F' => {
|
||||||
if value.data.len() != 4 {
|
if value.data.len() != 4 {
|
||||||
return Err(Error::new(
|
return Err(Error::new(
|
||||||
@ -682,6 +684,25 @@ impl DiskBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct SaveWriteback {
|
||||||
|
pub save: SaveType,
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Vec<u8>> for SaveWriteback {
|
||||||
|
type Error = Error;
|
||||||
|
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
|
||||||
|
if value.len() < 4 {
|
||||||
|
return Err(Error::new(
|
||||||
|
"Couldn't extract save info from save writeback packet",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let save: SaveType = u32::from_be_bytes(value[0..4].try_into().unwrap()).try_into()?;
|
||||||
|
let data = value[4..].to_vec();
|
||||||
|
Ok(SaveWriteback { save, data })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub enum FirmwareStatus {
|
pub enum FirmwareStatus {
|
||||||
Ok,
|
Ok,
|
||||||
ErrToken,
|
ErrToken,
|
||||||
@ -782,7 +803,10 @@ impl TryFrom<Vec<u8>> for FpgaDebugData {
|
|||||||
|
|
||||||
impl Display for FpgaDebugData {
|
impl Display for FpgaDebugData {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.write_fmt(format_args!("Last PI address: 0x{:08X}", self.last_pi_address))?;
|
f.write_fmt(format_args!(
|
||||||
|
"Last PI address: 0x{:08X}",
|
||||||
|
self.last_pi_address
|
||||||
|
))?;
|
||||||
if self.read_fifo_wait {
|
if self.read_fifo_wait {
|
||||||
f.write_str(" RW")?;
|
f.write_str(" RW")?;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user