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