1mod device;
9pub mod error;
10mod rtlsdr;
11mod tuners;
12
13use device::Device;
14use error::{Result, RtlsdrError};
15use rtlsdr::RtlSdr as Sdr;
16use rusb::{Context, DeviceHandle, DeviceList, UsbContext};
17use tuners::r82xx::{R820T_TUNER_ID, R828D_TUNER_ID};
18
19pub struct TunerId;
20impl TunerId {
21 pub const R820T: &'static str = R820T_TUNER_ID;
22 pub const R828D: &'static str = R828D_TUNER_ID;
23}
24
25pub const DEFAULT_BUF_LENGTH: usize = 16 * 16384;
26
27pub struct DeviceDescriptors {
28 list: DeviceList<Context>,
29}
30
31#[derive(Debug, Clone, PartialEq, Eq)]
32pub struct DeviceDescriptor {
33 pub index: usize,
34 pub vendor_id: u16,
35 pub product_id: u16,
36 pub manufacturer: String,
37 pub product: String,
38 pub serial: String,
39}
40
41impl DeviceDescriptors {
42 pub fn new() -> Result<Self> {
43 let context = Context::new()?;
44 let list = context.devices()?;
45 Ok(Self { list })
46 }
47
48 pub fn iter(&self) -> impl Iterator<Item = DeviceDescriptor> + '_ {
50 self.list
51 .iter()
52 .filter_map(|device| {
53 let desc = device.device_descriptor().ok()?;
54 device::is_known_device(desc.vendor_id(), desc.product_id()).then_some(device)
55 })
56 .enumerate()
57 .filter_map(|(index, device)| {
58 let desc = device.device_descriptor().ok()?;
59 match device.open() {
60 Ok(handle) => {
61 let manufacturer = read_string(&handle, desc.manufacturer_string_index());
62 let product = read_string(&handle, desc.product_string_index());
63 let serial = read_string(&handle, desc.serial_number_string_index());
64
65 Some(DeviceDescriptor {
66 index,
67 vendor_id: desc.vendor_id(),
68 product_id: desc.product_id(),
69 manufacturer,
70 product,
71 serial,
72 })
73 }
74 Err(e) => {
75 log::warn!("Could not open device at index {}: {}", index, e);
76 None
77 }
78 }
79 })
80 }
81}
82
83fn read_string<T: UsbContext>(handle: &DeviceHandle<T>, index: Option<u8>) -> String {
84 index
85 .and_then(|i| handle.read_string_descriptor_ascii(i).ok())
86 .unwrap_or_default()
87}
88
89#[derive(Debug, PartialEq, Eq, Clone)]
90pub enum DeviceId<'a> {
91 Index(usize),
92 Serial(&'a str),
93 Fd(i32),
94}
95
96#[derive(Debug)]
97pub enum TunerGain {
98 Auto,
99 Manual(i32),
100}
101#[derive(Debug)]
102pub enum DirectSampleMode {
103 Off,
104 On,
105 OnSwap, }
107
108#[derive(Debug, Copy, Clone, PartialEq, Eq)]
109pub enum Sensor {
110 TunerType,
111 TunerGainDb,
112 FrequencyCorrectionPpm,
113}
114
115#[derive(Debug, PartialEq)]
116pub enum SensorValue {
117 TunerType(String),
118 TunerGainDb(i32),
119 FrequencyCorrectionPpm(i32),
120}
121
122pub struct RtlSdr {
123 sdr: Sdr,
124}
125impl RtlSdr {
126 pub fn open(device_id: DeviceId) -> Result<RtlSdr> {
127 let dev = Device::new(device_id)?;
128 let mut sdr = Sdr::new(dev);
129 sdr.init()?;
130 Ok(RtlSdr { sdr })
131 }
132
133 pub fn open_with_serial(serial: &str) -> Result<RtlSdr> {
134 Self::open(DeviceId::Serial(serial))
135 }
136
137 pub fn open_with_index(index: usize) -> Result<RtlSdr> {
139 Self::open(DeviceId::Index(index))
140 }
141
142 pub fn open_with_fd(fd: i32) -> Result<RtlSdr> {
144 Self::open(DeviceId::Fd(fd))
145 }
146 pub fn close(&mut self) -> Result<()> {
147 self.sdr.deinit_baseband()
149 }
150 pub fn reset_buffer(&self) -> Result<()> {
151 self.sdr.reset_buffer()
152 }
153 pub fn read_sync(&self, buf: &mut [u8]) -> Result<usize> {
154 self.sdr.read_sync(buf)
155 }
156 pub fn get_center_freq(&self) -> u32 {
157 self.sdr.get_center_freq()
158 }
159 pub fn set_center_freq(&mut self, freq: u32) -> Result<()> {
160 self.sdr.set_center_freq(freq)
161 }
162 pub fn get_tuner_gains(&self) -> Result<Vec<i32>> {
163 self.sdr.get_tuner_gains()
164 }
165 pub fn read_tuner_gain(&self) -> Result<i32> {
166 self.sdr.read_tuner_gain()
167 }
168 pub fn set_tuner_gain(&mut self, gain: TunerGain) -> Result<()> {
169 self.sdr.set_tuner_gain(gain)
170 }
171 pub fn get_freq_correction(&self) -> i32 {
172 self.sdr.get_freq_correction()
173 }
174 pub fn set_freq_correction(&mut self, ppm: i32) -> Result<()> {
175 self.sdr.set_freq_correction(ppm)
176 }
177 pub fn get_sample_rate(&self) -> u32 {
178 self.sdr.get_sample_rate()
179 }
180 pub fn set_sample_rate(&mut self, rate: u32) -> Result<()> {
181 self.sdr.set_sample_rate(rate)
182 }
183 pub fn set_tuner_bandwidth(&mut self, bw: u32) -> Result<()> {
184 self.sdr.set_tuner_bandwidth(bw)
185 }
186 pub fn set_testmode(&mut self, on: bool) -> Result<()> {
187 self.sdr.set_testmode(on)
188 }
189 pub fn set_direct_sampling(&mut self, mode: DirectSampleMode) -> Result<()> {
190 self.sdr.set_direct_sampling(mode)
191 }
192 pub fn set_bias_tee(&self, on: bool) -> Result<()> {
193 self.sdr.set_bias_tee(on)
194 }
195 pub fn get_tuner_id(&self) -> Result<&str> {
196 self.sdr.get_tuner_id()
197 }
198 pub fn list_sensors(&self) -> Result<Vec<Sensor>> {
199 Ok(vec![
200 Sensor::TunerType,
201 Sensor::TunerGainDb,
202 Sensor::FrequencyCorrectionPpm,
203 ])
204 }
205 pub fn read_sensor(&self, sensor: Sensor) -> Result<SensorValue> {
206 match sensor {
207 Sensor::TunerType => self
208 .get_tuner_id()
209 .map(|s| SensorValue::TunerType(s.to_string())),
210 Sensor::TunerGainDb => self.sdr.read_tuner_gain().map(SensorValue::TunerGainDb),
211 Sensor::FrequencyCorrectionPpm => Ok(SensorValue::FrequencyCorrectionPpm(
212 self.get_freq_correction(),
213 )),
214 }
215 }
216
217 pub fn get_device_count() -> Result<usize> {
219 let descriptors = DeviceDescriptors::new()?;
220 Ok(descriptors.iter().count())
221 }
222
223 pub fn list_devices() -> Result<Vec<DeviceDescriptor>> {
225 let descriptors = DeviceDescriptors::new()?;
226 Ok(descriptors.iter().collect())
227 }
228
229 pub fn open_first_available() -> Result<RtlSdr> {
231 let descriptors = DeviceDescriptors::new()?;
232 let first_device = descriptors
233 .iter()
234 .next()
235 .ok_or_else(|| RtlsdrError::RtlsdrErr("No RTL-SDR devices found".to_string()))?;
236 Self::open_with_index(first_device.index)
237 }
238
239 pub fn get_device_info(index: usize) -> Result<DeviceDescriptor> {
241 let descriptors = DeviceDescriptors::new()?;
242 let devices: Vec<DeviceDescriptor> = descriptors.iter().collect();
243 devices
244 .into_iter()
245 .find(|d| d.index == index)
246 .ok_or_else(|| {
247 RtlsdrError::RtlsdrErr(format!("No device found at index {}", index))
248 })
249 }
250
251 pub fn get_device_serial(index: usize) -> Result<String> {
253 Self::get_device_info(index).map(|info| info.serial)
254 }
255}