mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-23 22:29:15 +01:00
[SC64][SW] Fix USB reset procedure (I/O buffer purge)
This commit is contained in:
parent
4a50e33acd
commit
3146cc8c99
@ -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());
|
||||
@ -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 {
|
||||
@ -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(())
|
||||
}
|
||||
|
||||
@ -330,6 +319,14 @@ 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]) {
|
||||
@ -337,14 +334,12 @@ impl Wrapper {
|
||||
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(());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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}"
|
||||
))),
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
@ -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)?;
|
||||
|
@ -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>;
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
@ -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))?,
|
||||
})
|
||||
}
|
||||
|
||||
@ -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))?,
|
||||
})
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
@ -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 {
|
||||
@ -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)?;
|
||||
@ -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(());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user