1mod sys;
2
3macro_rules! rtlsdr_result {
4 ($ret:expr) => {
5 unsafe {
6 if $ret < 0 {
7 Err($ret)
8 } else {
9 Ok($ret)
10 }
11 }
12 };
13}
14
15#[derive(Debug, Copy, Clone, PartialEq, Eq)]
16pub enum RtlsdrError {
17 LibusbError(LibusbError),
18 Unspecified(i32),
19}
20
21impl From<i32> for RtlsdrError {
22 fn from(err: i32) -> Self {
23 match LibusbError::try_from(err) {
24 Ok(e) => RtlsdrError::LibusbError(e),
25 Err(e) => RtlsdrError::Unspecified(e),
26 }
27 }
28}
29
30#[repr(i32)]
31#[derive(Debug, Copy, Clone, PartialEq, Eq)]
32pub enum LibusbError {
33 IoError = -1,
35 InvalidParam = -2,
37 AccessDenied = -3,
39 NoDevice = -4,
41 NoEntity = -5,
43 Busy = -6,
45 Timeout = -7,
47 Overflow = -8,
49 Pipe = -9,
51 Interrupted = -10,
53 InsufficientMemory = -11,
55 NotSupported = -12,
57 Other = -99,
59}
60
61impl TryFrom<i32> for LibusbError {
62 type Error = i32;
63
64 fn try_from(value: i32) -> Result<Self, Self::Error> {
65 match value {
66 -1 => Ok(LibusbError::IoError),
67 -2 => Ok(LibusbError::InvalidParam),
68 -3 => Ok(LibusbError::AccessDenied),
69 -4 => Ok(LibusbError::NoDevice),
70 -5 => Ok(LibusbError::NoEntity),
71 -6 => Ok(LibusbError::Busy),
72 -7 => Ok(LibusbError::Timeout),
73 -8 => Ok(LibusbError::Overflow),
74 -9 => Ok(LibusbError::Pipe),
75 -10 => Ok(LibusbError::Interrupted),
76 -11 => Ok(LibusbError::InsufficientMemory),
77 -12 => Ok(LibusbError::NotSupported),
78 -99 => Ok(LibusbError::Other),
79 e => Err(e),
80 }
81 }
82}
83
84#[repr(i32)]
85#[derive(Debug, Copy, Clone, PartialEq, Eq)]
86pub enum TunerType {
87 Unknown = 0,
89 E4000 = 1,
91 FC0012 = 2,
93 FC0013 = 3,
95 FC2580 = 4,
97 R820T = 5,
99 R828D = 6,
101}
102
103#[repr(i32)]
104#[derive(Debug, Copy, Clone, PartialEq, Eq)]
105pub enum Sideband {
106 Lower = 0,
107 Upper = 1,
108}
109
110#[repr(u32)]
111#[derive(Debug, Copy, Clone, PartialEq, Eq)]
112pub enum DirectSampling {
113 Disabled = 0,
114 I = 1,
115 Q = 2,
116}
117
118#[repr(u32)]
119#[derive(Debug, Copy, Clone, PartialEq, Eq)]
120pub enum DirectSamplingThreshold {
121 Disabled = 0,
122 I = 1,
123 Q = 2,
124 IBelow = 3,
125 QBelow = 4,
126}
127
128#[derive(Debug, Copy, Clone, PartialEq, Eq)]
129pub struct Device {
131 index: u32,
132 dev: *mut sys::rtlsdr_dev,
133}
134
135impl Device {
136 pub fn open(&mut self) -> Result<(), RtlsdrError> {
139 rtlsdr_result!(sys::rtlsdr_open(&mut self.dev, self.index))?;
140
141 Ok(())
142 }
143
144 pub fn close(&mut self) -> Result<(), String> {
148 rtlsdr_result!(sys::rtlsdr_close(self.dev)).map_err(|e| match e {
149 -1 => "Device was not opened or already closed".to_string(),
150 _ => format!("Failed to close device: {}", e),
151 })?;
152
153 self.dev = std::ptr::null_mut();
154
155 Ok(())
156 }
157
158 pub fn get_xtal_freq(&self) -> Result<(u32, u32), String> {
161 let mut rtl_freq = 0;
162 let mut tuner_freq = 0;
163
164 rtlsdr_result!(sys::rtlsdr_get_xtal_freq(
165 self.dev,
166 &mut rtl_freq,
167 &mut tuner_freq
168 ))
169 .map_err(|e| format!("Failed to get crystal frequency: {}", e))?;
170
171 Ok((rtl_freq, tuner_freq))
172 }
173
174 pub fn set_xtal_freq(&mut self, rtl_freq: u32, tuner_freq: u32) -> Result<(), String> {
180 rtlsdr_result!(sys::rtlsdr_set_xtal_freq(self.dev, rtl_freq, tuner_freq))
181 .map_err(|e| format!("Failed to set crystal frequency: {}", e))?;
182
183 Ok(())
184 }
185
186 pub fn get_usb_device_strings(&self) -> Result<(String, String, String), String> {
189 let mut manufact = [0u8; 256];
190 let mut product = [0u8; 256];
191 let mut serial = [0u8; 256];
192
193 rtlsdr_result!(sys::rtlsdr_get_usb_strings(
194 self.dev,
195 manufact.as_mut_ptr() as *mut i8,
196 product.as_mut_ptr() as *mut i8,
197 serial.as_mut_ptr() as *mut i8
198 ))
199 .map_err(|e| format!("Failed to get usb device strings: {}", e))?;
200
201 let manufact = std::ffi::CStr::from_bytes_until_nul(&manufact)
202 .map_err(|e| format!("Failed to get usb device strings: {}", e))?
203 .to_str()
204 .expect("Failed to convert usb device string to str")
205 .to_string();
206 let product = std::ffi::CStr::from_bytes_until_nul(&product)
207 .map_err(|e| format!("Failed to get usb device strings: {}", e))?
208 .to_str()
209 .expect("Failed to convert usb device string to str")
210 .to_string();
211 let serial = std::ffi::CStr::from_bytes_until_nul(&serial)
212 .map_err(|e| format!("Failed to get usb device strings: {}", e))?
213 .to_str()
214 .expect("Failed to convert usb device string to str")
215 .to_owned();
216
217 Ok((manufact, product, serial))
218 }
219
220 pub fn read_eeprom(&self, offset: u8, len: u16) -> Result<Vec<u8>, String> {
222 let mut buf = vec![0u8; len as usize];
223
224 rtlsdr_result!(sys::rtlsdr_read_eeprom(
225 self.dev,
226 buf.as_mut_ptr(),
227 offset,
228 len
229 ))
230 .map_err(|e| match e {
231 -1 => "Invalid Device".to_string(),
232 -2 => "EEPROM size exceeded".to_string(),
233 -3 => "No EEPROM found".to_string(),
234 _ => format!("Failed to read EEPROM: {}", e),
235 })?;
236
237 Ok(buf)
238 }
239
240 pub fn write_eeprom(&mut self, offset: u8, buf: &mut [u8]) -> Result<(), String> {
242 rtlsdr_result!(sys::rtlsdr_write_eeprom(
243 self.dev,
244 buf.as_mut_ptr(),
245 offset,
246 buf.len() as u16
247 ))
248 .map_err(|e| match e {
249 -1 => "Invalid Device".to_string(),
250 -2 => "EEPROM size exceeded".to_string(),
251 -3 => "No EEPROM found".to_string(),
252 _ => format!("Failed to write EEPROM: {}", e),
253 })?;
254
255 Ok(())
256 }
257
258 pub fn get_center_freq(&self) -> Result<u32, String> {
260 match unsafe { sys::rtlsdr_get_center_freq(self.dev) } {
261 0 => Err("Failed to get center frequency".to_string()),
262 freq => Ok(freq),
263 }
264 }
265
266 pub fn set_center_freq(&mut self, freq: u32) -> Result<(), String> {
268 rtlsdr_result!(sys::rtlsdr_set_center_freq(self.dev, freq))
269 .map_err(|e| format!("Failed to set center frequency: {}", e))?;
270
271 Ok(())
272 }
273
274 pub fn get_freq_correction(&self) -> i32 {
277 unsafe { sys::rtlsdr_get_freq_correction(self.dev) }
278 }
279
280 pub fn set_freq_correction(&mut self, ppm: i32) -> Result<(), String> {
283 rtlsdr_result!(sys::rtlsdr_set_freq_correction(self.dev, ppm))
284 .map_err(|e| format!("Failed to set frequency correction: {}", e))?;
285
286 Ok(())
287 }
288
289 pub fn get_tuner_type(&self) -> TunerType {
291 let tuner_type = unsafe { sys::rtlsdr_get_tuner_type(self.dev) };
292
293 match tuner_type {
294 0 => TunerType::Unknown,
295 1 => TunerType::E4000,
296 2 => TunerType::FC0012,
297 3 => TunerType::FC0013,
298 4 => TunerType::FC2580,
299 5 => TunerType::R820T,
300 6 => TunerType::R828D,
301 _ => TunerType::Unknown,
302 }
303 }
304
305 pub fn get_tuner_gains(&self) -> Vec<i32> {
308 let n = unsafe { sys::rtlsdr_get_tuner_gains(self.dev, std::ptr::null_mut()) };
309 let mut gains = vec![0i32; n as usize];
310 let n = unsafe { sys::rtlsdr_get_tuner_gains(self.dev, gains.as_mut_ptr()) };
311 gains.truncate(n as usize);
312 gains
313 }
314
315 pub fn get_tuner_gain(&self) -> i32 {
319 unsafe { sys::rtlsdr_get_tuner_gain(self.dev) }
320 }
321
322 pub fn set_tuner_gain(&mut self, gain: i32) -> Result<(), String> {
327 rtlsdr_result!(sys::rtlsdr_set_tuner_gain(self.dev, gain))
328 .map_err(|e| format!("Failed to set tuner gain: {}", e))?;
329
330 Ok(())
331 }
332
333 pub fn set_tuner_bandwidth(&mut self, bw: u32) -> Result<(), String> {
336 rtlsdr_result!(sys::rtlsdr_set_tuner_bandwidth(self.dev, bw,))
337 .map_err(|e| format!("Failed to set bandwidth: {}", e))?;
338
339 Ok(())
340 }
341
342 pub fn set_tuner_if_gain(&mut self, stage: i32, gain: i32) -> Result<(), String> {
346 rtlsdr_result!(sys::rtlsdr_set_tuner_if_gain(self.dev, stage, gain))
347 .map_err(|e| format!("Failed to set IF gain: {}", e))?;
348
349 Ok(())
350 }
351
352 pub fn set_tuner_gain_mode(&mut self, manual: bool) -> Result<(), String> {
355 rtlsdr_result!(sys::rtlsdr_set_tuner_gain_mode(self.dev, manual as i32))
356 .map_err(|e| format!("Failed to set tuner gain mode: {}", e))?;
357
358 Ok(())
359 }
360
361 pub fn get_sample_rate(&self) -> Result<u32, String> {
364 match unsafe { sys::rtlsdr_get_sample_rate(self.dev) } {
365 0 => Err("Failed to get sample rate".to_string()),
366 rate => Ok(rate),
367 }
368 }
369
370 pub fn set_sample_rate(&mut self, rate: u32) -> Result<(), String> {
373 rtlsdr_result!(sys::rtlsdr_set_sample_rate(self.dev, rate))
374 .map_err(|e| format!("Failed to set sample rate: {}", e))?;
375
376 Ok(())
377 }
378
379 pub fn set_test_mode(&mut self, test_mode: bool) -> Result<(), String> {
382 rtlsdr_result!(sys::rtlsdr_set_testmode(self.dev, test_mode as i32))
383 .map_err(|e| format!("Failed to set test mode: {}", e))?;
384
385 Ok(())
386 }
387
388 pub fn set_agc_mode(&mut self, enabled: bool) -> Result<(), String> {
390 rtlsdr_result!(sys::rtlsdr_set_agc_mode(self.dev, enabled as i32))
391 .map_err(|e| format!("Failed to set agc mode: {}", e))?;
392
393 Ok(())
394 }
395
396 pub fn get_direct_sampling(&self) -> Result<DirectSampling, String> {
398 rtlsdr_result!(sys::rtlsdr_get_direct_sampling(self.dev,))
399 .map_err(|e| format!("Failed to get direct sampling mode: {}", e))
400 .map(|mode| match mode {
401 0 => DirectSampling::Disabled,
402 1 => DirectSampling::I,
403 2 => DirectSampling::Q,
404 _ => DirectSampling::Disabled,
405 })
406 }
407
408 pub fn set_direct_sampling(&mut self, mode: DirectSampling) -> Result<(), String> {
412 rtlsdr_result!(sys::rtlsdr_set_direct_sampling(self.dev, mode as i32))
413 .map_err(|e| format!("Failed to set direct sampling mode: {}", e))?;
414
415 Ok(())
416 }
417
418 pub fn get_offset_tuning(&self) -> Result<bool, String> {
420 rtlsdr_result!(sys::rtlsdr_get_offset_tuning(self.dev))
421 .map_err(|e| format!("Failed to get offset tuning mode: {}", e))
422 .map(|mode| mode == 1)
423 }
424
425 pub fn set_offset_tuning(&mut self, enabled: bool) -> Result<(), String> {
427 rtlsdr_result!(sys::rtlsdr_set_offset_tuning(self.dev, enabled as i32))
428 .map_err(|e| format!("Failed to set offset tuning mode: {}", e))?;
429
430 Ok(())
431 }
432
433 pub fn reset_buffer(&mut self) -> Result<(), String> {
435 rtlsdr_result!(sys::rtlsdr_reset_buffer(self.dev))
436 .map_err(|e| format!("Failed to reset buffer: {}", e))?;
437
438 Ok(())
439 }
440
441 pub fn read_sync(&self, buf: &mut [u8]) -> Result<i32, RtlsdrError> {
443 let mut n_read = 0;
444
445 rtlsdr_result!(sys::rtlsdr_read_sync(
446 self.dev,
447 buf.as_mut_ptr() as *mut std::ffi::c_void,
448 buf.len() as i32,
449 &mut n_read
450 ))?;
451
452 Ok(n_read)
453 }
454
455 #[deprecated]
461 pub fn wait_async<F>(&self, cb: F) -> Result<(), String>
462 where
463 F: FnMut(Vec<u8>),
464 {
465 self.read_async(cb, 0, 0)
466 }
467
468 pub fn read_async<F>(&self, mut cb: F, buf_num: u32, buf_len: u32) -> Result<(), String>
476 where
477 F: FnMut(Vec<u8>),
478 {
479 unsafe extern "C" fn _cb<F>(buf: *mut u8, len: u32, ctx: *mut std::ffi::c_void)
480 where
481 F: FnMut(Vec<u8>),
482 {
483 let cb = &mut *(ctx as *mut F);
484 let mut vec = Vec::with_capacity(len as usize);
485 (0..len).for_each(|i| vec.push(*buf.offset(i as isize)));
486 cb(vec);
487 }
488
489 rtlsdr_result!(sys::rtlsdr_read_async(
490 self.dev,
491 Some(_cb::<F>),
492 &mut cb as *mut F as *mut std::ffi::c_void,
493 buf_num,
494 buf_len
495 ))
496 .map_err(|e| format!("Failed to wait async: {}", e))?;
497
498 Ok(())
499 }
500
501 pub fn cancel_async(&self) -> Result<(), String> {
505 rtlsdr_result!(sys::rtlsdr_cancel_async(self.dev))
506 .map_err(|e| format!("Failed to cancel async: {}", e))?;
507
508 Ok(())
509 }
510
511 pub fn set_bias_tee(&mut self, on: bool) -> Result<(), String> {
517 rtlsdr_result!(sys::rtlsdr_set_bias_tee(self.dev, on as i32)).map_err(|e| match e {
518 -1 => "Device is not initialized".to_string(),
519 _ => format!("Failed to set bias tee: {}", e),
520 })?;
521
522 Ok(())
523 }
524
525 pub fn set_bias_tee_gpio(&mut self, gpio: i32, on: bool) -> Result<(), String> {
533 rtlsdr_result!(sys::rtlsdr_set_bias_tee_gpio(self.dev, gpio, on as i32)).map_err(|e| {
534 match e {
535 -1 => "Device is not initialized".to_string(),
536 _ => format!("Failed to set bias tee gpio: {}", e),
537 }
538 })?;
539
540 Ok(())
541 }
542}
543
544#[doc = "Get all available devices"]
545pub fn get_devices() -> Vec<Device> {
546 let n = unsafe { sys::rtlsdr_get_device_count() };
547
548 (0..n)
549 .map(|index| Device {
550 index,
551 dev: std::ptr::null_mut(),
552 })
553 .collect()
554}