summaryrefslogtreecommitdiff
path: root/src/lib.rs
blob: 30af6af948d8e38fdba9fa1eefa2f9c4ca30ccff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
extern crate log;
extern crate pretty_env_logger;
extern crate rusb;

mod tuners;
mod usb;

use log::{error, info, trace, warn};
use tuners::*;
use usb::RtlSdrDeviceHandle;

const INTERFACE_ID: u8 = 0;

const KNOWN_DEVICES: [(u16, u16, &str); 2] = [
    (0x0bda, 0x2832, "Generic RTL2832U"),
    (0x0bda, 0x2838, "Generic RTL2832U OEM"),
];

const KNOWN_TUNERS: [TunerInfo; 2] = [r820t::TUNER_INFO, fc0013::TUNER_INFO];

pub struct RtlSdr {
    // ctx: rusb::Context,
    // device: UsbDevice,
    iface_id: u8,
}

impl RtlSdr {
    pub fn new() -> RtlSdr {
        pretty_env_logger::init();
        RtlSdr {
            // ctx: rusb::Context::new().unwrap(),
            iface_id: INTERFACE_ID,
        }
    }

    /// Open a new RTL-SDR device
    pub fn open(&mut self) {
        for dev in rusb::devices().unwrap().iter() {
            let desc = dev.device_descriptor().unwrap();
            let vid = desc.vendor_id();
            let pid = desc.product_id();

            trace!("Found USB device with vid {} and pid {}", vid, pid);

            for kd in KNOWN_DEVICES.iter() {
                if kd.0 == vid && kd.1 == pid {
                    info!("Found device {} {{{:04x}:{:04x}}}", kd.2, vid, pid);
                    let usb_handle = dev.open().unwrap();
                    let mut handle = RtlSdrDeviceHandle::new(usb_handle, self.iface_id);
                    // let kernel_driver_attached = handle.detach_kernel_driver();

                    let _iface = handle.claim_interface();

                    handle.test_write();
                    // reset device if write didn't succeed

                    handle.init_baseband();
                    handle.set_i2c_repeater(true);

                    {
                        let tuner_id = match self.search_tuner(&handle) {
                            Some(tid) => {
                                info!("Got tuner ID {}", tid);
                                tid
                            }
                            None => {
                                error!("Could not find a value tuner, aborting.");
                                return;
                            }
                        };

                        let tuner: Box<dyn Tuner> = match tuner_id {
                            r820t::TUNER_ID => Box::new(r820t::R820T::new(&handle)),
                            fc0013::TUNER_ID => Box::new(fc0013::FC0013::new(&handle)),
                            _ => {
                                error!("Could not find any valid tuner, aborting.");
                                return;
                            }
                        };

                        info!("Found tuner {}", tuner.display());
                    }
                }
            }
        }
    }

    /// Probe all known tuners at their I2C addresses
    /// and search for expected return values
    fn search_tuner(&mut self, handle: &RtlSdrDeviceHandle) -> Option<&str> {
        for tuner_info in KNOWN_TUNERS.iter() {
            let regval = handle.i2c_read_reg(tuner_info.i2c_addr, tuner_info.check_addr);
            trace!(
                "Probing I2C address {:#02x} checking address {:#02x}",
                tuner_info.i2c_addr,
                tuner_info.check_addr,
            );
            match regval {
                Ok(val) => {
                    trace!(
                        "Expecting value {:#02x}, got value {:#02x}",
                        tuner_info.check_val,
                        val
                    );
                    if val == tuner_info.check_val {
                        return Some(tuner_info.id);
                    }
                }
                Err(_) => {
                    warn!("Reading failed, continuing");
                }
            };
        }
        None
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_init() {
        let mut rtlsdr = RtlSdr::new();
        rtlsdr.open();
    }
}