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

417 lines
17 KiB
Rust

#![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: &gtk::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::<Message>();
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<Message>, gui2main_tx: Sender<Message>) {
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<String> = 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<String> = 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<Message>, rx: Receiver<Message>, ui_upd: glib::Sender<Message>) {
let (mut main2port_tx, _rx_port_receive) = channel::<Message>();
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::<Message>();
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::<u32>() {
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::<u32>() {
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::<u32>() {
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::<u32>() {
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::<u64>() {
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));
}
}