From 21c22bbddbfe456a98d72c07ebdfbf24d53515b2 Mon Sep 17 00:00:00 2001 From: "Sarver, Edwin" Date: Thu, 10 Oct 2024 11:44:58 -0400 Subject: [PATCH 1/4] Only Call ReadSTB when Necessary Two scenarios: 1. After writing commands/scripts to the instrument 2. Every 3 seconds as a heartbeat --- instrument-repl/src/repl.rs | 20 +++++++++++++++----- kic-visa/src/main.rs | 1 + kic/src/main.rs | 1 + 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/instrument-repl/src/repl.rs b/instrument-repl/src/repl.rs index 398b362..196cb25 100644 --- a/instrument-repl/src/repl.rs +++ b/instrument-repl/src/repl.rs @@ -17,7 +17,7 @@ use std::{ path::PathBuf, sync::mpsc::{channel, SendError, Sender, TryRecvError}, thread::JoinHandle, - time::Duration, + time::{Duration, Instant}, }; use tracing::{debug, error, info, instrument, trace, warn}; @@ -205,17 +205,23 @@ impl Repl { } let mut prompt = true; + let mut command_written = true; + let mut last_read = Instant::now(); debug!("Starting user loop"); 'user_loop: loop { self.inst.set_nonblocking(true)?; std::thread::sleep(Duration::from_micros(1)); - let mut read_buf: Vec = vec![0; 1024]; - let read_size = self.inst.read(&mut read_buf)?; - let read_buf: Vec = read_buf[..read_size].into(); - prompt = self.handle_data(&read_buf, prompt, &mut prev_state, &mut state)?; + if command_written || last_read.elapsed() >= Duration::from_secs(3) { + let mut read_buf: Vec = vec![0; 1024]; + let read_size = self.inst.read(&mut read_buf)?; + let read_buf: Vec = read_buf[..read_size].into(); + prompt = self.handle_data(&read_buf, prompt, &mut prev_state, &mut state)?; + last_read = Instant::now(); + } if prompt { prompt = false; + command_written = false; Self::print_flush(&"\nTSP> ".blue())?; } match loop_in.try_recv() { @@ -224,6 +230,7 @@ impl Repl { match msg { Request::Tsp(tsp) => { self.inst.write_all(format!("{tsp}\n").as_bytes())?; + command_written = true; prev_state = None; } Request::GetError => { @@ -268,6 +275,7 @@ impl Repl { } } prompt = false; + command_written = true; } Request::TspLinkNodes { json_file } => { self.set_lang_config_path(json_file.to_string_lossy().to_string()); @@ -293,6 +301,7 @@ impl Repl { // lose runtime state, so we can't save the previous // setting, so we just hardcode it to enabled here. self.inst.write_all(b"localnode.prompts=1\n")?; + command_written = true; } Request::Exit => { info!("Exiting..."); @@ -301,6 +310,7 @@ impl Repl { Request::Reset => { self.inst.as_mut().reset()?; prompt = true; + command_written = true; } Request::Help { sub_cmd } => { prompt = true; diff --git a/kic-visa/src/main.rs b/kic-visa/src/main.rs index 40d7184..060c159 100644 --- a/kic-visa/src/main.rs +++ b/kic-visa/src/main.rs @@ -619,6 +619,7 @@ fn connect(args: &ArgMatches) -> anyhow::Result<()> { info!("Starting instrument REPL"); if let Err(e) = repl.start() { error!("Error in REPL: {e}"); + eprintln!("{}", format!("{e}\nClosing...").red()); } Ok(()) diff --git a/kic/src/main.rs b/kic/src/main.rs index a56b84a..a90b15e 100644 --- a/kic/src/main.rs +++ b/kic/src/main.rs @@ -615,6 +615,7 @@ fn connect(args: &ArgMatches) -> anyhow::Result<()> { info!("Starting instrument REPL"); if let Err(e) = repl.start() { error!("Error in REPL: {e}"); + eprintln!("{}", format!("{e}\nClosing...").red()); } Ok(()) From 55e290b1427ffbbe5ed16a5d29e026032a1ba15b Mon Sep 17 00:00:00 2001 From: "Sarver, Edwin" Date: Thu, 10 Oct 2024 11:49:04 -0400 Subject: [PATCH 2/4] update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6108a6d..cc7e7dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,8 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how ### Changed - .script , .upgrade and .exit commands descriptions updated +- When using VISA, only call ReadSTB after writing commands to the instrument + (or every 3 seconds for a heartbeat) ## [0.18.2] From 4422c2d59852fb75640d0559ffc5c58863e4e032 Mon Sep 17 00:00:00 2001 From: "Sarver, Edwin" Date: Thu, 10 Oct 2024 11:50:47 -0400 Subject: [PATCH 3/4] remove unused import --- kic-discover-visa/src/visa.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/kic-discover-visa/src/visa.rs b/kic-discover-visa/src/visa.rs index 4edc77d..d286d43 100644 --- a/kic-discover-visa/src/visa.rs +++ b/kic-discover-visa/src/visa.rs @@ -1,6 +1,5 @@ use std::{collections::HashSet, ffi::CString, time::Duration}; -use async_std::fs::write; use serde::{Deserialize, Serialize}; use tracing::{error, trace}; use tsp_toolkit_kic_lib::{ From 12bef360b1aaab964663f837609c9c08f5b35657 Mon Sep 17 00:00:00 2001 From: "Sarver, Edwin" Date: Thu, 10 Oct 2024 14:07:06 -0400 Subject: [PATCH 4/4] Pause and wait for user input before closing upon most errors --- CHANGELOG.md | 1 + instrument-repl/src/repl.rs | 9 +++++---- kic-visa/src/main.rs | 40 ++++++++++++++++++++++++++++++++++++- kic/src/main.rs | 40 ++++++++++++++++++++++++++++++++++++- 4 files changed, 84 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc7e7dd..8bab15d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how - .script , .upgrade and .exit commands descriptions updated - When using VISA, only call ReadSTB after writing commands to the instrument (or every 3 seconds for a heartbeat) +- Pause when an error occurs so users can see the errors ## [0.18.2] diff --git a/instrument-repl/src/repl.rs b/instrument-repl/src/repl.rs index 196cb25..02bdb00 100644 --- a/instrument-repl/src/repl.rs +++ b/instrument-repl/src/repl.rs @@ -15,7 +15,8 @@ use std::{ fs::{self, File}, io::{self, Read, Write}, path::PathBuf, - sync::mpsc::{channel, SendError, Sender, TryRecvError}, + process::exit, + sync::mpsc::{channel, Sender, TryRecvError}, thread::JoinHandle, time::{Duration, Instant}, }; @@ -724,9 +725,9 @@ impl Repl { let mut input = String::new(); let _ = std::io::stdin().read_line(&mut input)?; let req = Self::parse_user_commands(&input)?; - match out.send(req.clone()) { - Ok(()) => {} - Err(SendError(_)) => break 'input_loop, + if out.send(req.clone()).is_err() { + error!("User input thread could not send to Receiver. Closing!"); + exit(1); } // This `if` statement seeks to fix the NOTE above about not exiting. // It feels a little awkward, but should be effective. diff --git a/kic-visa/src/main.rs b/kic-visa/src/main.rs index 060c159..0eca90d 100644 --- a/kic-visa/src/main.rs +++ b/kic-visa/src/main.rs @@ -576,6 +576,15 @@ fn get_instrument_access(inst: &mut Box) -> anyhow::Result<()> { Ok(()) } +fn pause_exit_on_error() { + eprintln!( + "\n\n{}", + "An error occured. Press Enter to close this program.".yellow() + ); + let mut buf = String::new(); + let _ = std::io::stdin().read_line(&mut buf); +} + #[instrument(skip(args))] fn connect(args: &ArgMatches) -> anyhow::Result<()> { info!("Connecting to instrument"); @@ -588,6 +597,11 @@ fn connect(args: &ArgMatches) -> anyhow::Result<()> { Ok(c) => c, Err(e) => { error!("Unable to parse connection information: {e}"); + eprintln!( + "{}", + format!("\nUnable to parse connection information: {e}\n\nUnrecoverable error. Closing.").red() + ); + pause_exit_on_error(); return Err(e); } }; @@ -595,12 +609,25 @@ fn connect(args: &ArgMatches) -> anyhow::Result<()> { Ok(i) => i, Err(e) => { error!("Error connecting to async instrument: {e}"); + eprintln!( + "{}", + format!( + "\nError connecting to async instrument: {e}\n\nUnrecoverable error. Closing." + ) + .red() + ); + pause_exit_on_error(); return Err(e); } }; if let Err(e) = get_instrument_access(&mut instrument) { error!("Error setting up instrument: {e}"); + eprintln!( + "{}", + format!("\nError setting up instrument: {e}\n\nUnrecoverable error. Closing.").red() + ); + pause_exit_on_error(); return Err(e); } @@ -608,6 +635,12 @@ fn connect(args: &ArgMatches) -> anyhow::Result<()> { Ok(i) => i, Err(e) => { error!("Error getting instrument info: {e}"); + eprintln!( + "{}", + format!("\nError getting instrument info: {e}\n\nUnrecoverable error. Closing.") + .red() + ); + pause_exit_on_error(); return Err(e.into()); } }; @@ -619,7 +652,12 @@ fn connect(args: &ArgMatches) -> anyhow::Result<()> { info!("Starting instrument REPL"); if let Err(e) = repl.start() { error!("Error in REPL: {e}"); - eprintln!("{}", format!("{e}\nClosing...").red()); + eprintln!( + "{}", + format!("\n{e}\n\nClosing instrument connection...").red() + ); + drop(repl); + pause_exit_on_error(); } Ok(()) diff --git a/kic/src/main.rs b/kic/src/main.rs index a90b15e..0602ef3 100644 --- a/kic/src/main.rs +++ b/kic/src/main.rs @@ -572,6 +572,15 @@ fn get_instrument_access(inst: &mut Box) -> anyhow::Result<()> { Ok(()) } +fn pause_exit_on_error() { + eprintln!( + "\n\n{}", + "An error occured. Press Enter to close this program.".yellow() + ); + let mut buf = String::new(); + let _ = std::io::stdin().read_line(&mut buf); +} + #[instrument(skip(args))] fn connect(args: &ArgMatches) -> anyhow::Result<()> { info!("Connecting to instrument"); @@ -584,6 +593,11 @@ fn connect(args: &ArgMatches) -> anyhow::Result<()> { Ok(c) => c, Err(e) => { error!("Unable to parse connection information: {e}"); + eprintln!( + "{}", + format!("\nUnable to parse connection information: {e}\n\nUnrecoverable error. Closing.").red() + ); + pause_exit_on_error(); return Err(e); } }; @@ -591,12 +605,25 @@ fn connect(args: &ArgMatches) -> anyhow::Result<()> { Ok(i) => i, Err(e) => { error!("Error connecting to async instrument: {e}"); + eprintln!( + "{}", + format!( + "\nError connecting to async instrument: {e}\n\nUnrecoverable error. Closing." + ) + .red() + ); + pause_exit_on_error(); return Err(e); } }; if let Err(e) = get_instrument_access(&mut instrument) { error!("Error setting up instrument: {e}"); + eprintln!( + "{}", + format!("\nError setting up instrument: {e}\n\nUnrecoverable error. Closing.").red() + ); + pause_exit_on_error(); return Err(e); } @@ -604,6 +631,12 @@ fn connect(args: &ArgMatches) -> anyhow::Result<()> { Ok(i) => i, Err(e) => { error!("Error getting instrument info: {e}"); + eprintln!( + "{}", + format!("\nError getting instrument info: {e}\n\nUnrecoverable error. Closing.") + .red() + ); + pause_exit_on_error(); return Err(e.into()); } }; @@ -615,7 +648,12 @@ fn connect(args: &ArgMatches) -> anyhow::Result<()> { info!("Starting instrument REPL"); if let Err(e) = repl.start() { error!("Error in REPL: {e}"); - eprintln!("{}", format!("{e}\nClosing...").red()); + eprintln!( + "{}", + format!("\n{e}\n\nClosing instrument connection...").red() + ); + drop(repl); + pause_exit_on_error(); } Ok(())