From d8976def97ec516ab3cf7e10054bb766480a5d9c Mon Sep 17 00:00:00 2001 From: Mateusz Faderewski Date: Tue, 23 Jul 2024 18:26:17 +0200 Subject: [PATCH] [SC64][SW] Optimized memory usage in the sc64deployer --- sw/deployer/src/main.rs | 18 ++-- sw/deployer/src/sc64/link.rs | 45 ++++----- sw/deployer/src/sc64/mod.rs | 172 ++++++++++----------------------- sw/deployer/src/sc64/server.rs | 12 +-- sw/deployer/src/sc64/types.rs | 5 + 5 files changed, 90 insertions(+), 162 deletions(-) diff --git a/sw/deployer/src/main.rs b/sw/deployer/src/main.rs index 49e0152..a87ae51 100644 --- a/sw/deployer/src/main.rs +++ b/sw/deployer/src/main.rs @@ -892,19 +892,15 @@ fn handle_test_command(connection: Connection) -> Result<(), sc64::Error> { println!("{}: USB", "[SC64 Tests]".bold()); - print!(" Performing USB write speed test... "); - stdout().flush().unwrap(); - println!( - "{}", - format!("{:.2} MiB/s", sc64.test_usb_speed(true)?).bright_green() - ); - print!(" Performing USB read speed test... "); stdout().flush().unwrap(); - println!( - "{}", - format!("{:.2} MiB/s", sc64.test_usb_speed(false)?).bright_green() - ); + let read_speed = sc64.test_usb_speed(sc64::SpeedTestDirection::Read)?; + println!("{}", format!("{read_speed:.2} MiB/s",).bright_green()); + + print!(" Performing USB write speed test... "); + stdout().flush().unwrap(); + let write_speed = sc64.test_usb_speed(sc64::SpeedTestDirection::Write)?; + println!("{}", format!("{write_speed:.2} MiB/s",).bright_green()); println!("{}: SDRAM (pattern)", "[SC64 Tests]".bold()); diff --git a/sw/deployer/src/sc64/link.rs b/sw/deployer/src/sc64/link.rs index 029870e..91937ca 100644 --- a/sw/deployer/src/sc64/link.rs +++ b/sw/deployer/src/sc64/link.rs @@ -38,12 +38,6 @@ impl TryFrom for DataType { } } -pub struct Command { - pub id: u8, - pub args: [u32; 2], - pub data: Vec, -} - pub struct Response { pub id: u8, pub data: Vec, @@ -167,14 +161,14 @@ pub trait Backend { } } - fn send_command(&mut self, command: &Command) -> std::io::Result<()> { + fn send_command(&mut self, id: u8, args: [u32; 2], data: &[u8]) -> std::io::Result<()> { self.write_all(b"CMD")?; - self.write_all(&command.id.to_be_bytes())?; + self.write_all(&id.to_be_bytes())?; - self.write_all(&command.args[0].to_be_bytes())?; - self.write_all(&command.args[1].to_be_bytes())?; + self.write_all(&args[0].to_be_bytes())?; + self.write_all(&args[1].to_be_bytes())?; - self.write_all(&command.data)?; + self.write_all(data)?; self.flush()?; @@ -332,17 +326,17 @@ impl Backend for TcpBackend { self.stream.shutdown(std::net::Shutdown::Both).ok(); } - fn send_command(&mut self, command: &Command) -> std::io::Result<()> { + fn send_command(&mut self, id: u8, args: [u32; 2], data: &[u8]) -> std::io::Result<()> { let payload_data_type: u32 = DataType::Command.into(); self.write_all(&payload_data_type.to_be_bytes())?; - self.write_all(&command.id.to_be_bytes())?; - self.write_all(&command.args[0].to_be_bytes())?; - self.write_all(&command.args[1].to_be_bytes())?; + self.write_all(&id.to_be_bytes())?; + self.write_all(&args[0].to_be_bytes())?; + self.write_all(&args[1].to_be_bytes())?; - let command_data_length = command.data.len() as u32; + let command_data_length = data.len() as u32; self.write_all(&command_data_length.to_be_bytes())?; - self.write_all(&command.data)?; + self.write_all(data)?; self.flush()?; @@ -445,22 +439,29 @@ pub struct Link { } impl Link { - pub fn execute_command(&mut self, command: &Command) -> Result, Error> { - self.execute_command_raw(command, false, false) + pub fn execute_command( + &mut self, + id: u8, + args: [u32; 2], + data: &[u8], + ) -> Result, Error> { + self.execute_command_raw(id, args, data, false, false) } pub fn execute_command_raw( &mut self, - command: &Command, + id: u8, + args: [u32; 2], + data: &[u8], no_response: bool, ignore_error: bool, ) -> Result, Error> { - self.backend.send_command(command)?; + self.backend.send_command(id, args, data)?; if no_response { return Ok(vec![]); } let response = self.receive_response()?; - if command.id != response.id { + if id != response.id { return Err(Error::new("Command response ID didn't match")); } if !ignore_error && response.error { diff --git a/sw/deployer/src/sc64/mod.rs b/sw/deployer/src/sc64/mod.rs index db6b4a4..71aa7bb 100644 --- a/sw/deployer/src/sc64/mod.rs +++ b/sw/deployer/src/sc64/mod.rs @@ -15,13 +15,14 @@ pub use self::{ types::{ BootMode, ButtonMode, ButtonState, CicSeed, DataPacket, DdDiskState, DdDriveType, DdMode, DebugPacket, DiagnosticData, DiskPacket, DiskPacketKind, FpgaDebugData, ISViewer, - MemoryTestPattern, MemoryTestPatternResult, SaveType, SaveWriteback, Switch, TvType, + MemoryTestPattern, MemoryTestPatternResult, SaveType, SaveWriteback, SpeedTestDirection, + Switch, TvType, }, }; use self::{ cic::{sign_ipl3, IPL3_LENGTH, IPL3_OFFSET}, - link::{Command, Link}, + link::Link, time::{convert_from_datetime, convert_to_datetime}, types::{ get_config, get_setting, Config, ConfigId, FirmwareStatus, Setting, SettingId, UpdateStatus, @@ -105,11 +106,7 @@ const MEMORY_CHUNK_LENGTH: usize = 8 * 1024 * 1024; impl SC64 { fn command_identifier_get(&mut self) -> Result<[u8; 4], Error> { - let data = self.link.execute_command(&Command { - id: b'v', - args: [0, 0], - data: vec![], - })?; + let data = self.link.execute_command(b'v', [0, 0], &[])?; if data.len() != 4 { return Err(Error::new( "Invalid data length received for identifier get command", @@ -119,11 +116,7 @@ impl SC64 { } fn command_version_get(&mut self) -> Result<(u16, u16, u32), Error> { - let data = self.link.execute_command(&Command { - id: b'V', - args: [0, 0], - data: vec![], - })?; + let data = self.link.execute_command(b'V', [0, 0], &[])?; if data.len() != 8 { return Err(Error::new( "Invalid data length received for version get command", @@ -136,11 +129,7 @@ impl SC64 { } fn command_state_reset(&mut self) -> Result<(), Error> { - self.link.execute_command(&Command { - id: b'R', - args: [0, 0], - data: vec![], - })?; + self.link.execute_command(b'R', [0, 0], &[])?; Ok(()) } @@ -156,20 +145,14 @@ impl SC64 { ((if disable { 1 } else { 0 }) << 24) | ((seed as u32) << 16) | checksum_high, checksum_low, ]; - self.link.execute_command(&Command { - id: b'B', - args, - data: vec![], - })?; + self.link.execute_command(b'B', args, &[])?; Ok(()) } fn command_config_get(&mut self, config_id: ConfigId) -> Result { - let data = self.link.execute_command(&Command { - id: b'c', - args: [config_id.into(), 0], - data: vec![], - })?; + let data = self + .link + .execute_command(b'c', [config_id.into(), 0], &[])?; if data.len() != 4 { return Err(Error::new( "Invalid data length received for config get command", @@ -180,20 +163,14 @@ impl SC64 { } fn command_config_set(&mut self, config: Config) -> Result<(), Error> { - self.link.execute_command(&Command { - id: b'C', - args: config.into(), - data: vec![], - })?; + self.link.execute_command(b'C', config.into(), &[])?; Ok(()) } fn command_setting_get(&mut self, setting_id: SettingId) -> Result { - let data = self.link.execute_command(&Command { - id: b'a', - args: [setting_id.into(), 0], - data: vec![], - })?; + let data = self + .link + .execute_command(b'a', [setting_id.into(), 0], &[])?; if data.len() != 4 { return Err(Error::new( "Invalid data length received for setting get command", @@ -204,20 +181,12 @@ impl SC64 { } fn command_setting_set(&mut self, setting: Setting) -> Result<(), Error> { - self.link.execute_command(&Command { - id: b'A', - args: setting.into(), - data: vec![], - })?; + self.link.execute_command(b'A', setting.into(), &[])?; Ok(()) } fn command_time_get(&mut self) -> Result { - let data = self.link.execute_command(&Command { - id: b't', - args: [0, 0], - data: vec![], - })?; + let data = self.link.execute_command(b't', [0, 0], &[])?; if data.len() != 8 { return Err(Error::new( "Invalid data length received for time get command", @@ -227,20 +196,15 @@ impl SC64 { } fn command_time_set(&mut self, datetime: NaiveDateTime) -> Result<(), Error> { - self.link.execute_command(&Command { - id: b'T', - args: convert_from_datetime(datetime), - data: vec![], - })?; + self.link + .execute_command(b'T', convert_from_datetime(datetime), &[])?; Ok(()) } fn command_memory_read(&mut self, address: u32, length: usize) -> Result, Error> { - let data = self.link.execute_command(&Command { - id: b'm', - args: [address, length as u32], - data: vec![], - })?; + let data = self + .link + .execute_command(b'm', [address, length as u32], &[])?; if data.len() != length { return Err(Error::new( "Invalid data length received for memory read command", @@ -250,21 +214,16 @@ impl SC64 { } fn command_memory_write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> { - self.link.execute_command(&Command { - id: b'M', - args: [address, data.len() as u32], - data: data.to_vec(), - })?; + self.link + .execute_command(b'M', [address, data.len() as u32], data)?; Ok(()) } fn command_usb_write(&mut self, datatype: u8, data: &[u8]) -> Result<(), Error> { self.link.execute_command_raw( - &Command { - id: b'U', - args: [datatype as u32, data.len() as u32], - data: data.to_vec(), - }, + b'U', + [datatype as u32, data.len() as u32], + data, true, false, )?; @@ -272,29 +231,17 @@ impl SC64 { } fn command_dd_set_block_ready(&mut self, error: bool) -> Result<(), Error> { - self.link.execute_command(&Command { - id: b'D', - args: [error as u32, 0], - data: vec![], - })?; + self.link.execute_command(b'D', [error as u32, 0], &[])?; Ok(()) } fn command_writeback_enable(&mut self) -> Result<(), Error> { - self.link.execute_command(&Command { - id: b'W', - args: [0, 0], - data: vec![], - })?; + self.link.execute_command(b'W', [0, 0], &[])?; Ok(()) } fn command_flash_wait_busy(&mut self, wait: bool) -> Result { - let data = self.link.execute_command(&Command { - id: b'p', - args: [wait as u32, 0], - data: vec![], - })?; + let data = self.link.execute_command(b'p', [wait as u32, 0], &[])?; if data.len() != 4 { return Err(Error::new( "Invalid data length received for flash wait busy command", @@ -305,24 +252,14 @@ impl SC64 { } fn command_flash_erase_block(&mut self, address: u32) -> Result<(), Error> { - self.link.execute_command(&Command { - id: b'P', - args: [address, 0], - data: vec![], - })?; + self.link.execute_command(b'P', [address, 0], &[])?; Ok(()) } fn command_firmware_backup(&mut self, address: u32) -> Result<(FirmwareStatus, u32), Error> { - let data = self.link.execute_command_raw( - &Command { - id: b'f', - args: [address, 0], - data: vec![], - }, - false, - true, - )?; + let data = self + .link + .execute_command_raw(b'f', [address, 0], &[], false, true)?; if data.len() != 8 { return Err(Error::new( "Invalid data length received for firmware backup command", @@ -338,15 +275,9 @@ impl SC64 { address: u32, length: usize, ) -> Result { - let data = self.link.execute_command_raw( - &Command { - id: b'F', - args: [address, length as u32], - data: vec![], - }, - false, - true, - )?; + let data = + self.link + .execute_command_raw(b'F', [address, length as u32], &[], false, true)?; if data.len() != 4 { return Err(Error::new( "Invalid data length received for firmware update command", @@ -356,20 +287,12 @@ impl SC64 { } fn command_fpga_debug_data_get(&mut self) -> Result { - let data = self.link.execute_command(&Command { - id: b'?', - args: [0, 0], - data: vec![], - })?; + let data = self.link.execute_command(b'?', [0, 0], &[])?; Ok(data.try_into()?) } fn command_diagnostic_data_get(&mut self) -> Result { - let data = self.link.execute_command(&Command { - id: b'%', - args: [0, 0], - data: vec![], - })?; + let data = self.link.execute_command(b'%', [0, 0], &[])?; Ok(data.try_into()?) } } @@ -752,22 +675,27 @@ impl SC64 { } } - pub fn test_usb_speed(&mut self, write: bool) -> Result { + pub fn test_usb_speed(&mut self, direction: SpeedTestDirection) -> Result { const TEST_ADDRESS: u32 = SDRAM_ADDRESS; - const TEST_LENGTH: usize = 8 * 1024 * 1024; + const TEST_LENGTH: usize = 16 * 1024 * 1024; const MIB_DIVIDER: f64 = 1024.0 * 1024.0; let data = vec![0x00; TEST_LENGTH]; let time = std::time::Instant::now(); - if write { - self.command_memory_write(TEST_ADDRESS, &data)?; - } else { - self.command_memory_read(TEST_ADDRESS, TEST_LENGTH)?; + match direction { + SpeedTestDirection::Read => { + self.command_memory_read(TEST_ADDRESS, TEST_LENGTH)?; + } + SpeedTestDirection::Write => { + self.command_memory_write(TEST_ADDRESS, &data)?; + } } - Ok((TEST_LENGTH as f64 / MIB_DIVIDER) / time.elapsed().as_secs_f64()) + let elapsed = time.elapsed(); + + Ok((TEST_LENGTH as f64 / MIB_DIVIDER) / elapsed.as_secs_f64()) } pub fn test_sdram_pattern( diff --git a/sw/deployer/src/sc64/server.rs b/sw/deployer/src/sc64/server.rs index 735d70f..70966cf 100644 --- a/sw/deployer/src/sc64/server.rs +++ b/sw/deployer/src/sc64/server.rs @@ -1,8 +1,6 @@ use super::{ error::Error, - link::{ - list_local_devices, new_local, AsynchronousPacket, Command, DataType, Response, UsbPacket, - }, + link::{list_local_devices, new_local, AsynchronousPacket, DataType, Response, UsbPacket}, }; use std::io::{Read, Write}; @@ -50,7 +48,7 @@ impl StreamHandler { result } - fn receive_command(&mut self) -> std::io::Result> { + fn receive_command(&mut self) -> std::io::Result)>> { if let Some(header) = self.try_read_header()? { if let Ok(data_type) = TryInto::::try_into(u32::from_be_bytes(header)) { if !matches!(data_type, DataType::Command) { @@ -77,7 +75,7 @@ impl StreamHandler { let mut data = vec![0u8; command_data_length]; self.reader.read_exact(&mut data)?; - Ok(Some(Command { id, args, data })) + Ok(Some((id, args, data))) } else { Ok(None) } @@ -121,8 +119,8 @@ fn server_accept_connection(port: String, connection: &mut StreamHandler) -> Res loop { match connection.receive_command() { - Ok(Some(command)) => { - link.execute_command_raw(&command, true, true)?; + Ok(Some((id, args, data))) => { + link.execute_command_raw(id, args, &data, true, true)?; } Ok(None) => {} Err(error) => match error.kind() { diff --git a/sw/deployer/src/sc64/types.rs b/sw/deployer/src/sc64/types.rs index d9e5e09..e052f12 100644 --- a/sw/deployer/src/sc64/types.rs +++ b/sw/deployer/src/sc64/types.rs @@ -1018,6 +1018,11 @@ impl Display for DiagnosticData { } } +pub enum SpeedTestDirection { + Read, + Write +} + pub enum MemoryTestPattern { OwnAddress(bool), AllZeros,