#![windows_subsystem = "windows"] mod port; mod hexdump; use closure::closure; use gtk::{Inhibit, TextView, Statusbar, Label}; use gtk::{gio, glib}; use gtk::prelude::{GtkWindowExt, BuilderExtManual, GtkMenuItemExt, WidgetExt, EntryExt, TextBufferExt, ScrolledWindowExt, AdjustmentExt}; use gio::prelude::{ApplicationExt, ApplicationExtManual}; use std::sync::mpsc::{Sender, Receiver, channel}; use serialport::{StopBits, FlowControl, Parity, DataBits}; use crate::port::*; use gtk::prelude::TextViewExt; use gtk::prelude::LabelExt; use std::str; use std::time::Duration; use std::num::ParseIntError; fn main() { let application = gtk::Application::new( Some("com.github.gtk-rs.examples.menu_bar_system"), Default::default(), ); // application.connect_startup(|app| { // }); application.connect_activate(build_ui); application.run(); } fn build_ui(application: >k::Application) { let builder = gtk::Builder::from_string(include_str!("test.ui")); let ui_main_window: gtk::ApplicationWindow = builder.object("main_window").expect("Can not get window!"); ui_main_window.set_application(Some(application)); let menu_view_command: gtk::MenuItem = builder.object("view_command").expect("Can not get command item"); let command_entry: gtk::Entry = builder.object("command_entry").expect("Can not get command entry"); let tmp = command_entry.clone(); menu_view_command.connect_activate(move |_| { if WidgetExt::is_visible(&tmp) { tmp.hide(); } else { tmp.show(); tmp.set_has_focus(true); } }); let ui_log_window: gtk::Window = builder.object("log_window").expect("Can not get log view"); let menu_log_command: gtk::MenuItem = builder.object("log_command").expect("Can not get log command"); let menu_hex_command: gtk::MenuItem = builder.object("hex_command").expect("Can not get log command"); let ui_receive_view: TextView = builder.object("receive_view").expect("can not get receive view"); let ui_baudrate: Label = builder.object("ui_baudrate").unwrap(); let ui_databit: Label = builder.object("ui_databit").unwrap(); let ui_parity: Label = builder.object("ui_parity").unwrap(); let ui_stopbit: Label = builder.object("ui_stopbit").unwrap(); let ui_period: Label = builder.object("ui_period").unwrap(); let ui_com: Label = builder.object("ui_com").unwrap(); let ui_statusbar: Statusbar = builder.object("statusbar").unwrap(); let ui_log_view: TextView = builder.object("log_view").unwrap(); let ui_hex_view: TextView = builder.object("hex_view").unwrap(); let ui_hex_window: gtk::Window = builder.object("hex_window").unwrap(); let ui_ascii_view: TextView = builder.object("ascii_view").unwrap(); let ui_hex_scroll: gtk::ScrolledWindow = builder.object("ui_hex_scroll").unwrap(); // ui_viewport.set_vscroll_policy(Sc) ui_log_window.show(); // ui_hex_window.show(); ui_log_window.connect_delete_event(|a, _| { a.hide(); Inhibit(true) }); ui_hex_window.connect_delete_event(|a, _| { a.hide(); Inhibit(true) }); let tmp = ui_log_window.clone(); menu_log_command.connect_activate(move |_| { if tmp.is_visible() { tmp.hide(); } else { tmp.show(); } }); let tmp = ui_hex_window.clone(); menu_hex_command.connect_activate(move |_| { if tmp.is_visible() { tmp.hide(); } else { tmp.show(); } }); let mut receive_char_counter = 0; let (sender_ui_upd, receiver_ui_upd) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); receiver_ui_upd.attach(None, move |msg| { match msg { Message::UiUpdateLog(text) => { let buf = ui_log_view.buffer().unwrap(); buf.insert(&mut buf.end_iter(), text.as_str()); } Message::UiUpdateReceiveMsg(data) => { let mut basic_show = String::new(); for i in data.clone() { if i.is_ascii_alphanumeric() || i.is_ascii_whitespace() || i.is_ascii_punctuation() || i.is_ascii_graphic() { basic_show.push(i as char); } } let buf = ui_hex_view.buffer().unwrap(); let hex = hexdump::get_hex(receive_char_counter, data.clone()); buf.insert(&mut buf.end_iter(), hex.as_str()); // println!("{:?}",std::mem::size_of_val(&buf)); let buf = ui_receive_view.buffer().unwrap(); buf.insert(&mut buf.end_iter(), basic_show.as_str()); let buf = ui_ascii_view.buffer().unwrap(); let ascii = hexdump::get_ascii(receive_char_counter, data.clone()); buf.insert(&mut buf.end_iter(), ascii.as_str()); receive_char_counter += data.len() as u32; let tmp = ui_hex_scroll.vadjustment(); tmp.set_value(tmp.upper()); } Message::UiCleanReceiveMsg => ui_receive_view.buffer().unwrap().set_text(""), Message::UiCleanLog => ui_log_view.buffer().unwrap().set_text(""), Message::UiShowLog => ui_log_window.show(), Message::UiHideLog => ui_log_window.hide(), Message::UiShowHex => ui_hex_window.show(), Message::UiHideHex => ui_hex_window.hide(), Message::UiUpdateStatusBarBaudrate(value) => ui_baudrate.set_text(value.to_string().as_str()), Message::UiUpdateStatusBarDatabit(value) => ui_databit.set_text(value.to_string().as_str()), Message::UiUpdateStatusBarParity(value) => ui_parity.set_text(value.to_string().as_str()), Message::UiUpdateStatusBarStopbit(value) => ui_stopbit.set_text(value.to_string().as_str()), Message::UiUpdateStatusBarPeriod(value) => ui_period.set_text(&*(value.to_string() + " ms")), Message::UiUpdateStatusBarCom(value) => ui_com.set_text(value.to_string().as_str()), _ => {} } glib::Continue(true) }); let (gui2main_tx, gui2main_rx) = channel::(); std::thread::spawn(closure!(clone gui2main_tx, clone sender_ui_upd, || {main_proc(gui2main_tx, gui2main_rx, sender_ui_upd)})); let to_ui = sender_ui_upd.clone(); command_entry.connect_activate(move |x| { let command_buf = x.buffer(); let command = command_buf.text(); command_buf.set_text(""); process_cmd(command, to_ui.clone(), gui2main_tx.clone()); }); ui_main_window.show(); } fn process_cmd(command: String, to_ui: glib::Sender, gui2main_tx: Sender) { let command_split: Vec<&str> = command.split_whitespace().collect(); if command_split.len() != 0 { let cmd = command_split[0].to_ascii_lowercase(); match cmd.as_str() { "set" => { if command_split.len() == 1 { to_ui.send(Message::UiUpdateLog("No enough argument\n".to_string())).unwrap(); } else { let args: Vec = command_split[1..].to_vec().into_iter().map(|item| String::from(item)).collect(); gui2main_tx.send(Message::MainCmdSet(args)).unwrap(); } } "open" => { if command_split.len() == 1 { // to_ui.send(Message::UiUpdateLog("No enough argument\n".to_string())).unwrap(); gui2main_tx.send(Message::MainCmdOpen("".to_string())).unwrap(); } else { let args: Vec = command_split[1..].to_vec().into_iter().map(|item| String::from(item)).collect(); gui2main_tx.send(Message::MainCmdOpen(args[0].clone())).unwrap(); } } "close" => { gui2main_tx.send(Message::MainCmdClose).unwrap(); } "list" => { to_ui.send(Message::UiUpdateLog(list_available_ports().0)).unwrap(); } "send" => { if command.len() <= 5 { to_ui.send(Message::UiUpdateLog("no data!\n".parse().unwrap())).unwrap(); } else { gui2main_tx.send(Message::MainCmdSend(command[5..].parse().unwrap())).unwrap(); } } "loop" => { if command.len() <= 5 { to_ui.send(Message::UiUpdateLog("no data!\n".parse().unwrap())).unwrap(); } else { gui2main_tx.send(Message::MainCmdSendPeriod(command[5..].parse().unwrap())).unwrap(); } } "loopend" => { gui2main_tx.send(Message::MainCmdStopPeriod).unwrap(); } "clean" => { to_ui.send(Message::UiCleanReceiveMsg).unwrap(); to_ui.send(Message::UiCleanLog).unwrap(); } "show" => { if command_split.len() == 1 { to_ui.send(Message::UiUpdateLog("No enough argument\n".to_string())).unwrap(); } else { match command_split[1] { "log" => to_ui.send(Message::UiShowLog).unwrap(), "hex" => to_ui.send(Message::UiShowHex).unwrap(), _ => {} } } } "hide" => { if command_split.len() == 1 { to_ui.send(Message::UiUpdateLog("No enough argument\n".to_string())).unwrap(); } else { match command_split[1] { "log" => to_ui.send(Message::UiHideLog).unwrap(), "hex" => to_ui.send(Message::UiHideHex).unwrap(), _ => {} } } } _ => {} } } } fn main_proc(to_main_tx: Sender, rx: Receiver, ui_upd: glib::Sender) { let (mut main2port_tx, _rx_port_receive) = channel::(); let mut port_default_config = PortConfig { baud_rate: 115_200, data_bits: DataBits::Eight, parity: Parity::None, flow_control: FlowControl::None, stopbit: StopBits::One, timeout: 10, }; let mut port_status_open = false; let mut default_com_port = list_available_ports().1; ui_upd.send(Message::UiUpdateStatusBarCom(default_com_port.clone())).unwrap(); loop { if let Ok(msg) = rx.try_recv() { match msg { Message::UiCleanReceiveMsg => {} Message::MainCmdOpen(arg) => { if port_status_open { ui_upd.send(Message::UiUpdateLog("Port Already Open\n".to_string())).unwrap(); continue; } let (tmp_to_port, main2port_rx) = channel::(); main2port_tx = tmp_to_port; let port_name = if arg.is_empty() { default_com_port.clone() } else { arg }; default_com_port = port_name.clone(); ui_upd.send(Message::UiUpdateStatusBarCom(default_com_port.clone())).unwrap(); match port_open(port_name, port_default_config) { Ok(port) => { port_status_open = true; std::thread::spawn(closure!(clone to_main_tx, || port_proc(port, to_main_tx, main2port_rx))); ui_upd.send(Message::UiUpdateLog("open port succeed\n".to_string())).unwrap(); } Err(e) => { match e { Error::PortOpenFailed(msg) => { ui_upd.send(Message::UiUpdateLog(msg)).unwrap(); } } } } } Message::MainCmdClose => { if port_status_open { main2port_tx.send(Message::PortCmdClose).unwrap(); } else { ui_upd.send(Message::UiUpdateLog("No port opened\n".to_string())).unwrap(); } } Message::MainCmdSend(msg) => main2port_tx.send(Message::PortCmdSend(msg)).unwrap(), Message::MainCmdSendPeriod(msg) => { main2port_tx.send(Message::PortPeriodSend(msg)).unwrap() } Message::MainCmdStopPeriod=> { main2port_tx.send(Message::PortPeriodStop).unwrap() } Message::MainCmdSet(args) => { match args[0].as_str() { "baudrate" => { if args.len() != 2 { ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap(); } else { if let Ok(value) = args[1].parse::() { port_default_config.baud_rate = value; ui_upd.send(Message::UiUpdateStatusBarBaudrate(value)).unwrap(); } else { ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap(); } } } "databit" => { if args.len() != 2 { ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap(); } else { if let Ok(value) = args[1].parse::() { ui_upd.send(Message::UiUpdateStatusBarDatabit(value)).unwrap(); match value { 8 => port_default_config.data_bits = DataBits::Eight, 7 => port_default_config.data_bits = DataBits::Seven, 6 => port_default_config.data_bits = DataBits::Six, 5 => port_default_config.data_bits = DataBits::Five, _ => { ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap(); } } } else { ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap(); } } } "parity" => { if args.len() != 2 { ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap(); } else { if let Ok(value) = args[1].parse::() { match value { 0 => { port_default_config.parity = Parity::None; ui_upd.send(Message::UiUpdateStatusBarParity("None".to_string())).unwrap(); } 1 => { port_default_config.parity = Parity::Odd; ui_upd.send(Message::UiUpdateStatusBarParity("Odd".to_string())).unwrap(); } 2 => { port_default_config.parity = Parity::Even; ui_upd.send(Message::UiUpdateStatusBarParity("Even".to_string())).unwrap(); } _ => { ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap(); } } } else { ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap(); } } } "stopbit" => { if args.len() != 2 { ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap(); } else { if let Ok(value) = args[1].parse::() { ui_upd.send(Message::UiUpdateStatusBarStopbit(value)).unwrap(); match value { 1 => port_default_config.stopbit = StopBits::One, 2 => port_default_config.stopbit = StopBits::Two, _ => ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap(), } } else { ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap(); } } } "flowcontrol" => { if args.len() != 2 { ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap(); } else { match args[1].as_str() { "hard" => port_default_config.flow_control = FlowControl::Hardware, "soft" => port_default_config.flow_control = FlowControl::Software, "none" => port_default_config.flow_control = FlowControl::None, _ => { ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap(); } } } } "period" => { if args.len() != 2 { ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap(); } else { match args[1].parse::() { Ok(value) => { if port_status_open { main2port_tx.send(Message::PortPeriodDuration(value)).unwrap(); ui_upd.send(Message::UiUpdateStatusBarPeriod(value)).unwrap(); } else{ ui_upd.send(Message::UiUpdateLog("No port open\n".parse().unwrap())).unwrap(); } } Err(e) => ui_upd.send(Message::UiUpdateLog(format!("{:?}\n", e))).unwrap(), } } } _ => { ui_upd.send(Message::UiUpdateLog("command does not support!\n".to_string())).unwrap(); } } } Message::PortHaveData(data) => { ui_upd.send(Message::UiUpdateReceiveMsg(data)).unwrap(); } Message::PortCloseSucceed => { ui_upd.send(Message::UiUpdateLog("Close port succeed\n".to_string())).unwrap(); port_status_open = false; } Message::PortError(msg) => { ui_upd.send(Message::UiUpdateLog(format!("port closed by error: {}\n", msg))).unwrap(); port_status_open = false; } Message::PortPeriodDuration(value) => { ui_upd.send(Message::UiUpdateStatusBarPeriod(value)).unwrap(); } _ => {} } } std::thread::sleep(Duration::from_millis(20)); } }