use serialport::SerialPort;
use log::*;
use std::thread;
use std::thread::JoinHandle;
use core::convert::TryFrom;
use std::io::ErrorKind;
use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError};
pub mod common_types;
pub use common_types::*;
#[derive(Debug)]
pub enum SerialFrameError {
CouldNotStart,
CouldNotSendStop,
SerialportDisconnected,
SerialThreadPaniced,
ReceiverDropped,
FailedConversion(Vec<u8>),
}
pub type Result<T> = core::result::Result<T, SerialFrameError>;
pub struct SerialFrameStopper {
handle: JoinHandle<()>,
stopsender: Sender<()>,
}
impl SerialFrameStopper {
pub fn stop(self) -> Result<()> {
self.stopsender
.send(())
.map_err(|_e| SerialFrameError::CouldNotSendStop)?;
self.handle
.join()
.map_err(|_e| SerialFrameError::SerialThreadPaniced)?;
Ok(())
}
}
pub struct SerialFrameSender {
separator: u8,
port: Box<dyn SerialPort>,
error_tx: Option<Sender<SerialFrameError>>,
}
impl SerialFrameSender {
pub fn new(separator: u8, port: Box<dyn SerialPort>) -> SerialFrameSender {
Self {
separator,
port,
error_tx: None,
}
}
pub fn add_error_channel(&mut self) -> Receiver<SerialFrameError> {
let (tx, rx) = channel();
self.error_tx = Some(tx);
rx
}
pub fn start<T: 'static + Send + TryFrom<Vec<u8>>>(
mut self,
type_send: Sender<T>,
) -> Result<SerialFrameStopper> {
let (stoptx, stoprx) = channel();
let handle = thread::Builder::new()
.name("SerialFrameSender".to_string())
.spawn(move || {
let mut buf: Vec<u8> = Vec::new();
let mut serial_byte = [0; 10240];
'thread: loop {
match stoprx.try_recv() {
Err(TryRecvError::Empty) => {
match self.port.read(&mut serial_byte[..]) {
Ok(n) => {
buf.extend_from_slice(&serial_byte[..n]);
}
Err(ref e) if e.kind() == ErrorKind::TimedOut => {
trace!("{}", e);
}
Err(e) => {
error!("{}", e);
if let Some(send) = &self.error_tx {
let res =
send.send(SerialFrameError::SerialportDisconnected);
if let Err(e) = res {
error!("Could not send error, quitting: {}", e);
}
}
break 'thread;
}
}
while let Some(end) = buf.iter().position(|&f| f == self.separator) {
trace!("end: {}", end);
let frame: Vec<u8> = buf.drain(..end + 1).collect();
trace!("frame: {:?}", frame);
if let Ok(framed) = T::try_from(frame.clone()) {
let res = type_send.send(framed);
if let Err(e) = res {
error!("Could not send frame, quitting: {}", e);
if let Some(send) = self.error_tx {
let _res = send.send(SerialFrameError::ReceiverDropped);
}
break 'thread;
}
} else {
if let Some(send) = &self.error_tx {
let res = send.send(SerialFrameError::FailedConversion(
frame.clone(),
));
if let Err(e) = res {
error!("Could not send frame, quitting: {}", e);
break 'thread;
}
}
}
}
}
Err(TryRecvError::Disconnected) => {
info!("Thread handle was dropped");
if let Some(panic) = &self.error_tx {
let _ = panic.send(SerialFrameError::ReceiverDropped);
}
}
_ => {
info!("Thread got stop request");
break 'thread;
}
}
}
});
let handle = handle.map_err(|_e| SerialFrameError::CouldNotStart)?;
let stopsend = SerialFrameStopper {
handle,
stopsender: stoptx,
};
Ok(stopsend)
}
pub fn stop(&mut self) -> () {}
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}