linux_gpib_rs/lowlevel/
multidevice.rs

1#![allow(non_snake_case)]
2use crate::error::{GpibError, IbError};
3use crate::lowlevel::utility::{Addr4882, ThreadIbcnt, ThreadIbcntl};
4use crate::status::IbStatus;
5use crate::types::{IbSendEOI, PrimaryAddress, SecondaryAddress};
6use linux_gpib_sys::Addr4882_t;
7use std::default::Default;
8use std::os::raw::{c_int, c_short, c_void};
9
10/// find devices
11///
12/// FindLstn() will check the primary addresses in the padList array for devices. The GPIB addresses of all devices found will be stored in the resultList array, and ibcnt will be set to the number of devices found. The maxNumResults parameter limits the maximum number of results that will be returned, and is usually set to the number of elements in the resultList array. If more than maxNumResults devices are found, an ETAB error is returned in iberr. The padList should consist of primary addresses only, with no secondary addresses (all possible secondary addresses will be checked as necessary).
13///
14/// Your GPIB board must have the capability to monitor the NDAC bus line in order to use this function (see iblines).
15///
16/// This function has the additional effect of addressing the board as talker for the duration of the Find Listeners protocol, which is beyond what IEEE 488.2 specifies. This is done because some boards cannot reliably read the state of the NDAC bus line unless they are the talker. Being the talker causes the board's gpib transceiver to configure NDAC as an input, so its state can be reliably read from the bus through the transceiver.
17///
18/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-findlstn.html)
19///
20pub fn FindLstn(board_desc: c_int, padList: Vec<Addr4882>) -> Result<Vec<Addr4882>, GpibError> {
21    let mut result: Vec<Addr4882_t> = Vec::new();
22    result.resize_with(31, || linux_gpib_sys::NOADDR);
23    let mut padList = padList
24        .into_iter()
25        .map(|a| a.addr)
26        .collect::<Vec<Addr4882_t>>();
27    padList.push(linux_gpib_sys::NOADDR);
28    log::debug!("FindLstn({}, {:?})", board_desc, padList);
29    unsafe {
30        linux_gpib_sys::FindLstn(
31            board_desc,
32            padList.as_ptr(),
33            result.as_mut_ptr(),
34            padList.len().try_into()?,
35        )
36    };
37    let status = IbStatus::current_thread_local_status();
38    if status.err {
39        let error = IbError::current_thread_local_error()?;
40        match error {
41            IbError::EARG => {
42                log::error!(
43                    "Invalid primary address at index {} in padlist",
44                    ThreadIbcnt()
45                );
46            }
47            IbError::EBUS => {
48                log::error!("No devices are connected to the GPIB.");
49            }
50            IbError::ETAB => {
51                log::error!("The number of devices found on the GPIB exceed limit.");
52            }
53            _ => {}
54        }
55        log::debug!("-> {:?}", error);
56        Err(GpibError::DriverError(status, error))
57    } else {
58        let n_values: usize = ThreadIbcntl().try_into()?;
59        result.truncate(n_values);
60        log::debug!("-> {:?}", result);
61        Ok(result.into_iter().map(|a| Addr4882 { addr: a }).collect())
62    }
63}
64
65/// Find all listeners on board.
66pub fn FindAllLstn(board_desc: c_int) -> Result<Vec<Addr4882>, GpibError> {
67    let padList = (1..31)
68        .into_iter()
69        .map(|pad| Addr4882::new(PrimaryAddress::new(pad)?, SecondaryAddress::default()))
70        .collect::<Result<Vec<Addr4882>, GpibError>>()?;
71    FindLstn(board_desc, padList)
72}
73
74/// clear a device
75///
76/// DevClear() causes the interface board specified by board_desc to send the clear command to the GPIB addresses specified by address. The results of the serial polls are stored into resultList. If you wish to clear multiple devices simultaneously, use DevClearList()
77pub fn DevClear(board: c_int, address: Addr4882) -> Result<(), GpibError> {
78    log::debug!("DevClear({}, {})", board, address);
79    unsafe {
80        linux_gpib_sys::DevClear(board, address.addr);
81    }
82    let status = IbStatus::current_thread_local_status();
83    if status.err {
84        log::debug!("-> {:?}", status);
85        Err(GpibError::DriverError(
86            status,
87            IbError::current_thread_local_error()?,
88        ))
89    } else {
90        log::debug!("-> {:?}", status);
91        Ok(())
92    }
93}
94
95/// clear multiple devices
96///
97/// DevClear() causes the interface board specified by board_desc to send the clear command simultaneously to all the GPIB addresses specified by the addressList array. If addressList is empty or NULL, then the clear command is sent to all devices on the bus. If you only wish to clear a single device, DevClear() or ibclr() may be slightly more convenient.
98pub fn DevClearList(board: c_int, addresses: &Vec<Addr4882>) -> Result<(), GpibError> {
99    let mut instruments = addresses
100        .iter()
101        .map(|a| a.addr)
102        .collect::<Vec<Addr4882_t>>();
103    instruments.push(linux_gpib_sys::NOADDR);
104    log::debug!("DevClearList({:?}, {:?})", board, addresses);
105    unsafe {
106        linux_gpib_sys::DevClearList(board, instruments.as_ptr());
107    }
108    let status = IbStatus::current_thread_local_status();
109    log::debug!("-> {:?}", status);
110    if status.err {
111        Err(GpibError::DriverError(
112            status,
113            IbError::current_thread_local_error()?,
114        ))
115    } else {
116        Ok(())
117    }
118}
119
120/// put devices into local mode.
121///
122/// 	EnableLocal() addresses all of the devices in the addressList array as listeners then sends the GTL (go to local) command byte, causing them to enter local mode. This requires that the board is the controller-in-charge. Note that while the REN (remote enable) bus line is asserted, the devices will return to remote mode the next time they are addressed.
123///
124///If addressList is empty or NULL, then the REN line is unasserted and all devices enter local mode. The board must be system controller to change the state of the REN line.
125///
126/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-enablelocal.html)
127pub fn EnableLocal(board: c_int, addresses: &Vec<Addr4882>) -> Result<(), GpibError> {
128    let mut instruments = addresses
129        .iter()
130        .map(|a| a.addr)
131        .collect::<Vec<Addr4882_t>>();
132    instruments.push(linux_gpib_sys::NOADDR);
133    unsafe {
134        linux_gpib_sys::EnableLocal(board, instruments.as_ptr());
135    }
136    let status = IbStatus::current_thread_local_status();
137    if status.err {
138        Err(GpibError::DriverError(
139            status,
140            IbError::current_thread_local_error()?,
141        ))
142    } else {
143        Ok(())
144    }
145}
146
147/// put devices into remote mode.
148///
149/// EnableRemote() asserts the REN (remote enable) line, and addresses all of the devices in the addressList array as listeners (causing them to enter remote mode). The board must be system controller.
150///
151/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-enableremote.html)
152pub fn EnableRemote(board: c_int, addresses: &Vec<Addr4882>) -> Result<(), GpibError> {
153    let mut instruments = addresses
154        .iter()
155        .map(|a| a.addr)
156        .collect::<Vec<Addr4882_t>>();
157    instruments.push(linux_gpib_sys::NOADDR);
158    unsafe {
159        linux_gpib_sys::EnableRemote(board, instruments.as_ptr());
160    }
161    let status = IbStatus::current_thread_local_status();
162    if status.err {
163        Err(GpibError::DriverError(
164            status,
165            IbError::current_thread_local_error()?,
166        ))
167    } else {
168        Ok(())
169    }
170}
171
172/// find device requesting service and read its status byte
173///
174/// FindRQS will serial poll the GPIB addresses specified in the addressList array until it finds a device requesting service. The status byte of the device requesting service and its address are returned. If no device requesting service is found, an ETAB error is returned.
175///
176/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-findrqs.html)
177pub fn FindRQS(board: c_int, addresses: &Vec<Addr4882>) -> Result<(Addr4882, c_short), GpibError> {
178    let mut instruments = addresses
179        .iter()
180        .map(|a| a.addr)
181        .collect::<Vec<Addr4882_t>>();
182    instruments.push(linux_gpib_sys::NOADDR);
183    let mut status_byte: c_short = 0;
184    unsafe {
185        linux_gpib_sys::FindRQS(board, instruments.as_ptr(), &mut status_byte);
186    }
187    let status = IbStatus::current_thread_local_status();
188    if status.err {
189        Err(GpibError::DriverError(
190            status,
191            IbError::current_thread_local_error()?,
192        ))
193    } else {
194        let index: usize = ThreadIbcnt().try_into()?;
195        if index >= addresses.len() {
196            Err(GpibError::ValueError(
197                "index stored in Ibcnt is larger than addresses array length".to_owned(),
198            ))
199        } else {
200            Ok((addresses[index], status_byte))
201        }
202    }
203}
204
205/// make device controller-in-charge
206///
207/// PassControl() causes the board specified by board_desc to pass control to the device specified by address. On success, the device becomes the new controller-in-charge.
208///
209/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-passcontrol.html)
210pub fn PassControl(board: c_int, address: Addr4882) -> Result<(), GpibError> {
211    unsafe {
212        linux_gpib_sys::PassControl(board, address.addr);
213    }
214    let status = IbStatus::current_thread_local_status();
215    if status.err {
216        Err(GpibError::DriverError(
217            status,
218            IbError::current_thread_local_error()?,
219        ))
220    } else {
221        Ok(())
222    }
223}
224
225/// parallel poll devices
226///
227/// PPoll() is similar to the 'traditional' API function ibrpp(). It causes the interface board to perform a parallel poll, and stores the parallel poll byte in the location specified by result. Bits 0 to 7 of the parallel poll byte correspond to the dio lines 1 to 8, with a 1 indicating the corresponding dio line is asserted. The devices on the bus you wish to poll should be configured beforehand with PPollConfig(). The board must be controller-in-charge to perform a parallel poll.
228///
229/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ppoll.html)
230pub fn PPoll(board: c_int) -> Result<c_short, GpibError> {
231    let mut result: c_short = 0;
232    unsafe {
233        linux_gpib_sys::PPoll(board, &mut result);
234    }
235    let status = IbStatus::current_thread_local_status();
236    if status.err {
237        Err(GpibError::DriverError(
238            status,
239            IbError::current_thread_local_error()?,
240        ))
241    } else {
242        Ok(result)
243    }
244}
245
246/// configure a device's parallel poll response
247///
248/// PPollConfig() configures the device specified by address to respond to parallel polls. The dio_line (valid values are 1 through 8) specifies which dio line the device being configured should use to send back its parallel poll response. The line_sense argument specifies the polarity of the response. If line_sense is nonzero, then the specified dio line will be asserted to indicate that the 'individual status bit' (or 'ist') is 1. If sense is zero, then the specified dio line will be asserted when ist is zero.
249///
250/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ppollconfig.html)
251pub fn PPollConfig(
252    board: c_int,
253    address: Addr4882,
254    dio_line: c_int,
255    line_sense: c_int,
256) -> Result<(), GpibError> {
257    unsafe {
258        linux_gpib_sys::PPollConfig(board, address.addr, dio_line, line_sense);
259    }
260    let status = IbStatus::current_thread_local_status();
261    if status.err {
262        Err(GpibError::DriverError(
263            status,
264            IbError::current_thread_local_error()?,
265        ))
266    } else {
267        Ok(())
268    }
269}
270
271/// disable devices' parallel poll response
272///
273/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ppollunconfig.html)
274pub fn PPollUnconfig(board: c_int, addresses: &Vec<Addr4882>) -> Result<(), GpibError> {
275    let mut instruments = addresses
276        .iter()
277        .map(|a| a.addr)
278        .collect::<Vec<Addr4882_t>>();
279    instruments.push(linux_gpib_sys::NOADDR);
280    unsafe {
281        linux_gpib_sys::PPollUnconfig(board, instruments.as_ptr());
282    }
283    let status = IbStatus::current_thread_local_status();
284    if status.err {
285        Err(GpibError::DriverError(
286            status,
287            IbError::current_thread_local_error()?,
288        ))
289    } else {
290        Ok(())
291    }
292}
293
294/// read data
295///
296/// 	RcvRespMsg() reads data from the bus. A device must have already been addressed as talker (and the board as listener) before calling this function. Addressing may be accomplished with the ReceiveSetup() function.
297///
298/// Up to count bytes are read into the array specified by buffer. The termination argument specifies the 8-bit end-of-string character (which must be a value from 0 to 255) whose reception will terminate a read. termination can also be set to the 'STOPend' constant, in which case no end-of-string character will be used. Assertion of the EOI line will always end a read.
299///
300/// You may find it simpler to use the slightly higher level function Receive(), since it does not require addressing and reading of data to be performed separately.
301///
302/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-rcvrespmsg.html)
303pub fn RcvRespMsg(board: c_int, buffer: &mut [u8], termination: c_int) -> Result<(), GpibError> {
304    unsafe {
305        linux_gpib_sys::RcvRespMsg(
306            board,
307            buffer.as_mut_ptr() as *mut c_void,
308            buffer.len().try_into()?,
309            termination,
310        );
311    }
312    let status = IbStatus::current_thread_local_status();
313    if status.err {
314        Err(GpibError::DriverError(
315            status,
316            IbError::current_thread_local_error()?,
317        ))
318    } else {
319        Ok(())
320    }
321}
322
323/// serial poll a device
324///
325/// ReadStatusByte() causes the board specified by the board descriptor board_desc to serial poll the GPIB address specified by address. The status byte is stored at the location specified by the result pointer. If you wish to serial poll multiple devices, it may be slightly more efficient to use AllSPoll(). Serial polls may also be conducted with the 'traditional API' function ibrsp().
326///
327/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-readstatusbyte.html)
328pub fn ReadStatusByte(board: c_int, address: Addr4882) -> Result<c_short, GpibError> {
329    let mut result: c_short = 0;
330    unsafe {
331        linux_gpib_sys::ReadStatusByte(board, address.addr, &mut result);
332    }
333    let status = IbStatus::current_thread_local_status();
334    if status.err {
335        Err(GpibError::DriverError(
336            status,
337            IbError::current_thread_local_error()?,
338        ))
339    } else {
340        Ok(result)
341    }
342}
343
344/// perform receive addressing and read data
345///
346/// Receive() performs the necessary addressing, then reads data from the device specified by address. It is equivalent to a ReceiveSetup() call followed by a RcvRespMsg() call.
347///
348/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-receive.html)
349pub fn Receive(
350    board: c_int,
351    address: Addr4882,
352    buffer: &mut [u8],
353    termination: c_int,
354) -> Result<(IbStatus, usize), GpibError> {
355    log::debug!("Receive({:?}, {:?})", board, address);
356    unsafe {
357        linux_gpib_sys::Receive(
358            board,
359            address.addr,
360            buffer.as_mut_ptr() as *mut c_void,
361            buffer.len().try_into()?,
362            termination,
363        );
364    }
365    let status = IbStatus::current_thread_local_status();
366    if status.err {
367        log::debug!("-> {:?}", status);
368        Err(GpibError::DriverError(
369            status,
370            IbError::current_thread_local_error()?,
371        ))
372    } else {
373        let n_read = ThreadIbcntl().try_into()?;
374        log::debug!(
375            "Receive({:?}, {:?}) -> Read {} bytes",
376            board,
377            address,
378            n_read
379        );
380        Ok((status, n_read))
381    }
382}
383
384/// perform receive addressing
385///
386/// 	ReceiveSetup() addresses the device specified by address as talker, and addresses the interface board as listener. A subsequent RcvRespMsg() call will read data from the device.
387///
388///You may find it simpler to use the slightly higher level function Receive(), since it does not require addressing and reading of data to be performed separately.
389///
390/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-receivesetup.html)
391pub fn ReceiveSetup(board: c_int, address: Addr4882) -> Result<(), GpibError> {
392    unsafe {
393        linux_gpib_sys::ReceiveSetup(board, address.addr);
394    }
395    let status = IbStatus::current_thread_local_status();
396    if status.err {
397        Err(GpibError::DriverError(
398            status,
399            IbError::current_thread_local_error()?,
400        ))
401    } else {
402        Ok(())
403    }
404}
405
406/// reset system
407///
408/// ResetSys() has the following effects:
409///
410/// - The remote enable bus line is asserted.
411/// - An interface clear is performed (the interface clear bus line is asserted for at least 100 microseconds).
412/// - The device clear command is sent to all the devices on the bus.
413/// - The *RST message is sent to every device specified in the addressList.
414///
415/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-resetsys.html)
416pub fn ResetSys(board: c_int, addresses: &Vec<Addr4882>) -> Result<(), GpibError> {
417    let mut instruments = addresses
418        .iter()
419        .map(|a| a.addr)
420        .collect::<Vec<Addr4882_t>>();
421    instruments.push(linux_gpib_sys::NOADDR);
422    unsafe {
423        linux_gpib_sys::ResetSys(board, instruments.as_ptr());
424    }
425    let status = IbStatus::current_thread_local_status();
426    if status.err {
427        Err(GpibError::DriverError(
428            status,
429            IbError::current_thread_local_error()?,
430        ))
431    } else {
432        Ok(())
433    }
434}
435
436/// perform send addressing and write data
437///
438/// Send() addresses the device specified by address as listener, then writes data onto the bus. It is equivalent to a SendList() except it only uses a single GPIB address to specify the listener instead of allowing an array of listeners.
439///
440/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-send.html)
441pub fn Send(
442    board: c_int,
443    address: Addr4882,
444    buffer: &[u8],
445    eot_mode: IbSendEOI,
446) -> Result<(), GpibError> {
447    log::debug!("Send({:?}, {:?}, {:?})", board, address, buffer);
448    unsafe {
449        linux_gpib_sys::Send(
450            board,
451            address.addr,
452            buffer.as_ptr() as *const c_void,
453            buffer.len().try_into()?,
454            eot_mode.as_eot(),
455        );
456    }
457    let status = IbStatus::current_thread_local_status();
458    log::debug!(
459        "Send({:?}, {:?}, {:?}) -> {:?}",
460        board,
461        address,
462        buffer,
463        status
464    );
465    if status.err {
466        Err(GpibError::DriverError(
467            status,
468            IbError::current_thread_local_error()?,
469        ))
470    } else {
471        Ok(())
472    }
473}
474
475/// perform interface clear
476///
477/// SendIFC() resets the GPIB bus by asserting the 'interface clear' (IFC) bus line for a duration of at least 100 microseconds. The board specified by board_desc must be the system controller in order to assert IFC. The interface clear causes all devices to untalk and unlisten, puts them into serial poll disabled state (don't worry, you will still be able to conduct serial polls), and the board becomes controller-in-charge.
478pub fn SendIFC(board: c_int) -> Result<(), GpibError> {
479    log::debug!("SendIFC({})", board);
480    unsafe {
481        linux_gpib_sys::SendIFC(board);
482    }
483    let status = IbStatus::current_thread_local_status();
484    log::debug!("endIFC({}) -> {:?}", board, status);
485    if status.err {
486        Err(GpibError::DriverError(
487            status,
488            IbError::current_thread_local_error()?,
489        ))
490    } else {
491        Ok(())
492    }
493}
494
495/// write data to multiple devices
496///
497/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-sendlist.html)
498pub fn SendList(
499    board: c_int,
500    addresses: &Vec<Addr4882>,
501    buffer: &[u8],
502    eot_mode: IbSendEOI,
503) -> Result<(), GpibError> {
504    log::debug!("SendList({:?}, {:?}, {:?})", board, addresses, buffer);
505    let mut instruments = addresses
506        .iter()
507        .map(|a| a.addr)
508        .collect::<Vec<Addr4882_t>>();
509    instruments.push(linux_gpib_sys::NOADDR);
510    unsafe {
511        linux_gpib_sys::SendList(
512            board,
513            instruments.as_ptr(),
514            buffer.as_ptr() as *const c_void,
515            buffer.len().try_into()?,
516            eot_mode.as_eot(),
517        );
518    }
519    let status = IbStatus::current_thread_local_status();
520    log::debug!(
521        "SendList({:?}, {:?}, {:?}) -> {:?}",
522        board,
523        addresses,
524        buffer,
525        status
526    );
527    if status.err {
528        Err(GpibError::DriverError(
529            status,
530            IbError::current_thread_local_error()?,
531        ))
532    } else {
533        Ok(())
534    }
535}
536
537/// put devices into local lockout mode
538///
539/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-sendllo.html)
540pub fn SendLLO(board: c_int) -> Result<(), GpibError> {
541    unsafe {
542        linux_gpib_sys::SendLLO(board);
543    }
544    let status = IbStatus::current_thread_local_status();
545    if status.err {
546        Err(GpibError::DriverError(
547            status,
548            IbError::current_thread_local_error()?,
549        ))
550    } else {
551        Ok(())
552    }
553}
554
555/// put devices into remote with lockout state
556///
557/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-setrwls.html)
558pub fn SetRWLS(board: c_int, addresses: &Vec<Addr4882>) -> Result<(), GpibError> {
559    let mut instruments = addresses
560        .iter()
561        .map(|a| a.addr)
562        .collect::<Vec<Addr4882_t>>();
563    instruments.push(linux_gpib_sys::NOADDR);
564    unsafe {
565        linux_gpib_sys::SetRWLS(board, instruments.as_ptr());
566    }
567    let status = IbStatus::current_thread_local_status();
568    if status.err {
569        Err(GpibError::DriverError(
570            status,
571            IbError::current_thread_local_error()?,
572        ))
573    } else {
574        Ok(())
575    }
576}
577
578///  query state of SRQ bus line
579///
580/// Returns true if the SRQ line is asserted, false if it is not asserted.
581///
582/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-testsrq.html)
583pub fn TestSRQ(board: c_int) -> Result<bool, GpibError> {
584    let mut result: c_short = 10;
585    unsafe {
586        linux_gpib_sys::TestSRQ(board, &mut result);
587    }
588    let status = IbStatus::current_thread_local_status();
589    if status.err {
590        Err(GpibError::DriverError(
591            status,
592            IbError::current_thread_local_error()?,
593        ))
594    } else {
595        match result {
596            0 => Ok(false),
597            1 => Ok(true),
598            other => Err(GpibError::ValueError(format!("Unexpected value {}", other))),
599        }
600    }
601}
602
603/// perform self-test queries on devices
604///
605/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-testsys.html)
606pub fn TestSys(board: c_int, addresses: &Vec<Addr4882>) -> Result<Vec<c_short>, GpibError> {
607    let mut instruments = addresses
608        .iter()
609        .map(|a| a.addr)
610        .collect::<Vec<Addr4882_t>>();
611    instruments.push(linux_gpib_sys::NOADDR);
612    let mut results: Vec<c_short> = Vec::with_capacity(addresses.len());
613    results.resize(addresses.len(), 0);
614    unsafe {
615        linux_gpib_sys::TestSys(board, instruments.as_ptr(), results.as_mut_ptr());
616    }
617    let status = IbStatus::current_thread_local_status();
618    if status.err {
619        Err(GpibError::DriverError(
620            status,
621            IbError::current_thread_local_error()?,
622        ))
623    } else {
624        Ok(results)
625    }
626}
627
628/// trigger a device
629///
630/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-trigger.html)
631pub fn Trigger(board: c_int, address: Addr4882) -> Result<(), GpibError> {
632    unsafe {
633        linux_gpib_sys::Trigger(board, address.addr);
634    }
635    let status = IbStatus::current_thread_local_status();
636    if status.err {
637        Err(GpibError::DriverError(
638            status,
639            IbError::current_thread_local_error()?,
640        ))
641    } else {
642        Ok(())
643    }
644}
645
646/// trigger multiple devices
647///
648/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-triggerlist.html)
649pub fn TriggerList(board: c_int, addresses: &Vec<Addr4882>) -> Result<(), GpibError> {
650    let mut instruments = addresses
651        .iter()
652        .map(|a| a.addr)
653        .collect::<Vec<Addr4882_t>>();
654    instruments.push(linux_gpib_sys::NOADDR);
655    unsafe {
656        linux_gpib_sys::TriggerList(board, instruments.as_ptr());
657    }
658    let status = IbStatus::current_thread_local_status();
659    if status.err {
660        Err(GpibError::DriverError(
661            status,
662            IbError::current_thread_local_error()?,
663        ))
664    } else {
665        Ok(())
666    }
667}
668
669#[cfg(feature = "async-tokio")]
670/// sleep until the SRQ bus line is asserted
671///
672/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-waitsrq.html)
673pub async fn WaitSRQ(board: c_int) -> Result<c_short, GpibError> {
674    tokio::task::spawn_blocking(move || {
675        let mut result: c_short = 0;
676        unsafe {
677            linux_gpib_sys::WaitSRQ(board, &mut result);
678        }
679        let status = IbStatus::current_thread_local_status();
680        if status.err {
681            Err(GpibError::DriverError(
682                status,
683                IbError::current_thread_local_error()?,
684            ))
685        } else {
686            Ok(result)
687        }
688    })
689    .await?
690}