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}