Skip to main content

vlfd_rs/
error.rs

1use std::{error::Error as StdError, fmt};
2pub type Result<T> = std::result::Result<T, Error>;
3
4#[derive(Debug)]
5pub enum Error {
6    DeviceNotOpen,
7    DeviceNotFound {
8        vid: u16,
9        pid: u16,
10    },
11    DeviceSelectionAmbiguous {
12        matches: usize,
13    },
14    DeviceSelectionNoMatch,
15    BufferTooLarge {
16        context: &'static str,
17        max_words: usize,
18        actual_words: usize,
19    },
20    FeatureUnavailable(&'static str),
21    InvalidBitfile(&'static str),
22    InvalidBitfileLine {
23        line: usize,
24        reason: &'static str,
25    },
26    InvalidBufferLength {
27        context: &'static str,
28        expected: usize,
29        actual: usize,
30    },
31    InvalidMode {
32        expected: &'static str,
33        actual: &'static str,
34    },
35    PipelineEmpty,
36    PipelineFull {
37        capacity: usize,
38    },
39    NotProgrammed,
40    Timeout(&'static str),
41    UnexpectedResponse(&'static str),
42    VersionMismatch {
43        expected: u16,
44        actual: u16,
45    },
46    Usb {
47        source: Box<dyn StdError + Send + Sync>,
48        context: &'static str,
49    },
50    Io(std::io::Error),
51}
52
53impl fmt::Display for Error {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        match self {
56            Error::DeviceNotOpen => write!(f, "device is not open"),
57            Error::DeviceNotFound { vid, pid } => {
58                write!(f, "device {vid:#06x}:{pid:#06x} not found")
59            }
60            Error::DeviceSelectionAmbiguous { matches } => write!(
61                f,
62                "device selection matched {matches} boards; select one by serial number or USB location"
63            ),
64            Error::DeviceSelectionNoMatch => write!(f, "device selection matched no boards"),
65            Error::BufferTooLarge {
66                context,
67                max_words,
68                actual_words,
69            } => write!(
70                f,
71                "{context} exceeds FIFO capacity ({actual_words} words > {max_words} words)"
72            ),
73            Error::FeatureUnavailable(feature) => write!(f, "feature `{feature}` is unavailable"),
74            Error::InvalidBitfile(reason) => write!(f, "invalid bitfile: {reason}"),
75            Error::InvalidBitfileLine { line, reason } => {
76                write!(f, "invalid bitfile line {line}: {reason}")
77            }
78            Error::InvalidBufferLength {
79                context,
80                expected,
81                actual,
82            } => write!(
83                f,
84                "invalid buffer length for `{context}` (expected {expected}, got {actual})"
85            ),
86            Error::InvalidMode { expected, actual } => {
87                write!(
88                    f,
89                    "invalid device mode (expected `{expected}`, got `{actual}`)"
90                )
91            }
92            Error::PipelineEmpty => write!(f, "transfer pipeline has no pending transfers"),
93            Error::PipelineFull { capacity } => write!(
94                f,
95                "transfer pipeline is full (capacity {capacity} outstanding transfers)"
96            ),
97            Error::NotProgrammed => write!(f, "FPGA is not programmed"),
98            Error::Timeout(context) => write!(f, "operation `{context}` timed out"),
99            Error::UnexpectedResponse(context) => {
100                write!(f, "unexpected response during `{context}`")
101            }
102            Error::VersionMismatch { expected, actual } => write!(
103                f,
104                "SMIMS version mismatch (expected {expected:#06x}, found {actual:#06x})"
105            ),
106            Error::Usb { source, context } => {
107                write!(f, "usb error {source} in `{context}`")
108            }
109            Error::Io(err) => err.fmt(f),
110        }
111    }
112}
113
114impl std::error::Error for Error {
115    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
116        match self {
117            Error::Usb { source, .. } => Some(source.as_ref()),
118            Error::Io(err) => Some(err),
119            _ => None,
120        }
121    }
122}
123
124impl From<std::io::Error> for Error {
125    fn from(value: std::io::Error) -> Self {
126        Self::Io(value)
127    }
128}