Skip to content

Commit

Permalink
Get TCPIP VISA Instrument Info from LXI ID Page Instead of *IDN? (#44)
Browse files Browse the repository at this point in the history
This is a less disruptive way to get the Instrument information since it
gets this information from the webpage instead of from the command
processor on the instrument.

Testing: This has been tested using NI VISA and a Keithley Model 2461
  • Loading branch information
esarver authored Nov 14, 2024
1 parent 72473ab commit 308dfb0
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 33 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how
### Fixed

- Fixed CI issue where macOS artifacts would overwrite linux artifacts
- VISA discovery now properly cleans up instrument after getting info

## [0.18.4]

Expand Down
3 changes: 2 additions & 1 deletion kic-discover-visa/src/ethernet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ use crate::{insert_disc_device, model_check, IoType};

pub const COMM_PORT: u16 = 5025;
pub const DST_PORT: u16 = 5030;
pub const SERVICE_NAMES: [&str; 3] = [
pub const SERVICE_NAMES: [&str; 4] = [
"_scpi-raw._tcp.local",
"_lxi._tcp.local",
"_vxi-11._tcp.local",
"_hislip._tcp.local",
//"_scpi-telnet._tcp.local",
];

Expand Down
88 changes: 57 additions & 31 deletions kic-discover-visa/src/visa.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
use std::{collections::HashSet, ffi::CString, time::Duration};
use std::{collections::HashSet, ffi::CString, net::IpAddr, time::Duration};

use serde::{Deserialize, Serialize};
use tracing::{error, trace};
use tsp_toolkit_kic_lib::{
instrument::info::{get_info, InstrumentInfo},
instrument::{info::InstrumentInfo, Instrument},
interface::connection_addr::ConnectionAddr,
protocol::Protocol,
};
use visa_rs::{flags::AccessMode, AsResourceManager};
use visa_rs::AsResourceManager;

use crate::{insert_disc_device, model_check, IoType};
use crate::{ethernet::LxiDeviceInfo, insert_disc_device, model_check, IoType};

/// Extract the IP address from the resource string and then get the [`LxiDeviceInfo`]
/// which can be converted to [`InstrumentInfo`].
/// Returns [`None`] in all error cases
pub async fn visa_tcpip_info(rsc: String) -> Option<InstrumentInfo> {
let [_, ip_addr, ..] = rsc.split("::").collect::<Vec<&str>>()[..] else {
return None;
};
let instr_addr: IpAddr = ip_addr.parse().ok()?;
let lxi_xml = LxiDeviceInfo::query_lxi_xml(instr_addr).await?;
Some(LxiDeviceInfo::parse_lxi_xml(&lxi_xml, instr_addr)?.into())
}

#[tracing::instrument]
pub async fn visa_discover(timeout: Option<Duration>) -> anyhow::Result<HashSet<InstrumentInfo>> {
Expand All @@ -31,39 +44,52 @@ pub async fn visa_discover(timeout: Option<Duration>) -> anyhow::Result<HashSet<
let Ok(i) = i else {
continue;
};

if i.to_string().contains("SOCKET") || i.to_string().contains("INTFC") {
continue;
}
trace!("Connecting to {i:?} to get info");
let Ok(mut connected) = rm.open(&i, AccessMode::NO_LOCK, visa_rs::TIMEOUT_IMMEDIATE) else {
trace!("Resource {i} no longer available, skipping.");
continue;
};

trace!("Getting info from {connected:?}");
let Ok(mut info) = get_info(&mut connected) else {
trace!("Unable to write to {i}, skipping");
drop(connected);
continue;
let info = if i.to_string().starts_with("TCPIP") {
trace!("Getting info from LXI page");
visa_tcpip_info(i.to_string()).await
} else {
trace!("Connecting to {i:?} to get info");
let Ok(interface) = Protocol::try_from_visa(i.to_string()) else {
trace!("Resource {i} no longer available, skipping.");
continue;
};
let mut connected: Box<dyn Instrument> = match interface.try_into() {
Ok(c) => c,
Err(_) => {
trace!("Resource {i} no longer available, skipping.");
continue;
}
};

trace!("Getting info from {:?}", i);
connected.info().ok()
};
info.address = Some(ConnectionAddr::Visa(i.clone()));
trace!("Got info: {info:?}");
let res = model_check(info.clone().model.unwrap_or("".to_string()).as_str());
if res.0 {
if let Ok(out_str) = serde_json::to_string(&VisaDeviceInfo {
io_type: IoType::Visa,
instr_address: i.to_string(),
manufacturer: "Keithley Instruments".to_string(),
model: info.clone().model.unwrap_or("UNKNOWN".to_string()),
serial_number: info.clone().serial_number.unwrap_or("UNKNOWN".to_string()),
firmware_revision: info.clone().firmware_rev.unwrap_or("UNKNOWN".to_string()),
instr_categ: model_check(info.clone().model.unwrap_or("".to_string()).as_str())
.1
.to_string(),
}) {
insert_disc_device(out_str.as_str())?;

if let Some(mut info) = info {
info.address = Some(ConnectionAddr::Visa(i.clone()));
trace!("Got info: {info:?}");
let res = model_check(info.clone().model.unwrap_or("".to_string()).as_str());
if res.0 {
if let Ok(out_str) = serde_json::to_string(&VisaDeviceInfo {
io_type: IoType::Visa,
instr_address: i.to_string(),
manufacturer: "Keithley Instruments".to_string(),
model: info.clone().model.unwrap_or("UNKNOWN".to_string()),
serial_number: info.clone().serial_number.unwrap_or("UNKNOWN".to_string()),
firmware_revision: info.clone().firmware_rev.unwrap_or("UNKNOWN".to_string()),
instr_categ: model_check(info.clone().model.unwrap_or("".to_string()).as_str())
.1
.to_string(),
}) {
insert_disc_device(out_str.as_str())?;
}
discovered_instruments.insert(info);
}
discovered_instruments.insert(info);
}
}
Ok(discovered_instruments)
Expand Down
3 changes: 2 additions & 1 deletion kic-discover/src/ethernet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ use crate::{insert_disc_device, model_check, IoType};

pub const COMM_PORT: u16 = 5025;
pub const DST_PORT: u16 = 5030;
pub const SERVICE_NAMES: [&str; 3] = [
pub const SERVICE_NAMES: [&str; 4] = [
"_scpi-raw._tcp.local",
"_lxi._tcp.local",
"_vxi-11._tcp.local",
"_hislip._tcp.local",
//"_scpi-telnet._tcp.local",
];

Expand Down

0 comments on commit 308dfb0

Please sign in to comment.