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