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<Error> for wasm_bindgen::JsValue {
45    fn from(e: Error) -> Self {
46        wasm_bindgen::JsValue::from_str(&format!("rtlsdr_pure: {e}"))
47    }
48}
49
50#[cfg(target_family = "wasm")]
51impl From<js_sys::Error> for Error {
52    fn from(value: js_sys::Error) -> Self {
53        Self::WebUsb(value.message().into())
54    }
55}
56
57impl fmt::Display for Error {
58    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59        match self {
60            Self::Usb(cross_usb::usb::Error::CommunicationError(message)) => {
61                write!(f, "USB communication failed: {message}")
62            }
63            Self::Usb(err) => write!(f, "USB error: {err}"),
64            #[cfg(target_family = "wasm")]
65            Self::WebUsb(message) => write!(f, "WebUSB error: {message}"),
66            Self::DeviceNotFound => f.write_str("no known RTL-SDR device found"),
67            Self::TunerNotFound => f.write_str("no supported tuner was detected"),
68            Self::UnsupportedTuner(tuner) => write!(f, "unsupported tuner: {tuner:?}"),
69            Self::InvalidSampleRate(rate) => write!(f, "invalid RTL2832 sample rate: {rate} Hz"),
70            Self::InvalidFrequency(freq) => write!(f, "invalid frequency: {freq} Hz"),
71            Self::InvalidGain(gain) => write!(f, "invalid tuner gain: {gain} tenths of a dB"),
72            Self::InvalidTransferLength(len) => {
73                write!(f, "USB control transfer length is too large: {len}")
74            }
75            Self::ShortTransfer { expected, actual } => {
76                write!(
77                    f,
78                    "short USB transfer: expected {expected} bytes, got {actual}"
79                )
80            }
81            Self::PllDidNotLock => f.write_str("R82xx tuner PLL did not lock"),
82            Self::ArithmeticOverflow => f.write_str("integer overflow while configuring device"),
83            Self::ControlTransfer {
84                operation,
85                value,
86                index,
87                source,
88            } => write!(
89                f,
90                "{operation} failed (value=0x{value:04x}, index=0x{index:04x}): {source}"
91            ),
92            Self::Operation { operation, source } => {
93                write!(f, "{operation} failed: {source}")
94            }
95        }
96    }
97}
98
99impl std::error::Error for Error {
100    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
101        match self {
102            Self::Usb(err) => Some(err),
103            Self::ControlTransfer { source, .. } | Self::Operation { source, .. } => Some(source),
104            _ => None,
105        }
106    }
107}
108
109impl Error {
110    pub(crate) fn context(self, operation: &'static str) -> Self {
111        Self::Operation {
112            operation,
113            source: Box::new(self),
114        }
115    }
116
117    pub(crate) fn control(self, operation: &'static str, value: u16, index: u16) -> Self {
118        Self::ControlTransfer {
119            operation,
120            value,
121            index,
122            source: Box::new(self),
123        }
124    }
125}
126
127pub(crate) trait ResultExt<T> {
128    fn context(self, operation: &'static str) -> Result<T>;
129}
130
131impl<T> ResultExt<T> for Result<T> {
132    fn context(self, operation: &'static str) -> Result<T> {
133        self.map_err(|err| err.context(operation))
134    }
135}