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