visa_api/
lib.rs

1use std::fmt::Display;
2
3use thiserror::Error;
4use visa_rs::{flags::AccessMode, AsResourceManager, DefaultRM, TIMEOUT_IMMEDIATE};
5pub mod prelude;
6
7#[derive(Debug, Error)]
8pub enum Error {
9    #[error(transparent)]
10    StdIo(#[from] std::io::Error),
11    #[error(transparent)]
12    VisaRs(#[from] visa_rs::Error),
13    #[error("No instrument was found")]
14    NoInstrumentFound(),
15}
16
17pub type Result<T> = core::result::Result<T, Error>;
18
19#[derive(Debug, PartialEq, strum::AsRefStr, strum::Display)]
20pub enum Commands {
21    #[strum(serialize = "CLS")]
22    ClearStatus,
23    #[strum(serialize = "*ESE")]
24    EventStatusEnable,
25    #[strum(serialize = "*ESE?")]
26    EventStatusEnableQuery,
27    #[strum(serialize = "*ESR?")]
28    EventStatusEnableRegister,
29    #[strum(serialize = "*IDN?")]
30    Identify,
31    #[strum(serialize = "*OPC")]
32    OperationCompleteCommand,
33    #[strum(serialize = "*OPC?")]
34    OperationCompleteQuery,
35    #[strum(serialize = "*OPT?")]
36    IdentifyOptionsQuery,
37    #[strum(serialize = "*RST")]
38    Reset,
39    #[strum(serialize = "*SRE")]
40    ServiceRequestEnable,
41    #[strum(serialize = "*SRE?")]
42    ServiceRequestEnableQuery,
43    #[strum(serialize = "*STB?")]
44    StatusByteQuery,
45    #[strum(serialize = "*TST?")]
46    ResultOfSelfTestQuery,
47    #[strum(serialize = "*WAI")]
48    Wait,
49}
50
51#[derive(Clone, Debug)]
52pub struct Idn {
53    pub manufacturer: String,
54    pub model: String,
55    pub serial_number: String,
56    pub software_version: String,
57}
58
59pub fn find_resources(rm: &visa_rs::DefaultRM) -> Result<Vec<visa_rs::VisaString>> {
60    let expr = visa_rs::VisaString::from(
61        std::ffi::CString::new("?*INSTR").expect("Failed to create C compatible String."),
62    );
63    let mut visa_rs_reslist = rm.find_res_list(&expr)?;
64    let mut res_exhausted = false;
65    let mut res: Vec<visa_rs::VisaString> = vec![];
66    while !res_exhausted {
67        let visa_rs_res = visa_rs_reslist.find_next()?;
68        if let Some(visa_rs_res) = visa_rs_res {
69            res.push(visa_rs_res);
70        } else {
71            res_exhausted = true;
72        };
73    }
74    Ok(res)
75}
76
77fn get_idn(instrument: &mut visa_rs::Instrument) -> Result<Idn> {
78    std::io::Write::write_all(instrument, Commands::Identify.as_ref().as_bytes())?;
79    let mut r = std::io::BufReader::new(instrument);
80    let mut buf = String::new();
81    std::io::BufRead::read_line(&mut r, &mut buf)?;
82
83    let buf = buf
84        .split(',')
85        .map(|s| s.trim().to_string())
86        .collect::<Vec<String>>();
87    Ok(Idn {
88        manufacturer: buf[0].to_owned(),
89        model: buf[1].to_owned(),
90        serial_number: buf[2].to_owned(),
91        software_version: buf[3].to_owned(),
92    })
93}
94
95pub trait Visa {
96    fn into_inner(&self) -> &visa_rs::Instrument;
97
98    fn find_instrument<T>(rm: &DefaultRM, manufacturer: T, model: T) -> Result<visa_rs::Instrument>
99    where
100        T: Into<String> + Display,
101    {
102        let resources = find_resources(rm)?;
103        for resource in resources {
104            let mut instrument = rm.open(&resource, AccessMode::NO_LOCK, TIMEOUT_IMMEDIATE)?;
105            let idn = get_idn(&mut instrument).unwrap();
106            let manufacturer_and_model = format!("{} {}", idn.manufacturer, idn.model);
107            if manufacturer_and_model.contains(&format!("{} {}", manufacturer, model)) {
108                return Ok(instrument);
109            }
110        }
111        Err(Error::NoInstrumentFound())
112    }
113
114    fn write<T>(&mut self, cmd: T) -> Result<()>
115    where
116        T: Into<String>,
117    {
118        let cmd: String = cmd.into();
119        std::io::Write::write_all(&mut self.into_inner(), cmd.as_bytes())?;
120        Ok(())
121    }
122
123    fn read(&self) -> Result<String> {
124        let mut buf = String::new();
125        std::io::Read::read_to_string(&mut self.into_inner(), &mut buf)?;
126        Ok(buf)
127    }
128
129    fn get_idn(&mut self) -> Result<Idn> {
130        self.write(Commands::Identify.as_ref())?;
131        let buf = self.read()?;
132        let buf = buf
133            .split(',')
134            .map(|s| s.trim().to_string())
135            .collect::<Vec<String>>();
136        Ok(Idn {
137            manufacturer: buf[0].to_owned(),
138            model: buf[1].to_owned(),
139            serial_number: buf[2].to_owned(),
140            software_version: buf[3].to_owned(),
141        })
142    }
143
144    fn reset(&mut self) -> Result<()> {
145        self.write(Commands::Reset.as_ref())?;
146        Ok(())
147    }
148}