use std::io;
use std::thread;
use std::sync::mpsc;
use std::time::Duration;
use clap::{ArgMatches, App, SubCommand};
use crossterm::KeyEvent;
use crate::commands;
use crate::windows::{WindowManager, Event};
use serial_unit_testing::serial::Serial;
mod helpers;
mod main_window;
mod help_window;
use main_window::MainWindow;
pub fn run(matches: &ArgMatches) -> Result<(), String> {
let (io_tx, io_rx) = mpsc::channel();
let (settings, port_name) = commands::get_serial_settings(matches).unwrap();
let mut window_manager = match WindowManager::new() {
Ok(window_manager) => window_manager,
Err(e) => return Err(e.to_string())
};
let ui_tx = window_manager.get_tx().clone();
let mut main_window = MainWindow::new(io_tx);
main_window.input_format = commands::get_text_input_format(matches);
main_window.output_format = commands::get_text_output_format(matches);
main_window.newline_format = commands::get_newline_format(matches);
main_window.title = format!("{}, {} ", port_name, settings.to_short_string());
let mut serial = match Serial::open_with_settings(port_name, &settings) {
Ok(serial) => serial,
Err(e) => return Err(format!("Unable to connect to port: {:?}", e.into_inner().unwrap().description()))
};
{
thread::spawn(move || {
loop {
match serial.read_with_timeout(Duration::from_millis(10)) {
Ok(bytes) => {
if let Err(_) = ui_tx.send(Event::Output(bytes.to_vec())) {
eprintln!("Unable to send to ui thread");
return;
}
},
Err(ref e) if e.kind() == io::ErrorKind::TimedOut => (),
Err(_) => {
show_error(&ui_tx, "Unable to read from serial".to_string());
return;
}
}
match io_rx.try_recv() {
Ok((data, format)) => {
if let Err(_err) = serial.write_format(data.as_str(), format) {
show_error(&ui_tx, "Unable to write to serial".to_string());
return;
}
},
Err(e) if e == mpsc::TryRecvError::Empty => (),
Err(_) => {
show_error(&ui_tx, "I/O thread closed".to_string());
return;
}
}
}
});
}
match window_manager.run(main_window) {
Ok(_) => Ok(()),
Err(e) => Err(e.to_string())
}
}
pub fn command<'a>() -> App<'a, 'a> {
SubCommand::with_name("monitor")
.about("Interactive serial communication monitor")
.args(commands::serial_arguments(false, true).as_slice())
.args(commands::text_input_arguments().as_slice())
.args(commands::text_output_arguments().as_slice())
}
fn show_error(tx: &mpsc::Sender<Event<KeyEvent>>, text: String) {
if let Err(_err) = tx.send(Event::Error(text)) {
eprintln!("Unable to send to ui thread");
}
}