linux_gpib_rs/
lib.rs

1//!
2//! Low-level wrapper for Linux GPIB.
3//! 
4//! Documentation for the functions comes from [Linux GPIB Reference](https://linux-gpib.sourceforge.io/doc_html/reference.html).
5//! At the moment, only the 'Traditional' API Functions are wrapped.
6//! 
7//! ## Requirements
8//! 
9//! This crate needs to link to an installed linux-gpib user library. It will look for `gpib/ib.h` in either `/usr/include` or `/usr/local/include`,
10//! and for `libgpib.so` in either `/usr/lib` or `/usr/local/lib`.
11//! 
12//! 
13//! ## Example
14//! 
15//! Add dependencies below to `Cargo.toml`
16//! 
17//! ```toml
18//! linux-gpib-rs = { version = "0.1", features = ["async-tokio"] }
19//! ```
20//! 
21//! Codes below will connect to the instrument on `GPIB0::1::INSTR` and print out its `*IDN?` response.
22//! 
23//! **Synchronous example**
24//! 
25//! We can use the low-level synchronous functions `ibrd` and `ibwrt`.
26//! 
27//! ```rust
28//! use linux_gpib_rs::{
29//!     OpenParam,
30//!     open,
31//!     ibwrt,
32//!     ibrd,
33//! };
34//! use std::error::Error;
35//! 
36//! fn main() -> Result<(), Box<dyn Error>> {
37//!     let ud = open("GPIB0::1::INSTR", OpenParam::default())?;
38//!     ibwrt(ud, b"*IDN?\r\n")?;
39//!     let mut buffer: [u8; 256] = [0; 256];
40//!     ibrd(ud, &mut buffer)?;
41//!     let iden = String::from_utf8(buffer.to_vec())?;
42//!     println!("{iden}");
43//!     Ok(())
44//! }
45//! ```
46//! 
47//! **Asynchronous example**
48//! 
49//! We can use slightly higher-level asynchronous functions `write` and `read` (based on `ibrda` and `ibwrta`).
50//! This requires the `async-tokio` feature.
51//! 
52//! ```rust
53//! use linux_gpib_rs::{open, write, read, OpenParam};
54//! use std::error::Error;
55//! 
56//! #[tokio::main]
57//! async fn main() -> Result<(), Box<dyn Error>> {
58//!     let ud = open("GPIB0::1::INSTR", OpenParam::default())?;
59//!     write(ud, "*IDN?\r\n").await?;
60//!     let iden = read(ud).await?;
61//!     println!("{iden}");
62//!     Ok(())
63//! }
64//! ```
65
66mod error;
67mod status;
68mod traditional;
69
70pub use error::{GpibError, IbError};
71pub use status::IbStatus;
72use std::os::raw::c_int;
73pub use traditional::{
74    ibask, ibbna, ibcac, ibclr, ibcmd, ibconfig, ibdev, ibeos, ibeot, ibevent, ibfind, ibgts,
75    ibist, iblines, ibln, ibloc, ibonl, ibpad, ibpct, ibppc, ibrd, ibrdf, ibrpp, ibrsc, ibrsp,
76    ibrsv, ibrsv2, ibsad, ibsic, ibspb, ibsre, ibstop, ibtmo, ibtrg, ibvers, ibwait, ibwrt, ibwrtf,
77    IbEosMode, IbEvent, IbLineStatus, IbOnline, IbOption, IbSendEOI, IbTimeout, PrimaryAddress,
78    SecondaryAddress,
79};
80
81#[cfg(feature = "async-tokio")]
82mod asynchronous;
83
84#[cfg(feature = "async-tokio")]
85pub use asynchronous::{read, wait, write};
86
87pub struct OpenParam {
88    timeout: IbTimeout,
89    send_eoi: IbSendEOI,
90    eos_mode: IbEosMode,
91}
92
93impl Default for OpenParam {
94    fn default() -> Self {
95        Self {
96            timeout: IbTimeout::T1s,
97            send_eoi: IbSendEOI::default(),
98            eos_mode: IbEosMode::default(),
99        }
100    }
101}
102
103/// Quickly open a device from a VISA-style address, e.g. 'GPIB0::1::INSTR'.
104///
105/// `timeout`, `send_eoi` and `eos_mode` are specified with an `OpenParam` structure.
106/// Default parameters can be obtained with `OpenParam::default()`.
107pub fn open(address: &str, params: OpenParam) -> Result<c_int, GpibError> {
108    let v: Vec<&str> = address.split("::").collect();
109    if v.len() < 2 {
110        return Err(GpibError::ValueError(format!(
111            "Invalid address '{}'.",
112            address
113        )));
114    }
115    if v[0].starts_with("GPIB") {
116        let (_, board_number) = v[0].split_at(4);
117        let board_number = i32::from_str_radix(board_number, 10).map_err(|e| {
118            GpibError::ValueError(format!(
119                "Unable to parse GPIB Board index from string '{}' ({:?})",
120                board_number, e,
121            ))
122        })?;
123        let primary_address = i32::from_str_radix(v[1], 10).map_err(|e| {
124            GpibError::ValueError(format!(
125                "Unable to parse GPIB primary address from string '{}' ({:?})",
126                v[1], e,
127            ))
128        })?;
129        ibdev(
130            board_number,
131            PrimaryAddress::new(primary_address)?,
132            SecondaryAddress::default(),
133            params.timeout,
134            params.send_eoi,
135            params.eos_mode,
136        )
137    } else {
138        Err(GpibError::ValueError(
139            "Address is expected as GPIBN::primary_address::INSTR".to_owned(),
140        ))
141    }
142}