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
298pub 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
313pub 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
326pub 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
337pub 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
354pub 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
371pub 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 sad
532 } else if sad <= 30 {
533 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
670pub 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
709pub 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
721pub 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
795pub 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
809pub 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
824pub 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
835pub 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
904pub 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
918pub 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
941pub 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
979pub 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
997pub 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
1009pub 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
1020pub 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
1031pub 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
1066pub 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
1081pub 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
1095pub 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
1106pub 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
1119pub 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
1130pub 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
1147pub 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
1159pub 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
1170pub 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
1183pub 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
1194pub 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
1205pub 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
1217pub 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
1228pub 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
1236pub 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
1254pub 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
1273pub 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}