1use crate::error::{GpibError, IbError};
2use crate::lowlevel::multidevice;
3use crate::lowlevel::traditional::{ibclr, ibdev, ibonl, ibrd, ibrda, ibwait, ibwrt, ibwrta};
4use crate::lowlevel::utility::Addr4882;
5use crate::status::IbStatus;
6use crate::types::{IbEosMode, IbOnline, IbSendEOI, IbTimeout, PrimaryAddress, SecondaryAddress};
7use std::default::Default;
8use std::fmt;
9use std::os::raw::c_int;
10
11pub struct Parameters {
12 pub timeout: IbTimeout,
13 pub send_eoi: IbSendEOI,
14 pub eos_mode: IbEosMode,
15}
16
17impl Default for Parameters {
18 fn default() -> Self {
19 Self {
20 timeout: IbTimeout::T1s,
21 send_eoi: IbSendEOI::default(),
22 eos_mode: IbEosMode::default(),
23 }
24 }
25}
26
27#[derive(Clone, PartialEq)]
28pub struct Board {
29 board_number: c_int,
30}
31
32#[derive(Clone)]
33pub struct Instrument {
34 board: Board,
35 addr: Addr4882,
36}
37
38pub struct InstrumentHandle {
39 ud: c_int,
40}
41
42impl Board {
43 pub fn with_board_number(board_number: c_int) -> Self {
44 Board {
45 board_number: board_number,
46 }
47 }
48
49 pub fn clear_devices(&self, instruments: &Vec<Instrument>) -> Result<(), GpibError> {
51 if instruments
52 .iter()
53 .any(|instr| instr.board.board_number != self.board_number)
54 {
55 return Err(GpibError::ValueError(
56 "clear_devices can only send to devices belonging to this board.".to_owned(),
57 ));
58 }
59 let address_list = instruments.iter().map(|instr| instr.addr).collect();
60 multidevice::DevClearList(self.board_number, &address_list)
61 }
62
63 pub fn interface_clear(&self) -> Result<(), GpibError> {
67 multidevice::SendIFC(self.board_number)
68 }
69
70 pub fn find_listeners(&self) -> Result<Vec<Instrument>, GpibError> {
72 Ok(multidevice::FindAllLstn(self.board_number)?
73 .into_iter()
74 .map(|addr| Instrument {
75 board: self.clone(),
76 addr: addr,
77 })
78 .collect())
79 }
80
81 pub fn send_list(
83 &self,
84 instruments: &Vec<Instrument>,
85 data: &[u8],
86 mode: IbSendEOI,
87 ) -> Result<(), GpibError> {
88 if instruments
89 .iter()
90 .any(|instr| instr.board.board_number != self.board_number)
91 {
92 return Err(GpibError::ValueError(
93 "clear_devices can only send to devices belonging to this board.".to_owned(),
94 ));
95 }
96 let address_list = instruments.iter().map(|instr| instr.addr).collect();
97 multidevice::SendList(self.board_number, &address_list, data, mode)
98 }
99}
100
101impl Default for Board {
102 fn default() -> Self {
103 Board::with_board_number(0)
104 }
105}
106
107impl fmt::Display for Board {
108 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
109 write!(f, "Board({})", self.board_number)
110 }
111}
112
113impl fmt::Debug for Board {
114 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115 write!(f, "Board({})", self.board_number)
116 }
117}
118
119impl Instrument {
120 pub fn send(&self, data: &[u8], mode: IbSendEOI) -> Result<(), GpibError> {
122 multidevice::Send(self.board.board_number, self.addr, data, mode)
123 }
124
125 pub fn receive(&self) -> Result<String, GpibError> {
127 const BUFFER_SIZE: usize = 1024;
128 let mut result: Vec<u8> = Vec::new();
129 loop {
130 let mut buffer: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];
131 let (status, n_read) = multidevice::Receive(
132 self.board.board_number,
133 self.addr,
134 &mut buffer,
135 linux_gpib_sys::STOPend,
136 )?;
137 if n_read > 0 {
138 result.extend(buffer[0..n_read].to_vec());
139 }
140 if status.end || n_read < BUFFER_SIZE || n_read == 0 {
141 break;
142 }
143 }
144 let answer = String::from_utf8(result)?;
145 Ok(answer)
146 }
147
148 pub fn query(&self, data: &str) -> Result<String, GpibError> {
150 self.send(data.as_bytes(), IbSendEOI::default())?;
151 self.receive()
152 }
153
154 pub fn from_visa_string(address: &str) -> Result<Self, GpibError> {
156 let v: Vec<&str> = address.split("::").collect();
157 if v.len() < 2 {
158 return Err(GpibError::ValueError(format!(
159 "Invalid address '{}'.",
160 address
161 )));
162 }
163 if v[0].starts_with("GPIB") {
164 let (_, board_number) = v[0].split_at(4);
165 let board_number = i32::from_str_radix(board_number, 10).map_err(|e| {
166 GpibError::ValueError(format!(
167 "Unable to parse GPIB Board index from string '{}' ({:?})",
168 board_number, e,
169 ))
170 })?;
171 let primary_address = i32::from_str_radix(v[1], 10).map_err(|e| {
172 GpibError::ValueError(format!(
173 "Unable to parse GPIB primary address from string '{}' ({:?})",
174 v[1], e,
175 ))
176 })?;
177 Ok(Self {
178 board: Board::with_board_number(board_number),
179 addr: Addr4882::new(
180 PrimaryAddress::new(primary_address)?,
181 SecondaryAddress::default(),
182 )?,
183 })
184 } else {
185 Err(GpibError::ValueError(
186 "Address is expected as GPIBN::primary_address::INSTR".to_owned(),
187 ))
188 }
189 }
190
191 pub fn visa_string(&self) -> String {
193 format!(
194 "GPIB{}::{}::INSTR",
195 self.board.board_number,
196 self.addr.pad(),
197 )
198 }
199
200 pub fn open(&self, params: Parameters) -> Result<InstrumentHandle, GpibError> {
202 let ud = ibdev(
203 self.board.board_number,
204 self.addr.primary_address()?,
205 self.addr.secondary_address()?,
206 params.timeout,
207 params.send_eoi,
208 params.eos_mode,
209 )?;
210 ibclr(ud)?;
211 Ok(InstrumentHandle { ud })
212 }
213}
214
215impl fmt::Display for Instrument {
216 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
217 write!(f, "{}", self.visa_string())
218 }
219}
220
221impl fmt::Debug for Instrument {
222 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
223 write!(f, "Instrument({:?}, {:?})", self.board, self.addr)
224 }
225}
226
227impl InstrumentHandle {
228 pub fn blocking_read_raw(&self) -> Result<Vec<u8>, GpibError> {
229 const BUFFER_SIZE: usize = 1024;
230 let mut result: Vec<u8> = Vec::new();
231 loop {
232 let mut buffer: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];
233 let (status, n_read) = ibrd(self.ud, &mut buffer)?;
234 if n_read > 0 {
235 result.extend(buffer[0..n_read].to_vec());
236 }
237 if status.end || n_read < BUFFER_SIZE || n_read == 0 {
238 break;
239 }
240 }
241 Ok(result)
242 }
243
244 pub fn blocking_read(&self) -> Result<String, GpibError> {
245 let result = self.blocking_read_raw()?;
246 let answer = String::from_utf8(result)?;
247 Ok(answer)
248 }
249
250 #[cfg(feature = "async-tokio")]
251 pub async fn read_raw(&self) -> Result<Vec<u8>, GpibError> {
252 const BUFFER_SIZE: usize = 1024;
253 let mut result: Vec<u8> = Vec::new();
254 loop {
255 let mut buffer: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];
256 unsafe { ibrda(self.ud, &mut buffer) }?;
257 let (status, n_read) = ibwait(
258 self.ud,
259 IbStatus::default()
260 .with_timo(true)
261 .with_cmpl(true)
262 .with_end(true),
263 )
264 .await?;
265 if status.err {
266 return Err(GpibError::DriverError(
267 status,
268 IbError::current_thread_local_error()?,
269 ));
270 } else if status.timo {
271 return Err(GpibError::Timeout);
272 }
273 log::debug!("read({}) -> {} bytes read.", self.ud, n_read);
274 if n_read > 0 {
275 result.extend(buffer[0..n_read].to_vec());
276 }
277 if status.end || n_read < BUFFER_SIZE || n_read == 0 {
278 break;
279 }
280 }
281 Ok(result)
282 }
283
284 #[cfg(feature = "async-tokio")]
285 pub async fn read(&self) -> Result<String, GpibError> {
286 let result = self.read_raw().await?;
287 let answer = String::from_utf8(result)?;
288 Ok(answer)
289 }
290
291 pub fn blocking_write(&self, data: &str) -> Result<(), GpibError> {
292 let _n_written = ibwrt(self.ud, data.as_bytes())?;
293 Ok(())
294 }
295
296 #[cfg(feature = "async-tokio")]
297 pub async fn write(&self, data: &str) -> Result<(), GpibError> {
298 let data = data.as_bytes();
299 unsafe { ibwrta(self.ud, data) }?;
300 let (status, _count) = ibwait(
301 self.ud,
302 IbStatus::default()
303 .with_timo(true)
304 .with_cmpl(true)
305 .with_end(true)
306 .with_rqs(true),
307 )
308 .await?;
309 if status.err {
310 Err(GpibError::DriverError(
311 status,
312 IbError::current_thread_local_error()?,
313 ))
314 } else if status.timo {
315 Err(GpibError::Timeout)
316 } else if status.cmpl || status.end {
317 Ok(())
318 } else {
319 Err(GpibError::ValueError(format!(
320 "Unexpected status after waiting: {:?}",
321 status
322 )))
323 }
324 }
325
326 pub fn blocking_query(&self, data: &str) -> Result<String, GpibError> {
327 self.blocking_write(data)?;
328 self.blocking_read()
329 }
330
331 #[cfg(feature = "async-tokio")]
332 pub async fn query(&self, data: &str) -> Result<String, GpibError> {
333 self.write(data).await?;
334 self.read().await
335 }
336}
337
338impl Drop for InstrumentHandle {
339 fn drop(&mut self) {
340 match ibonl(self.ud, IbOnline::Close) {
341 Ok(()) => {}
342 Err(e) => {
343 println!("Error while closing (ud = {}): {:?}", self.ud, e);
344 }
345 }
346 }
347}
348
349impl fmt::Display for InstrumentHandle {
350 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
351 write!(f, "{}", self.ud)
352 }
353}
354
355impl fmt::Debug for InstrumentHandle {
356 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
357 write!(f, "InstrumentHandle({})", self.ud)
358 }
359}