2021-10-09 01:57:27 -04:00

147 lines
4.0 KiB
Rust

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<u8>),
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<String>),
MainCmdSendPeriod(String),
MainCmdStopPeriod,
PortCmdClose,
PortCmdSend(String),
PortPeriodSend(String),
PortPeriodStop,
PortPeriodDuration(u64),
PortCloseSucceed,
PortHaveData(Vec<u8>),
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<Box<dyn SerialPort>, 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<dyn SerialPort>, to_main: Sender<Message>, from_main: Receiver<Message>) {
let mut buf: Vec<u8> = 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)
}