use std::io::{BufRead, Write};
use thiserror::Error;
use visa_rs::AsResourceManager;
pub use visa_rs::DefaultRM;
#[derive(Debug, Clone, Copy, Error)]
pub enum Error {
#[error(transparent)]
VisaRs(#[from] visa_rs::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, PartialEq, strum::AsRefStr, strum::Display)]
pub enum CommonCommands {
#[strum(serialize = "CLS")]
ClearStatus,
#[strum(serialize = "*ESE")]
EventStatusEnable,
#[strum(serialize = "*ESE?")]
EventStatusEnableQuery,
#[strum(serialize = "*ESR?")]
EventStatusEnableRegister,
#[strum(serialize = "*IDN?")]
Identify,
#[strum(serialize = "*OPC")]
OperationCompleteCommand,
#[strum(serialize = "*OPC?")]
OperationCompleteQuery,
#[strum(serialize = "*OPT?")]
IdentifyOptionsQuery,
#[strum(serialize = "*RST")]
Reset,
#[strum(serialize = "*SRE")]
ServiceRequestEnable,
#[strum(serialize = "*SRE?")]
ServiceRequestEnableQuery,
#[strum(serialize = "*STB?")]
StatusByteQuery,
#[strum(serialize = "*TST?")]
ResultOfSelfTestQuery,
#[strum(serialize = "*WAI")]
Wait,
}
#[derive(Clone, Debug)]
pub struct Idn {
pub manufacturer: String,
pub model: String,
pub serial_number: String,
pub software_version: String,
}
#[derive(Debug)]
pub struct Instrument {
pub idn: Idn,
pub session: visa_rs::Instrument,
pub address: visa_rs::VisaString,
}
impl Instrument {
pub fn new(idn: Idn, session: visa_rs::Instrument, address: visa_rs::VisaString) -> Instrument {
Instrument {
idn,
session,
address,
}
}
pub fn write(&mut self, command: &str) -> Result<()> {
self.session
.write_all(command.as_bytes())
.map_err(visa_rs::io_to_vs_err)?;
Ok(())
}
fn private_write(session: &mut visa_rs::Instrument, command: &str) -> Result<()> {
session
.write_all(command.as_bytes())
.map_err(visa_rs::io_to_vs_err)?;
Ok(())
}
pub fn read(&self) -> Result<String> {
let mut reader = std::io::BufReader::new(&self.session);
let mut buffer = String::new();
reader
.read_line(&mut buffer)
.map_err(visa_rs::io_to_vs_err)?;
Ok(buffer)
}
pub fn private_read(session: &visa_rs::Instrument) -> Result<String> {
let mut reader = std::io::BufReader::new(session);
let mut buffer = String::new();
reader
.read_line(&mut buffer)
.map_err(visa_rs::io_to_vs_err)?;
Ok(buffer)
}
pub fn query_idn(&mut self) -> Result<Idn> {
self.write(CommonCommands::Identify.as_ref())?;
let response = self.read()?;
let idn = response
.split(',')
.map(|x| x.trim().to_string())
.collect::<Vec<String>>();
Ok(Idn {
manufacturer: idn[0].to_owned(),
model: idn[1].to_owned(),
serial_number: idn[2].to_owned(),
software_version: idn[3].to_owned(),
})
}
fn private_query_idn(session: &mut visa_rs::Instrument) -> Result<Idn> {
Self::private_write(session, CommonCommands::Identify.as_ref())?;
let response = Self::private_read(session)?;
let idn = response
.split(',')
.map(|x| x.trim().to_string())
.collect::<Vec<String>>();
Ok(Idn {
manufacturer: idn[0].to_owned(),
model: idn[1].to_owned(),
serial_number: idn[2].to_owned(),
software_version: idn[3].to_owned(),
})
}
pub fn get_instrument(
resource_manager: &visa_rs::DefaultRM,
manufacturer: &str,
model: &str,
) -> Result<Option<Instrument>> {
let addresses = Self::get_addresses(resource_manager)?;
for address in addresses {
let mut session = resource_manager.open(
&address,
visa_rs::flags::AccessMode::NO_LOCK,
visa_rs::TIMEOUT_IMMEDIATE,
)?;
let idn = Self::private_query_idn(&mut session)?;
let manufacturer_and_model = format!("{} {}", idn.manufacturer, idn.model);
if manufacturer_and_model.contains(&format!("{} {}", manufacturer, model)) {
return Ok(Some(Instrument {
idn,
session,
address,
}));
}
}
Ok(None)
}
pub fn get_addresses(
resource_manager: &visa_rs::DefaultRM,
) -> Result<Vec<visa_rs::VisaString>> {
let expression = visa_rs::VisaString::from(
std::ffi::CString::new("?*INSTR").expect("Failed to create C compatible String."),
);
let mut resources = resource_manager.find_res_list(&expression)?;
let mut resources_checked = false;
let mut addresses: Vec<visa_rs::VisaString> = vec![];
while !resources_checked {
let resource = resources.find_next()?;
if resource.is_none() {
resources_checked = true;
} else {
let resource = resource.expect("No VISA Resource Found");
addresses.push(resource);
}
}
Ok(addresses)
}
pub fn reset(&mut self) -> Result<()> {
self.write(CommonCommands::Reset.as_ref())?;
Ok(())
}
}