use std::sync::mpsc::{Sender, Receiver}; use std::env; use serialport::{SerialPort, DataBits, Parity, FlowControl, StopBits}; use std::time::Duration; pub enum Message { UiUpdateLog(String), UiUpdateReceiveMsg(Vec), UiCleanReceiveMsg, UiCleanLog, UiShowLog, UiHideLog, UiShowHex, UiHideHex, UiUpdateStatusBarCom(String), UiUpdateStatusBarBaudrate(u32), UiUpdateStatusBarParity(String), UiUpdateStatusBarStopbit(u32), UiUpdateStatusBarPeriod(u64), UiUpdateStatusBarDatabit(u32), MainCmdOpen(String), MainCmdClose, MainCmdSend(String), MainCmdSet(Vec), MainCmdSendPeriod(String), MainCmdStopPeriod, PortCmdClose, PortCmdSend(String), PortPeriodSend(String), PortPeriodStop, PortPeriodDuration(u64), PortCloseSucceed, PortHaveData(Vec), PortError(String), } pub enum Error { PortOpenFailed(String), } #[derive(Copy, Clone)] pub struct PortConfig { pub baud_rate: u32, pub data_bits: DataBits, pub parity: Parity, pub flow_control: FlowControl, pub stopbit: StopBits, pub timeout: u32, } pub fn port_open(port: String, config: PortConfig) -> Result, Error> { let mut prelude = ""; if env::consts::OS == "linux" { prelude = "/dev/tty"; } else if env::consts::OS == "windows" { prelude = "" } let port_builder = serialport::new(prelude.to_owned() + &port, config.baud_rate) .data_bits(config.data_bits) .parity(config.parity) .flow_control(config.flow_control) .stop_bits(config.stopbit) .timeout(Duration::from_millis(config.timeout as u64)); match port_builder.open() { Ok(port) => { return Ok(port); } Err(e) => { let err_msg = format!("Open port failed with error {}\n", e).to_string(); return Err(Error::PortOpenFailed(err_msg)); } } } pub fn port_proc(mut port: Box, to_main: Sender, from_main: Receiver) { let mut buf: Vec = vec![0; 128]; let mut period_send = false; let mut period_timeout = std::time::Duration::from_millis(100); let mut period_send_msg = String::new(); let mut last_send = std::time::Instant::now(); to_main.send(Message::PortPeriodDuration(100)); loop { if let Ok(msg) = from_main.try_recv() { match msg { Message::PortCmdClose => { to_main.send(Message::PortCloseSucceed).unwrap(); break; } Message::PortCmdSend(msg) => { match port.write(msg.as_bytes()) { Err(e) => { to_main.send(Message::PortError(format!("{}", e).to_string())).unwrap(); } _ => {} } } Message::PortPeriodSend(msg) => { period_send = true; period_send_msg = msg; } Message::PortPeriodStop=> { period_send = false; } Message::PortPeriodDuration(value) => { period_timeout = std::time::Duration::from_millis(value); } _ => {} } } match port.read(buf.as_mut_slice()) { Ok(size) => to_main.send(Message::PortHaveData(buf[0..size].to_owned())).unwrap(), Err(e) => { if e.kind() != std::io::ErrorKind::TimedOut { to_main.send(Message::PortError(format!("{}", e).to_string())).unwrap(); break; } } } if period_send && (last_send.elapsed() > period_timeout){ last_send = std::time::Instant::now(); match port.write(period_send_msg.as_bytes()) { Err(e) => to_main.send(Message::PortError(format!("{}", e).to_string())).unwrap(), _ => {} } } } } pub(crate) fn list_available_ports() -> (String, String) { let mut ret = String::new(); let mut ret_portname = String::new(); match serialport::available_ports() { Ok(ports) => { for p in ports { ret += &*String::from(format!("{:?}\n", p)); if ret_portname.is_empty() { ret_portname = p.port_name; } } } Err(err) => { ret = format!("{}", err); } } (ret, ret_portname) }