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}