linux_gpib_rs/
traditional.rs

1use crate::error::{GpibError, IbError};
2use crate::status::IbStatus;
3use std::ffi::{CStr, CString};
4use std::fmt;
5use std::os::raw::{c_char, c_int, c_short, c_void};
6use std::path::Path;
7
8const DEBUG: bool = false;
9
10pub enum IbOption {
11    PAD,
12    SAD,
13    TMO,
14    EOT,
15    PPC,
16    READDR,
17    AUTOPOLL,
18    CICPROT,
19    SC,
20    SRE,
21    EOSrd,
22    EOSwrt,
23    EOScmp,
24    EOSchar,
25    PP2,
26    TIMING,
27    ReadAdjust,
28    WriteAdjust,
29    EventQueue,
30    SPollBit,
31    SendLLO,
32    SPollTime,
33    PPollTime,
34    EndBitIsNormal,
35    UnAddr,
36    HSCableLength,
37    Ist,
38    Rsv,
39    BNA,
40    SevenBitEOS,
41}
42
43impl fmt::Display for IbOption {
44    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45        match self {
46            IbOption::PAD => {
47                write!(f, "IbOption::PAD")
48            }
49            IbOption::SAD => {
50                write!(f, "IbOption::SAD")
51            }
52            IbOption::TMO => {
53                write!(f, "IbOption::TMO")
54            }
55            IbOption::EOT => {
56                write!(f, "IbOption::EOT")
57            }
58            IbOption::PPC => {
59                write!(f, "IbOption::PPC")
60            }
61            IbOption::READDR => {
62                write!(f, "IbOption::READDR")
63            }
64            IbOption::AUTOPOLL => {
65                write!(f, "IbOption::AUTOPOLL")
66            }
67            IbOption::CICPROT => {
68                write!(f, "IbOption::CICPROT")
69            }
70            IbOption::SC => {
71                write!(f, "IbOption::SC")
72            }
73            IbOption::SRE => {
74                write!(f, "IbOption::SRE")
75            }
76            IbOption::EOSrd => {
77                write!(f, "IbOption::EOSrd")
78            }
79            IbOption::EOSwrt => {
80                write!(f, "IbOption::EOSwrt")
81            }
82            IbOption::EOScmp => {
83                write!(f, "IbOption::EOScmp")
84            }
85            IbOption::EOSchar => {
86                write!(f, "IbOption::EOSchar")
87            }
88            IbOption::PP2 => {
89                write!(f, "IbOption::PP2")
90            }
91            IbOption::TIMING => {
92                write!(f, "IbOption::TIMING")
93            }
94            IbOption::ReadAdjust => {
95                write!(f, "IbOption::ReadAdjust")
96            }
97            IbOption::WriteAdjust => {
98                write!(f, "IbOption::WriteAdjust")
99            }
100            IbOption::EventQueue => {
101                write!(f, "IbOption::EventQueue")
102            }
103            IbOption::SPollBit => {
104                write!(f, "IbOption::SPollBit")
105            }
106            IbOption::SendLLO => {
107                write!(f, "IbOption::SendLLO")
108            }
109            IbOption::SPollTime => {
110                write!(f, "IbOption::SPollTime")
111            }
112            IbOption::PPollTime => {
113                write!(f, "IbOption::PPollTime")
114            }
115            IbOption::EndBitIsNormal => {
116                write!(f, "IbOption::EndBitIsNormal")
117            }
118            IbOption::UnAddr => {
119                write!(f, "IbOption::UnAddr")
120            }
121            IbOption::HSCableLength => {
122                write!(f, "IbOption::HSCableLength")
123            }
124            IbOption::Ist => {
125                write!(f, "IbOption::Ist")
126            }
127            IbOption::Rsv => {
128                write!(f, "IbOption::Rsv")
129            }
130            IbOption::BNA => {
131                write!(f, "IbOption::BNA")
132            }
133            IbOption::SevenBitEOS => {
134                write!(f, "IbOption::SevenBitEOS")
135            }
136        }
137    }
138}
139
140impl fmt::Debug for IbOption {
141    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
142        match self {
143            IbOption::PAD => {
144                write!(f, "IbOption::PAD (0x1): GPIB primary address")
145            }
146            IbOption::SAD => {
147                write!(f, "IbOption::SAD (0x2): GPIB secondary address (0 for none, 0x60 to 0x7e for secondary addresses 0 to 30)")
148            }
149            IbOption::TMO => {
150                write!(f, "IbOption::TMO (0x3): Timeout setting for io operations (a number from 0 to 17). See ibmto().")
151            }
152            IbOption::EOT => {
153                write!(f, "IbOption::EOT (0x4): Nonzero if EOI is asserted with last byte on writes. See ibeot().")
154            }
155            IbOption::PPC => {
156                write!(
157                    f,
158                    "IbOption::PPC (0x5): Parallel poll configuration. See ibppc()."
159                )
160            }
161            IbOption::READDR => {
162                write!(
163                    f,
164                    "IbOption::READDR (0x6): Useless, included for compatibility only."
165                )
166            }
167            IbOption::AUTOPOLL => {
168                write!(
169                    f,
170                    "IbOption::AUTOPOLL (0x7): Nonzero if automatic serial polling is enabled."
171                )
172            }
173            IbOption::CICPROT => {
174                write!(
175                    f,
176                    "IbOption::CICPROT (0x8): Useless, included for compatibility only."
177                )
178            }
179            IbOption::SC => {
180                write!(
181                    f,
182                    "IbOption::SC (0xa): Nonzero if board is system controller. See ibrsc(). "
183                )
184            }
185            IbOption::SRE => {
186                write!(f, "IbOption::SRE (0xb): Nonzero if board autmatically asserts REN line when it becomes the system controller. See ibsre().")
187            }
188            IbOption::EOSrd => {
189                write!(f, "IbOption::EOSrd (0xc): Nonzero if termination of reads on reception of the end-of-string character is enabled. See ibeos(), in particular the REOS bit.")
190            }
191            IbOption::EOSwrt => {
192                write!(f, "IbOption::EOSwrt (0xd): Nonzero if EOI is asserted whenever end-of-string character is sent. See ibeos(), in particular the XEOS bit.")
193            }
194            IbOption::EOScmp => {
195                write!(f, "IbOption::EOScmp (0xe): Nonzero if all 8 bits are used to match end-of-string character. Zero if only least significant 7 bits are used. See ibeos(), in particular the BIN bit.")
196            }
197            IbOption::EOSchar => {
198                write!(f, "IbOption::EOSchar (0xf): The end-of-string byte.")
199            }
200            IbOption::PP2 => {
201                write!(f, "IbOption::PP2 (0x10): Nonzero if in local parallel poll configure mode. Zero if in remote parallel poll configure mode.")
202            }
203            IbOption::TIMING => {
204                write!(f, "IbOption::TIMING (0x11): Number indicating T1 delay. 1 for 2 microseconds, 2 for 500 nanoseconds, 3 for 350 nanoseconds. The values are declared in the header files as the constants T1_DELAY_2000ns, T1_DELAY_500ns, and T1_DELAY_350ns.")
205            }
206            IbOption::ReadAdjust => {
207                write!(f, "IbOption::ReadAdjust (0x13): Nonzero if byte pairs are automatically swapped during reads.")
208            }
209            IbOption::WriteAdjust => {
210                write!(f, "IbOption::WriteAdjust (0x14): Nonzero if byte pairs are automatically swapped during writes.")
211            }
212            IbOption::EventQueue => {
213                write!(
214                    f,
215                    "IbOption::EventQueue (0x15): Nonzero if event queue is enabled."
216                )
217            }
218            IbOption::SPollBit => {
219                write!(f, "IbOption::SPollBit (0x16): Nonzero if the use of the SPOLL bit in ibsta is enabled.")
220            }
221            IbOption::SendLLO => {
222                write!(f, "IbOption::SendLLO (0x17): Nonzero if devices connected to this board are automatically put into local lockout mode when brought online with ibfind() or ibdev().")
223            }
224            IbOption::SPollTime => {
225                write!(f, "IbOption::SPollTime (0x18): Timeout for serial polls. The value of the result is between 0 and 17, and has the same meaning as in ibtmo().")
226            }
227            IbOption::PPollTime => {
228                write!(f, "IbOption::PPollTime (0x19): Timeout for parallel polls. The value of the result is between 0 and 17, and has the same meaning as in ibtmo().")
229            }
230            IbOption::EndBitIsNormal => {
231                write!(f, "IbOption::EndBitIsNormal (0x1a): Nonzero if END bit of ibsta is set on reception of end-of-string character or EOI. Zero if END bit is only set on EOI.")
232            }
233            IbOption::UnAddr => {
234                write!(f, "IbOption::UnAddr (0x1b): Nonzero if UNT (untalk) and UNL (unlisten) commands are automatically sent after a completed io operation using this descriptor.")
235            }
236            IbOption::HSCableLength => {
237                write!(
238                    f,
239                    "IbOption::HSCableLength (0x1f): Useless, included only for compatibility."
240                )
241            }
242            IbOption::Ist => {
243                write!(
244                    f,
245                    "IbOption::Ist (0x20): Individual status bit, a.k.a. 'ist'."
246                )
247            }
248            IbOption::Rsv => {
249                write!(f, "IbOption::Rsv (0x21): The current status byte this board will use to respond to serial polls.")
250            }
251            IbOption::BNA => {
252                write!(f, "IbOption::BNA (0x200): For a device: the board index (minor number) of interface board through which the device is being accessed. For a board: the board index of the board itself.")
253            }
254            IbOption::SevenBitEOS => {
255                write!(f, "IbOption::SevenBitEOS (0x1000): Nonzero if board supports 7 bit EOS comparisons. See ibeos(), in particular the BIN bit. This is a Linux-GPIB extension.")
256            }
257        }
258    }
259}
260
261impl IbOption {
262    pub fn as_option(&self) -> c_int {
263        match self {
264            IbOption::PAD => 0x1,
265            IbOption::SAD => 0x2,
266            IbOption::TMO => 0x3,
267            IbOption::EOT => 0x4,
268            IbOption::PPC => 0x5,
269            IbOption::READDR => 0x6,
270            IbOption::AUTOPOLL => 0x7,
271            IbOption::CICPROT => 0x8,
272            IbOption::SC => 0xa,
273            IbOption::SRE => 0xb,
274            IbOption::EOSrd => 0xc,
275            IbOption::EOSwrt => 0xd,
276            IbOption::EOScmp => 0xe,
277            IbOption::EOSchar => 0xf,
278            IbOption::PP2 => 0x10,
279            IbOption::TIMING => 0x11,
280            IbOption::ReadAdjust => 0x13,
281            IbOption::WriteAdjust => 0x14,
282            IbOption::EventQueue => 0x15,
283            IbOption::SPollBit => 0x16,
284            IbOption::SendLLO => 0x17,
285            IbOption::SPollTime => 0x18,
286            IbOption::PPollTime => 0x19,
287            IbOption::EndBitIsNormal => 0x1a,
288            IbOption::UnAddr => 0x1b,
289            IbOption::HSCableLength => 0x1f,
290            IbOption::Ist => 0x20,
291            IbOption::Rsv => 0x21,
292            IbOption::BNA => 0x200,
293            IbOption::SevenBitEOS => 0x1000,
294        }
295    }
296}
297
298/// ibask -- query configuration (board or device)
299/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibask.html)
300pub fn ibask(ud: c_int, option: IbOption) -> Result<c_int, GpibError> {
301    let option = option.as_option();
302    let mut result: c_int = 0;
303    let status = IbStatus::from_ibsta(unsafe {
304        linux_gpib_sys::ibask(ud, option, &mut result as *mut c_int)
305    });
306    if status.err {
307        Err(GpibError::DriverError(status, IbError::current_error()?))
308    } else {
309        Ok(result)
310    }
311}
312
313/// ibbna -- change access board (device)
314/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibbna.html)
315pub fn ibbna(ud: c_int, name: &str) -> Result<(), GpibError> {
316    let name = CString::new(name)?;
317    let status =
318        IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibbna(ud, name.as_ptr() as *mut c_char) });
319    if status.err {
320        Err(GpibError::DriverError(status, IbError::current_error()?))
321    } else {
322        Ok(())
323    }
324}
325
326/// ibcac -- assert ATN (board)
327/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibcac.html)
328pub fn ibcac(ud: c_int, synchronous: c_int) -> Result<(), GpibError> {
329    let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibcac(ud, synchronous) });
330    if status.err {
331        Err(GpibError::DriverError(status, IbError::current_error()?))
332    } else {
333        Ok(())
334    }
335}
336
337/// ibclr -- clear device (device)
338/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibclr.html)
339pub fn ibclr(ud: c_int) -> Result<(), GpibError> {
340    if DEBUG {
341        println!("ibclr({})", ud);
342    }
343    let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibclr(ud) });
344    if DEBUG {
345        println!("-> {:?}", status);
346    }
347    if status.err {
348        Err(GpibError::DriverError(status, IbError::current_error()?))
349    } else {
350        Ok(())
351    }
352}
353
354/// ibcmd -- write command bytes (board)
355/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibcmd.html)
356pub fn ibcmd(ud: c_int, commands: &[u8]) -> Result<(), GpibError> {
357    let status = IbStatus::from_ibsta(unsafe {
358        linux_gpib_sys::ibcmd(
359            ud,
360            commands.as_ptr() as *const c_void,
361            commands.len().try_into()?,
362        )
363    });
364    if status.err {
365        Err(GpibError::DriverError(status, IbError::current_error()?))
366    } else {
367        Ok(())
368    }
369}
370
371/// ibconfig -- change configuration (board or device)
372/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibconfig.html)
373pub fn ibconfig(ud: c_int, option: IbOption, setting: c_int) -> Result<(), GpibError> {
374    let option = option.as_option();
375    let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibconfig(ud, option, setting) });
376    if status.err {
377        Err(GpibError::DriverError(status, IbError::current_error()?))
378    } else {
379        Ok(())
380    }
381}
382
383#[derive(Clone, Copy)]
384pub enum IbTimeout {
385    TNone,
386    T10us,
387    T30us,
388    T100us,
389    T300us,
390    T1ms,
391    T3ms,
392    T10ms,
393    T30ms,
394    T100ms,
395    T300ms,
396    T1s,
397    T3s,
398    T10s,
399    T30s,
400    T100s,
401    T300s,
402    T1000s,
403}
404
405impl fmt::Display for IbTimeout {
406    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
407        match self {
408            IbTimeout::TNone => {
409                write!(f, "Never timeout")
410            }
411            IbTimeout::T10us => {
412                write!(f, "10 microseconds")
413            }
414            IbTimeout::T30us => {
415                write!(f, "30 microseconds")
416            }
417            IbTimeout::T100us => {
418                write!(f, "100 microseconds")
419            }
420            IbTimeout::T300us => {
421                write!(f, "300 microseconds")
422            }
423            IbTimeout::T1ms => {
424                write!(f, "1 millisecond")
425            }
426            IbTimeout::T3ms => {
427                write!(f, "3 milliseconds")
428            }
429            IbTimeout::T10ms => {
430                write!(f, "10 milliseconds")
431            }
432            IbTimeout::T30ms => {
433                write!(f, "30 milliseconds")
434            }
435            IbTimeout::T100ms => {
436                write!(f, "100 milliseconds")
437            }
438            IbTimeout::T300ms => {
439                write!(f, "300 milliseconds")
440            }
441            IbTimeout::T1s => {
442                write!(f, "1 second")
443            }
444            IbTimeout::T3s => {
445                write!(f, "3 seconds")
446            }
447            IbTimeout::T10s => {
448                write!(f, "10 seconds")
449            }
450            IbTimeout::T30s => {
451                write!(f, "30 seconds")
452            }
453            IbTimeout::T100s => {
454                write!(f, "100 seconds")
455            }
456            IbTimeout::T300s => {
457                write!(f, "300 seconds")
458            }
459            IbTimeout::T1000s => {
460                write!(f, "1000 seconds")
461            }
462        }
463    }
464}
465
466impl IbTimeout {
467    fn as_timeout(&self) -> c_int {
468        match self {
469            IbTimeout::TNone => 0,
470            IbTimeout::T10us => 1,
471            IbTimeout::T30us => 2,
472            IbTimeout::T100us => 3,
473            IbTimeout::T300us => 4,
474            IbTimeout::T1ms => 5,
475            IbTimeout::T3ms => 6,
476            IbTimeout::T10ms => 7,
477            IbTimeout::T30ms => 8,
478            IbTimeout::T100ms => 9,
479            IbTimeout::T300ms => 10,
480            IbTimeout::T1s => 11,
481            IbTimeout::T3s => 12,
482            IbTimeout::T10s => 13,
483            IbTimeout::T30s => 14,
484            IbTimeout::T100s => 15,
485            IbTimeout::T300s => 16,
486            IbTimeout::T1000s => 17,
487        }
488    }
489}
490
491#[derive(Copy, Clone)]
492pub struct PrimaryAddress {
493    pad: c_int,
494}
495
496impl PrimaryAddress {
497    pub fn new(pad: c_int) -> Result<PrimaryAddress, GpibError> {
498        if pad >= 0 && pad <= 30 {
499            Ok(PrimaryAddress { pad })
500        } else {
501            Err(GpibError::ValueError(format!(
502                "Primary address must be between 0 and 30. Got: {}.",
503                pad
504            )))
505        }
506    }
507
508    fn as_pad(&self) -> c_int {
509        self.pad
510    }
511}
512
513impl fmt::Display for PrimaryAddress {
514    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
515        write!(f, "{}", self.pad)
516    }
517}
518
519#[derive(Copy, Clone)]
520pub struct SecondaryAddress {
521    sad: c_int,
522}
523
524impl SecondaryAddress {
525    pub fn new(sad: c_int) -> Result<SecondaryAddress, GpibError> {
526        let desc = "Secondary address must be between 0 and 30 (without the 0x60 prefix), or equivalently between 0x60 and 0x7e (with the 0x60 addition). sad = 0 disables secondary address.";
527        let sad = if sad < 0 {
528            return Err(GpibError::ValueError(desc.to_owned()));
529        } else if sad == 0 {
530            // disable secondary address
531            sad
532        } else if sad <= 30 {
533            // sad are between 0 and 30 but
534            // NI convention adds 0x60 to the secondary address
535            sad + 0x60
536        } else if sad >= 0x60 && sad <= 0x7e {
537            sad
538        } else {
539            return Err(GpibError::ValueError(desc.to_owned()));
540        };
541        Ok(SecondaryAddress { sad })
542    }
543
544    fn as_sad(&self) -> c_int {
545        self.sad
546    }
547}
548
549impl Default for SecondaryAddress {
550    fn default() -> SecondaryAddress {
551        SecondaryAddress { sad: 0 }
552    }
553}
554
555impl fmt::Display for SecondaryAddress {
556    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
557        write!(f, "{}", self.sad)
558    }
559}
560
561#[derive(Copy, Clone)]
562pub enum IbSendEOI {
563    Disabled,
564    Enabled(c_int),
565}
566
567impl IbSendEOI {
568    fn as_eot(&self) -> c_int {
569        match self {
570            IbSendEOI::Disabled => 0,
571            IbSendEOI::Enabled(val) => *val,
572        }
573    }
574}
575
576impl Default for IbSendEOI {
577    fn default() -> IbSendEOI {
578        IbSendEOI::Disabled
579    }
580}
581
582impl fmt::Display for IbSendEOI {
583    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
584        match self {
585            IbSendEOI::Disabled => {
586                write!(f, "IbSendEOI::Disabled")
587            }
588            IbSendEOI::Enabled(value) => {
589                write!(f, "IbSendEOI::Enabled({})", value)
590            }
591        }
592    }
593}
594
595#[derive(Copy, Clone)]
596pub struct IbEosMode {
597    pub reos: bool,
598    pub xeos: bool,
599    pub bin: bool,
600}
601
602impl fmt::Display for IbEosMode {
603    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
604        let mut description = String::new();
605        if self.reos {
606            description.push_str("REOS ");
607        }
608        if self.xeos {
609            description.push_str("XEOS ");
610        }
611        if self.bin {
612            description.push_str("BIN");
613        }
614        if description.len() > 0 {
615            write!(f, "EosMod({description})")
616        } else {
617            write!(f, "EosMod(No flag set)")
618        }
619    }
620}
621
622impl fmt::Debug for IbEosMode {
623    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
624        let mut description = String::new();
625        if self.reos {
626            description.push_str(
627                "REOS (0x400) Enable termination of reads when eos character is received.",
628            );
629        }
630        if self.xeos {
631            description.push_str("XEOS (0x800) Assert the EOI line whenever the eos character is sent during writes.");
632        }
633        if self.bin {
634            description.push_str("BIN (0x1000) Match eos character using all 8 bits (instead of only looking at the 7 least significant bits).");
635        }
636        if description.len() > 0 {
637            write!(f, "EosMod({description})")
638        } else {
639            write!(f, "EosMod(No flag set)")
640        }
641    }
642}
643
644impl IbEosMode {
645    pub fn as_mode(&self) -> c_int {
646        let mut mode = 0;
647        if self.reos {
648            mode = mode | 0x400;
649        }
650        if self.xeos {
651            mode = mode | 0x800;
652        }
653        if self.bin {
654            mode = mode | 0x1000;
655        }
656        mode
657    }
658}
659
660impl Default for IbEosMode {
661    fn default() -> IbEosMode {
662        IbEosMode {
663            reos: true,
664            xeos: false,
665            bin: false,
666        }
667    }
668}
669
670/// ibdev -- open a device (device)
671/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibdev.html)
672pub fn ibdev(
673    board_index: c_int,
674    primary_address: PrimaryAddress,
675    secondary_address: SecondaryAddress,
676    timeout: IbTimeout,
677    send_eoi: IbSendEOI,
678    eos: IbEosMode,
679) -> Result<c_int, GpibError> {
680    if DEBUG {
681        println!(
682            "ibdev({}, {}, {}, {}, {}, {}",
683            board_index, primary_address, secondary_address, timeout, send_eoi, eos
684        );
685    }
686    let ud = unsafe {
687        linux_gpib_sys::ibdev(
688            board_index,
689            primary_address.as_pad(),
690            secondary_address.as_sad(),
691            timeout.as_timeout(),
692            send_eoi.as_eot(),
693            eos.as_mode(),
694        )
695    };
696    if DEBUG {
697        println!("-> {}", ud);
698    }
699    if ud >= 0 {
700        Ok(ud)
701    } else {
702        Err(GpibError::DriverError(
703            IbStatus::current_status(),
704            IbError::current_error()?,
705        ))
706    }
707}
708
709/// ibeos -- set end-of-string mode (board or device)
710/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibeos.html)
711pub fn ibeos(ud: c_int, eosmod: IbEosMode) -> Result<(), GpibError> {
712    let eosmod = eosmod.as_mode();
713    let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibeos(ud, eosmod) });
714    if status.err {
715        Err(GpibError::DriverError(status, IbError::current_error()?))
716    } else {
717        Ok(())
718    }
719}
720
721/// ibeot -- assert EOI with last data byte (board or device)
722/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibeot.html)
723pub fn ibeot(ud: c_int, send_eoi: IbSendEOI) -> Result<(), GpibError> {
724    let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibeot(ud, send_eoi.as_eot()) });
725    if status.err {
726        Err(GpibError::DriverError(status, IbError::current_error()?))
727    } else {
728        Ok(())
729    }
730}
731
732pub enum IbEvent {
733    None,
734    DevTrg,
735    DevClr,
736    IFC,
737}
738
739impl fmt::Display for IbEvent {
740    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
741        match self {
742            IbEvent::None => {
743                write!(f, "None")
744            }
745            IbEvent::DevTrg => {
746                write!(f, "DevTrg")
747            }
748            IbEvent::DevClr => {
749                write!(f, "DevClr")
750            }
751            IbEvent::IFC => {
752                write!(f, "IFC")
753            }
754        }
755    }
756}
757
758impl fmt::Debug for IbEvent {
759    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
760        match self {
761            IbEvent::None => {
762                write!(f, "None (The board's event queue is empty)")
763            }
764            IbEvent::DevTrg => {
765                write!(f, "DevTrg (The board has received a trigger command from the controller-in-charge)")
766            }
767            IbEvent::DevClr => {
768                write!(
769                    f,
770                    "DevClr (The board has received a clear command from the controller-in-charge)"
771                )
772            }
773            IbEvent::IFC => {
774                write!(f, "IFC (The board has received an interface clear from the system controller. Note, some models of GPIB interface board lack the ability to report interface clear events)")
775            }
776        }
777    }
778}
779
780impl IbEvent {
781    fn from_value(value: c_short) -> Result<IbEvent, GpibError> {
782        match value {
783            0 => Ok(IbEvent::None),
784            1 => Ok(IbEvent::DevTrg),
785            2 => Ok(IbEvent::DevClr),
786            3 => Ok(IbEvent::IFC),
787            other => Err(GpibError::ValueError(format!(
788                "Unexpected value ({}) for event.",
789                other,
790            ))),
791        }
792    }
793}
794
795/// ibevent -- get events from event queue (board)
796/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibevent.html)
797pub fn ibevent(ud: c_int) -> Result<IbEvent, GpibError> {
798    let mut event_value: c_short = 0;
799    let status = IbStatus::from_ibsta(unsafe {
800        linux_gpib_sys::ibevent(ud, &mut event_value as *mut c_short)
801    });
802    if status.err {
803        Err(GpibError::DriverError(status, IbError::current_error()?))
804    } else {
805        Ok(IbEvent::from_value(event_value)?)
806    }
807}
808
809/// ibfind -- open a board or device (board or device)
810/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibfind.html)
811pub fn ibfind(name: &str) -> Result<c_int, GpibError> {
812    let name = CString::new(name)?;
813    let ud = unsafe { linux_gpib_sys::ibfind(name.as_ptr()) };
814    if ud >= 0 {
815        Ok(ud)
816    } else {
817        Err(GpibError::DriverError(
818            IbStatus::current_status(),
819            IbError::current_error()?,
820        ))
821    }
822}
823
824/// ibgts -- release ATN (board)
825/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibgts.html)
826pub fn ibgts(ud: c_int, shadow_handshake: c_int) -> Result<(), GpibError> {
827    let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibgts(ud, shadow_handshake) });
828    if status.err {
829        Err(GpibError::DriverError(status, IbError::current_error()?))
830    } else {
831        Ok(())
832    }
833}
834
835/// ibist -- set individual status bit (board)
836/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibist.html)
837pub fn ibist(ud: c_int, ist: c_int) -> Result<(), GpibError> {
838    let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibist(ud, ist) });
839    if status.err {
840        Err(GpibError::DriverError(status, IbError::current_error()?))
841    } else {
842        Ok(())
843    }
844}
845
846pub struct IbLineStatus {
847    pub valid_dav: bool,
848    pub valid_ndac: bool,
849    pub valid_nrfd: bool,
850    pub valid_ifc: bool,
851    pub valid_ren: bool,
852    pub valid_srq: bool,
853    pub valid_atn: bool,
854    pub valid_eoi: bool,
855    pub bus_dav: bool,
856    pub bus_ndac: bool,
857    pub bus_nrfd: bool,
858    pub bus_ifc: bool,
859    pub bus_ren: bool,
860    pub bus_srq: bool,
861    pub bus_atn: bool,
862    pub bus_eoi: bool,
863}
864
865impl IbLineStatus {
866    fn from_line_status(line_status: c_short) -> IbLineStatus {
867        let valid_dav = (line_status & 0x1) != 0;
868        let valid_ndac = (line_status & 0x2) != 0;
869        let valid_nrfd = (line_status & 0x4) != 0;
870        let valid_ifc = (line_status & 0x8) != 0;
871        let valid_ren = (line_status & 0x10) != 0;
872        let valid_srq = (line_status & 0x20) != 0;
873        let valid_atn = (line_status & 0x40) != 0;
874        let valid_eoi = (line_status & 0x80) != 0;
875        let bus_dav = (line_status & 0x100) != 0;
876        let bus_ndac = (line_status & 0x200) != 0;
877        let bus_nrfd = (line_status & 0x400) != 0;
878        let bus_ifc = (line_status & 0x800) != 0;
879        let bus_ren = (line_status & 0x1000) != 0;
880        let bus_srq = (line_status & 0x2000) != 0;
881        let bus_atn = (line_status & 0x4000) != 0;
882        let bus_eoi = (line_status & 0x8000u16 as i16) != 0;
883        Self {
884            valid_dav,
885            valid_ndac,
886            valid_nrfd,
887            valid_ifc,
888            valid_ren,
889            valid_srq,
890            valid_atn,
891            valid_eoi,
892            bus_dav,
893            bus_ndac,
894            bus_nrfd,
895            bus_ifc,
896            bus_ren,
897            bus_srq,
898            bus_atn,
899            bus_eoi,
900        }
901    }
902}
903
904/// iblines -- monitor bus lines (board)
905/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-iblines.html)
906pub fn iblines(ud: c_int) -> Result<IbLineStatus, GpibError> {
907    let mut line_status: c_short = 0;
908    let status = IbStatus::from_ibsta(unsafe {
909        linux_gpib_sys::iblines(ud, &mut line_status as *mut c_short)
910    });
911    if status.err {
912        Err(GpibError::DriverError(status, IbError::current_error()?))
913    } else {
914        Ok(IbLineStatus::from_line_status(line_status))
915    }
916}
917
918/// ibln -- check if listener is present (board or device)
919/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibln.html)
920pub fn ibln(
921    ud: c_int,
922    primary_address: PrimaryAddress,
923    secondary_address: SecondaryAddress,
924) -> Result<bool, GpibError> {
925    let mut found_listener: c_short = 0;
926    let status = IbStatus::from_ibsta(unsafe {
927        linux_gpib_sys::ibln(
928            ud,
929            primary_address.as_pad(),
930            secondary_address.as_sad(),
931            &mut found_listener as *mut c_short,
932        )
933    });
934    if status.err {
935        Err(GpibError::DriverError(status, IbError::current_error()?))
936    } else {
937        Ok(found_listener != 0)
938    }
939}
940
941/// ibloc -- go to local mode (board or device)
942/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibloc.html)
943pub fn ibloc(ud: c_int) -> Result<(), GpibError> {
944    let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibloc(ud) });
945    if status.err {
946        Err(GpibError::DriverError(status, IbError::current_error()?))
947    } else {
948        Ok(())
949    }
950}
951
952pub enum IbOnline {
953    Close,
954    Reset(c_int),
955}
956
957impl IbOnline {
958    fn as_online(&self) -> c_int {
959        match self {
960            IbOnline::Close => 0,
961            IbOnline::Reset(val) => *val,
962        }
963    }
964}
965
966impl fmt::Display for IbOnline {
967    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
968        match self {
969            IbOnline::Close => {
970                write!(f, "IbOnline::Close")
971            }
972            IbOnline::Reset(val) => {
973                write!(f, "IbOnline::Reset({})", val)
974            }
975        }
976    }
977}
978
979/// ibonl -- close or reinitialize descriptor (board or device)
980/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibonl.html)
981pub fn ibonl(ud: c_int, online: IbOnline) -> Result<(), GpibError> {
982    if DEBUG {
983        println!("ibonl({}, {})", ud, online);
984    }
985    let online = online.as_online();
986    let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibonl(ud, online) });
987    if DEBUG {
988        println!("-> {:?}", status);
989    }
990    if status.err {
991        Err(GpibError::DriverError(status, IbError::current_error()?))
992    } else {
993        Ok(())
994    }
995}
996
997/// ibpad -- set primary GPIB address (board or device)
998/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibpad.html)
999pub fn ibpad(ud: c_int, primary_address: PrimaryAddress) -> Result<(), GpibError> {
1000    let status =
1001        IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibpad(ud, primary_address.as_pad()) });
1002    if status.err {
1003        Err(GpibError::DriverError(status, IbError::current_error()?))
1004    } else {
1005        Ok(())
1006    }
1007}
1008
1009/// ibpct -- pass control (board)
1010/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibpct.html)
1011pub fn ibpct(ud: c_int) -> Result<(), GpibError> {
1012    let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibpct(ud) });
1013    if status.err {
1014        Err(GpibError::DriverError(status, IbError::current_error()?))
1015    } else {
1016        Ok(())
1017    }
1018}
1019
1020/// ibppc -- parallel poll configure (board or device)
1021/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibppc.html)
1022pub fn ibppc(ud: c_int, configuration: c_int) -> Result<(), GpibError> {
1023    let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibppc(ud, configuration) });
1024    if status.err {
1025        Err(GpibError::DriverError(status, IbError::current_error()?))
1026    } else {
1027        Ok(())
1028    }
1029}
1030
1031/// ibrd -- read data bytes (board or device)
1032/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibrd.html)
1033pub fn ibrd(ud: c_int, buffer: &mut [u8]) -> Result<usize, GpibError> {
1034    if DEBUG {
1035        println!("ibrd({}, count = {})", ud, buffer.len());
1036    }
1037    let status = IbStatus::from_ibsta(unsafe {
1038        linux_gpib_sys::ibrd(
1039            ud,
1040            buffer.as_mut_ptr() as *mut c_void,
1041            buffer.len().try_into()?,
1042        )
1043    });
1044    if DEBUG {
1045        println!("-> {:?}", status);
1046    }
1047    if status.err {
1048        Err(GpibError::DriverError(status, IbError::current_error()?))
1049    } else {
1050        let bytes_read = unsafe { linux_gpib_sys::ibcntl };
1051        if bytes_read > buffer.len().try_into()? {
1052            Err(GpibError::ValueError(format!(
1053                "bytes_read ({}) > buffer.len() ({})",
1054                bytes_read,
1055                buffer.len(),
1056            )))
1057        } else {
1058            if DEBUG {
1059                println!("-> {} bytes read", bytes_read);
1060            }
1061            Ok(bytes_read.try_into()?)
1062        }
1063    }
1064}
1065
1066/// ibrdf -- read data bytes to file (board or device)
1067/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibrdf.html)
1068pub fn ibrdf(ud: c_int, file_path: &Path) -> Result<(), GpibError> {
1069    let file_path = CString::new(file_path.to_str().ok_or(GpibError::ValueError(format!(
1070        "Unable to convert path '{:?}' to string",
1071        file_path
1072    )))?)?;
1073    let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibrdf(ud, file_path.as_ptr()) });
1074    if status.err {
1075        Err(GpibError::DriverError(status, IbError::current_error()?))
1076    } else {
1077        Ok(())
1078    }
1079}
1080
1081/// ibrpp -- perform a parallel poll (board or device)
1082/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibrpp.html)
1083pub fn ibrpp(ud: c_int) -> Result<c_char, GpibError> {
1084    let mut ppoll_result: c_char = 0;
1085    let status = IbStatus::from_ibsta(unsafe {
1086        linux_gpib_sys::ibrpp(ud, &mut ppoll_result as *mut c_char)
1087    });
1088    if status.err {
1089        Err(GpibError::DriverError(status, IbError::current_error()?))
1090    } else {
1091        Ok(ppoll_result)
1092    }
1093}
1094
1095/// ibrsc -- request system control (board)
1096/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibrsc.html)
1097pub fn ibrsc(ud: c_int, request_control: c_int) -> Result<(), GpibError> {
1098    let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibrsc(ud, request_control) });
1099    if status.err {
1100        Err(GpibError::DriverError(status, IbError::current_error()?))
1101    } else {
1102        Ok(())
1103    }
1104}
1105
1106/// ibrsp --  read status byte / serial poll (device)
1107/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibrsp.html)
1108pub fn ibrsp(ud: c_int) -> Result<c_char, GpibError> {
1109    let mut result: c_char = 0;
1110    let status =
1111        IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibrsp(ud, &mut result as *mut c_char) });
1112    if status.err {
1113        Err(GpibError::DriverError(status, IbError::current_error()?))
1114    } else {
1115        Ok(result)
1116    }
1117}
1118
1119/// ibrsv -- request service (board)
1120/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibrsv.html)
1121pub fn ibrsv(ud: c_int, status_byte: c_int) -> Result<(), GpibError> {
1122    let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibrsv(ud, status_byte) });
1123    if status.err {
1124        Err(GpibError::DriverError(status, IbError::current_error()?))
1125    } else {
1126        Ok(())
1127    }
1128}
1129
1130/// ibrsv2 -- request service (board)
1131/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibrsv2.html)
1132pub fn ibrsv2(
1133    ud: c_int,
1134    status_byte: c_int,
1135    new_reason_for_request: c_int,
1136) -> Result<(), GpibError> {
1137    let status = IbStatus::from_ibsta(unsafe {
1138        linux_gpib_sys::ibrsv2(ud, status_byte, new_reason_for_request)
1139    });
1140    if status.err {
1141        Err(GpibError::DriverError(status, IbError::current_error()?))
1142    } else {
1143        Ok(())
1144    }
1145}
1146
1147/// ibsad -- set secondary GPIB address (board or device)
1148/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibsad.html)
1149pub fn ibsad(ud: c_int, secondary_address: SecondaryAddress) -> Result<(), GpibError> {
1150    let status =
1151        IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibsad(ud, secondary_address.as_sad()) });
1152    if status.err {
1153        Err(GpibError::DriverError(status, IbError::current_error()?))
1154    } else {
1155        Ok(())
1156    }
1157}
1158
1159/// ibsic -- perform interface clear (board)
1160/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibsic.html)
1161pub fn ibsic(ud: c_int) -> Result<(), GpibError> {
1162    let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibsic(ud) });
1163    if status.err {
1164        Err(GpibError::DriverError(status, IbError::current_error()?))
1165    } else {
1166        Ok(())
1167    }
1168}
1169
1170/// ibspb --  obtain length of serial poll bytes queue (device)
1171/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibspb.html)
1172pub fn ibspb(ud: c_int) -> Result<c_short, GpibError> {
1173    let mut result: c_short = 0;
1174    let status =
1175        IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibspb(ud, &mut result as *mut c_short) });
1176    if status.err {
1177        Err(GpibError::DriverError(status, IbError::current_error()?))
1178    } else {
1179        Ok(result)
1180    }
1181}
1182
1183/// ibsre -- set remote enable (board)
1184/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibsre.html)
1185pub fn ibsre(ud: c_int, enable: c_int) -> Result<(), GpibError> {
1186    let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibsre(ud, enable) });
1187    if status.err {
1188        Err(GpibError::DriverError(status, IbError::current_error()?))
1189    } else {
1190        Ok(())
1191    }
1192}
1193
1194/// ibstop -- abort asynchronous i/o operation (board or device)
1195/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibstop.html)
1196pub fn ibstop(ud: c_int) -> Result<(), GpibError> {
1197    let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibstop(ud) });
1198    if status.err {
1199        Err(GpibError::DriverError(status, IbError::current_error()?))
1200    } else {
1201        Ok(())
1202    }
1203}
1204
1205/// ibtmo -- adjust io timeout (board or device)
1206/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibtmo.html)
1207pub fn ibtmo(ud: c_int, timeout: IbTimeout) -> Result<(), GpibError> {
1208    let timeout = timeout.as_timeout();
1209    let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibtmo(ud, timeout) });
1210    if status.err {
1211        Err(GpibError::DriverError(status, IbError::current_error()?))
1212    } else {
1213        Ok(())
1214    }
1215}
1216
1217/// ibtrg -- trigger device (device)
1218/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibtrg.html)
1219pub fn ibtrg(ud: c_int) -> Result<(), GpibError> {
1220    let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibtrg(ud) });
1221    if status.err {
1222        Err(GpibError::DriverError(status, IbError::current_error()?))
1223    } else {
1224        Ok(())
1225    }
1226}
1227
1228/// ibvers -- Obtain the current linux gpib version
1229/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibvers.html)
1230pub fn ibvers() -> Result<String, GpibError> {
1231    let mut buffer_ptr: *mut c_char = std::ptr::null_mut();
1232    unsafe { linux_gpib_sys::ibvers(&mut buffer_ptr as *mut *mut c_char) }
1233    Ok(unsafe { CStr::from_ptr(buffer_ptr) }.to_str()?.to_owned())
1234}
1235
1236/// ibwait -- wait for event (board or device)
1237/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibwait.html)
1238pub fn ibwait(ud: c_int, status_mask: IbStatus) -> Result<(), GpibError> {
1239    if DEBUG {
1240        println!("ibwait({}, {})", ud, status_mask);
1241    }
1242    let status_mask = status_mask.as_ibsta();
1243    let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibwait(ud, status_mask) });
1244    if DEBUG {
1245        println!("-> {:?}", status);
1246    }
1247    if status.err {
1248        Err(GpibError::DriverError(status, IbError::current_error()?))
1249    } else {
1250        Ok(())
1251    }
1252}
1253
1254/// ibwrt -- write data bytes (board or device)
1255/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibwrt.html)
1256pub fn ibwrt(ud: c_int, data: &[u8]) -> Result<usize, GpibError> {
1257    if DEBUG {
1258        println!("ibwrt({}, {:?})", ud, String::from_utf8(data.to_vec())?);
1259    }
1260    let status = IbStatus::from_ibsta(unsafe {
1261        linux_gpib_sys::ibwrt(ud, data.as_ptr() as *const c_void, data.len().try_into()?)
1262    });
1263    if DEBUG {
1264        println!("-> {:?}", status);
1265    }
1266    if status.err {
1267        Err(GpibError::DriverError(status, IbError::current_error()?))
1268    } else {
1269        Ok(unsafe { linux_gpib_sys::ibcntl }.try_into()?)
1270    }
1271}
1272
1273/// ibwrtf -- write data bytes from file (board or device)
1274/// See: [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference-function-ibwrtf.html)
1275pub fn ibwrtf(ud: c_int, file_path: &Path) -> Result<usize, GpibError> {
1276    let file_path = CString::new(file_path.to_str().ok_or(GpibError::ValueError(format!(
1277        "Unable to convert path '{:?}' to string",
1278        file_path
1279    )))?)?;
1280    let status = IbStatus::from_ibsta(unsafe { linux_gpib_sys::ibwrtf(ud, file_path.as_ptr()) });
1281    if status.err {
1282        Err(GpibError::DriverError(status, IbError::current_error()?))
1283    } else {
1284        Ok(unsafe { linux_gpib_sys::ibcntl }.try_into()?)
1285    }
1286}