mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-22 05:59:15 +01:00
serial refactor
This commit is contained in:
parent
6d460e83bd
commit
db9e9fa515
@ -45,12 +45,26 @@ module memory_dma (
|
|||||||
|
|
||||||
logic dma_start;
|
logic dma_start;
|
||||||
logic dma_stop;
|
logic dma_stop;
|
||||||
|
logic dma_stop_requested;
|
||||||
|
|
||||||
always_comb begin
|
always_comb begin
|
||||||
dma_start = dma_scb.start && !dma_scb.stop && !dma_scb.busy;
|
dma_start = dma_scb.start && !dma_scb.stop && !dma_scb.busy;
|
||||||
dma_stop = dma_scb.stop;
|
dma_stop = dma_scb.stop;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
always_ff @(posedge clk) begin
|
||||||
|
if (reset) begin
|
||||||
|
dma_stop_requested <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
if (dma_stop) begin
|
||||||
|
dma_stop_requested <= 1'b1;
|
||||||
|
end
|
||||||
|
if (dma_start) begin
|
||||||
|
dma_stop_requested <= 1'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
// Remaining counter and FIFO enable
|
// Remaining counter and FIFO enable
|
||||||
|
|
||||||
@ -197,7 +211,7 @@ module memory_dma (
|
|||||||
remaining <= dma_scb.transfer_length;
|
remaining <= dma_scb.transfer_length;
|
||||||
end
|
end
|
||||||
|
|
||||||
if ((mem_bus.write && rx_rdata_pop) || (!mem_bus.write && tx_wdata_push)) begin
|
if (!dma_stop_requested && ((mem_bus.write && rx_rdata_pop) || (!mem_bus.write && tx_wdata_push))) begin
|
||||||
remaining <= remaining - 1'd1;
|
remaining <= remaining - 1'd1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
36
sw/deployer/Cargo.lock
generated
36
sw/deployer/Cargo.lock
generated
@ -218,9 +218,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.101"
|
version = "1.0.103"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ac367972e516d45567c7eafc73d24e1c193dcf200a8d94e9db7b3d38b349572d"
|
checksum = "2755ff20a1d93490d26ba33a6f092a38a508398a5320df5d4b3014fcccce9410"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
@ -265,9 +265,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.7"
|
version = "4.5.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f"
|
checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@ -284,9 +284,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.7"
|
version = "4.5.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f"
|
checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@ -296,9 +296,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.5.5"
|
version = "4.5.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6"
|
checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@ -799,9 +799,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.21"
|
version = "0.4.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "loop9"
|
name = "loop9"
|
||||||
@ -906,9 +906,9 @@ checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-bigint"
|
name = "num-bigint"
|
||||||
version = "0.4.5"
|
version = "0.4.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7"
|
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
@ -1196,9 +1196,9 @@ checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rgb"
|
name = "rgb"
|
||||||
version = "0.8.37"
|
version = "0.8.40"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8"
|
checksum = "a7439be6844e40133eda024efd85bf07f59d0dd2f59b10c00dd6cfb92cc5c741"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
]
|
]
|
||||||
@ -1291,9 +1291,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serialport"
|
name = "serialport"
|
||||||
version = "4.3.0"
|
version = "4.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f5a15d0be940df84846264b09b51b10b931fb2f275becb80934e3568a016828"
|
checksum = "de7c4f0cce25b9b3518eea99618112f9ee4549f974480c8f43d3c06f03c131a0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
@ -1452,9 +1452,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unescaper"
|
name = "unescaper"
|
||||||
version = "0.1.4"
|
version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0adf6ad32eb5b3cadff915f7b770faaac8f7ff0476633aa29eb0d9584d889d34"
|
checksum = "c878a167baa8afd137494101a688ef8c67125089ff2249284bd2b5f9bfedb815"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
@ -8,7 +8,7 @@ documentation = "https://github.com/Polprzewodnikowy/SummerCart64"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = "0.4.38"
|
chrono = "0.4.38"
|
||||||
clap = { version = "4.5.7", features = ["derive"] }
|
clap = { version = "4.5.8", features = ["derive"] }
|
||||||
clap-num = "1.1.1"
|
clap-num = "1.1.1"
|
||||||
colored = "2.1.0"
|
colored = "2.1.0"
|
||||||
crc32fast = "1.4.2"
|
crc32fast = "1.4.2"
|
||||||
@ -24,7 +24,7 @@ panic-message = "0.3.0"
|
|||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
rust-ini = "0.18.0"
|
rust-ini = "0.18.0"
|
||||||
serial2 = "0.2.26"
|
serial2 = "0.2.26"
|
||||||
serialport = "4.3.0"
|
serialport = "4.4.0"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
|
@ -36,24 +36,24 @@ struct Wrapper {
|
|||||||
impl Wrapper {
|
impl Wrapper {
|
||||||
const DEFAULT_POLL_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(16);
|
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_RW_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(5);
|
||||||
const DEFAULT_CHUNKSIZE: usize = 4096;
|
const WRITE_CHUNK_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(100);
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
read_timeout: Option<std::time::Duration>,
|
read_timeout: Option<std::time::Duration>,
|
||||||
write_timeout: Option<std::time::Duration>,
|
write_timeout: Option<std::time::Duration>,
|
||||||
) -> std::io::Result<Wrapper> {
|
) -> std::io::Result<Self> {
|
||||||
let context = unsafe { libftdi1_sys::ftdi_new() };
|
let context = unsafe { libftdi1_sys::ftdi_new() };
|
||||||
if context.is_null() {
|
if context.is_null() {
|
||||||
return Err(std::io::ErrorKind::OutOfMemory.into());
|
return Err(std::io::ErrorKind::OutOfMemory.into());
|
||||||
}
|
}
|
||||||
let mut wrapper = Wrapper {
|
let mut wrapper = Self {
|
||||||
context,
|
context,
|
||||||
unclog_buffer: std::collections::VecDeque::new(),
|
unclog_buffer: std::collections::VecDeque::new(),
|
||||||
write_buffer: vec![],
|
write_buffer: vec![],
|
||||||
read_timeout: Wrapper::DEFAULT_RW_TIMEOUT,
|
read_timeout: Self::DEFAULT_RW_TIMEOUT,
|
||||||
write_timeout: Wrapper::DEFAULT_RW_TIMEOUT,
|
write_timeout: Self::DEFAULT_RW_TIMEOUT,
|
||||||
read_chunksize: Wrapper::DEFAULT_CHUNKSIZE,
|
read_chunksize: 4096,
|
||||||
write_chunksize: Wrapper::DEFAULT_CHUNKSIZE,
|
write_chunksize: 4096,
|
||||||
};
|
};
|
||||||
wrapper.set_timeouts(read_timeout, write_timeout)?;
|
wrapper.set_timeouts(read_timeout, write_timeout)?;
|
||||||
wrapper.read_data_set_chunksize(wrapper.read_chunksize)?;
|
wrapper.read_data_set_chunksize(wrapper.read_chunksize)?;
|
||||||
@ -62,7 +62,7 @@ impl Wrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn list_devices(vendor: u16, product: u16) -> std::io::Result<Vec<DeviceInfo>> {
|
fn list_devices(vendor: u16, product: u16) -> std::io::Result<Vec<DeviceInfo>> {
|
||||||
let wrapper = Wrapper::new(None, None)?;
|
let wrapper = Self::new(None, None)?;
|
||||||
|
|
||||||
let mut device_list: *mut libftdi1_sys::ftdi_device_list = std::ptr::null_mut();
|
let mut device_list: *mut libftdi1_sys::ftdi_device_list = std::ptr::null_mut();
|
||||||
let devices = unsafe {
|
let devices = unsafe {
|
||||||
@ -152,8 +152,8 @@ impl Wrapper {
|
|||||||
read_timeout: Option<std::time::Duration>,
|
read_timeout: Option<std::time::Duration>,
|
||||||
write_timeout: Option<std::time::Duration>,
|
write_timeout: Option<std::time::Duration>,
|
||||||
) -> std::io::Result<()> {
|
) -> std::io::Result<()> {
|
||||||
let read_timeout = read_timeout.unwrap_or(Wrapper::DEFAULT_RW_TIMEOUT);
|
let read_timeout = read_timeout.unwrap_or(Self::DEFAULT_RW_TIMEOUT);
|
||||||
let write_timeout = write_timeout.unwrap_or(Wrapper::DEFAULT_RW_TIMEOUT);
|
let write_timeout = write_timeout.unwrap_or(Self::DEFAULT_RW_TIMEOUT);
|
||||||
unsafe {
|
unsafe {
|
||||||
(*self.context).usb_read_timeout = i32::try_from(read_timeout.as_millis())
|
(*self.context).usb_read_timeout = i32::try_from(read_timeout.as_millis())
|
||||||
.map_err(|_| std::io::ErrorKind::InvalidInput)?;
|
.map_err(|_| std::io::ErrorKind::InvalidInput)?;
|
||||||
@ -236,7 +236,7 @@ impl Wrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_latency_timer(&mut self, latency: Option<std::time::Duration>) -> std::io::Result<()> {
|
fn set_latency_timer(&mut self, latency: Option<std::time::Duration>) -> std::io::Result<()> {
|
||||||
let latency = u8::try_from(latency.unwrap_or(Wrapper::DEFAULT_POLL_TIMEOUT).as_millis())
|
let latency = u8::try_from(latency.unwrap_or(Self::DEFAULT_POLL_TIMEOUT).as_millis())
|
||||||
.map_err(|_| std::io::ErrorKind::InvalidInput)?;
|
.map_err(|_| std::io::ErrorKind::InvalidInput)?;
|
||||||
match unsafe { libftdi1_sys::ftdi_set_latency_timer(self.context, latency) } {
|
match unsafe { libftdi1_sys::ftdi_set_latency_timer(self.context, latency) } {
|
||||||
0 => Ok(()),
|
0 => Ok(()),
|
||||||
@ -320,7 +320,9 @@ impl Wrapper {
|
|||||||
match self.read(&mut vec![0u8; self.read_chunksize]) {
|
match self.read(&mut vec![0u8; self.read_chunksize]) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(error) => match error.kind() {
|
Err(error) => match error.kind() {
|
||||||
std::io::ErrorKind::Interrupted | std::io::ErrorKind::WouldBlock => {
|
std::io::ErrorKind::Interrupted
|
||||||
|
| std::io::ErrorKind::TimedOut
|
||||||
|
| std::io::ErrorKind::WouldBlock => {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
_ => return Err(error),
|
_ => return Err(error),
|
||||||
@ -369,7 +371,7 @@ impl Wrapper {
|
|||||||
Vec::from(buffer).as_mut_ptr(),
|
Vec::from(buffer).as_mut_ptr(),
|
||||||
buffer.len() as i32,
|
buffer.len() as i32,
|
||||||
&mut transferred,
|
&mut transferred,
|
||||||
100,
|
Self::WRITE_CHUNK_TIMEOUT.as_millis() as u32,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
*written = transferred as usize;
|
*written = transferred as usize;
|
||||||
@ -469,7 +471,7 @@ impl FtdiDevice {
|
|||||||
wrapper.set_module_detach_mode(ModuleDetachMode::AutoDetachReattach);
|
wrapper.set_module_detach_mode(ModuleDetachMode::AutoDetachReattach);
|
||||||
wrapper.set_interface(InterfaceIndex::A)?;
|
wrapper.set_interface(InterfaceIndex::A)?;
|
||||||
|
|
||||||
const CHUNK_SIZE: usize = 64 * 1024;
|
const CHUNK_SIZE: usize = 16 * 1024;
|
||||||
|
|
||||||
wrapper.read_data_set_chunksize(CHUNK_SIZE)?;
|
wrapper.read_data_set_chunksize(CHUNK_SIZE)?;
|
||||||
wrapper.write_data_set_chunksize(CHUNK_SIZE)?;
|
wrapper.write_data_set_chunksize(CHUNK_SIZE)?;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::{error::Error, ftdi::FtdiDevice};
|
use super::{error::Error, ftdi::FtdiDevice, serial::SerialDevice};
|
||||||
use std::{
|
use std::{
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
@ -75,34 +75,58 @@ pub trait Backend {
|
|||||||
|
|
||||||
fn flush(&mut self) -> std::io::Result<()>;
|
fn flush(&mut self) -> std::io::Result<()>;
|
||||||
|
|
||||||
fn reset(&mut self) -> std::io::Result<()> {
|
fn discard_input(&mut self) -> std::io::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn discard_output(&mut self) -> std::io::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_dtr(&mut self, _value: bool) -> std::io::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_dsr(&mut self) -> std::io::Result<bool> {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
|
||||||
fn close(&mut self) {}
|
fn close(&mut self) {}
|
||||||
|
|
||||||
fn purge_incoming_data(&mut self) -> std::io::Result<()> {
|
fn reset(&mut self) -> std::io::Result<()> {
|
||||||
|
self.discard_output()?;
|
||||||
|
|
||||||
let timeout = Instant::now();
|
let timeout = Instant::now();
|
||||||
|
self.set_dtr(true)?;
|
||||||
loop {
|
loop {
|
||||||
match self.read(&mut vec![0; 1]) {
|
if self.read_dsr()? {
|
||||||
Ok(length) => match length {
|
break;
|
||||||
0 => return Ok(()),
|
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
Err(error) => match error.kind() {
|
|
||||||
std::io::ErrorKind::Interrupted
|
|
||||||
| std::io::ErrorKind::TimedOut
|
|
||||||
| std::io::ErrorKind::WouldBlock => return Ok(()),
|
|
||||||
_ => return Err(error),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
if timeout.elapsed() >= RESET_TIMEOUT {
|
if timeout.elapsed() > RESET_TIMEOUT {
|
||||||
return Err(std::io::Error::new(
|
return Err(std::io::Error::new(
|
||||||
std::io::ErrorKind::TimedOut,
|
std::io::ErrorKind::TimedOut,
|
||||||
"SC64 read buffer flush took too long",
|
"Couldn't reset SC64 device (on)",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.discard_input()?;
|
||||||
|
|
||||||
|
let timeout = Instant::now();
|
||||||
|
self.set_dtr(false)?;
|
||||||
|
loop {
|
||||||
|
if !self.read_dsr()? {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if timeout.elapsed() > RESET_TIMEOUT {
|
||||||
|
return Err(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::TimedOut,
|
||||||
|
"Couldn't reset SC64 device (off)",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_read_exact(&mut self, buffer: &mut [u8], block: bool) -> std::io::Result<Option<()>> {
|
fn try_read_exact(&mut self, buffer: &mut [u8], block: bool) -> std::io::Result<Option<()>> {
|
||||||
@ -196,7 +220,7 @@ pub trait Backend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct SerialBackend {
|
pub struct SerialBackend {
|
||||||
device: serial2::SerialPort,
|
device: SerialDevice,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Backend for SerialBackend {
|
impl Backend for SerialBackend {
|
||||||
@ -212,47 +236,32 @@ impl Backend for SerialBackend {
|
|||||||
self.device.flush()
|
self.device.flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset(&mut self) -> std::io::Result<()> {
|
fn discard_input(&mut self) -> std::io::Result<()> {
|
||||||
self.device.set_dtr(true)?;
|
self.device.discard_input()
|
||||||
let timeout = Instant::now();
|
}
|
||||||
loop {
|
|
||||||
self.device.discard_buffers()?;
|
|
||||||
if self.device.read_dsr()? {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if timeout.elapsed() > RESET_TIMEOUT {
|
|
||||||
return Err(std::io::Error::new(
|
|
||||||
std::io::ErrorKind::TimedOut,
|
|
||||||
"Couldn't reset SC64 device (on)",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.purge_incoming_data()?;
|
fn discard_output(&mut self) -> std::io::Result<()> {
|
||||||
|
self.device.discard_output()
|
||||||
|
}
|
||||||
|
|
||||||
self.device.set_dtr(false)?;
|
fn set_dtr(&mut self, value: bool) -> std::io::Result<()> {
|
||||||
let timeout = Instant::now();
|
self.device.set_dtr(value)
|
||||||
loop {
|
}
|
||||||
if !self.device.read_dsr()? {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if timeout.elapsed() > RESET_TIMEOUT {
|
|
||||||
return Err(std::io::Error::new(
|
|
||||||
std::io::ErrorKind::TimedOut,
|
|
||||||
"Couldn't reset SC64 device (off)",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
fn read_dsr(&mut self) -> std::io::Result<bool> {
|
||||||
|
self.device.read_dsr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_serial_backend(port: &str) -> std::io::Result<SerialBackend> {
|
fn new_serial_backend(port: &str) -> std::io::Result<SerialBackend> {
|
||||||
let mut serial = serial2::SerialPort::open(port, 115_200)?;
|
Ok(SerialBackend {
|
||||||
serial.set_read_timeout(POLL_TIMEOUT)?;
|
device: SerialDevice::new(
|
||||||
serial.set_write_timeout(WRITE_TIMEOUT)?;
|
port,
|
||||||
Ok(SerialBackend { device: serial })
|
Some(POLL_TIMEOUT),
|
||||||
|
Some(READ_TIMEOUT),
|
||||||
|
Some(WRITE_TIMEOUT),
|
||||||
|
)?,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FtdiBackend {
|
struct FtdiBackend {
|
||||||
@ -272,40 +281,20 @@ impl Backend for FtdiBackend {
|
|||||||
self.device.flush()
|
self.device.flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset(&mut self) -> std::io::Result<()> {
|
fn discard_input(&mut self) -> std::io::Result<()> {
|
||||||
self.device.discard_output()?;
|
self.device.discard_input()
|
||||||
|
}
|
||||||
|
|
||||||
let timeout = Instant::now();
|
fn discard_output(&mut self) -> std::io::Result<()> {
|
||||||
self.device.set_dtr(true)?;
|
self.device.discard_output()
|
||||||
loop {
|
}
|
||||||
if self.device.read_dsr()? {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if timeout.elapsed() > RESET_TIMEOUT {
|
|
||||||
return Err(std::io::Error::new(
|
|
||||||
std::io::ErrorKind::TimedOut,
|
|
||||||
"Couldn't reset SC64 device (on)",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.device.discard_input()?;
|
fn set_dtr(&mut self, value: bool) -> std::io::Result<()> {
|
||||||
|
self.device.set_dtr(value)
|
||||||
|
}
|
||||||
|
|
||||||
let timeout = Instant::now();
|
fn read_dsr(&mut self) -> std::io::Result<bool> {
|
||||||
self.device.set_dtr(false)?;
|
self.device.read_dsr()
|
||||||
loop {
|
|
||||||
if !self.device.read_dsr()? {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if timeout.elapsed() > RESET_TIMEOUT {
|
|
||||||
return Err(std::io::Error::new(
|
|
||||||
std::io::ErrorKind::TimedOut,
|
|
||||||
"Couldn't reset SC64 device (off)",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -580,18 +569,14 @@ pub fn list_local_devices() -> Result<Vec<DeviceInfo>, Error> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(list) = serialport::available_ports() {
|
if let Ok(list) = SerialDevice::list(SC64_VID, SC64_PID) {
|
||||||
for device in list.into_iter() {
|
for device in list.into_iter() {
|
||||||
if let serialport::SerialPortType::UsbPort(i) = device.port_type {
|
if device.serial.starts_with(SC64_SID) {
|
||||||
if let Some(serial) = i.serial_number {
|
devices.push(DeviceInfo {
|
||||||
if i.vid == SC64_VID && i.pid == SC64_PID && serial.starts_with(SC64_SID) {
|
backend: BackendType::Serial,
|
||||||
devices.push(DeviceInfo {
|
port: format!("{SERIAL_PREFIX}{}", device.port),
|
||||||
backend: BackendType::Serial,
|
serial: device.serial,
|
||||||
port: format!("{SERIAL_PREFIX}{}", device.port_name),
|
});
|
||||||
serial,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ mod error;
|
|||||||
pub mod firmware;
|
pub mod firmware;
|
||||||
mod ftdi;
|
mod ftdi;
|
||||||
mod link;
|
mod link;
|
||||||
|
mod serial;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
mod time;
|
mod time;
|
||||||
mod types;
|
mod types;
|
||||||
|
155
sw/deployer/src/sc64/serial.rs
Normal file
155
sw/deployer/src/sc64/serial.rs
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
pub struct DeviceInfo {
|
||||||
|
pub port: String,
|
||||||
|
pub serial: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SerialDevice {
|
||||||
|
serial: serial2::SerialPort,
|
||||||
|
unclog_buffer: std::collections::VecDeque<u8>,
|
||||||
|
poll_timeout: std::time::Duration,
|
||||||
|
read_timeout: std::time::Duration,
|
||||||
|
write_timeout: std::time::Duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SerialDevice {
|
||||||
|
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 WRITE_CHUNK_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(100);
|
||||||
|
const BUFFER_SIZE: usize = 16 * 1024;
|
||||||
|
|
||||||
|
pub fn new(
|
||||||
|
port: &str,
|
||||||
|
poll_timeout: Option<std::time::Duration>,
|
||||||
|
read_timeout: Option<std::time::Duration>,
|
||||||
|
write_timeout: Option<std::time::Duration>,
|
||||||
|
) -> std::io::Result<Self> {
|
||||||
|
let mut device = Self {
|
||||||
|
serial: serial2::SerialPort::open(port, 115_200)?,
|
||||||
|
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),
|
||||||
|
};
|
||||||
|
device.serial.set_read_timeout(device.poll_timeout)?;
|
||||||
|
device.serial.set_write_timeout(Self::WRITE_CHUNK_TIMEOUT)?;
|
||||||
|
Ok(device)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn list(vendor: u16, product: u16) -> std::io::Result<Vec<DeviceInfo>> {
|
||||||
|
let mut devices = vec![];
|
||||||
|
|
||||||
|
for port in serialport::available_ports()? {
|
||||||
|
if let serialport::SerialPortType::UsbPort(info) = port.port_type {
|
||||||
|
if info.vid == vendor && info.pid == product && info.serial_number.is_some() {
|
||||||
|
devices.push(DeviceInfo {
|
||||||
|
port: port.port_name,
|
||||||
|
serial: info.serial_number.unwrap(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(devices)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_dtr(&mut self, value: bool) -> std::io::Result<()> {
|
||||||
|
self.serial.set_dtr(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_dsr(&mut self) -> std::io::Result<bool> {
|
||||||
|
self.serial.read_dsr()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn discard_input(&mut self) -> std::io::Result<()> {
|
||||||
|
let timeout = std::time::Instant::now();
|
||||||
|
self.serial.discard_input_buffer()?;
|
||||||
|
loop {
|
||||||
|
match self.serial.read(&mut vec![0u8; Self::BUFFER_SIZE]) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(error) => match error.kind() {
|
||||||
|
std::io::ErrorKind::Interrupted
|
||||||
|
| std::io::ErrorKind::TimedOut
|
||||||
|
| std::io::ErrorKind::WouldBlock => {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
_ => return Err(error),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if timeout.elapsed() > self.read_timeout {
|
||||||
|
return Err(std::io::ErrorKind::TimedOut.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn discard_output(&mut self) -> std::io::Result<()> {
|
||||||
|
self.serial.discard_output_buffer()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unclog_pipe(&mut self) -> std::io::Result<()> {
|
||||||
|
let mut buffer = vec![0u8; Self::BUFFER_SIZE];
|
||||||
|
let read = match self.serial.read(&mut buffer) {
|
||||||
|
Ok(read) => read,
|
||||||
|
Err(error) => match error.kind() {
|
||||||
|
std::io::ErrorKind::Interrupted
|
||||||
|
| std::io::ErrorKind::TimedOut
|
||||||
|
| std::io::ErrorKind::WouldBlock => 0,
|
||||||
|
_ => return Err(error),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
self.unclog_buffer.extend(buffer[0..read].iter());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::io::Read for SerialDevice {
|
||||||
|
fn read(&mut self, buffer: &mut [u8]) -> std::io::Result<usize> {
|
||||||
|
if buffer.is_empty() {
|
||||||
|
Err(std::io::ErrorKind::InvalidInput.into())
|
||||||
|
} else if self.unclog_buffer.is_empty() {
|
||||||
|
self.serial.read(buffer)
|
||||||
|
} else {
|
||||||
|
for (index, item) in buffer.iter_mut().enumerate() {
|
||||||
|
if let Some(byte) = self.unclog_buffer.pop_front() {
|
||||||
|
*item = byte;
|
||||||
|
} else {
|
||||||
|
return Ok(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(buffer.len())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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 {
|
||||||
|
return Err(std::io::ErrorKind::TimedOut.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> std::io::Result<()> {
|
||||||
|
let timeout = std::time::Instant::now();
|
||||||
|
loop {
|
||||||
|
match self.serial.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 {
|
||||||
|
return Err(std::io::ErrorKind::TimedOut.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user