linux_gpib_rs/
error.rs

1#[cfg(feature = "linuxgpib")]
2use crate::lowlevel::utility::{AsyncIberr, ThreadIberr};
3
4use crate::status::IbStatus;
5use std::convert::Infallible;
6use std::error::Error;
7use std::ffi::NulError;
8use std::fmt;
9use std::num::TryFromIntError;
10use std::str::Utf8Error;
11use std::string::FromUtf8Error;
12#[cfg(feature = "async-tokio")]
13use tokio::task::JoinError;
14
15pub enum IbError {
16    EDVR(i64), // In this case, we hold also ibcntl value
17    ECIC,
18    ENOL,
19    EADR,
20    EARG,
21    ESAC,
22    EABO,
23    ENEB,
24    EDMA,
25    EOIP,
26    ECAP,
27    EFSO(i64), // In this case, we hold also ibcntl value
28    EBUS,
29    ESTB,
30    ESRQ,
31    ETAB,
32}
33
34pub enum GpibError {
35    DriverError(IbStatus, IbError),
36    Timeout,
37    ValueError(String),
38    #[cfg(feature = "async-tokio")]
39    TokioError(JoinError),
40}
41
42impl Error for GpibError {}
43
44impl fmt::Display for GpibError {
45    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
46        match self {
47            GpibError::DriverError(status, error) => {
48                write!(f, "GpibError({}, {})", status, error)
49            }
50            GpibError::Timeout => {
51                write!(f, "Timeout")
52            }
53            GpibError::ValueError(desc) => {
54                write!(f, "ValueError({})", desc)
55            }
56            #[cfg(feature = "async-tokio")]
57            GpibError::TokioError(e) => {
58                write!(f, "Tokio Error ({})", e)
59            }
60        }
61    }
62}
63
64impl fmt::Debug for GpibError {
65    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66        match self {
67            GpibError::DriverError(status, error) => {
68                write!(f, "GpibError({:?}, {:?})", status, error)
69            }
70            GpibError::Timeout => {
71                write!(f, "Timeout")
72            }
73            GpibError::ValueError(desc) => {
74                write!(f, "ValueError({})", desc)
75            }
76            #[cfg(feature = "async-tokio")]
77            GpibError::TokioError(e) => {
78                write!(f, "Tokio Error ({:?})", e)
79            }
80        }
81    }
82}
83
84impl fmt::Display for IbError {
85    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86        match self {
87            IbError::EDVR(ibcntl) => {
88                write!(f, "EDVR  (ibcntl = {ibcntl})")
89            }
90            IbError::ECIC => {
91                write!(f, "ECIC")
92            }
93            IbError::ENOL => {
94                write!(f, "ENOL")
95            }
96            IbError::EADR => {
97                write!(f, "EADR")
98            }
99            IbError::EARG => {
100                write!(f, "EARG")
101            }
102            IbError::ESAC => {
103                write!(f, "ESAC")
104            }
105            IbError::EABO => {
106                write!(f, "EABO")
107            }
108            IbError::ENEB => {
109                write!(f, "ENEB")
110            }
111            IbError::EDMA => {
112                write!(f, "EDMA")
113            }
114            IbError::EOIP => {
115                write!(f, "EOIP")
116            }
117            IbError::ECAP => {
118                write!(f, "ECAP")
119            }
120            IbError::EFSO(ibcntl) => {
121                write!(f, "EFSO (ibcntl = {ibcntl})")
122            }
123            IbError::EBUS => {
124                write!(f, "EBUS")
125            }
126            IbError::ESTB => {
127                write!(f, "ESTB")
128            }
129            IbError::ESRQ => {
130                write!(f, "ESRQ")
131            }
132            IbError::ETAB => {
133                write!(f, "ETAB")
134            }
135        }
136    }
137}
138
139impl fmt::Debug for IbError {
140    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
141        match self {
142            IbError::EDVR(ibcntl) => {
143                write!(f, "EDVR  (A system call has failed. ibcntl = {ibcntl})")
144            }
145            IbError::ECIC => {
146                write!(
147                    f,
148                    "ECIC (Your interface board needs to be controller-in-charge, but is not)"
149                )
150            }
151            IbError::ENOL => {
152                write!(
153                    f,
154                    "ENOL (You have attempted to write data or command bytes, but there are no listeners currently addressed)"
155                )
156            }
157            IbError::EADR => {
158                write!(
159                    f,
160                    "EADR (The interface board has failed to address itself properly before starting an io operation)"
161                )
162            }
163            IbError::EARG => {
164                write!(
165                    f,
166                    "EARG (One or more arguments to the function call were invalid)"
167                )
168            }
169            IbError::ESAC => {
170                write!(
171                    f,
172                    "ESAC (The interface board needs to be system controller, but is not)"
173                )
174            }
175            IbError::EABO => {
176                write!(
177                    f,
178                    "EABO (A read or write of data bytes has been aborted, possibly due to a timeout or reception of a device clear command)"
179                )
180            }
181            IbError::ENEB => {
182                write!(
183                    f,
184                    "ENEB (The GPIB interface board does not exist, its driver is not loaded, or it is not configured properly)"
185                )
186            }
187            IbError::EDMA => {
188                write!(
189                    f,
190                    "EDMA (Not used DMA error, included for compatibility purposes)"
191                )
192            }
193            IbError::EOIP => {
194                write!(
195                    f,
196                    "EOIP (Function call can not proceed due to an asynchronous IO operation in progress)"
197                )
198            }
199            IbError::ECAP => {
200                write!(
201                    f,
202                    "ECAP (incapable of executing function call, due the GPIB board lacking the capability, or the capability being disabled in software)"
203                )
204            }
205            IbError::EFSO(ibcntl) => {
206                write!(f, "EFSO (file system error, ibcntl = {ibcntl})")
207            }
208            IbError::EBUS => {
209                write!(
210                    f,
211                    "EBUS (an attempt to write command bytes to the bus has timed out)"
212                )
213            }
214            IbError::ESTB => {
215                write!(
216                    f,
217                    "ESTB (one or more serial poll status bytes have been lost. This can occur due to too many status bytes accumulating, through automatic serial polling, without being read)"
218                )
219            }
220            IbError::ESRQ => {
221                write!(
222                    f,
223                    "ESRQ (the serial poll request service line is stuck on. This can occur if a physical device on the bus requests service, but its GPIB address has not been opened by any process. Thus the automatic serial polling routines are unaware of the device's existence and will never serial poll it)"
224                )
225            }
226            IbError::ETAB => {
227                write!(
228                    f,
229                    "ETAB (this error can be returned by ibevent(), FindLstn(), or FindRQS(). See their descriptions for more information)"
230                )
231            }
232        }
233    }
234}
235
236impl IbError {
237    /// Create IbError from iberr value
238    pub fn from_iberr(iberr: linux_gpib_sys::iberr_type) -> Result<IbError, GpibError> {
239        match iberr {
240            #[cfg(feature = "linuxgpib")]
241            0 => Ok(IbError::EDVR(unsafe { linux_gpib_sys::ibcntl })),
242            #[cfg(feature = "nigpib")]
243            0 => Ok(IbError::EDVR(unsafe { linux_gpib_sys::Ibcnt().into() })),
244            1 => Ok(IbError::ECIC),
245            2 => Ok(IbError::ENOL),
246            3 => Ok(IbError::EADR),
247            4 => Ok(IbError::EARG),
248            5 => Ok(IbError::ESAC),
249            6 => Ok(IbError::EABO),
250            7 => Ok(IbError::ENEB),
251            8 => Ok(IbError::EDMA),
252            10 => Ok(IbError::EOIP),
253            11 => Ok(IbError::ECAP),
254            #[cfg(feature = "linuxgpib")]
255            12 => Ok(IbError::EFSO(unsafe { linux_gpib_sys::ibcntl })),
256            #[cfg(feature = "nigpib")]
257            12 => Ok(IbError::EFSO(unsafe { linux_gpib_sys::Ibcnt().into() })),
258            14 => Ok(IbError::EBUS),
259            15 => Ok(IbError::ESTB),
260            16 => Ok(IbError::ESRQ),
261            20 => Ok(IbError::ETAB),
262            other => Err(GpibError::ValueError(format!(
263                "Unexpected iberr value = {}.",
264                other
265            ))),
266        }
267    }
268
269    /// Create IbError from current Linux-GPIB global iberr variable
270    pub unsafe fn current_global_error() -> Result<IbError, GpibError> {
271        let status = unsafe { IbStatus::current_global_status() };
272        if status.err {
273            #[cfg(feature = "linuxgpib")]
274            return IbError::from_iberr(unsafe { linux_gpib_sys::iberr });
275            #[cfg(feature = "nigpib")]
276            return IbError::from_iberr(linux_gpib_sys::Iberr());
277        } else {
278            Err(GpibError::ValueError(format!(
279                "Unable to get error because is not ERR (status = {:?})",
280                status
281            )))
282        }
283    }
284
285    #[cfg(feature = "linuxgpib")]
286    /// Create IbError from current thread-local iberr value
287    pub fn current_thread_local_error() -> Result<IbError, GpibError> {
288        let status = IbStatus::current_thread_local_status();
289        if status.err {
290            IbError::from_iberr(ThreadIberr())
291        } else {
292            Err(GpibError::ValueError(format!(
293                "Unable to get error because is not ERR (status = {:?})",
294                status
295            )))
296        }
297    }
298
299    #[cfg(feature = "linuxgpib")]
300    /// Create IbError for last asynchronous I/O operation
301    pub fn current_async_local_error() -> Result<IbError, GpibError> {
302        let status = IbStatus::current_async_local_status();
303        if status.err {
304            IbError::from_iberr(AsyncIberr())
305        } else {
306            Err(GpibError::ValueError(format!(
307                "Unable to get error because is not ERR (status = {:?})",
308                status
309            )))
310        }
311    }
312}
313
314impl From<NulError> for GpibError {
315    fn from(e: NulError) -> GpibError {
316        GpibError::ValueError(format!("{:?}", e))
317    }
318}
319
320impl From<TryFromIntError> for GpibError {
321    fn from(e: TryFromIntError) -> GpibError {
322        GpibError::ValueError(format!("{:?}", e,))
323    }
324}
325
326impl From<FromUtf8Error> for GpibError {
327    fn from(e: FromUtf8Error) -> GpibError {
328        GpibError::ValueError(format!("{:?}", e,))
329    }
330}
331
332impl From<Utf8Error> for GpibError {
333    fn from(e: Utf8Error) -> GpibError {
334        GpibError::ValueError(format!("{:?}", e,))
335    }
336}
337
338impl From<Infallible> for GpibError {
339    fn from(e: Infallible) -> GpibError {
340        GpibError::ValueError(e.to_string())
341    }
342}
343
344#[cfg(feature = "async-tokio")]
345impl From<JoinError> for GpibError {
346    fn from(e: JoinError) -> GpibError {
347        GpibError::TokioError(e)
348    }
349}