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}