Skip to main content

rtlsdr_pure/
rtl2832.rs

1use std::time::Duration;
2
3use async_lock::Mutex;
4use nusb::transfer::{Buffer, Bulk, ControlIn, ControlOut, ControlType, In, Recipient};
5
6use crate::error::{Error, Result, ResultExt};
7use crate::r82xx::{R82XX_CHECK_ADDR, R82XX_CHECK_VAL, R82XX_IF_FREQ, R82xx, R82xxKind};
8
9pub const DEFAULT_SAMPLE_RATE: u32 = 2_048_000;
10
11const DEF_RTL_XTAL_FREQ: u32 = 28_800_000;
12
13const DEFAULT_BULK_ENDPOINT: u8 = 0x81;
14const DEFAULT_READ_LENGTH: usize = 16 * 32 * 512;
15const CONTROL_TIMEOUT: Duration = Duration::from_secs(1);
16
17const E4K_I2C_ADDR: u8 = 0xc8;
18const E4K_CHECK_ADDR: u8 = 0x02;
19const E4K_CHECK_VAL: u8 = 0x40;
20
21const FC0012_I2C_ADDR: u8 = 0xc6;
22const FC0012_CHECK_ADDR: u8 = 0x00;
23const FC0012_CHECK_VAL: u8 = 0xa1;
24
25const FC0013_I2C_ADDR: u8 = 0xc6;
26const FC0013_CHECK_ADDR: u8 = 0x00;
27const FC0013_CHECK_VAL: u8 = 0xa3;
28
29const FC2580_I2C_ADDR: u8 = 0xac;
30const FC2580_CHECK_ADDR: u8 = 0x01;
31const FC2580_CHECK_VAL: u8 = 0x56;
32
33const R820T_I2C_ADDR: u8 = 0x34;
34const R828D_I2C_ADDR: u8 = 0x74;
35const R828D_XTAL_FREQ: u32 = 16_000_000;
36
37const USB_SYSCTL: u16 = 0x2000;
38const USB_EPA_CTL: u16 = 0x2148;
39const USB_EPA_MAXPKT: u16 = 0x2158;
40
41const DEMOD_CTL: u16 = 0x3000;
42const GPO: u16 = 0x3001;
43const GPOE: u16 = 0x3003;
44const GPD: u16 = 0x3004;
45const DEMOD_CTL_1: u16 = 0x300b;
46
47const USBB: u8 = 1;
48const SYSB: u8 = 2;
49const IICB: u8 = 6;
50
51const FIR_DEFAULT: [i16; 16] = [
52    -54, -36, -41, -40, -32, -14, 14, 53, 101, 156, 215, 273, 327, 372, 404, 421,
53];
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub struct KnownDevice {
57    pub vendor_id: u16,
58    pub product_id: u16,
59    pub name: &'static str,
60}
61
62pub const KNOWN_DEVICES: &[KnownDevice] = &[
63    KnownDevice {
64        vendor_id: 0x0bda,
65        product_id: 0x2832,
66        name: "Generic RTL2832U",
67    },
68    KnownDevice {
69        vendor_id: 0x0bda,
70        product_id: 0x2838,
71        name: "Generic RTL2832U OEM",
72    },
73    KnownDevice {
74        vendor_id: 0x0413,
75        product_id: 0x6680,
76        name: "DigitalNow Quad DVB-T PCI-E card",
77    },
78    KnownDevice {
79        vendor_id: 0x0413,
80        product_id: 0x6f0f,
81        name: "Leadtek WinFast DTV Dongle mini D",
82    },
83    KnownDevice {
84        vendor_id: 0x0458,
85        product_id: 0x707f,
86        name: "Genius TVGo DVB-T03 USB dongle (Ver. B)",
87    },
88    KnownDevice {
89        vendor_id: 0x0ccd,
90        product_id: 0x00a9,
91        name: "Terratec Cinergy T Stick Black (rev 1)",
92    },
93    KnownDevice {
94        vendor_id: 0x0ccd,
95        product_id: 0x00b3,
96        name: "Terratec NOXON DAB/DAB+ USB dongle (rev 1)",
97    },
98    KnownDevice {
99        vendor_id: 0x0ccd,
100        product_id: 0x00b4,
101        name: "Terratec Deutschlandradio DAB Stick",
102    },
103    KnownDevice {
104        vendor_id: 0x0ccd,
105        product_id: 0x00b5,
106        name: "Terratec NOXON DAB Stick - Radio Energy",
107    },
108    KnownDevice {
109        vendor_id: 0x0ccd,
110        product_id: 0x00b7,
111        name: "Terratec Media Broadcast DAB Stick",
112    },
113    KnownDevice {
114        vendor_id: 0x0ccd,
115        product_id: 0x00b8,
116        name: "Terratec BR DAB Stick",
117    },
118    KnownDevice {
119        vendor_id: 0x0ccd,
120        product_id: 0x00b9,
121        name: "Terratec WDR DAB Stick",
122    },
123    KnownDevice {
124        vendor_id: 0x0ccd,
125        product_id: 0x00c0,
126        name: "Terratec MuellerVerlag DAB Stick",
127    },
128    KnownDevice {
129        vendor_id: 0x0ccd,
130        product_id: 0x00c6,
131        name: "Terratec Fraunhofer DAB Stick",
132    },
133    KnownDevice {
134        vendor_id: 0x0ccd,
135        product_id: 0x00d3,
136        name: "Terratec Cinergy T Stick RC (Rev.3)",
137    },
138    KnownDevice {
139        vendor_id: 0x0ccd,
140        product_id: 0x00d7,
141        name: "Terratec T Stick PLUS",
142    },
143    KnownDevice {
144        vendor_id: 0x0ccd,
145        product_id: 0x00e0,
146        name: "Terratec NOXON DAB/DAB+ USB dongle (rev 2)",
147    },
148    KnownDevice {
149        vendor_id: 0x1554,
150        product_id: 0x5020,
151        name: "PixelView PV-DT235U(RN)",
152    },
153    KnownDevice {
154        vendor_id: 0x15f4,
155        product_id: 0x0131,
156        name: "Astrometa DVB-T/DVB-T2",
157    },
158    KnownDevice {
159        vendor_id: 0x15f4,
160        product_id: 0x0133,
161        name: "HanfTek DAB+FM+DVB-T",
162    },
163    KnownDevice {
164        vendor_id: 0x185b,
165        product_id: 0x0620,
166        name: "Compro Videomate U620F",
167    },
168    KnownDevice {
169        vendor_id: 0x185b,
170        product_id: 0x0650,
171        name: "Compro Videomate U650F",
172    },
173    KnownDevice {
174        vendor_id: 0x185b,
175        product_id: 0x0680,
176        name: "Compro Videomate U680F",
177    },
178    KnownDevice {
179        vendor_id: 0x1b80,
180        product_id: 0xd393,
181        name: "GIGABYTE GT-U7300",
182    },
183    KnownDevice {
184        vendor_id: 0x1b80,
185        product_id: 0xd394,
186        name: "DIKOM USB-DVBT HD",
187    },
188    KnownDevice {
189        vendor_id: 0x1b80,
190        product_id: 0xd395,
191        name: "Peak 102569AGPK",
192    },
193    KnownDevice {
194        vendor_id: 0x1b80,
195        product_id: 0xd397,
196        name: "KWorld KW-UB450-T USB DVB-T Pico TV",
197    },
198    KnownDevice {
199        vendor_id: 0x1b80,
200        product_id: 0xd398,
201        name: "Zaapa ZT-MINDVBZP",
202    },
203    KnownDevice {
204        vendor_id: 0x1b80,
205        product_id: 0xd39d,
206        name: "SVEON STV20 DVB-T USB & FM",
207    },
208    KnownDevice {
209        vendor_id: 0x1b80,
210        product_id: 0xd3a4,
211        name: "Twintech UT-40",
212    },
213    KnownDevice {
214        vendor_id: 0x1b80,
215        product_id: 0xd3a8,
216        name: "ASUS U3100MINI_PLUS_V2",
217    },
218    KnownDevice {
219        vendor_id: 0x1b80,
220        product_id: 0xd3af,
221        name: "SVEON STV27 DVB-T USB & FM",
222    },
223    KnownDevice {
224        vendor_id: 0x1b80,
225        product_id: 0xd3b0,
226        name: "SVEON STV21 DVB-T USB & FM",
227    },
228    KnownDevice {
229        vendor_id: 0x1d19,
230        product_id: 0x1101,
231        name: "Dexatek DK DVB-T Dongle (Logilink VG0002A)",
232    },
233    KnownDevice {
234        vendor_id: 0x1d19,
235        product_id: 0x1102,
236        name: "Dexatek DK DVB-T Dongle (MSI DigiVox mini II V3.0)",
237    },
238    KnownDevice {
239        vendor_id: 0x1d19,
240        product_id: 0x1103,
241        name: "Dexatek Technology Ltd. DK 5217 DVB-T Dongle",
242    },
243    KnownDevice {
244        vendor_id: 0x1d19,
245        product_id: 0x1104,
246        name: "MSI DigiVox Micro HD",
247    },
248    KnownDevice {
249        vendor_id: 0x1f4d,
250        product_id: 0xa803,
251        name: "Sweex DVB-T USB",
252    },
253    KnownDevice {
254        vendor_id: 0x1f4d,
255        product_id: 0xb803,
256        name: "GTek T803",
257    },
258    KnownDevice {
259        vendor_id: 0x1f4d,
260        product_id: 0xc803,
261        name: "Lifeview LV5TDeluxe",
262    },
263    KnownDevice {
264        vendor_id: 0x1f4d,
265        product_id: 0xd286,
266        name: "MyGica TD312",
267    },
268    KnownDevice {
269        vendor_id: 0x1f4d,
270        product_id: 0xd803,
271        name: "PROlectrix DV107669",
272    },
273];
274
275#[derive(Debug, Clone, PartialEq, Eq)]
276pub struct DeviceDescription {
277    pub vendor_id: u16,
278    pub product_id: u16,
279    pub name: Option<&'static str>,
280    pub manufacturer: Option<String>,
281    pub product: Option<String>,
282}
283
284#[derive(Debug, Clone, Copy, PartialEq, Eq)]
285pub enum TunerKind {
286    Unknown,
287    E4000,
288    Fc0012,
289    Fc0013,
290    Fc2580,
291    R820T,
292    R828D,
293}
294
295impl TunerKind {
296    pub fn is_supported(self) -> bool {
297        matches!(self, Self::R820T | Self::R828D)
298    }
299}
300
301#[derive(Debug, Clone, Copy, PartialEq, Eq)]
302pub enum GainMode {
303    Auto,
304    ManualTenthsDb(i32),
305}
306
307#[derive(Debug, Clone, Copy, PartialEq)]
308pub struct IqSample {
309    pub i: f32,
310    pub q: f32,
311}
312
313pub struct RtlSdr {
314    usb: RtlUsb,
315    vendor_id: u16,
316    product_id: u16,
317    manufacturer: Option<String>,
318    product: Option<String>,
319    tuner: TunerState,
320    rtl_xtal_hz: u32,
321    sample_rate_hz: u32,
322    center_freq_hz: Option<u32>,
323    bandwidth_hz: Option<u32>,
324    freq_correction_ppm: i32,
325}
326
327enum TunerState {
328    Unknown,
329    Unsupported(TunerKind),
330    R82xx(R82xx),
331}
332
333impl RtlSdr {
334    pub async fn open_first() -> Result<Self> {
335        let mut infos = nusb::list_devices().await?;
336        if let Some(info) =
337            infos.find(|info| known_device_name(info.vendor_id(), info.product_id()).is_some())
338        {
339            return Self::open(info).await;
340        }
341
342        #[cfg(target_family = "wasm")]
343        {
344            let info = nusb::request_device(&device_selectors())
345                .await?
346                .ok_or(Error::DeviceNotFound)?;
347            Self::open(info).await
348        }
349
350        #[cfg(not(target_family = "wasm"))]
351        {
352            Err(Error::DeviceNotFound)
353        }
354    }
355
356    #[cfg(not(target_family = "wasm"))]
357    pub async fn list_devices() -> Result<Vec<DeviceDescription>> {
358        let infos = nusb::list_devices().await?;
359        let mut devices = Vec::new();
360
361        for info in infos {
362            let vendor_id = info.vendor_id();
363            let product_id = info.product_id();
364            let name = known_device_name(vendor_id, product_id);
365            if name.is_none() {
366                continue;
367            }
368            devices.push(DeviceDescription {
369                vendor_id,
370                product_id,
371                name,
372                manufacturer: info.manufacturer_string().map(str::to_owned),
373                product: info.product_string().map(str::to_owned),
374            });
375        }
376
377        Ok(devices)
378    }
379
380    pub async fn open(info: nusb::DeviceInfo) -> Result<Self> {
381        let vendor_id = info.vendor_id();
382        let product_id = info.product_id();
383        let manufacturer = info.manufacturer_string().map(str::to_owned);
384        let product = info.product_string().map(str::to_owned);
385        let device = info.open().await?;
386        let interface = device.detach_and_claim_interface(0).await?;
387        let bulk_in = interface.endpoint::<Bulk, In>(DEFAULT_BULK_ENDPOINT)?;
388
389        let mut sdr = Self {
390            usb: RtlUsb {
391                _device: device,
392                interface,
393                bulk_in: Mutex::new(BulkReader::new(bulk_in)),
394            },
395            vendor_id,
396            product_id,
397            manufacturer,
398            product,
399            tuner: TunerState::Unknown,
400            rtl_xtal_hz: DEF_RTL_XTAL_FREQ,
401            sample_rate_hz: 0,
402            center_freq_hz: None,
403            bandwidth_hz: None,
404            freq_correction_ppm: 0,
405        };
406
407        sdr.usb
408            .write_reg(USBB, USB_SYSCTL, 0x09, 1)
409            .await
410            .context("initial USB_SYSCTL write")?;
411        sdr.init_baseband()
412            .await
413            .context("RTL2832 baseband initialization")?;
414        sdr.probe_tuner().await.context("tuner probe")?;
415        sdr.set_sample_rate(DEFAULT_SAMPLE_RATE)
416            .await
417            .context("default sample-rate setup")?;
418        sdr.reset_buffer().await.context("USB FIFO reset")?;
419
420        Ok(sdr)
421    }
422
423    pub fn vendor_id(&self) -> u16 {
424        self.vendor_id
425    }
426
427    pub fn product_id(&self) -> u16 {
428        self.product_id
429    }
430
431    pub fn known_name(&self) -> Option<&'static str> {
432        known_device_name(self.vendor_id, self.product_id)
433    }
434
435    pub fn manufacturer(&self) -> Option<&str> {
436        self.manufacturer.as_deref()
437    }
438
439    pub fn product(&self) -> Option<&str> {
440        self.product.as_deref()
441    }
442
443    pub fn tuner_kind(&self) -> TunerKind {
444        match &self.tuner {
445            TunerState::Unknown => TunerKind::Unknown,
446            TunerState::Unsupported(kind) => *kind,
447            TunerState::R82xx(tuner) => match tuner.kind() {
448                R82xxKind::R820T => TunerKind::R820T,
449                R82xxKind::R828D => TunerKind::R828D,
450            },
451        }
452    }
453
454    pub fn sample_rate(&self) -> u32 {
455        self.sample_rate_hz
456    }
457
458    pub fn center_frequency(&self) -> Option<u32> {
459        self.center_freq_hz
460    }
461
462    pub fn frequency_correction(&self) -> i32 {
463        self.freq_correction_ppm
464    }
465
466    pub async fn set_sample_rate(&mut self, sample_rate_hz: u32) -> Result<u32> {
467        if sample_rate_hz <= 225_000
468            || sample_rate_hz > 3_200_000
469            || (sample_rate_hz > 300_000 && sample_rate_hz <= 900_000)
470        {
471            return Err(Error::InvalidSampleRate(sample_rate_hz));
472        }
473
474        let numerator = (self.rtl_xtal_hz as u64)
475            .checked_shl(22)
476            .ok_or(Error::ArithmeticOverflow)?;
477        let mut ratio = numerator / sample_rate_hz as u64;
478        ratio &= 0x0fff_fffc;
479        if ratio == 0 {
480            return Err(Error::InvalidSampleRate(sample_rate_hz));
481        }
482
483        let real_ratio = ratio | ((ratio & 0x0800_0000) << 1);
484        let real_rate = (numerator / real_ratio) as u32;
485
486        let bandwidth_hz = self.bandwidth_hz.unwrap_or(real_rate);
487        let new_if = if matches!(self.tuner, TunerState::R82xx(_)) {
488            self.set_i2c_repeater(true).await?;
489            let result = match &mut self.tuner {
490                TunerState::R82xx(tuner) => {
491                    tuner
492                        .set_bandwidth(&self.usb, bandwidth_hz, real_rate)
493                        .await
494                }
495                _ => unreachable!(),
496            };
497            let repeater_result = self.set_i2c_repeater(false).await;
498            let if_hz = result?;
499            repeater_result?;
500            Some(if_hz)
501        } else {
502            None
503        };
504        if let Some(if_hz) = new_if {
505            self.set_if_freq(if_hz).await?;
506        }
507
508        self.usb
509            .demod_write_reg(1, 0x9f, ((ratio >> 16) & 0xffff) as u16, 2)
510            .await?;
511        self.usb
512            .demod_write_reg(1, 0xa1, (ratio & 0xffff) as u16, 2)
513            .await?;
514        self.set_sample_freq_correction(self.freq_correction_ppm)
515            .await?;
516        self.reset_demod().await?;
517
518        self.sample_rate_hz = real_rate;
519        if self.center_freq_hz.is_some() && new_if.is_some() {
520            self.retune().await?;
521        }
522
523        Ok(real_rate)
524    }
525
526    pub async fn set_center_frequency(&mut self, frequency_hz: u32) -> Result<()> {
527        if frequency_hz == 0 {
528            return Err(Error::InvalidFrequency(frequency_hz));
529        }
530
531        self.set_i2c_repeater(true).await?;
532        let result = match &mut self.tuner {
533            TunerState::R82xx(tuner) => tuner.set_freq(&self.usb, frequency_hz).await,
534            TunerState::Unsupported(kind) => Err(Error::UnsupportedTuner(*kind)),
535            TunerState::Unknown => Err(Error::TunerNotFound),
536        };
537        let repeater_result = self.set_i2c_repeater(false).await;
538
539        result?;
540        repeater_result?;
541
542        self.center_freq_hz = Some(frequency_hz);
543        Ok(())
544    }
545
546    pub async fn set_tuner_gain(&mut self, gain: GainMode) -> Result<()> {
547        let (manual, gain_tenths_db) = match gain {
548            GainMode::Auto => (false, 0),
549            GainMode::ManualTenthsDb(gain) => {
550                if !(-100..=500).contains(&gain) {
551                    return Err(Error::InvalidGain(gain));
552                }
553                (true, gain)
554            }
555        };
556
557        self.set_i2c_repeater(true).await?;
558        let result = match &mut self.tuner {
559            TunerState::R82xx(tuner) => tuner.set_gain(&self.usb, manual, gain_tenths_db).await,
560            TunerState::Unsupported(kind) => Err(Error::UnsupportedTuner(*kind)),
561            TunerState::Unknown => Err(Error::TunerNotFound),
562        };
563        let repeater_result = self.set_i2c_repeater(false).await;
564
565        result?;
566        repeater_result?;
567
568        Ok(())
569    }
570
571    pub async fn set_bandwidth(&mut self, bandwidth_hz: Option<u32>) -> Result<()> {
572        self.bandwidth_hz = bandwidth_hz;
573        let bandwidth = bandwidth_hz.unwrap_or(self.sample_rate_hz);
574        self.set_i2c_repeater(true).await?;
575        let result = match &mut self.tuner {
576            TunerState::R82xx(tuner) => {
577                tuner
578                    .set_bandwidth(&self.usb, bandwidth, self.sample_rate_hz)
579                    .await
580            }
581            TunerState::Unsupported(kind) => Err(Error::UnsupportedTuner(*kind)),
582            TunerState::Unknown => Err(Error::TunerNotFound),
583        };
584        let repeater_result = self.set_i2c_repeater(false).await;
585        let new_if = Some(result?);
586        repeater_result?;
587
588        if let Some(if_hz) = new_if {
589            self.set_if_freq(if_hz).await?;
590            if self.center_freq_hz.is_some() {
591                self.retune().await?;
592            }
593        }
594
595        Ok(())
596    }
597
598    pub async fn set_frequency_correction(&mut self, ppm: i32) -> Result<()> {
599        self.freq_correction_ppm = ppm;
600        self.set_sample_freq_correction(ppm).await?;
601        if self.center_freq_hz.is_some() {
602            self.retune().await?;
603        }
604        Ok(())
605    }
606
607    pub async fn set_agc_mode(&self, enabled: bool) -> Result<()> {
608        self.usb
609            .demod_write_reg(0, 0x19, if enabled { 0x25 } else { 0x05 }, 1)
610            .await
611    }
612
613    pub async fn set_test_mode(&self, enabled: bool) -> Result<()> {
614        self.usb
615            .demod_write_reg(0, 0x19, if enabled { 0x03 } else { 0x05 }, 1)
616            .await
617    }
618
619    pub async fn reset_buffer(&self) -> Result<()> {
620        self.usb.write_reg(USBB, USB_EPA_CTL, 0x1002, 2).await?;
621        self.usb.write_reg(USBB, USB_EPA_CTL, 0x0000, 2).await
622    }
623
624    pub async fn read_bytes(&self, len: usize) -> Result<Vec<u8>> {
625        let len = if len == 0 { DEFAULT_READ_LENGTH } else { len };
626        self.usb.bulk_in.lock().await.read(len).await
627    }
628
629    pub async fn read_iq_samples(&self, sample_count: usize) -> Result<Vec<IqSample>> {
630        let bytes = self.read_bytes(sample_count.saturating_mul(2)).await?;
631        Ok(bytes_to_iq_samples(&bytes))
632    }
633
634    async fn init_baseband(&mut self) -> Result<()> {
635        self.usb.write_reg(USBB, USB_SYSCTL, 0x09, 1).await?;
636        self.usb.write_reg(USBB, USB_EPA_MAXPKT, 0x0002, 2).await?;
637        self.usb.write_reg(USBB, USB_EPA_CTL, 0x1002, 2).await?;
638
639        self.usb.write_reg(SYSB, DEMOD_CTL_1, 0x22, 1).await?;
640        self.usb.write_reg(SYSB, DEMOD_CTL, 0xe8, 1).await?;
641        self.reset_demod().await?;
642
643        self.usb.demod_write_reg(1, 0x15, 0x00, 1).await?;
644        self.usb.demod_write_reg(1, 0x16, 0x0000, 2).await?;
645        for offset in 0..6 {
646            self.usb.demod_write_reg(1, 0x16 + offset, 0x00, 1).await?;
647        }
648
649        self.set_fir().await?;
650        self.usb.demod_write_reg(0, 0x19, 0x05, 1).await?;
651        self.usb.demod_write_reg(1, 0x93, 0xf0, 1).await?;
652        self.usb.demod_write_reg(1, 0x94, 0x0f, 1).await?;
653        self.usb.demod_write_reg(1, 0x11, 0x00, 1).await?;
654        self.usb.demod_write_reg(1, 0x04, 0x00, 1).await?;
655        self.usb.demod_write_reg(0, 0x61, 0x60, 1).await?;
656        self.usb.demod_write_reg(0, 0x06, 0x80, 1).await?;
657        self.usb.demod_write_reg(1, 0xb1, 0x1b, 1).await?;
658        self.usb.demod_write_reg(0, 0x0d, 0x83, 1).await
659    }
660
661    async fn probe_tuner(&mut self) -> Result<()> {
662        self.set_i2c_repeater(true).await?;
663        let result = self.probe_tuner_inner().await;
664        let repeater_result = self.set_i2c_repeater(false).await;
665
666        result?;
667        repeater_result?;
668        Ok(())
669    }
670
671    async fn probe_tuner_inner(&mut self) -> Result<()> {
672        if self.try_i2c_read_reg(E4K_I2C_ADDR, E4K_CHECK_ADDR).await == Some(E4K_CHECK_VAL) {
673            self.tuner = TunerState::Unsupported(TunerKind::E4000);
674            return Ok(());
675        }
676        if self
677            .try_i2c_read_reg(FC0013_I2C_ADDR, FC0013_CHECK_ADDR)
678            .await
679            == Some(FC0013_CHECK_VAL)
680        {
681            self.tuner = TunerState::Unsupported(TunerKind::Fc0013);
682            return Ok(());
683        }
684        if self
685            .try_i2c_read_reg(R820T_I2C_ADDR, R82XX_CHECK_ADDR)
686            .await
687            == Some(R82XX_CHECK_VAL)
688        {
689            self.configure_r82xx(R82xxKind::R820T).await?;
690            return Ok(());
691        }
692        if self
693            .try_i2c_read_reg(R828D_I2C_ADDR, R82XX_CHECK_ADDR)
694            .await
695            == Some(R82XX_CHECK_VAL)
696        {
697            self.configure_r82xx(R82xxKind::R828D).await?;
698            return Ok(());
699        }
700
701        self.set_gpio_output(4).await?;
702        self.set_gpio_bit(4, true).await?;
703        self.set_gpio_bit(4, false).await?;
704
705        if self
706            .try_i2c_read_reg(FC2580_I2C_ADDR, FC2580_CHECK_ADDR)
707            .await
708            .is_some_and(|reg| (reg & 0x7f) == FC2580_CHECK_VAL)
709        {
710            self.tuner = TunerState::Unsupported(TunerKind::Fc2580);
711            return Ok(());
712        }
713        if self
714            .try_i2c_read_reg(FC0012_I2C_ADDR, FC0012_CHECK_ADDR)
715            .await
716            == Some(FC0012_CHECK_VAL)
717        {
718            self.set_gpio_output(6).await?;
719            self.tuner = TunerState::Unsupported(TunerKind::Fc0012);
720            return Ok(());
721        }
722
723        self.tuner = TunerState::Unknown;
724        Ok(())
725    }
726
727    async fn configure_r82xx(&mut self, kind: R82xxKind) -> Result<()> {
728        self.usb.demod_write_reg(1, 0xb1, 0x1a, 1).await?;
729        self.usb.demod_write_reg(0, 0x08, 0x4d, 1).await?;
730        self.set_if_freq(R82XX_IF_FREQ).await?;
731        self.usb.demod_write_reg(1, 0x15, 0x01, 1).await?;
732
733        let tuner_xtal = match kind {
734            R82xxKind::R820T => self.rtl_xtal_hz,
735            R82xxKind::R828D if self.is_blog_v4() => self.rtl_xtal_hz,
736            R82xxKind::R828D => R828D_XTAL_FREQ,
737        };
738
739        let mut tuner = R82xx::new(kind, tuner_xtal, self.is_blog_v4());
740        tuner.init(&self.usb).await?;
741        self.tuner = TunerState::R82xx(tuner);
742        Ok(())
743    }
744
745    async fn retune(&mut self) -> Result<()> {
746        if let Some(frequency) = self.center_freq_hz {
747            self.set_center_frequency(frequency).await?;
748        }
749        Ok(())
750    }
751
752    async fn set_if_freq(&self, frequency_hz: u32) -> Result<()> {
753        let ratio = ((frequency_hz as i64) << 22) / self.rtl_xtal_hz as i64;
754        let if_freq = -ratio;
755        self.usb
756            .demod_write_reg(1, 0x19, ((if_freq >> 16) & 0x3f) as u16, 1)
757            .await?;
758        self.usb
759            .demod_write_reg(1, 0x1a, ((if_freq >> 8) & 0xff) as u16, 1)
760            .await?;
761        self.usb
762            .demod_write_reg(1, 0x1b, (if_freq & 0xff) as u16, 1)
763            .await
764    }
765
766    async fn set_sample_freq_correction(&self, ppm: i32) -> Result<()> {
767        let offset = (ppm as i64)
768            .checked_mul(-1)
769            .and_then(|v| v.checked_mul(1 << 24))
770            .ok_or(Error::ArithmeticOverflow)?
771            / 1_000_000;
772        self.usb
773            .demod_write_reg(1, 0x3f, (offset & 0xff) as u16, 1)
774            .await?;
775        self.usb
776            .demod_write_reg(1, 0x3e, ((offset >> 8) & 0x3f) as u16, 1)
777            .await
778    }
779
780    async fn reset_demod(&self) -> Result<()> {
781        self.usb.demod_write_reg(1, 0x01, 0x14, 1).await?;
782        self.usb.demod_write_reg(1, 0x01, 0x10, 1).await
783    }
784
785    async fn set_i2c_repeater(&self, enabled: bool) -> Result<()> {
786        self.usb
787            .demod_write_reg(1, 0x01, if enabled { 0x18 } else { 0x10 }, 1)
788            .await
789    }
790
791    async fn set_fir(&self) -> Result<()> {
792        let mut fir = [0u8; 20];
793        for (i, value) in FIR_DEFAULT.iter().take(8).enumerate() {
794            fir[i] = *value as i8 as u8;
795        }
796        for i in (0..8).step_by(2) {
797            let val0 = FIR_DEFAULT[8 + i];
798            let val1 = FIR_DEFAULT[8 + i + 1];
799            let out = 8 + i * 3 / 2;
800            fir[out] = (val0 >> 4) as u8;
801            fir[out + 1] = ((val0 << 4) as u8) | (((val1 >> 8) as u8) & 0x0f);
802            fir[out + 2] = val1 as u8;
803        }
804
805        for (offset, value) in fir.into_iter().enumerate() {
806            self.usb
807                .demod_write_reg(1, 0x1c + offset as u16, value as u16, 1)
808                .await?;
809        }
810
811        Ok(())
812    }
813
814    async fn try_i2c_read_reg(&self, i2c_addr: u8, reg: u8) -> Option<u8> {
815        self.usb.i2c_read_reg(i2c_addr, reg).await.ok()
816    }
817
818    async fn set_gpio_output(&self, gpio: u8) -> Result<()> {
819        self.usb.set_gpio_output(gpio).await
820    }
821
822    pub(crate) async fn set_gpio_bit(&self, gpio: u8, enabled: bool) -> Result<()> {
823        self.usb.set_gpio_bit(gpio, enabled).await
824    }
825
826    fn is_blog_v4(&self) -> bool {
827        self.manufacturer.as_deref() == Some("RTLSDRBlog")
828            && self.product.as_deref() == Some("Blog V4")
829    }
830}
831
832pub fn bytes_to_iq_samples(bytes: &[u8]) -> Vec<IqSample> {
833    bytes
834        .chunks_exact(2)
835        .map(|pair| IqSample {
836            i: (pair[0] as f32 - 127.5) / 127.5,
837            q: (pair[1] as f32 - 127.5) / 127.5,
838        })
839        .collect()
840}
841
842pub(crate) struct RtlUsb {
843    _device: nusb::Device,
844    interface: nusb::Interface,
845    bulk_in: Mutex<BulkReader>,
846}
847
848struct BulkReader {
849    endpoint: nusb::Endpoint<Bulk, In>,
850    buffered: Vec<u8>,
851    buffered_offset: usize,
852}
853
854impl BulkReader {
855    fn new(endpoint: nusb::Endpoint<Bulk, In>) -> Self {
856        Self {
857            endpoint,
858            buffered: Vec::new(),
859            buffered_offset: 0,
860        }
861    }
862
863    async fn read(&mut self, len: usize) -> Result<Vec<u8>> {
864        let mut output = Vec::with_capacity(len);
865
866        while output.len() < len {
867            self.copy_buffered(&mut output, len);
868            if output.len() == len {
869                break;
870            }
871
872            let remaining = len - output.len();
873            let packet_size = self.endpoint.max_packet_size();
874            let transfer_len = remaining
875                .checked_add(packet_size - 1)
876                .map(|rounded| rounded / packet_size * packet_size)
877                .filter(|length| *length <= u32::MAX as usize)
878                .ok_or(Error::InvalidTransferLength(len))?;
879
880            self.endpoint.submit(Buffer::new(transfer_len));
881            let completion = self.endpoint.next_complete().await;
882            let short_transfer = completion.actual_len < transfer_len;
883            let received = completion.into_result()?.into_vec();
884
885            let needed = len - output.len();
886            let take = needed.min(received.len());
887            output.extend_from_slice(&received[..take]);
888
889            if take < received.len() {
890                self.buffered = received;
891                self.buffered_offset = take;
892            }
893
894            if short_transfer {
895                break;
896            }
897        }
898
899        Ok(output)
900    }
901
902    fn copy_buffered(&mut self, output: &mut Vec<u8>, requested_len: usize) {
903        let available = self.buffered.len().saturating_sub(self.buffered_offset);
904        let take = available.min(requested_len - output.len());
905        output.extend_from_slice(
906            &self.buffered[self.buffered_offset..self.buffered_offset.saturating_add(take)],
907        );
908        self.buffered_offset += take;
909
910        if self.buffered_offset == self.buffered.len() {
911            self.buffered.clear();
912            self.buffered_offset = 0;
913        }
914    }
915}
916
917impl RtlUsb {
918    pub(crate) async fn set_gpio_output(&self, gpio: u8) -> Result<()> {
919        let bit = 1u16 << gpio;
920        let direction = self.read_reg(SYSB, GPD, 1).await?;
921        self.write_reg(SYSB, GPD, direction & !bit, 1).await?;
922        let output_enable = self.read_reg(SYSB, GPOE, 1).await?;
923        self.write_reg(SYSB, GPOE, output_enable | bit, 1).await
924    }
925
926    pub(crate) async fn set_gpio_bit(&self, gpio: u8, enabled: bool) -> Result<()> {
927        let bit = 1u16 << gpio;
928        let value = self.read_reg(SYSB, GPO, 1).await?;
929        let value = if enabled { value | bit } else { value & !bit };
930        self.write_reg(SYSB, GPO, value, 1).await
931    }
932    pub(crate) async fn read_reg(&self, block: u8, addr: u16, len: u16) -> Result<u16> {
933        let data = self.read_array(block, addr, len).await?;
934        Ok(match data.as_slice() {
935            [lo] => *lo as u16,
936            [lo, hi, ..] => ((*hi as u16) << 8) | *lo as u16,
937            _ => 0,
938        })
939    }
940
941    pub(crate) async fn write_reg(
942        &self,
943        block: u8,
944        addr: u16,
945        value: u16,
946        len: usize,
947    ) -> Result<()> {
948        let data = reg_value_bytes(value, len)?;
949        self.write_array(block, addr, &data).await
950    }
951
952    pub(crate) async fn read_array(&self, block: u8, addr: u16, len: u16) -> Result<Vec<u8>> {
953        self.interface
954            .control_in(
955                ControlIn {
956                    control_type: ControlType::Vendor,
957                    recipient: Recipient::Device,
958                    request: 0,
959                    value: addr,
960                    index: (block as u16) << 8,
961                    length: len,
962                },
963                CONTROL_TIMEOUT,
964            )
965            .await
966            .map_err(Error::from)
967            .map_err(|err| err.control("control_in", addr, (block as u16) << 8))
968    }
969
970    pub(crate) async fn write_array(&self, block: u8, addr: u16, data: &[u8]) -> Result<()> {
971        if data.len() > u16::MAX as usize {
972            return Err(Error::InvalidTransferLength(data.len()));
973        }
974
975        self.interface
976            .control_out(
977                ControlOut {
978                    control_type: ControlType::Vendor,
979                    recipient: Recipient::Device,
980                    request: 0,
981                    value: addr,
982                    index: ((block as u16) << 8) | 0x10,
983                    data,
984                },
985                CONTROL_TIMEOUT,
986            )
987            .await
988            .map_err(Error::from)
989            .map_err(|err| err.control("control_out", addr, ((block as u16) << 8) | 0x10))
990    }
991
992    pub(crate) async fn demod_write_reg(
993        &self,
994        page: u8,
995        addr: u16,
996        value: u16,
997        len: usize,
998    ) -> Result<()> {
999        let data = reg_value_bytes(value, len)?;
1000        self.interface
1001            .control_out(
1002                ControlOut {
1003                    control_type: ControlType::Vendor,
1004                    recipient: Recipient::Device,
1005                    request: 0,
1006                    value: (addr << 8) | 0x20,
1007                    index: 0x10 | page as u16,
1008                    data: &data,
1009                },
1010                CONTROL_TIMEOUT,
1011            )
1012            .await
1013            .map_err(Error::from)
1014            .map_err(|err| {
1015                err.control("demod_control_out", (addr << 8) | 0x20, 0x10 | page as u16)
1016            })?;
1017
1018        let _ = self.demod_read_reg(0x0a, 0x01, 1).await?;
1019        Ok(())
1020    }
1021
1022    pub(crate) async fn demod_read_reg(&self, page: u8, addr: u16, len: u16) -> Result<u16> {
1023        let data = self
1024            .interface
1025            .control_in(
1026                ControlIn {
1027                    control_type: ControlType::Vendor,
1028                    recipient: Recipient::Device,
1029                    request: 0,
1030                    value: (addr << 8) | 0x20,
1031                    index: page as u16,
1032                    length: len,
1033                },
1034                CONTROL_TIMEOUT,
1035            )
1036            .await
1037            .map_err(Error::from)
1038            .map_err(|err| err.control("demod_control_in", (addr << 8) | 0x20, page as u16))?;
1039
1040        Ok(match data.as_slice() {
1041            [lo] => *lo as u16,
1042            [lo, hi, ..] => ((*hi as u16) << 8) | *lo as u16,
1043            _ => 0,
1044        })
1045    }
1046
1047    pub(crate) async fn i2c_write(&self, i2c_addr: u8, data: &[u8]) -> Result<()> {
1048        self.write_array(IICB, i2c_addr as u16, data).await
1049    }
1050
1051    pub(crate) async fn i2c_read(&self, i2c_addr: u8, len: u16) -> Result<Vec<u8>> {
1052        self.read_array(IICB, i2c_addr as u16, len).await
1053    }
1054
1055    pub(crate) async fn i2c_read_reg(&self, i2c_addr: u8, reg: u8) -> Result<u8> {
1056        self.i2c_write(i2c_addr, &[reg]).await?;
1057        let data = self.i2c_read(i2c_addr, 1).await?;
1058        data.first().copied().ok_or(Error::ShortTransfer {
1059            expected: 1,
1060            actual: 0,
1061        })
1062    }
1063}
1064
1065fn reg_value_bytes(value: u16, len: usize) -> Result<Vec<u8>> {
1066    match len {
1067        1 => Ok(vec![(value & 0xff) as u8]),
1068        2 => Ok(vec![(value >> 8) as u8, (value & 0xff) as u8]),
1069        _ => Err(Error::InvalidTransferLength(len)),
1070    }
1071}
1072
1073#[cfg(target_family = "wasm")]
1074fn device_selectors() -> Vec<nusb::DeviceSelector> {
1075    KNOWN_DEVICES
1076        .iter()
1077        .map(|device| nusb::DeviceSelector::all().with_vid_pid(device.vendor_id, device.product_id))
1078        .collect()
1079}
1080
1081fn known_device_name(vendor_id: u16, product_id: u16) -> Option<&'static str> {
1082    KNOWN_DEVICES
1083        .iter()
1084        .find(|device| device.vendor_id == vendor_id && device.product_id == product_id)
1085        .map(|device| device.name)
1086}