Skip to main content

rtlsdr_pure/
rtl2832.rs

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