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}