summaryrefslogtreecommitdiff
path: root/src/lib.rs
blob: 9ec7734187c3e6a1f930e291bb0de451446edb90 (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
extern crate libusb;

use std::time::Duration;
use libusb::{Direction, RequestType, Recipient};

const BLOCK_USBB: u16 = 1;
const ADDR_USB_SYSCTL: u16 = 0x2000;

const INTERFACE_ID: u8 = 0;
const CTRL_TIMEOUT: Duration = Duration::from_millis(300);
const KNOWN_DEVICES: [(u16, u16, &str); 2] = [
    (0x0bda, 0x2832, "Generic RTL2832U"),
    (0x0bda, 0x2838, "Generic RTL2832U OEM")
];

pub struct RtlSdr<'a> {
    ctx: &'a libusb::Context,
    dev: Option<libusb::DeviceHandle<'a>>,
    iface_id: u8,
}

impl<'a> RtlSdr<'a> {
    
    pub fn new(ctx: &'a libusb::Context) -> RtlSdr<'a> {
        RtlSdr {
            ctx,
            dev: None,
            iface_id: INTERFACE_ID,
        }
    }

    pub fn init(&mut self) {
        self.find_device();
    }

    fn write_reg(&self, handle: &libusb::DeviceHandle, block: u16, addr: u16, val: u8, _len: u8) -> usize {
        let vendor_out = libusb::request_type(Direction::Out, RequestType::Vendor, Recipient::Device);
        let mut data: [u8; 2] = [0, 0];
        let index: u16 = (block << 8) | 0x10;

        data[0] = val;
        data[1] = val;

        match handle.write_control(vendor_out, 0, addr, index, &data, CTRL_TIMEOUT) {
            Ok(n) => n,
            Err(_) => 0
        }
    }

    pub fn find_device(&mut self) {
        for mut dev in self.ctx.devices().unwrap().iter() {
            let desc = dev.device_descriptor().unwrap();
            let vid = desc.vendor_id();
            let pid = desc.product_id();

            for kd in KNOWN_DEVICES.iter() {
                if kd.0 == vid && kd.1 == pid {
                    let mut handle = dev.open().unwrap();

                    let has_kernel_driver = match handle.kernel_driver_active(self.iface_id) {
                            Ok(true) => {
                                handle.detach_kernel_driver(self.iface_id).ok();
                                true
                            },
                            _ => false
                    };

                    let _iface = handle.claim_interface(self.iface_id).unwrap();

                    let res = self.write_reg(&handle, BLOCK_USBB, ADDR_USB_SYSCTL, 0x09, 1);
                    println!("Got {}", res);

                    if has_kernel_driver {
                        handle.attach_kernel_driver(self.iface_id).ok();
                    }

                    self.dev = Some(handle);
                }
            }
        }
    }
}

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

    #[test]
    fn test_init() {
        let ctx = libusb::Context::new().unwrap();
        let mut rtlsdr = RtlSdr::new(&ctx);
        assert!(rtlsdr.dev.is_none());
        rtlsdr.init();
        assert!(rtlsdr.dev.is_some());
    }
}