Skip to main content

rtlsdr_pure/
error.rs

1use std::fmt;
2
3use crate::TunerKind;
4
5pub type Result<T> = std::result::Result<T, Error>;
6
7#[derive(Debug)]
8pub enum Error {
9    Usb(cross_usb::usb::Error),
10    #[cfg(target_family = "wasm")]
11    WebUsb(String),
12    DeviceNotFound,
13    TunerNotFound,
14    UnsupportedTuner(TunerKind),
15    InvalidSampleRate(u32),
16    InvalidFrequency(u32),
17    InvalidGain(i32),
18    InvalidTransferLength(usize),
19    ShortTransfer {
20        expected: usize,
21        actual: usize,
22    },
23    PllDidNotLock,
24    ArithmeticOverflow,
25    ControlTransfer {
26        operation: &'static str,
27        value: u16,
28        index: u16,
29        source: Box<Error>,
30    },
31    Operation {
32        operation: &'static str,
33        source: Box<Error>,
34    },
35}
36
37impl From<cross_usb::usb::Error> for Error {
38    fn from(value: cross_usb::usb::Error) -> Self {
39        Self::Usb(value)
40    }
41}
42
43#[cfg(target_family = "wasm")]
44impl From<js_sys::Error> for Error {
45    fn from(value: js_sys::Error) -> Self {
46        Self::WebUsb(value.message().into())
47    }
48}
49
50impl fmt::Display for Error {
51    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52        match self {
53            Self::Usb(cross_usb::usb::Error::CommunicationError(message)) => {
54                write!(f, "USB communication failed: {message}")
55            }
56            Self::Usb(err) => write!(f, "USB error: {err}"),
57            #[cfg(target_family = "wasm")]
58            Self::WebUsb(message) => write!(f, "WebUSB error: {message}"),
59            Self::DeviceNotFound => f.write_str("no known RTL-SDR device found"),
60            Self::TunerNotFound => f.write_str("no supported tuner was detected"),
61            Self::UnsupportedTuner(tuner) => write!(f, "unsupported tuner: {tuner:?}"),
62            Self::InvalidSampleRate(rate) => write!(f, "invalid RTL2832 sample rate: {rate} Hz"),
63            Self::InvalidFrequency(freq) => write!(f, "invalid frequency: {freq} Hz"),
64            Self::InvalidGain(gain) => write!(f, "invalid tuner gain: {gain} tenths of a dB"),
65            Self::InvalidTransferLength(len) => {
66                write!(f, "USB control transfer length is too large: {len}")
67            }
68            Self::ShortTransfer { expected, actual } => {
69                write!(
70                    f,
71                    "short USB transfer: expected {expected} bytes, got {actual}"
72                )
73            }
74            Self::PllDidNotLock => f.write_str("R82xx tuner PLL did not lock"),
75            Self::ArithmeticOverflow => f.write_str("integer overflow while configuring device"),
76            Self::ControlTransfer {
77                operation,
78                value,
79                index,
80                source,
81            } => write!(
82                f,
83                "{operation} failed (value=0x{value:04x}, index=0x{index:04x}): {source}"
84            ),
85            Self::Operation { operation, source } => {
86                write!(f, "{operation} failed: {source}")
87            }
88        }
89    }
90}
91
92impl std::error::Error for Error {
93    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
94        match self {
95            Self::Usb(err) => Some(err),
96            Self::ControlTransfer { source, .. } | Self::Operation { source, .. } => Some(source),
97            _ => None,
98        }
99    }
100}
101
102impl Error {
103    pub(crate) fn context(self, operation: &'static str) -> Self {
104        Self::Operation {
105            operation,
106            source: Box::new(self),
107        }
108    }
109
110    pub(crate) fn control(self, operation: &'static str, value: u16, index: u16) -> Self {
111        Self::ControlTransfer {
112            operation,
113            value,
114            index,
115            source: Box::new(self),
116        }
117    }
118}
119
120pub(crate) trait ResultExt<T> {
121    fn context(self, operation: &'static str) -> Result<T>;
122}
123
124impl<T> ResultExt<T> for Result<T> {
125    fn context(self, operation: &'static str) -> Result<T> {
126        self.map_err(|err| err.context(operation))
127    }
128}