1use std::str::FromStr;
2use visa_api::*;
3pub struct Keithley2230 {
4 pub inner: visa_api::Instrument,
5}
6
7pub const MANUFACTURER: &str = "Keithley Instruments";
8pub const MODEL: &str = "2230";
9
10#[derive(Clone, Copy, Debug, thiserror::Error)]
11pub enum Error {
12 #[error(transparent)]
13 VisaApiError(#[from] visa_api::Error),
14 #[error(transparent)]
15 StrumParseError(#[from] strum::ParseError),
16 #[error("No Instrument found")]
17 NoInstrumentFound(),
18}
19
20pub type Result<T> = std::result::Result<T, Error>;
21
22#[derive(Debug, PartialEq, strum::AsRefStr, strum::Display, Default, strum::EnumString)]
23pub enum Channel {
24 #[default]
25 #[strum(serialize = "CH1")]
26 CH1,
27 #[strum(serialize = "CH2")]
28 CH2,
29 #[strum(serialize = "CH3")]
30 CH3,
31}
32
33#[derive(Debug, PartialEq, strum::AsRefStr, strum::Display, Default)]
34pub enum State {
35 #[default]
36 #[strum(serialize = "ON", serialize = "1")]
37 ON,
38 #[strum(serialize = "OFF", serialize = "0")]
39 OFF,
40}
41#[derive(Debug, Default)]
42pub struct Meas {
43 pub ch1: ChMeas,
44 pub ch2: ChMeas,
45 pub ch3: ChMeas,
46}
47
48#[derive(Debug, Default)]
49pub struct ChMeas {
50 pub v: f32,
51 pub i: f32,
52 pub p: f32,
53}
54
55impl ChMeas {
56 pub fn new(v: f32, i: f32, p: f32) -> Self {
57 Self { v, i, p }
58 }
59}
60
61impl Keithley2230 {
62 pub fn new(rm: &DefaultRM) -> Result<Self> {
63 let session = Instrument::new_session(&rm, MANUFACTURER, MODEL)?;
64 if let Some(session) = session {
65 Ok(Self { inner: session })
66 } else {
67 Err(Error::NoInstrumentFound())
68 }
69 }
70
71 pub fn set_channel(&mut self, ch: Channel, v: f32, i: f32) -> Result<()> {
72 let cmd = format!("APPL {}, {}, {}", ch, v, i);
73 self.inner.write(&cmd)?;
74 Ok(())
75 }
76
77 pub fn enable_output(&mut self, state: State) -> Result<()> {
78 let cmd = format!("OUTP:ENAB {}", state);
79 self.inner.write(&cmd)?;
80 Ok(())
81 }
82
83 pub fn enable_channel(&mut self, ch: Channel, state: State) -> Result<()> {
84 let prev_ch = self.get_channel()?;
85 self.select_channel(ch)?;
86 let cmd = format!("CHAN:OUTP {}", state);
87 self.inner.write(&cmd)?;
88 self.select_channel(prev_ch)?;
89 Ok(())
90 }
91
92 pub fn get_channel(&mut self) -> Result<Channel> {
93 self.inner.write("INST?")?;
94 let ch = self.inner.read()?;
95 let ch = Channel::from_str(&ch)?;
96 Ok(ch)
97 }
98
99 pub fn select_channel(&mut self, ch: Channel) -> Result<()> {
100 let cmd = format!("INST {}", ch);
101 self.inner.write(&cmd)?;
102 Ok(())
103 }
104
105 pub fn front_panel_ctrl(&mut self) -> Result<()> {
106 self.inner.write("SYST:LOC")?;
107 Ok(())
108 }
109
110 pub fn remote_ctrl(&mut self) -> Result<()> {
111 self.inner.write("SYST:REM")?;
112 Ok(())
113 }
114
115 pub fn read_i(&mut self) -> Result<(f32, f32, f32)> {
116 self.inner.write("FETC:CURR? ALL")?;
117 let response = self.inner.read()?;
118
119 let response = response
120 .split(',')
121 .map(|x| x.trim().parse::<f32>().ok().unwrap_or(0.0))
122 .collect::<Vec<f32>>();
123
124 if response.len() == 3 {
125 Ok((response[0], response[1], response[2]))
126 } else {
127 Ok((0.0, 0.0, 0.0))
128 }
129 }
130
131 pub fn read_v(&mut self) -> Result<(f32, f32, f32)> {
132 self.inner.write("FETC:VOLT? ALL")?;
133 let response = self.inner.read()?;
134
135 let response = response
136 .split(',')
137 .map(|x| x.trim().parse::<f32>().ok().unwrap_or(0.0))
138 .collect::<Vec<f32>>();
139
140 if response.len() == 3 {
141 Ok((response[0], response[1], response[2]))
142 } else {
143 Ok((0.0, 0.0, 0.0))
144 }
145 }
146
147 pub fn read_p(&mut self) -> Result<(f32, f32, f32)> {
148 self.inner.write("FETC:POW? ALL")?;
149 let response = self.inner.read()?;
150
151 let response = response
152 .split(',')
153 .map(|x| x.trim().parse::<f32>().ok().unwrap_or(0.0))
154 .collect::<Vec<f32>>();
155
156 if response.len() == 3 {
157 Ok((response[0], response[1], response[2]))
158 } else {
159 Ok((0.0, 0.0, 0.0))
160 }
161 }
162
163 pub fn read_all(&mut self) -> Result<Meas> {
164 let v = self.read_v()?;
165 let i = self.read_i()?;
166 let p = self.read_p()?;
167
168 let meas = Meas {
169 ch1: ChMeas::new(v.0, i.0, p.0),
170 ch2: ChMeas::new(v.1, i.1, p.1),
171 ch3: ChMeas::new(v.2, i.2, p.2),
172 };
173
174 Ok(meas)
175 }
176
177 pub fn set_paralel(&mut self, state: State) -> Result<()> {
178 let cmd = format!("OUT:PAR {}", state);
179 self.inner.write(&cmd)?;
180 Ok(())
181 }
182
183 pub fn set_series(&mut self, state: State) -> Result<()> {
184 let cmd = format!("OUT:SER {}", state);
185 self.inner.write(&cmd)?;
186 Ok(())
187 }
188}