mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-22 05:59:15 +01:00
libftdi support
This commit is contained in:
parent
acc3e588d8
commit
346c65fc9c
790
sw/deployer/Cargo.lock
generated
790
sw/deployer/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -7,21 +7,22 @@ description = "SummerCart64 loader and control software"
|
||||
documentation = "https://github.com/Polprzewodnikowy/SummerCart64"
|
||||
|
||||
[dependencies]
|
||||
chrono = "0.4.23"
|
||||
clap = { version = "4.1.6", features = ["derive"] }
|
||||
clap-num = "1.0.2"
|
||||
colored = "2.0.0"
|
||||
crc32fast = "1.3.2"
|
||||
ctrlc = "3.2.5"
|
||||
encoding_rs = "0.8.32"
|
||||
chrono = "0.4.38"
|
||||
clap = { version = "4.5.7", features = ["derive"] }
|
||||
clap-num = "1.1.1"
|
||||
colored = "2.1.0"
|
||||
crc32fast = "1.4.2"
|
||||
ctrlc = "3.4.4"
|
||||
encoding_rs = "0.8.34"
|
||||
hex = "0.4.3"
|
||||
image = "0.24.5"
|
||||
image = "0.25.1"
|
||||
include-flate = { version = "0.2.0", features = ["stable"] }
|
||||
libftdi1-sys = "1.1.3"
|
||||
md5 = "0.7.0"
|
||||
panic-message = "0.3.0"
|
||||
rand = "0.8.5"
|
||||
rust-ini = "0.18.0"
|
||||
serial2 = "0.2.20"
|
||||
serial2 = "0.2.26"
|
||||
serialport = "4.3.0"
|
||||
|
||||
[profile.release]
|
||||
|
@ -350,7 +350,13 @@ fn handle_list_command() -> Result<(), sc64::Error> {
|
||||
|
||||
println!("{}", "Found devices:".bold());
|
||||
for (i, d) in devices.iter().enumerate() {
|
||||
println!(" {i}: [{}] at port [{}]", d.serial_number, d.port);
|
||||
let index = i + 1;
|
||||
println!(
|
||||
" {index}: [{}] at port [{}] (using \"{}\" backend)",
|
||||
d.serial.bold(),
|
||||
d.port.bold(),
|
||||
d.backend.to_string().bold()
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -1,3 +1,4 @@
|
||||
use super::ftdi::FtdiError;
|
||||
use std::fmt::{Display, Formatter, Result};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -32,3 +33,9 @@ impl From<serialport::Error> for Error {
|
||||
Error::new(format!("SerialPort error: {}", value.description).as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FtdiError> for Error {
|
||||
fn from(value: FtdiError) -> Self {
|
||||
Error::new(format!("libftdi error: {}", value.description).as_str())
|
||||
}
|
||||
}
|
||||
|
227
sw/deployer/src/sc64/ftdi.rs
Normal file
227
sw/deployer/src/sc64/ftdi.rs
Normal file
@ -0,0 +1,227 @@
|
||||
pub struct FtdiError {
|
||||
pub description: String,
|
||||
}
|
||||
|
||||
impl FtdiError {
|
||||
fn malloc() -> FtdiError {
|
||||
FtdiError {
|
||||
description: format!("Couldn't allocate memory for the context"),
|
||||
}
|
||||
}
|
||||
|
||||
fn libftdi(context: *mut libftdi1_sys::ftdi_context) -> FtdiError {
|
||||
let raw = unsafe { std::ffi::CStr::from_ptr(libftdi1_sys::ftdi_get_error_string(context)) };
|
||||
FtdiError {
|
||||
description: format!("{}", raw.to_str().unwrap_or("Unknown error")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FtdiError> for std::io::Error {
|
||||
fn from(value: FtdiError) -> Self {
|
||||
return Self::new(std::io::ErrorKind::Other, value.description);
|
||||
}
|
||||
}
|
||||
|
||||
struct Context {
|
||||
context: *mut libftdi1_sys::ftdi_context,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
fn new() -> Result<Context, FtdiError> {
|
||||
let ctx = unsafe { libftdi1_sys::ftdi_new() };
|
||||
if ctx.is_null() {
|
||||
return Err(FtdiError::malloc());
|
||||
}
|
||||
let context = Context { context: ctx };
|
||||
let result = unsafe {
|
||||
libftdi1_sys::ftdi_set_interface(
|
||||
context.get(),
|
||||
libftdi1_sys::ftdi_interface::INTERFACE_A,
|
||||
)
|
||||
};
|
||||
context.check_result(result)?;
|
||||
Ok(context)
|
||||
}
|
||||
|
||||
fn get(&self) -> *mut libftdi1_sys::ftdi_context {
|
||||
return self.context;
|
||||
}
|
||||
|
||||
fn check_result(&self, result: i32) -> Result<(), FtdiError> {
|
||||
if result < 0 {
|
||||
return Err(FtdiError::libftdi(self.get()));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Context {
|
||||
fn drop(&mut self) {
|
||||
unsafe { libftdi1_sys::ftdi_free(self.get()) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FtdiDevice {
|
||||
context: Context,
|
||||
read_timeout: std::time::Duration,
|
||||
write_timeout: std::time::Duration,
|
||||
}
|
||||
|
||||
impl FtdiDevice {
|
||||
pub fn open(
|
||||
port: &str,
|
||||
read_timeout: std::time::Duration,
|
||||
write_timeout: std::time::Duration,
|
||||
) -> Result<FtdiDevice, FtdiError> {
|
||||
let context = Context::new()?;
|
||||
unsafe {
|
||||
let mode = libftdi1_sys::ftdi_module_detach_mode::AUTO_DETACH_REATACH_SIO_MODULE;
|
||||
(*context.get()).module_detach_mode = mode;
|
||||
}
|
||||
let description = std::ffi::CString::new(port).unwrap_or_default().into_raw();
|
||||
let result = unsafe { libftdi1_sys::ftdi_usb_open_string(context.get(), description) };
|
||||
context.check_result(result)?;
|
||||
let result = unsafe { libftdi1_sys::ftdi_set_latency_timer(context.get(), 1) };
|
||||
context.check_result(result)?;
|
||||
Ok(FtdiDevice {
|
||||
context,
|
||||
read_timeout,
|
||||
write_timeout,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_dtr(&self, value: bool) -> Result<(), FtdiError> {
|
||||
let state = if value { 1 } else { 0 };
|
||||
let result = unsafe { libftdi1_sys::ftdi_setdtr(self.context.get(), state) };
|
||||
self.context.check_result(result)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_dsr(&self) -> Result<bool, FtdiError> {
|
||||
const DSR_BIT: u16 = 1 << 5;
|
||||
let mut status: u16 = 0;
|
||||
let result = unsafe {
|
||||
libftdi1_sys::ftdi_poll_modem_status(
|
||||
self.context.get(),
|
||||
std::slice::from_mut(&mut status).as_mut_ptr(),
|
||||
)
|
||||
};
|
||||
self.context.check_result(result)?;
|
||||
Ok((status & DSR_BIT) != 0)
|
||||
}
|
||||
|
||||
pub fn read(&self, data: &mut [u8]) -> std::io::Result<usize> {
|
||||
let timeout = std::time::Instant::now();
|
||||
loop {
|
||||
let result = unsafe {
|
||||
libftdi1_sys::ftdi_read_data(
|
||||
self.context.get(),
|
||||
data.as_mut_ptr(),
|
||||
data.len() as i32,
|
||||
)
|
||||
};
|
||||
self.context.check_result(result)?;
|
||||
if result > 0 {
|
||||
return Ok(result as usize);
|
||||
}
|
||||
if timeout.elapsed() > self.read_timeout {
|
||||
return Err(std::io::ErrorKind::TimedOut.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&self, data: &[u8]) -> std::io::Result<usize> {
|
||||
let timeout = std::time::Instant::now();
|
||||
loop {
|
||||
let result = unsafe {
|
||||
libftdi1_sys::ftdi_write_data(self.context.get(), data.as_ptr(), data.len() as i32)
|
||||
};
|
||||
self.context.check_result(result)?;
|
||||
if result > 0 {
|
||||
return Ok(result as usize);
|
||||
}
|
||||
if timeout.elapsed() > self.write_timeout {
|
||||
return Err(std::io::ErrorKind::TimedOut.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_all(&self, data: &[u8]) -> std::io::Result<()> {
|
||||
let mut data = data;
|
||||
while !data.is_empty() {
|
||||
let written = self.write(data)?;
|
||||
data = &data[written..];
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn discard_buffers(&self) -> std::io::Result<()> {
|
||||
let result = unsafe { libftdi1_sys::ftdi_tcioflush(self.context.get()) };
|
||||
self.context.check_result(result)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for FtdiDevice {
|
||||
fn drop(&mut self) {
|
||||
unsafe { libftdi1_sys::ftdi_usb_close(self.context.get()) };
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FtdiDeviceInfo {
|
||||
pub port: String,
|
||||
pub serial: String,
|
||||
}
|
||||
|
||||
pub fn list_ftdi_devices(vendor: u16, product: u16) -> Result<Vec<FtdiDeviceInfo>, FtdiError> {
|
||||
let context = Context::new()?;
|
||||
|
||||
let mut device_list: *mut libftdi1_sys::ftdi_device_list = std::ptr::null_mut();
|
||||
let result = unsafe {
|
||||
libftdi1_sys::ftdi_usb_find_all(
|
||||
context.get(),
|
||||
&mut device_list,
|
||||
vendor as i32,
|
||||
product as i32,
|
||||
)
|
||||
};
|
||||
context.check_result(result)?;
|
||||
|
||||
let mut list: Vec<FtdiDeviceInfo> = vec![];
|
||||
|
||||
let mut serial = [0i8; 128];
|
||||
|
||||
let mut device = device_list;
|
||||
let mut index = 0;
|
||||
while !device.is_null() {
|
||||
let result = unsafe {
|
||||
libftdi1_sys::ftdi_usb_get_strings(
|
||||
context.get(),
|
||||
(*device).dev,
|
||||
std::ptr::null_mut(),
|
||||
0,
|
||||
std::ptr::null_mut(),
|
||||
0,
|
||||
serial.as_mut_ptr(),
|
||||
serial.len() as i32,
|
||||
)
|
||||
};
|
||||
|
||||
if let Ok(()) = context.check_result(result) {
|
||||
list.push(FtdiDeviceInfo {
|
||||
port: format!("i:0x{vendor:04X}:0x{product:04X}:{index}"),
|
||||
serial: unsafe { std::ffi::CStr::from_ptr(serial.as_ptr()) }
|
||||
.to_string_lossy()
|
||||
.into_owned(),
|
||||
});
|
||||
}
|
||||
|
||||
device = unsafe { (*device).next };
|
||||
index += 1;
|
||||
}
|
||||
|
||||
unsafe { libftdi1_sys::ftdi_list_free(&mut device_list) }
|
||||
|
||||
Ok(list)
|
||||
}
|
@ -1,10 +1,13 @@
|
||||
use super::error::Error;
|
||||
use super::{
|
||||
error::Error,
|
||||
ftdi::{list_ftdi_devices, FtdiDevice, FtdiError},
|
||||
};
|
||||
use serial2::SerialPort;
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
fmt::Display,
|
||||
io::{BufReader, BufWriter, ErrorKind, Read, Write},
|
||||
net::TcpStream,
|
||||
thread,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
@ -56,74 +59,54 @@ pub struct Packet {
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
pub struct Serial {
|
||||
serial: SerialPort,
|
||||
}
|
||||
const SERIAL_PREFIX: &str = "serial://";
|
||||
const FTDI_PREFIX: &str = "ftdi://";
|
||||
|
||||
impl Serial {
|
||||
fn reset(&self) -> Result<(), Error> {
|
||||
const RESET_WAIT_DURATION: Duration = Duration::from_millis(10);
|
||||
const RESET_RETRY_COUNT: i32 = 100;
|
||||
const FLUSH_TIMEOUT: Duration = Duration::from_secs(1);
|
||||
const RESET_TIMEOUT: Duration = Duration::from_secs(1);
|
||||
const POLL_TIMEOUT: Duration = Duration::from_millis(1);
|
||||
const READ_TIMEOUT: Duration = Duration::from_secs(5);
|
||||
const WRITE_TIMEOUT: Duration = Duration::from_secs(5);
|
||||
|
||||
self.serial.set_dtr(true)?;
|
||||
for n in 0..=RESET_RETRY_COUNT {
|
||||
self.serial.discard_buffers()?;
|
||||
thread::sleep(RESET_WAIT_DURATION);
|
||||
if self.serial.read_dsr()? {
|
||||
break;
|
||||
}
|
||||
if n == RESET_RETRY_COUNT {
|
||||
return Err(Error::new("Couldn't reset SC64 device (on)"));
|
||||
}
|
||||
}
|
||||
pub trait Backend {
|
||||
fn reset(&mut self) -> Result<(), Error>;
|
||||
|
||||
let flush_timeout = Instant::now();
|
||||
fn close(&self);
|
||||
|
||||
fn read(&mut self, buffer: &mut [u8]) -> std::io::Result<usize>;
|
||||
|
||||
fn write(&mut self, buffer: &[u8]) -> std::io::Result<()>;
|
||||
|
||||
fn flush(&mut self) -> std::io::Result<()>;
|
||||
|
||||
fn purge_incoming_data(&mut self) -> std::io::Result<()> {
|
||||
let timeout = Instant::now();
|
||||
loop {
|
||||
match self.serial.read(&mut vec![0; 1]) {
|
||||
match self.read(&mut vec![0; 1]) {
|
||||
Ok(length) => match length {
|
||||
0 => break,
|
||||
0 => return Ok(()),
|
||||
_ => {}
|
||||
},
|
||||
Err(error) => match error.kind() {
|
||||
ErrorKind::TimedOut => break,
|
||||
_ => {
|
||||
return Err(Error::new(
|
||||
format!("Couldn't flush SC64 serial buffer: {error}").as_str(),
|
||||
))
|
||||
}
|
||||
ErrorKind::TimedOut => return Ok(()),
|
||||
_ => return Err(error),
|
||||
},
|
||||
}
|
||||
if flush_timeout.elapsed() >= FLUSH_TIMEOUT {
|
||||
return Err(Error::new("SC64 serial buffer flush took too long"));
|
||||
if timeout.elapsed() >= RESET_TIMEOUT {
|
||||
return Err(std::io::Error::new(
|
||||
ErrorKind::TimedOut,
|
||||
"SC64 read buffer flush took too long",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
self.serial.set_dtr(false)?;
|
||||
for n in 0..=RESET_RETRY_COUNT {
|
||||
thread::sleep(RESET_WAIT_DURATION);
|
||||
if !self.serial.read_dsr()? {
|
||||
break;
|
||||
}
|
||||
if n == RESET_RETRY_COUNT {
|
||||
return Err(Error::new("Couldn't reset SC64 device (off)"));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_data(&self, buffer: &mut [u8], block: bool) -> Result<Option<()>, Error> {
|
||||
let timeout = Instant::now();
|
||||
fn try_read(&mut self, buffer: &mut [u8], block: bool) -> Result<Option<()>, Error> {
|
||||
let mut position = 0;
|
||||
let length = buffer.len();
|
||||
let timeout = Instant::now();
|
||||
while position < length {
|
||||
if timeout.elapsed() > Duration::from_secs(10) {
|
||||
return Err(Error::new("Serial read timeout"));
|
||||
}
|
||||
match self.serial.read(&mut buffer[position..length]) {
|
||||
Ok(0) => return Err(Error::new("Unexpected end of serial data")),
|
||||
match self.read(&mut buffer[position..length]) {
|
||||
Ok(0) => return Err(Error::new("Unexpected end of stream data")),
|
||||
Ok(bytes) => position += bytes,
|
||||
Err(error) => match error.kind() {
|
||||
ErrorKind::Interrupted | ErrorKind::TimedOut | ErrorKind::WouldBlock => {
|
||||
@ -134,42 +117,47 @@ impl Serial {
|
||||
_ => return Err(error.into()),
|
||||
},
|
||||
}
|
||||
if timeout.elapsed() > READ_TIMEOUT {
|
||||
return Err(Error::new("Read timeout"));
|
||||
}
|
||||
}
|
||||
Ok(Some(()))
|
||||
}
|
||||
|
||||
fn read_exact(&self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||
match self.read_data(buffer, true)? {
|
||||
fn try_read_header(&mut self, block: bool) -> Result<Option<[u8; 4]>, Error> {
|
||||
let mut header = [0u8; 4];
|
||||
Ok(self.try_read(&mut header, block)?.map(|_| header))
|
||||
}
|
||||
|
||||
fn read_exact(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||
match self.try_read(buffer, true)? {
|
||||
Some(()) => Ok(()),
|
||||
None => Err(Error::new("Unexpected end of serial data")),
|
||||
None => Err(Error::new("Unexpected end of data")),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_header(&self, block: bool) -> Result<Option<[u8; 4]>, Error> {
|
||||
let mut header = [0u8; 4];
|
||||
Ok(self.read_data(&mut header, block)?.map(|_| header))
|
||||
}
|
||||
fn send_command(&mut self, command: &Command) -> Result<(), Error> {
|
||||
self.write(b"CMD")?;
|
||||
self.write(&command.id.to_be_bytes())?;
|
||||
|
||||
pub fn send_command(&self, command: &Command) -> Result<(), Error> {
|
||||
self.serial.write_all(b"CMD")?;
|
||||
self.serial.write_all(&command.id.to_be_bytes())?;
|
||||
self.serial.write_all(&command.args[0].to_be_bytes())?;
|
||||
self.serial.write_all(&command.args[1].to_be_bytes())?;
|
||||
self.write(&command.args[0].to_be_bytes())?;
|
||||
self.write(&command.args[1].to_be_bytes())?;
|
||||
|
||||
self.serial.write_all(&command.data)?;
|
||||
self.write(&command.data)?;
|
||||
|
||||
self.serial.flush()?;
|
||||
self.flush()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn process_incoming_data(
|
||||
&self,
|
||||
fn process_incoming_data(
|
||||
&mut self,
|
||||
data_type: DataType,
|
||||
packets: &mut VecDeque<Packet>,
|
||||
) -> Result<Option<Response>, Error> {
|
||||
let block = matches!(data_type, DataType::Response);
|
||||
while let Some(header) = self.read_header(block)? {
|
||||
|
||||
while let Some(header) = self.try_read_header(block)? {
|
||||
let (packet_token, error) = (match &header[0..3] {
|
||||
b"CMP" => Ok((false, false)),
|
||||
b"PKT" => Ok((true, false)),
|
||||
@ -200,48 +188,115 @@ impl Serial {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_serial(port: &str) -> Result<Serial, Error> {
|
||||
let mut serial = SerialPort::open(port, 115_200)?;
|
||||
serial.set_write_timeout(Duration::from_secs(10))?;
|
||||
serial.set_read_timeout(Duration::from_millis(10))?;
|
||||
let backend = Serial { serial };
|
||||
backend.reset()?;
|
||||
Ok(backend)
|
||||
}
|
||||
|
||||
trait Backend {
|
||||
fn send_command(&mut self, command: &Command) -> Result<(), Error>;
|
||||
fn process_incoming_data(
|
||||
&mut self,
|
||||
data_type: DataType,
|
||||
packets: &mut VecDeque<Packet>,
|
||||
) -> Result<Option<Response>, Error>;
|
||||
fn close(&self) {}
|
||||
}
|
||||
|
||||
struct SerialBackend {
|
||||
inner: Serial,
|
||||
pub struct SerialBackend {
|
||||
device: SerialPort,
|
||||
}
|
||||
|
||||
impl Backend for SerialBackend {
|
||||
fn send_command(&mut self, command: &Command) -> Result<(), Error> {
|
||||
self.inner.send_command(command)
|
||||
fn reset(&mut self) -> Result<(), Error> {
|
||||
self.device.set_dtr(true)?;
|
||||
let timeout = Instant::now();
|
||||
loop {
|
||||
self.device.discard_buffers()?;
|
||||
if self.device.read_dsr()? {
|
||||
break;
|
||||
}
|
||||
if timeout.elapsed() > RESET_TIMEOUT {
|
||||
return Err(Error::new("Couldn't reset SC64 device (on)"));
|
||||
}
|
||||
}
|
||||
|
||||
self.purge_incoming_data()?;
|
||||
|
||||
self.device.set_dtr(false)?;
|
||||
let timeout = Instant::now();
|
||||
loop {
|
||||
if !self.device.read_dsr()? {
|
||||
break;
|
||||
}
|
||||
if timeout.elapsed() > RESET_TIMEOUT {
|
||||
return Err(Error::new("Couldn't reset SC64 device (off)"));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_incoming_data(
|
||||
&mut self,
|
||||
data_type: DataType,
|
||||
packets: &mut VecDeque<Packet>,
|
||||
) -> Result<Option<Response>, Error> {
|
||||
self.inner.process_incoming_data(data_type, packets)
|
||||
fn close(&self) {}
|
||||
|
||||
fn read(&mut self, buffer: &mut [u8]) -> std::io::Result<usize> {
|
||||
self.device.read(buffer)
|
||||
}
|
||||
|
||||
fn write(&mut self, buffer: &[u8]) -> std::io::Result<()> {
|
||||
self.device.write_all(buffer)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
self.device.flush()
|
||||
}
|
||||
}
|
||||
|
||||
fn new_serial_backend(port: &str) -> Result<SerialBackend, Error> {
|
||||
let backend = SerialBackend {
|
||||
inner: new_serial(port)?,
|
||||
};
|
||||
Ok(backend)
|
||||
fn new_serial_backend(port: &str) -> std::io::Result<SerialBackend> {
|
||||
let mut serial = SerialPort::open(port, 115_200)?;
|
||||
serial.set_read_timeout(POLL_TIMEOUT)?;
|
||||
serial.set_write_timeout(WRITE_TIMEOUT)?;
|
||||
Ok(SerialBackend { device: serial })
|
||||
}
|
||||
|
||||
struct FtdiBackend {
|
||||
device: FtdiDevice,
|
||||
}
|
||||
|
||||
impl Backend for FtdiBackend {
|
||||
fn reset(&mut self) -> Result<(), Error> {
|
||||
self.device.set_dtr(true)?;
|
||||
let timeout = Instant::now();
|
||||
loop {
|
||||
self.device.discard_buffers()?;
|
||||
if self.device.read_dsr()? {
|
||||
break;
|
||||
}
|
||||
if timeout.elapsed() > RESET_TIMEOUT {
|
||||
return Err(Error::new("Couldn't reset SC64 device (on)"));
|
||||
}
|
||||
}
|
||||
|
||||
self.purge_incoming_data()?;
|
||||
|
||||
self.device.set_dtr(false)?;
|
||||
let timeout = Instant::now();
|
||||
loop {
|
||||
if !self.device.read_dsr()? {
|
||||
break;
|
||||
}
|
||||
if timeout.elapsed() > RESET_TIMEOUT {
|
||||
return Err(Error::new("Couldn't reset SC64 device (off)"));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn close(&self) {}
|
||||
|
||||
fn read(&mut self, buffer: &mut [u8]) -> std::io::Result<usize> {
|
||||
self.device.read(buffer)
|
||||
}
|
||||
|
||||
fn write(&mut self, buffer: &[u8]) -> std::io::Result<()> {
|
||||
self.device.write_all(buffer)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn new_ftdi_backend(port: &str) -> Result<FtdiBackend, FtdiError> {
|
||||
Ok(FtdiBackend {
|
||||
device: FtdiDevice::open(port, POLL_TIMEOUT, WRITE_TIMEOUT)?,
|
||||
})
|
||||
}
|
||||
|
||||
struct TcpBackend {
|
||||
@ -250,58 +305,40 @@ struct TcpBackend {
|
||||
writer: BufWriter<TcpStream>,
|
||||
}
|
||||
|
||||
impl TcpBackend {
|
||||
fn read_data(&mut self, buffer: &mut [u8], block: bool) -> Result<Option<()>, Error> {
|
||||
let timeout = Instant::now();
|
||||
let mut position = 0;
|
||||
let length = buffer.len();
|
||||
while position < length {
|
||||
if timeout.elapsed() > Duration::from_secs(10) {
|
||||
return Err(Error::new("Stream read timeout"));
|
||||
}
|
||||
match self.reader.read(&mut buffer[position..length]) {
|
||||
Ok(0) => return Err(Error::new("Unexpected end of stream data")),
|
||||
Ok(bytes) => position += bytes,
|
||||
Err(error) => match error.kind() {
|
||||
ErrorKind::Interrupted | ErrorKind::TimedOut | ErrorKind::WouldBlock => {
|
||||
if !block && position == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
_ => return Err(error.into()),
|
||||
},
|
||||
}
|
||||
}
|
||||
Ok(Some(()))
|
||||
}
|
||||
|
||||
fn read_exact(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||
match self.read_data(buffer, true)? {
|
||||
Some(()) => Ok(()),
|
||||
None => Err(Error::new("Unexpected end of stream data")),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_header(&mut self, block: bool) -> Result<Option<[u8; 4]>, Error> {
|
||||
let mut header = [0u8; 4];
|
||||
Ok(self.read_data(&mut header, block)?.map(|_| header))
|
||||
}
|
||||
}
|
||||
|
||||
impl Backend for TcpBackend {
|
||||
fn reset(&mut self) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn close(&self) {
|
||||
self.stream.shutdown(std::net::Shutdown::Both).ok();
|
||||
}
|
||||
|
||||
fn read(&mut self, buffer: &mut [u8]) -> std::io::Result<usize> {
|
||||
self.reader.read(buffer)
|
||||
}
|
||||
|
||||
fn write(&mut self, buffer: &[u8]) -> std::io::Result<()> {
|
||||
self.writer.write_all(buffer)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
self.writer.flush()
|
||||
}
|
||||
|
||||
fn send_command(&mut self, command: &Command) -> Result<(), Error> {
|
||||
let payload_data_type: u32 = DataType::Command.into();
|
||||
self.writer.write_all(&payload_data_type.to_be_bytes())?;
|
||||
self.write(&payload_data_type.to_be_bytes())?;
|
||||
|
||||
self.writer.write_all(&command.id.to_be_bytes())?;
|
||||
self.writer.write_all(&command.args[0].to_be_bytes())?;
|
||||
self.writer.write_all(&command.args[1].to_be_bytes())?;
|
||||
self.write(&command.id.to_be_bytes())?;
|
||||
self.write(&command.args[0].to_be_bytes())?;
|
||||
self.write(&command.args[1].to_be_bytes())?;
|
||||
|
||||
let command_data_length = command.data.len() as u32;
|
||||
self.writer.write_all(&command_data_length.to_be_bytes())?;
|
||||
self.writer.write_all(&command.data)?;
|
||||
self.write(&command_data_length.to_be_bytes())?;
|
||||
self.write(&command.data)?;
|
||||
|
||||
self.writer.flush()?;
|
||||
self.flush()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -312,7 +349,7 @@ impl Backend for TcpBackend {
|
||||
packets: &mut VecDeque<Packet>,
|
||||
) -> Result<Option<Response>, Error> {
|
||||
let block = matches!(data_type, DataType::Response);
|
||||
while let Some(header) = self.read_header(block)? {
|
||||
while let Some(header) = self.try_read_header(block)? {
|
||||
let payload_data_type: DataType = u32::from_be_bytes(header).try_into()?;
|
||||
let mut buffer = [0u8; 4];
|
||||
match payload_data_type {
|
||||
@ -357,17 +394,13 @@ impl Backend for TcpBackend {
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn close(&self) {
|
||||
self.stream.shutdown(std::net::Shutdown::Both).ok();
|
||||
}
|
||||
}
|
||||
|
||||
fn new_tcp_backend(address: &str) -> Result<TcpBackend, Error> {
|
||||
let stream = match TcpStream::connect(address) {
|
||||
Ok(stream) => {
|
||||
stream.set_write_timeout(Some(Duration::from_secs(10)))?;
|
||||
stream.set_read_timeout(Some(Duration::from_millis(10)))?;
|
||||
stream.set_write_timeout(Some(WRITE_TIMEOUT))?;
|
||||
stream.set_read_timeout(Some(POLL_TIMEOUT))?;
|
||||
stream
|
||||
}
|
||||
Err(error) => {
|
||||
@ -385,8 +418,28 @@ fn new_tcp_backend(address: &str) -> Result<TcpBackend, Error> {
|
||||
})
|
||||
}
|
||||
|
||||
fn new_local_backend(port: &str) -> Result<Box<dyn Backend>, Error> {
|
||||
let mut backend: Box<dyn Backend> = if port.starts_with(SERIAL_PREFIX) {
|
||||
Box::new(new_serial_backend(
|
||||
port.strip_prefix(SERIAL_PREFIX).unwrap_or_default(),
|
||||
)?)
|
||||
} else if port.starts_with(FTDI_PREFIX) {
|
||||
Box::new(new_ftdi_backend(
|
||||
port.strip_prefix(FTDI_PREFIX).unwrap_or_default(),
|
||||
)?)
|
||||
} else {
|
||||
return Err(Error::new("Invalid port prefix provided"));
|
||||
};
|
||||
backend.reset()?;
|
||||
Ok(backend)
|
||||
}
|
||||
|
||||
fn new_remote_backend(address: &str) -> Result<Box<dyn Backend>, Error> {
|
||||
Ok(Box::new(new_tcp_backend(address)?))
|
||||
}
|
||||
|
||||
pub struct Link {
|
||||
backend: Box<dyn Backend>,
|
||||
pub backend: Box<dyn Backend>,
|
||||
packets: VecDeque<Packet>,
|
||||
}
|
||||
|
||||
@ -451,45 +504,76 @@ impl Drop for Link {
|
||||
|
||||
pub fn new_local(port: &str) -> Result<Link, Error> {
|
||||
Ok(Link {
|
||||
backend: Box::new(new_serial_backend(port)?),
|
||||
backend: new_local_backend(port)?,
|
||||
packets: VecDeque::new(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_remote(address: &str) -> Result<Link, Error> {
|
||||
Ok(Link {
|
||||
backend: Box::new(new_tcp_backend(address)?),
|
||||
backend: new_remote_backend(address)?,
|
||||
packets: VecDeque::new(),
|
||||
})
|
||||
}
|
||||
|
||||
pub struct LocalDevice {
|
||||
pub port: String,
|
||||
pub serial_number: String,
|
||||
pub enum BackendType {
|
||||
Serial,
|
||||
Ftdi,
|
||||
}
|
||||
|
||||
pub fn list_local_devices() -> Result<Vec<LocalDevice>, Error> {
|
||||
impl Display for BackendType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(match self {
|
||||
Self::Serial => "serial",
|
||||
Self::Ftdi => "libftdi",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DeviceInfo {
|
||||
pub backend: BackendType,
|
||||
pub port: String,
|
||||
pub serial: String,
|
||||
}
|
||||
|
||||
pub fn list_local_devices() -> Result<Vec<DeviceInfo>, Error> {
|
||||
const SC64_VID: u16 = 0x0403;
|
||||
const SC64_PID: u16 = 0x6014;
|
||||
const SC64_SID: &str = "SC64";
|
||||
|
||||
let mut serial_devices: Vec<LocalDevice> = Vec::new();
|
||||
let mut devices: Vec<DeviceInfo> = Vec::new();
|
||||
|
||||
for device in serialport::available_ports()?.into_iter() {
|
||||
if let serialport::SerialPortType::UsbPort(info) = device.port_type {
|
||||
let serial_number = info.serial_number.unwrap_or("".to_string());
|
||||
if info.vid == SC64_VID && info.pid == SC64_PID && serial_number.starts_with(SC64_SID) {
|
||||
serial_devices.push(LocalDevice {
|
||||
port: device.port_name,
|
||||
serial_number,
|
||||
});
|
||||
if let Ok(list) = list_ftdi_devices(SC64_VID, SC64_PID) {
|
||||
for device in list.into_iter() {
|
||||
if device.serial.starts_with(SC64_SID) {
|
||||
devices.push(DeviceInfo {
|
||||
backend: BackendType::Ftdi,
|
||||
port: format!("{FTDI_PREFIX}{}", device.port),
|
||||
serial: device.serial,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if serial_devices.len() == 0 {
|
||||
if let Ok(list) = serialport::available_ports() {
|
||||
for device in list.into_iter() {
|
||||
if let serialport::SerialPortType::UsbPort(i) = device.port_type {
|
||||
if let Some(serial) = i.serial_number {
|
||||
if i.vid == SC64_VID && i.pid == SC64_PID && serial.starts_with(SC64_SID) {
|
||||
devices.push(DeviceInfo {
|
||||
backend: BackendType::Serial,
|
||||
port: format!("{SERIAL_PREFIX}{}", device.port_name),
|
||||
serial,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if devices.len() == 0 {
|
||||
return Err(Error::new("No SC64 devices found"));
|
||||
}
|
||||
|
||||
return Ok(serial_devices);
|
||||
return Ok(devices);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
mod cic;
|
||||
mod error;
|
||||
pub mod firmware;
|
||||
mod ftdi;
|
||||
mod link;
|
||||
pub mod server;
|
||||
mod time;
|
||||
|
@ -1,19 +1,5 @@
|
||||
use super::{
|
||||
error::Error,
|
||||
link::{list_local_devices, new_serial, Command, DataType, Packet, Response, Serial},
|
||||
};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
io::{BufReader, BufWriter, ErrorKind, Read, Write},
|
||||
net::{TcpListener, TcpStream},
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
mpsc::{channel, Receiver, Sender},
|
||||
Arc,
|
||||
},
|
||||
thread,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use super::{error::Error, link::list_local_devices};
|
||||
use std::net::{TcpListener, TcpStream};
|
||||
|
||||
pub enum ServerEvent {
|
||||
Listening(String),
|
||||
@ -55,204 +41,208 @@ pub fn run(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
enum Event {
|
||||
Command(Command),
|
||||
Response(Response),
|
||||
Packet(Packet),
|
||||
KeepAlive,
|
||||
Closed(Option<Error>),
|
||||
}
|
||||
// enum Event {
|
||||
// Command(Command),
|
||||
// Response(Response),
|
||||
// Packet(Packet),
|
||||
// KeepAlive,
|
||||
// Closed(Option<Error>),
|
||||
// }
|
||||
|
||||
fn server_accept_connection(port: String, stream: &mut TcpStream) -> Result<(), Error> {
|
||||
let (event_sender, event_receiver) = channel::<Event>();
|
||||
let exit_flag = Arc::new(AtomicBool::new(false));
|
||||
fn server_accept_connection(_port: String, _stream: &mut TcpStream) -> Result<(), Error> {
|
||||
// let (event_sender, event_receiver) = channel::<Event>();
|
||||
// let exit_flag = Arc::new(AtomicBool::new(false));
|
||||
|
||||
let mut stream_writer = BufWriter::new(stream.try_clone()?);
|
||||
let mut stream_reader = stream.try_clone()?;
|
||||
// let mut stream_writer = BufWriter::new(stream.try_clone()?);
|
||||
// let mut stream_reader = stream.try_clone()?;
|
||||
|
||||
let serial = Arc::new(new_serial(&port)?);
|
||||
let serial_writer = serial.clone();
|
||||
let serial_reader = serial.clone();
|
||||
// let serial = Arc::new(new_local(&port)?);
|
||||
// let serial_writer = serial.clone();
|
||||
// let serial_reader = serial.clone();
|
||||
|
||||
let stream_event_sender = event_sender.clone();
|
||||
let stream_exit_flag = exit_flag.clone();
|
||||
let stream_thread = thread::spawn(move || {
|
||||
let closed_sender = stream_event_sender.clone();
|
||||
match server_stream_thread(&mut stream_reader, stream_event_sender, stream_exit_flag) {
|
||||
Ok(()) => closed_sender.send(Event::Closed(None)),
|
||||
Err(error) => closed_sender.send(Event::Closed(Some(error))),
|
||||
}
|
||||
.ok();
|
||||
});
|
||||
// let stream_event_sender = event_sender.clone();
|
||||
// let stream_exit_flag = exit_flag.clone();
|
||||
// let stream_thread = thread::spawn(move || {
|
||||
// let closed_sender = stream_event_sender.clone();
|
||||
// match server_stream_thread(&mut stream_reader, stream_event_sender, stream_exit_flag) {
|
||||
// Ok(()) => closed_sender.send(Event::Closed(None)),
|
||||
// Err(error) => closed_sender.send(Event::Closed(Some(error))),
|
||||
// }
|
||||
// .ok();
|
||||
// });
|
||||
|
||||
let serial_event_sender = event_sender.clone();
|
||||
let serial_exit_flag = exit_flag.clone();
|
||||
let serial_thread = thread::spawn(move || {
|
||||
let closed_sender = serial_event_sender.clone();
|
||||
match server_serial_thread(serial_reader, serial_event_sender, serial_exit_flag) {
|
||||
Ok(()) => closed_sender.send(Event::Closed(None)),
|
||||
Err(error) => closed_sender.send(Event::Closed(Some(error))),
|
||||
}
|
||||
.ok();
|
||||
});
|
||||
// let serial_event_sender = event_sender.clone();
|
||||
// let serial_exit_flag = exit_flag.clone();
|
||||
// let serial_thread = thread::spawn(move || {
|
||||
// let closed_sender = serial_event_sender.clone();
|
||||
// match server_serial_thread(serial_reader, serial_event_sender, serial_exit_flag) {
|
||||
// Ok(()) => closed_sender.send(Event::Closed(None)),
|
||||
// Err(error) => closed_sender.send(Event::Closed(Some(error))),
|
||||
// }
|
||||
// .ok();
|
||||
// });
|
||||
|
||||
let keepalive_event_sender = event_sender.clone();
|
||||
let keepalive_exit_flag = exit_flag.clone();
|
||||
let keepalive_thread = thread::spawn(move || {
|
||||
server_keepalive_thread(keepalive_event_sender, keepalive_exit_flag);
|
||||
});
|
||||
// let keepalive_event_sender = event_sender.clone();
|
||||
// let keepalive_exit_flag = exit_flag.clone();
|
||||
// let keepalive_thread = thread::spawn(move || {
|
||||
// server_keepalive_thread(keepalive_event_sender, keepalive_exit_flag);
|
||||
// });
|
||||
|
||||
let result = server_process_events(&mut stream_writer, serial_writer, event_receiver);
|
||||
// let result = server_process_events(&mut stream_writer, serial_writer, event_receiver);
|
||||
|
||||
exit_flag.store(true, Ordering::Relaxed);
|
||||
stream_thread.join().ok();
|
||||
serial_thread.join().ok();
|
||||
keepalive_thread.join().ok();
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn server_process_events(
|
||||
stream_writer: &mut BufWriter<TcpStream>,
|
||||
serial_writer: Arc<Serial>,
|
||||
event_receiver: Receiver<Event>,
|
||||
) -> Result<(), Error> {
|
||||
for event in event_receiver.into_iter() {
|
||||
match event {
|
||||
Event::Command(command) => {
|
||||
serial_writer.send_command(&command)?;
|
||||
}
|
||||
Event::Response(response) => {
|
||||
stream_writer.write_all(&u32::to_be_bytes(DataType::Response.into()))?;
|
||||
stream_writer.write_all(&[response.id])?;
|
||||
stream_writer.write_all(&[response.error as u8])?;
|
||||
stream_writer.write_all(&(response.data.len() as u32).to_be_bytes())?;
|
||||
stream_writer.write_all(&response.data)?;
|
||||
stream_writer.flush()?;
|
||||
}
|
||||
Event::Packet(packet) => {
|
||||
stream_writer.write_all(&u32::to_be_bytes(DataType::Packet.into()))?;
|
||||
stream_writer.write_all(&[packet.id])?;
|
||||
stream_writer.write_all(&(packet.data.len() as u32).to_be_bytes())?;
|
||||
stream_writer.write_all(&packet.data)?;
|
||||
stream_writer.flush()?;
|
||||
}
|
||||
Event::KeepAlive => {
|
||||
stream_writer.write_all(&u32::to_be_bytes(DataType::KeepAlive.into()))?;
|
||||
stream_writer.flush()?;
|
||||
}
|
||||
Event::Closed(result) => match result {
|
||||
Some(error) => return Err(error),
|
||||
None => {
|
||||
break;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
// exit_flag.store(true, Ordering::Relaxed);
|
||||
// stream_thread.join().ok();
|
||||
// serial_thread.join().ok();
|
||||
// keepalive_thread.join().ok();
|
||||
|
||||
// result
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn server_stream_thread(
|
||||
stream: &mut TcpStream,
|
||||
event_sender: Sender<Event>,
|
||||
exit_flag: Arc<AtomicBool>,
|
||||
) -> Result<(), Error> {
|
||||
let mut stream_reader = BufReader::new(stream.try_clone()?);
|
||||
// fn server_process_events(
|
||||
// stream_writer: &mut BufWriter<TcpStream>,
|
||||
// link: &mut Link,
|
||||
// event_receiver: Receiver<Event>,
|
||||
// ) -> Result<(), Error> {
|
||||
// for event in event_receiver.into_iter() {
|
||||
// match event {
|
||||
// Event::Command(command) => {
|
||||
// // serial_writer.send_command(&command)?;
|
||||
// // serial_writer.
|
||||
// // link.execute_command(&command)?;
|
||||
// link.execute_command(&command)?;
|
||||
// }
|
||||
// Event::Response(response) => {
|
||||
// stream_writer.write_all(&u32::to_be_bytes(DataType::Response.into()))?;
|
||||
// stream_writer.write_all(&[response.id])?;
|
||||
// stream_writer.write_all(&[response.error as u8])?;
|
||||
// stream_writer.write_all(&(response.data.len() as u32).to_be_bytes())?;
|
||||
// stream_writer.write_all(&response.data)?;
|
||||
// stream_writer.flush()?;
|
||||
// }
|
||||
// Event::Packet(packet) => {
|
||||
// stream_writer.write_all(&u32::to_be_bytes(DataType::Packet.into()))?;
|
||||
// stream_writer.write_all(&[packet.id])?;
|
||||
// stream_writer.write_all(&(packet.data.len() as u32).to_be_bytes())?;
|
||||
// stream_writer.write_all(&packet.data)?;
|
||||
// stream_writer.flush()?;
|
||||
// }
|
||||
// Event::KeepAlive => {
|
||||
// stream_writer.write_all(&u32::to_be_bytes(DataType::KeepAlive.into()))?;
|
||||
// stream_writer.flush()?;
|
||||
// }
|
||||
// Event::Closed(result) => match result {
|
||||
// Some(error) => return Err(error),
|
||||
// None => {
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
|
||||
let mut header = [0u8; 4];
|
||||
let header_length = header.len();
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
loop {
|
||||
let mut header_position = 0;
|
||||
// fn server_stream_thread(
|
||||
// stream: &mut TcpStream,
|
||||
// event_sender: Sender<Event>,
|
||||
// exit_flag: Arc<AtomicBool>,
|
||||
// ) -> Result<(), Error> {
|
||||
// let mut stream_reader = BufReader::new(stream.try_clone()?);
|
||||
|
||||
let timeout = stream.read_timeout()?;
|
||||
stream.set_read_timeout(Some(Duration::from_millis(10)))?;
|
||||
while header_position < header_length {
|
||||
if exit_flag.load(Ordering::Relaxed) {
|
||||
return Ok(());
|
||||
}
|
||||
match stream_reader.read(&mut header[header_position..header_length]) {
|
||||
Ok(0) => return Ok(()),
|
||||
Ok(bytes) => header_position += bytes,
|
||||
Err(error) => match error.kind() {
|
||||
ErrorKind::Interrupted | ErrorKind::TimedOut | ErrorKind::WouldBlock => {}
|
||||
_ => return Err(error.into()),
|
||||
},
|
||||
}
|
||||
}
|
||||
stream.set_read_timeout(timeout)?;
|
||||
// let mut header = [0u8; 4];
|
||||
// let header_length = header.len();
|
||||
|
||||
let data_type: DataType = u32::from_be_bytes(header).try_into()?;
|
||||
if !matches!(data_type, DataType::Command) {
|
||||
return Err(Error::new("Received data type was not a command data type"));
|
||||
}
|
||||
// loop {
|
||||
// let mut header_position = 0;
|
||||
|
||||
let mut buffer = [0u8; 4];
|
||||
let mut id_buffer = [0u8; 1];
|
||||
let mut args = [0u32; 2];
|
||||
// let timeout = stream.read_timeout()?;
|
||||
// stream.set_read_timeout(Some(Duration::from_millis(10)))?;
|
||||
// while header_position < header_length {
|
||||
// if exit_flag.load(Ordering::Relaxed) {
|
||||
// return Ok(());
|
||||
// }
|
||||
// match stream_reader.read(&mut header[header_position..header_length]) {
|
||||
// Ok(0) => return Ok(()),
|
||||
// Ok(bytes) => header_position += bytes,
|
||||
// Err(error) => match error.kind() {
|
||||
// ErrorKind::Interrupted | ErrorKind::TimedOut | ErrorKind::WouldBlock => {}
|
||||
// _ => return Err(error.into()),
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
// stream.set_read_timeout(timeout)?;
|
||||
|
||||
stream_reader.read_exact(&mut id_buffer)?;
|
||||
let id = id_buffer[0];
|
||||
// let data_type: DataType = u32::from_be_bytes(header).try_into()?;
|
||||
// if !matches!(data_type, DataType::Command) {
|
||||
// return Err(Error::new("Received data type was not a command data type"));
|
||||
// }
|
||||
|
||||
stream_reader.read_exact(&mut buffer)?;
|
||||
args[0] = u32::from_be_bytes(buffer);
|
||||
stream_reader.read_exact(&mut buffer)?;
|
||||
args[1] = u32::from_be_bytes(buffer);
|
||||
// let mut buffer = [0u8; 4];
|
||||
// let mut id_buffer = [0u8; 1];
|
||||
// let mut args = [0u32; 2];
|
||||
|
||||
stream_reader.read_exact(&mut buffer)?;
|
||||
let command_data_length = u32::from_be_bytes(buffer) as usize;
|
||||
let mut data = vec![0u8; command_data_length];
|
||||
stream_reader.read_exact(&mut data)?;
|
||||
// stream_reader.read_exact(&mut id_buffer)?;
|
||||
// let id = id_buffer[0];
|
||||
|
||||
if event_sender
|
||||
.send(Event::Command(Command { id, args, data }))
|
||||
.is_err()
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// stream_reader.read_exact(&mut buffer)?;
|
||||
// args[0] = u32::from_be_bytes(buffer);
|
||||
// stream_reader.read_exact(&mut buffer)?;
|
||||
// args[1] = u32::from_be_bytes(buffer);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
// stream_reader.read_exact(&mut buffer)?;
|
||||
// let command_data_length = u32::from_be_bytes(buffer) as usize;
|
||||
// let mut data = vec![0u8; command_data_length];
|
||||
// stream_reader.read_exact(&mut data)?;
|
||||
|
||||
fn server_serial_thread(
|
||||
serial_reader: Arc<Serial>,
|
||||
event_sender: Sender<Event>,
|
||||
exit_flag: Arc<AtomicBool>,
|
||||
) -> Result<(), Error> {
|
||||
let mut packets: VecDeque<Packet> = VecDeque::new();
|
||||
// if event_sender
|
||||
// .send(Event::Command(Command { id, args, data }))
|
||||
// .is_err()
|
||||
// {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
while !exit_flag.load(Ordering::Relaxed) {
|
||||
let response = serial_reader.process_incoming_data(DataType::Packet, &mut packets)?;
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
if let Some(response) = response {
|
||||
if event_sender.send(Event::Response(response)).is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// fn server_serial_thread(
|
||||
// link: &mut Link,
|
||||
// event_sender: Sender<Event>,
|
||||
// exit_flag: Arc<AtomicBool>,
|
||||
// ) -> Result<(), Error> {
|
||||
// let mut packets: VecDeque<Packet> = VecDeque::new();
|
||||
|
||||
if let Some(packet) = packets.pop_front() {
|
||||
if event_sender.send(Event::Packet(packet)).is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// while !exit_flag.load(Ordering::Relaxed) {
|
||||
// let response = link.backend.process_incoming_data(DataType::Packet, &mut packets)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
// if let Some(response) = response {
|
||||
// if event_sender.send(Event::Response(response)).is_err() {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
fn server_keepalive_thread(event_sender: Sender<Event>, exit_flag: Arc<AtomicBool>) {
|
||||
let mut keepalive = Instant::now();
|
||||
// if let Some(packet) = packets.pop_front() {
|
||||
// if event_sender.send(Event::Packet(packet)).is_err() {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
while !exit_flag.load(Ordering::Relaxed) {
|
||||
if keepalive.elapsed() >= Duration::from_secs(5) {
|
||||
keepalive = Instant::now();
|
||||
if event_sender.send(Event::KeepAlive).is_err() {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
// fn server_keepalive_thread(event_sender: Sender<Event>, exit_flag: Arc<AtomicBool>) {
|
||||
// let mut keepalive = Instant::now();
|
||||
|
||||
// while !exit_flag.load(Ordering::Relaxed) {
|
||||
// if keepalive.elapsed() >= Duration::from_secs(5) {
|
||||
// keepalive = Instant::now();
|
||||
// if event_sender.send(Event::KeepAlive).is_err() {
|
||||
// break;
|
||||
// }
|
||||
// } else {
|
||||
// thread::sleep(Duration::from_millis(100));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
Loading…
Reference in New Issue
Block a user