diff --git a/sw/deployer/src/main.rs b/sw/deployer/src/main.rs index 42201b7..25bcb34 100644 --- a/sw/deployer/src/main.rs +++ b/sw/deployer/src/main.rs @@ -38,6 +38,9 @@ enum Commands { /// Upload ROM (and save) to the SC64 Upload(UploadArgs), + /// Download save and write it to file + DownloadSave(DownloadSaveArgs), + /// Upload ROM, 64DD IPL and run disk server _64DD(_64DDArgs), @@ -89,6 +92,12 @@ struct UploadArgs { tv: Option, } +#[derive(Args)] +struct DownloadSaveArgs { + /// Path to the save file + path: PathBuf, +} + #[derive(Args)] struct _64DDArgs { /// Path to the ROM file @@ -234,14 +243,15 @@ fn main() { fn handle_command(command: &Commands, sn: Option) { let result = match command { + Commands::List => handle_list_command(), Commands::Upload(args) => handle_upload_command(sn, args), + Commands::DownloadSave(args) => handle_download_save_command(sn, args), Commands::_64DD(args) => handle_64dd_command(sn, args), - Commands::Dump(args) => handle_dump_command(sn, args), Commands::Debug(args) => handle_debug_command(sn, args), + Commands::Dump(args) => handle_dump_command(sn, args), Commands::Info => handle_info_command(sn), Commands::Set { command } => handle_set_command(sn, command), Commands::Firmware { command } => handle_firmware_command(sn, command), - Commands::List => handle_list_command(), }; match result { Ok(()) => {} @@ -249,14 +259,25 @@ fn handle_command(command: &Commands, sn: Option) { }; } +fn handle_list_command() -> Result<(), sc64::Error> { + let devices = sc64::list_serial_devices()?; + + println!("{}", "Found devices:".bold()); + for (i, d) in devices.iter().enumerate() { + println!(" {i}: {}", d.sn); + } + + Ok(()) +} + fn handle_upload_command(sn: Option, args: &UploadArgs) -> Result<(), sc64::Error> { let mut sc64 = init_sc64(sn, true)?; - sc64.reset_state()?; - let (rom_file_unbuffered, rom_name, rom_length) = open_file(&args.rom)?; let mut rom_file = BufReader::new(rom_file_unbuffered); + sc64.reset_state()?; + log_wait(format!("Uploading ROM [{rom_name}]"), || { sc64.upload_rom(&mut rom_file, rom_length, args.no_shadow) })?; @@ -306,6 +327,21 @@ fn handle_upload_command(sn: Option, args: &UploadArgs) -> Result<(), sc Ok(()) } +fn handle_download_save_command( + sn: Option, + args: &DownloadSaveArgs, +) -> Result<(), sc64::Error> { + let mut sc64 = init_sc64(sn, true)?; + + let (mut file, name) = create_file(&args.path)?; + + log_wait(format!("Downloading save [{name}]"), || { + sc64.download_save(&mut file) + })?; + + Ok(()) +} + fn handle_64dd_command(sn: Option, args: &_64DDArgs) -> Result<(), sc64::Error> { let _ = (sn, args); @@ -314,24 +350,7 @@ fn handle_64dd_command(sn: Option, args: &_64DDArgs) -> Result<(), sc64: // TODO: print BIG warning to not use this mode together with real 64DD println!("{}", "Sorry nothing".yellow()); - - Ok(()) -} - -fn handle_dump_command(sn: Option, args: &DumpArgs) -> Result<(), sc64::Error> { - let mut sc64 = init_sc64(sn, true)?; - - let (mut dump_file, dump_name) = create_file(&args.path)?; - - let data = log_wait( - format!( - "Dumping from [0x{:08X}] length [0x{:X}] to [{dump_name}]", - args.address, args.length - ), - || sc64.dump_memory(args.address, args.length), - )?; - - dump_file.write(&data)?; + println!("{}", "64DD emulation not implemented yet".red()); Ok(()) } @@ -384,6 +403,24 @@ fn handle_debug_command(sn: Option, args: &DebugArgs) -> Result<(), sc64 Ok(()) } +fn handle_dump_command(sn: Option, args: &DumpArgs) -> Result<(), sc64::Error> { + let mut sc64 = init_sc64(sn, true)?; + + let (mut dump_file, dump_name) = create_file(&args.path)?; + + let data = log_wait( + format!( + "Dumping from [0x{:08X}] length [0x{:X}] to [{dump_name}]", + args.address, args.length + ), + || sc64.dump_memory(args.address, args.length), + )?; + + dump_file.write(&data)?; + + Ok(()) +} + fn handle_info_command(sn: Option) -> Result<(), sc64::Error> { let mut sc64 = init_sc64(sn, false)?; @@ -509,17 +546,6 @@ fn handle_firmware_command( } } -fn handle_list_command() -> Result<(), sc64::Error> { - let devices = sc64::list_serial_devices()?; - - println!("{}", "Found devices:".bold()); - for (i, d) in devices.iter().enumerate() { - println!(" {i}: {}", d.sn); - } - - Ok(()) -} - fn init_sc64(sn: Option, check_firmware: bool) -> Result { let mut sc64 = sc64::new(sn)?; diff --git a/sw/deployer/src/sc64/mod.rs b/sw/deployer/src/sc64/mod.rs index c479d59..2e880ed 100644 --- a/sw/deployer/src/sc64/mod.rs +++ b/sw/deployer/src/sc64/mod.rs @@ -24,7 +24,7 @@ use self::{ }; use chrono::{DateTime, Local}; use std::{ - io::{Read, Seek}, + io::{Read, Seek, Write}, time::Instant, {cmp::min, time::Duration}, }; @@ -413,6 +413,27 @@ impl SC64 { self.memory_write_chunked(reader, address, save_length, None) } + pub fn download_save(&mut self, writer: &mut T) -> Result<(), Error> { + let save_type = get_config!(self, SaveType)?; + + let (address, save_length) = match save_type { + SaveType::None => { + return Err(Error::new("No save type is enabled")); + } + SaveType::Eeprom4k => (EEPROM_ADDRESS, EEPROM_4K_LENGTH), + SaveType::Eeprom16k => (EEPROM_ADDRESS, EEPROM_16K_LENGTH), + SaveType::Sram => (SAVE_ADDRESS, SRAM_LENGTH), + SaveType::SramBanked => (SAVE_ADDRESS, SRAM_BANKED_LENGTH), + SaveType::Flashram => (SAVE_ADDRESS, FLASHRAM_LENGTH), + }; + + let mut data = self.command_memory_read(address, save_length)?; + + writer.write_all(&mut data)?; + + Ok(()) + } + pub fn dump_memory(&mut self, address: u32, length: usize) -> Result, Error> { if address + length as u32 > MEMORY_LENGTH as u32 { return Err(Error::new("Invalid dump address or length"));