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