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), ECIC,
18 ENOL,
19 EADR,
20 EARG,
21 ESAC,
22 EABO,
23 ENEB,
24 EDMA,
25 EOIP,
26 ECAP,
27 EFSO(i64), EBUS,
29 ESTB,
30 ESRQ,
31 ETAB,
32 ELCK,
33 EARM,
34 EHDL,
35 ECFG,
36 EWIP,
37 ERST,
38 EPWR,
39}
40
41pub enum GpibError {
42 DriverError(IbStatus, IbError),
43 Timeout,
44 ValueError(String),
45 #[cfg(feature = "async-tokio")]
46 TokioError(JoinError),
47}
48
49impl Error for GpibError {}
50
51pub fn edvr_description(val: i64) -> String {
54 match val {
55 0xE014002C | -535560148 => "ibcntl = 0xE014002C: a call is made with a board number that is within the range of allowed board numbers, but which has not been assigned to a GPIB interface".to_owned(),
56 0xE0140025 | -535560155 => "ibcntl = 0xE0140025: a call is made with a board number that is not within the range of allowed board numbers".to_owned(),
57 0xE0140035 | -535560139 => "ibcntl = 0XE0140035: a call is made with a device name that is not listed in the logical device templates".to_owned(),
58 0xE1080080 | -519569280 | 0xE1080081 | -519569279 => format!("ibcntl = {:x}: you are using a removable interface (for example, a GPIB-USB-HS) and you removed or ejected the interface while the software is trying to communicate with it", val),
59 0xE00A0047 | -536215481 => "ibcntl = 0xE00A0047: the driver encounters an access violation when attempting to access an object supplied by the user. This can happen if the user's buffer does not have appropriate read/write characteristics. For example, this error is returned if a required pointer passed to a call is NULL.".to_owned(),
60 0xE1030043 | -519897021 => "ibcntl = 0xE1030043: you have enabled DOS NI-488.2 support and attempted to run an existing DOS NI-488.2 application that was compiled with an older, unsupported DOS application interface".to_owned(),
61 0xE1060075 | -519700363 => "ibcntl = 0xE1060075: the driver is unable to communicate with a GPIB-ENET/100 during an ibfind or ibdev".to_owned(),
62 0xE1060078 | -519700360 => "ibcntl = 0xE1060078: you are using a GPIB-ENET/100 and the network link is broken between the host and the GPIB-ENET/100 interface".to_owned(),
63 other => format!("unknown ibcntl value {:x}", other),
64 }
65}
66
67impl fmt::Display for GpibError {
68 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69 match self {
70 GpibError::DriverError(status, error) => {
71 write!(f, "GpibError({}, {})", status, error)
72 }
73 GpibError::Timeout => {
74 write!(f, "Timeout")
75 }
76 GpibError::ValueError(desc) => {
77 write!(f, "ValueError({})", desc)
78 }
79 #[cfg(feature = "async-tokio")]
80 GpibError::TokioError(e) => {
81 write!(f, "Tokio Error ({})", e)
82 }
83 }
84 }
85}
86
87impl fmt::Debug for GpibError {
88 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89 match self {
90 GpibError::DriverError(status, error) => {
91 write!(f, "GpibError({:?}, {:?})", status, error)
92 }
93 GpibError::Timeout => {
94 write!(f, "Timeout")
95 }
96 GpibError::ValueError(desc) => {
97 write!(f, "ValueError({})", desc)
98 }
99 #[cfg(feature = "async-tokio")]
100 GpibError::TokioError(e) => {
101 write!(f, "Tokio Error ({:?})", e)
102 }
103 }
104 }
105}
106
107impl fmt::Display for IbError {
108 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
109 match self {
110 IbError::EDVR(ibcntl) => {
111 write!(f, "EDVR ({})", edvr_description(*ibcntl))
112 }
113 IbError::ECIC => {
114 write!(f, "ECIC")
115 }
116 IbError::ENOL => {
117 write!(f, "ENOL")
118 }
119 IbError::EADR => {
120 write!(f, "EADR")
121 }
122 IbError::EARG => {
123 write!(f, "EARG")
124 }
125 IbError::ESAC => {
126 write!(f, "ESAC")
127 }
128 IbError::EABO => {
129 write!(f, "EABO")
130 }
131 IbError::ENEB => {
132 write!(f, "ENEB")
133 }
134 IbError::EDMA => {
135 write!(f, "EDMA")
136 }
137 IbError::EOIP => {
138 write!(f, "EOIP")
139 }
140 IbError::ECAP => {
141 write!(f, "ECAP")
142 }
143 IbError::EFSO(ibcntl) => {
144 write!(f, "EFSO (ibcntl = {ibcntl})")
145 }
146 IbError::EBUS => {
147 write!(f, "EBUS")
148 }
149 IbError::ESTB => {
150 write!(f, "ESTB")
151 }
152 IbError::ESRQ => {
153 write!(f, "ESRQ")
154 }
155 IbError::ETAB => {
156 write!(f, "ETAB")
157 }
158 IbError::ELCK => {
159 write!(f, "ELCK")
160 }
161 IbError::EARM => {
162 write!(f, "EARM")
163 }
164 IbError::EHDL => {
165 write!(f, "EHDL")
166 }
167 IbError::ECFG => {
168 write!(f, "WCFG")
169 }
170 IbError::EWIP => {
171 write!(f, "EWIP")
172 }
173 IbError::ERST => {
174 write!(f, "ERST")
175 }
176 IbError::EPWR => {
177 write!(f, "EPWR")
178 }
179 }
180 }
181}
182
183impl fmt::Debug for IbError {
184 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
185 match self {
186 IbError::EDVR(ibcntl) => {
187 write!(
188 f,
189 "EDVR (A system call has failed. {})",
190 edvr_description(*ibcntl)
191 )
192 }
193 IbError::ECIC => {
194 write!(
195 f,
196 "ECIC (Your interface board needs to be controller-in-charge, but is not)"
197 )
198 }
199 IbError::ENOL => {
200 write!(
201 f,
202 "ENOL (You have attempted to write data or command bytes, but there are no listeners currently addressed)"
203 )
204 }
205 IbError::EADR => {
206 write!(
207 f,
208 "EADR (The interface board has failed to address itself properly before starting an io operation)"
209 )
210 }
211 IbError::EARG => {
212 write!(
213 f,
214 "EARG (One or more arguments to the function call were invalid)"
215 )
216 }
217 IbError::ESAC => {
218 write!(
219 f,
220 "ESAC (The interface board needs to be system controller, but is not)"
221 )
222 }
223 IbError::EABO => {
224 write!(
225 f,
226 "EABO (A read or write of data bytes has been aborted, possibly due to a timeout or reception of a device clear command)"
227 )
228 }
229 IbError::ENEB => {
230 write!(
231 f,
232 "ENEB (The GPIB interface board does not exist, its driver is not loaded, or it is not configured properly)"
233 )
234 }
235 IbError::EDMA => {
236 write!(
237 f,
238 "EDMA (Not used DMA error, included for compatibility purposes)"
239 )
240 }
241 IbError::EOIP => {
242 write!(
243 f,
244 "EOIP (Function call can not proceed due to an asynchronous IO operation in progress)"
245 )
246 }
247 IbError::ECAP => {
248 write!(
249 f,
250 "ECAP (incapable of executing function call, due the GPIB board lacking the capability, or the capability being disabled in software)"
251 )
252 }
253 IbError::EFSO(ibcntl) => {
254 write!(f, "EFSO (file system error, ibcntl = {ibcntl})")
255 }
256 IbError::EBUS => {
257 write!(
258 f,
259 "EBUS (an attempt to write command bytes to the bus has timed out)"
260 )
261 }
262 IbError::ESTB => {
263 write!(
264 f,
265 "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)"
266 )
267 }
268 IbError::ESRQ => {
269 write!(
270 f,
271 "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)"
272 )
273 }
274 IbError::ETAB => {
275 write!(
276 f,
277 "ETAB (this error can be returned by ibevent(), FindLstn(), or FindRQS(). See their descriptions for more information)"
278 )
279 }
280 IbError::ELCK => {
281 write!(f, "ELCK (Address or board is locked)")
282 }
283 IbError::EARM => {
284 write!(f, "EARM (The ibnotify Callback failed to rearm)")
285 }
286 IbError::EHDL => {
287 write!(f, "EHDL (The input handle is invalid)",)
288 }
289 IbError::ECFG => {
290 write!(f, "WCFG (Configuration warning)",)
291 }
292 IbError::EWIP => {
293 write!(f, "EWIP (Wait already in progress on input ud)")
294 }
295 IbError::ERST => {
296 write!(
297 f,
298 "ERST (The event notification was cancelled due to a reset of the interface)"
299 )
300 }
301 IbError::EPWR => {
302 write!(
303 f,
304 "EPWR (The system or board has lost power or gone to standby)"
305 )
306 }
307 }
308 }
309}
310
311impl IbError {
312 pub fn from_iberr(iberr: linux_gpib_sys::iberr_type) -> Result<IbError, GpibError> {
314 match iberr {
315 #[cfg(feature = "linuxgpib")]
316 0 => Ok(IbError::EDVR(unsafe { linux_gpib_sys::ibcntl })),
317 #[cfg(feature = "nigpib")]
318 0 => Ok(IbError::EDVR(unsafe { linux_gpib_sys::Ibcnt().into() })),
319 1 => Ok(IbError::ECIC),
320 2 => Ok(IbError::ENOL),
321 3 => Ok(IbError::EADR),
322 4 => Ok(IbError::EARG),
323 5 => Ok(IbError::ESAC),
324 6 => Ok(IbError::EABO),
325 7 => Ok(IbError::ENEB),
326 8 => Ok(IbError::EDMA),
327 10 => Ok(IbError::EOIP),
328 11 => Ok(IbError::ECAP),
329 #[cfg(feature = "linuxgpib")]
330 12 => Ok(IbError::EFSO(unsafe { linux_gpib_sys::ibcntl })),
331 #[cfg(feature = "nigpib")]
332 12 => Ok(IbError::EFSO(unsafe { linux_gpib_sys::Ibcnt().into() })),
333 14 => Ok(IbError::EBUS),
334 15 => Ok(IbError::ESTB),
335 16 => Ok(IbError::ESRQ),
336 20 => Ok(IbError::ETAB),
337 21 => Ok(IbError::ELCK),
338 22 => Ok(IbError::EARM),
339 23 => Ok(IbError::EHDL),
340 24 => Ok(IbError::ECFG),
341 26 => Ok(IbError::EWIP),
342 27 => Ok(IbError::ERST),
343 28 => Ok(IbError::EPWR),
344 other => Err(GpibError::ValueError(format!(
345 "Unexpected iberr value = {}.",
346 other
347 ))),
348 }
349 }
350
351 pub unsafe fn current_global_error() -> Result<IbError, GpibError> {
353 let status = unsafe { IbStatus::current_global_status() };
354 if status.err {
355 #[cfg(feature = "linuxgpib")]
356 return IbError::from_iberr(unsafe { linux_gpib_sys::iberr });
357 #[cfg(feature = "nigpib")]
358 return IbError::from_iberr(unsafe { linux_gpib_sys::Iberr() });
359 } else {
360 Err(GpibError::ValueError(format!(
361 "Unable to get error because is not ERR (status = {:?})",
362 status
363 )))
364 }
365 }
366
367 #[cfg(feature = "linuxgpib")]
368 pub fn current_thread_local_error() -> Result<IbError, GpibError> {
370 let status = IbStatus::current_thread_local_status();
371 if status.err {
372 IbError::from_iberr(ThreadIberr())
373 } else {
374 Err(GpibError::ValueError(format!(
375 "Unable to get error because is not ERR (status = {:?})",
376 status
377 )))
378 }
379 }
380
381 #[cfg(feature = "linuxgpib")]
382 pub fn current_async_local_error() -> Result<IbError, GpibError> {
384 let status = IbStatus::current_async_local_status();
385 if status.err {
386 IbError::from_iberr(AsyncIberr())
387 } else {
388 Err(GpibError::ValueError(format!(
389 "Unable to get error because is not ERR (status = {:?})",
390 status
391 )))
392 }
393 }
394}
395
396impl From<NulError> for GpibError {
397 fn from(e: NulError) -> GpibError {
398 GpibError::ValueError(format!("{:?}", e))
399 }
400}
401
402impl From<TryFromIntError> for GpibError {
403 fn from(e: TryFromIntError) -> GpibError {
404 GpibError::ValueError(format!("{:?}", e,))
405 }
406}
407
408impl From<FromUtf8Error> for GpibError {
409 fn from(e: FromUtf8Error) -> GpibError {
410 GpibError::ValueError(format!("{:?}", e,))
411 }
412}
413
414impl From<Utf8Error> for GpibError {
415 fn from(e: Utf8Error) -> GpibError {
416 GpibError::ValueError(format!("{:?}", e,))
417 }
418}
419
420impl From<Infallible> for GpibError {
421 fn from(e: Infallible) -> GpibError {
422 GpibError::ValueError(e.to_string())
423 }
424}
425
426#[cfg(feature = "async-tokio")]
427impl From<JoinError> for GpibError {
428 fn from(e: JoinError) -> GpibError {
429 GpibError::TokioError(e)
430 }
431}