Skip to content

Commit

Permalink
[SC64][SW] Fix USB reset procedure (I/O buffer purge)
Browse files Browse the repository at this point in the history
  • Loading branch information
Polprzewodnikowy committed Sep 3, 2024
1 parent 4a50e33 commit 3146cc8
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 65 deletions.
59 changes: 26 additions & 33 deletions sw/deployer/src/sc64/ftdi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,17 @@ struct Wrapper {
context: *mut libftdi1_sys::ftdi_context,
unclog_buffer: std::collections::VecDeque<u8>,
write_buffer: Vec<u8>,
read_timeout: std::time::Duration,
write_timeout: std::time::Duration,
io_timeout: std::time::Duration,
read_chunksize: usize,
write_chunksize: usize,
}

impl Wrapper {
const DEFAULT_POLL_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(16);
const DEFAULT_RW_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(5);
const DEFAULT_IO_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(5);
const WRITE_CHUNK_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(100);

fn new(
read_timeout: Option<std::time::Duration>,
write_timeout: Option<std::time::Duration>,
) -> std::io::Result<Self> {
fn new(io_timeout: Option<std::time::Duration>) -> std::io::Result<Self> {
let context = unsafe { libftdi1_sys::ftdi_new() };
if context.is_null() {
return Err(std::io::ErrorKind::OutOfMemory.into());
Expand All @@ -51,19 +47,18 @@ impl Wrapper {
context,
unclog_buffer: std::collections::VecDeque::new(),
write_buffer: vec![],
read_timeout: Self::DEFAULT_RW_TIMEOUT,
write_timeout: Self::DEFAULT_RW_TIMEOUT,
io_timeout: Self::DEFAULT_IO_TIMEOUT,
read_chunksize: 4096,
write_chunksize: 4096,
};
wrapper.set_timeouts(read_timeout, write_timeout)?;
wrapper.set_io_timeout(io_timeout)?;
wrapper.read_data_set_chunksize(wrapper.read_chunksize)?;
wrapper.write_data_set_chunksize(wrapper.write_chunksize)?;
Ok(wrapper)
}

fn list_devices(vendor: u16, product: u16) -> std::io::Result<Vec<DeviceInfo>> {
let wrapper = Self::new(None, None)?;
let wrapper = Self::new(None)?;

let mut device_list: *mut libftdi1_sys::ftdi_device_list = std::ptr::null_mut();
let devices = unsafe {
Expand Down Expand Up @@ -162,21 +157,15 @@ impl Wrapper {
.into()
}

fn set_timeouts(
&mut self,
read_timeout: Option<std::time::Duration>,
write_timeout: Option<std::time::Duration>,
) -> std::io::Result<()> {
let read_timeout = read_timeout.unwrap_or(Self::DEFAULT_RW_TIMEOUT);
let write_timeout = write_timeout.unwrap_or(Self::DEFAULT_RW_TIMEOUT);
fn set_io_timeout(&mut self, io_timeout: Option<std::time::Duration>) -> std::io::Result<()> {
let io_timeout = io_timeout.unwrap_or(Self::DEFAULT_IO_TIMEOUT);
unsafe {
(*self.context).usb_read_timeout = i32::try_from(read_timeout.as_millis())
(*self.context).usb_read_timeout = i32::try_from(io_timeout.as_millis())
.map_err(|_| std::io::ErrorKind::InvalidInput)?;
(*self.context).usb_write_timeout = i32::try_from(write_timeout.as_millis())
(*self.context).usb_write_timeout = i32::try_from(io_timeout.as_millis())
.map_err(|_| std::io::ErrorKind::InvalidInput)?;
}
self.read_timeout = read_timeout;
self.write_timeout = write_timeout;
self.io_timeout = io_timeout;
Ok(())
}

Expand Down Expand Up @@ -330,21 +319,27 @@ impl Wrapper {
}

fn tciflush(&mut self) -> std::io::Result<()> {
match unsafe { libftdi1_sys::ftdi_tciflush(self.context) } {
0 => Ok(()),
-1 => Err(std::io::ErrorKind::BrokenPipe.into()),
-2 => Err(std::io::ErrorKind::NotConnected.into()),
result => Err(std::io::Error::other(format!(
"Unexpected response from ftdi_tciflush: {result}"
))),
}?;
let timeout = std::time::Instant::now();
loop {
match self.read(&mut vec![0u8; self.read_chunksize]) {
Ok(_) => {}
Err(error) => match error.kind() {
std::io::ErrorKind::Interrupted
| std::io::ErrorKind::TimedOut
| std::io::ErrorKind::WouldBlock => {
return Ok(());
}
| std::io::ErrorKind::WouldBlock => {}
_ => return Err(error),
},
};
if timeout.elapsed() > self.read_timeout {
return Err(std::io::ErrorKind::TimedOut.into());
if timeout.elapsed() > std::time::Duration::from_millis(1) {
return Ok(());
}
}
}
Expand All @@ -354,8 +349,7 @@ impl Wrapper {
match unsafe { libftdi1_sys::ftdi_tcoflush(self.context) } {
0 => Ok(()),
-1 => Err(std::io::ErrorKind::BrokenPipe.into()),
-2 => Err(std::io::ErrorKind::BrokenPipe.into()),
-3 => Err(std::io::ErrorKind::NotConnected.into()),
-2 => Err(std::io::ErrorKind::NotConnected.into()),
result => Err(std::io::Error::other(format!(
"Unexpected response from ftdi_tcoflush: {result}"
))),
Expand Down Expand Up @@ -421,7 +415,7 @@ impl Wrapper {
_ => return Err(error),
}
}
if timeout.elapsed() > self.write_timeout {
if timeout.elapsed() > self.io_timeout {
return Err(std::io::ErrorKind::TimedOut.into());
}
}
Expand Down Expand Up @@ -478,10 +472,9 @@ impl FtdiDevice {
pub fn open(
description: &str,
poll_timeout: Option<std::time::Duration>,
read_timeout: Option<std::time::Duration>,
write_timeout: Option<std::time::Duration>,
io_timeout: Option<std::time::Duration>,
) -> std::io::Result<FtdiDevice> {
let mut wrapper = Wrapper::new(read_timeout, write_timeout)?;
let mut wrapper = Wrapper::new(io_timeout)?;

wrapper.set_module_detach_mode(ModuleDetachMode::AutoDetachReattach);
wrapper.set_interface(InterfaceIndex::A)?;
Expand Down
21 changes: 5 additions & 16 deletions sw/deployer/src/sc64/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,7 @@ const FTDI_PREFIX: &str = "ftdi://";

const RESET_TIMEOUT: Duration = Duration::from_secs(1);
const POLL_TIMEOUT: Duration = Duration::from_millis(5);
const READ_TIMEOUT: Duration = Duration::from_secs(10);
const WRITE_TIMEOUT: Duration = Duration::from_secs(10);
const IO_TIMEOUT: Duration = Duration::from_secs(10);

pub trait Backend {
fn read(&mut self, buffer: &mut [u8]) -> std::io::Result<usize>;
Expand Down Expand Up @@ -142,7 +141,7 @@ pub trait Backend {
_ => return Err(error.into()),
},
}
if timeout.elapsed() > READ_TIMEOUT {
if timeout.elapsed() > IO_TIMEOUT {
return Err(std::io::ErrorKind::TimedOut.into());
}
}
Expand Down Expand Up @@ -249,12 +248,7 @@ impl Backend for SerialBackend {

fn new_serial_backend(port: &str) -> std::io::Result<SerialBackend> {
Ok(SerialBackend {
device: SerialDevice::new(
port,
Some(POLL_TIMEOUT),
Some(READ_TIMEOUT),
Some(WRITE_TIMEOUT),
)?,
device: SerialDevice::new(port, Some(POLL_TIMEOUT), Some(IO_TIMEOUT))?,
})
}

Expand Down Expand Up @@ -294,12 +288,7 @@ impl Backend for FtdiBackend {

fn new_ftdi_backend(port: &str) -> std::io::Result<FtdiBackend> {
Ok(FtdiBackend {
device: FtdiDevice::open(
port,
Some(POLL_TIMEOUT),
Some(READ_TIMEOUT),
Some(WRITE_TIMEOUT),
)?,
device: FtdiDevice::open(port, Some(POLL_TIMEOUT), Some(IO_TIMEOUT))?,
})
}

Expand Down Expand Up @@ -403,7 +392,7 @@ fn new_tcp_backend(address: &str) -> Result<TcpBackend, Error> {
Error::new(format!("Couldn't connect to [{address}]: {error}").as_str())
})?;
stream.set_read_timeout(Some(POLL_TIMEOUT))?;
stream.set_write_timeout(Some(WRITE_TIMEOUT))?;
stream.set_write_timeout(Some(IO_TIMEOUT))?;
let reader = BufReader::new(stream.try_clone()?);
let writer = BufWriter::new(stream.try_clone()?);
Ok(TcpBackend {
Expand Down
31 changes: 15 additions & 16 deletions sw/deployer/src/sc64/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ pub struct DeviceInfo {

pub struct SerialDevice {
serial: serial2::SerialPort,
writer: std::io::BufWriter<serial2::SerialPort>,
unclog_buffer: std::collections::VecDeque<u8>,
poll_timeout: std::time::Duration,
read_timeout: std::time::Duration,
write_timeout: std::time::Duration,
io_timeout: std::time::Duration,
}

impl SerialDevice {
Expand All @@ -21,15 +21,16 @@ impl SerialDevice {
pub fn new(
port: &str,
poll_timeout: Option<std::time::Duration>,
read_timeout: Option<std::time::Duration>,
write_timeout: Option<std::time::Duration>,
io_timeout: Option<std::time::Duration>,
) -> std::io::Result<Self> {
let serial = serial2::SerialPort::open(port, 115_200)?;
let writer = std::io::BufWriter::with_capacity(Self::BUFFER_SIZE, serial.try_clone()?);
let mut device = Self {
serial: serial2::SerialPort::open(port, 115_200)?,
serial,
writer,
unclog_buffer: std::collections::VecDeque::new(),
poll_timeout: poll_timeout.unwrap_or(Self::DEFAULT_POLL_TIMEOUT),
read_timeout: read_timeout.unwrap_or(Self::DEFAULT_RW_TIMEOUT),
write_timeout: write_timeout.unwrap_or(Self::DEFAULT_RW_TIMEOUT),
io_timeout: io_timeout.unwrap_or(Self::DEFAULT_RW_TIMEOUT),
};
device.serial.set_read_timeout(device.poll_timeout)?;
device.serial.set_write_timeout(Self::WRITE_CHUNK_TIMEOUT)?;
Expand Down Expand Up @@ -73,14 +74,12 @@ impl SerialDevice {
Err(error) => match error.kind() {
std::io::ErrorKind::Interrupted
| std::io::ErrorKind::TimedOut
| std::io::ErrorKind::WouldBlock => {
return Ok(());
}
| std::io::ErrorKind::WouldBlock => {}
_ => return Err(error),
},
};
if timeout.elapsed() > self.read_timeout {
return Err(std::io::ErrorKind::TimedOut.into());
if timeout.elapsed() > std::time::Duration::from_millis(1) {
return Ok(());
}
}
}
Expand Down Expand Up @@ -128,14 +127,14 @@ impl std::io::Write for SerialDevice {
fn write(&mut self, buffer: &[u8]) -> std::io::Result<usize> {
let timeout = std::time::Instant::now();
loop {
match self.serial.write(buffer) {
match self.writer.write(buffer) {
Ok(bytes) => return Ok(bytes),
Err(error) => match error.kind() {
std::io::ErrorKind::TimedOut => self.unclog_pipe()?,
_ => return Err(error),
},
};
if timeout.elapsed() > self.write_timeout {
if timeout.elapsed() > self.io_timeout {
return Err(std::io::ErrorKind::TimedOut.into());
}
}
Expand All @@ -144,14 +143,14 @@ impl std::io::Write for SerialDevice {
fn flush(&mut self) -> std::io::Result<()> {
let timeout = std::time::Instant::now();
loop {
match self.serial.flush() {
match self.writer.flush() {
Ok(()) => return Ok(()),
Err(error) => match error.kind() {
std::io::ErrorKind::TimedOut => self.unclog_pipe()?,
_ => return Err(error),
},
};
if timeout.elapsed() > self.write_timeout {
if timeout.elapsed() > self.io_timeout {
return Err(std::io::ErrorKind::TimedOut.into());
}
}
Expand Down

0 comments on commit 3146cc8

Please sign in to comment.