rtlsdr/
lib.rs

1// Copyright (c) 2016 Joseph D Poirier <jdpoirier@gmail.com>
2// Licensed under the MIT License <LICENSE-MIT.md>
3
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10#![allow(dead_code)]
11use std::sync::Arc;
12use std::os::raw::{c_int, c_void, c_uchar, c_char};
13use std::option::Option;
14use std::string::String;
15use std::ffi::CStr;
16use std::ptr;
17use std::str;
18
19
20// TODO:
21// - better function/method documnentation
22// - better way to handle errors
23// - String vs str
24// - proper documentation
25// - tests
26// - read more Rust code, learn more Rust, make this lib better
27
28/// Sampling modes.
29pub enum SamplingMode {
30    None = 0,
31    IADC = 1,
32    QADC = 2,
33    Error = 3,
34}
35
36// Convenience constants
37// pub const DefaultGain: String = "auto";
38pub const DEFAULT_FC: i32 = 80_000_000;
39pub const DEFAULT_RS: i32 = 1_024_000;
40pub const DEFAULT_READ_SIZE: i32 = 1024;
41pub const CRYSTAL_FREQ: i32 = 28800000;
42pub const DEFAULT_SAMPLE_RATE: i32 = 2048000;
43pub const DEFAULT_ASYNC_BUF_NUMBER: i32 = 32;
44pub const DEFAULT_BUF_LENGTH: i32 = (16 * 16384);
45pub const MIN_BUF_LENGTH: i32 = 512;
46pub const MAX_BUF_LENGTH: i32 = (256 * 16384);
47/// Hardware info strings (product, manufacturer, serial) maximum size.
48/// MAX_STR_SIZE = (max string length - 2 (header bytes)) \ 2. Where each
49/// info character is followed by a null character.
50pub const MAX_STR_SIZE: usize = 35;
51
52// EEPROM stored device information starts after the header bytes.
53const STR_OFFSET_START: usize = 0x09;
54const EEPROM_SIZE: i32 = 256;
55/// Get/set hardware info errors.
56const NO_VALID_EEPROM_HEADER: i32 = -13;
57const STRING_VALUE_TOO_LONG: i32 = -14;
58const STRING_DESCRIPTOR_INVALID: i32 = -15;
59const STRING__DESCRIPTOR_TOO_LONG: i32 = -16;
60
61//
62const ERROR_ONKNOWN: i32 = -98;
63const LIBUSB_ERROR_ONKNOWN: i32 = -99;
64
65// C lib opaque device struct
66enum RTLSDRDev { }
67type RTLSDRDevT = RTLSDRDev;
68
69#[derive(Copy, Clone)]
70pub struct Device {
71    dev: *mut RTLSDRDevT,
72}
73
74unsafe impl Send for Device {}
75unsafe impl Sync for Device {}
76
77// HwInfo holds dongle specific information.
78#[derive(Debug)]
79pub struct HwInfo {
80    pub vendor_id: u16,
81    pub product_id: u16,
82    pub manufact: String,
83    pub product: String,
84    pub serial: String,
85    pub have_serial: bool,
86    pub enable_ir: bool,
87    pub remote_wakeup: bool,
88}
89
90#[derive(Copy, Clone)]
91#[repr(u32)]
92#[derive(Debug)]
93enum RTLSDRTuner {
94    Unknown = 0,
95    E4000 = 1,
96    FC0012 = 2,
97    FC0013 = 3,
98    FC2580 = 4,
99    R820T = 5,
100    R828D = 6,
101}
102
103#[derive(Copy, Clone)]
104#[derive(Debug)]
105pub enum Error {
106    NoError,
107    Io,
108    InvalidParam,
109    Access,
110    NoDevice,
111    NotFound,
112    Busy,
113    Timeout,
114    Overflow,
115    Pipe,
116    Interrupted,
117    NoMem,
118    NotSupported,
119    NoValidEEPROMHeader,
120    StringValueTooLong,
121    StringDescriptorInvalid,
122    StringDescriptorTooLong,
123    Unknown,
124}
125
126
127
128/// read async callback function
129pub type ReadAsyncCbT = Option<unsafe extern "C" fn(buf: *mut c_uchar, len: u32, ctx: *mut c_void)>;
130
131#[link(name = "rtlsdr")]
132extern "C" {
133    fn rtlsdr_get_device_count() -> u32;
134    fn rtlsdr_get_device_name(index: u32) -> *const c_char;
135    fn rtlsdr_get_device_usb_strings(index: u32,
136                                     manufact: *mut c_char,
137                                     product: *mut c_char,
138                                     serial: *mut c_char)
139                                     -> c_int;
140    fn rtlsdr_get_index_by_serial(serial: *const c_char) -> c_int;
141
142    fn rtlsdr_open(dev: *mut *mut RTLSDRDevT, index: u32) -> c_int;
143    fn rtlsdr_close(dev: *mut RTLSDRDevT) -> c_int;
144    fn rtlsdr_set_xtal_freq(dev: *mut RTLSDRDevT, rtl_freq: u32, tuner_freq: u32) -> c_int;
145    fn rtlsdr_get_xtal_freq(dev: *mut RTLSDRDevT,
146                            rtl_freq: *mut u32,
147                            tuner_freq: *mut u32)
148                            -> c_int;
149    fn rtlsdr_get_usb_strings(dev: *mut RTLSDRDevT,
150                              manufact: *mut c_char,
151                              product: *mut c_char,
152                              serial: *mut c_char)
153                              -> c_int;
154    fn rtlsdr_write_eeprom(dev: *mut RTLSDRDevT, data: *mut u8, offset: u8, len: u16) -> c_int;
155    fn rtlsdr_read_eeprom(dev: *mut RTLSDRDevT, data: *mut u8, offset: u8, len: u16) -> c_int;
156    fn rtlsdr_set_center_freq(dev: *mut RTLSDRDevT, freq: u32) -> c_int;
157    fn rtlsdr_get_center_freq(dev: *mut RTLSDRDevT) -> c_int;
158    fn rtlsdr_set_freq_correction(dev: *mut RTLSDRDevT, ppm: c_int) -> c_int;
159    fn rtlsdr_get_freq_correction(dev: *mut RTLSDRDevT) -> c_int;
160    fn rtlsdr_get_tuner_type(dev: *mut RTLSDRDevT) -> RTLSDRTuner;
161    fn rtlsdr_get_tuner_gains(dev: *mut RTLSDRDevT, gains: *mut c_int) -> c_int;
162    fn rtlsdr_set_tuner_gain(dev: *mut RTLSDRDevT, gain: c_int) -> c_int;
163    fn rtlsdr_set_tuner_bandwidth(dev: *mut RTLSDRDevT, bw: u32) -> c_int;
164    fn rtlsdr_get_tuner_gain(dev: *mut RTLSDRDevT) -> c_int;
165    fn rtlsdr_set_tuner_if_gain(dev: *mut RTLSDRDevT, stage: c_int, gain: c_int) -> c_int;
166    fn rtlsdr_set_tuner_gain_mode(dev: *mut RTLSDRDevT, manual: c_int) -> c_int;
167    fn rtlsdr_set_sample_rate(dev: *mut RTLSDRDevT, rate: u32) -> c_int;
168    fn rtlsdr_get_sample_rate(dev: *mut RTLSDRDevT) -> c_int;
169    fn rtlsdr_set_testmode(dev: *mut RTLSDRDevT, on: c_int) -> c_int;
170    fn rtlsdr_set_agc_mode(dev: *mut RTLSDRDevT, on: c_int) -> c_int;
171    fn rtlsdr_set_direct_sampling(dev: *mut RTLSDRDevT, on: c_int) -> c_int;
172    fn rtlsdr_get_direct_sampling(dev: *mut RTLSDRDevT) -> c_int;
173    fn rtlsdr_set_offset_tuning(dev: *mut RTLSDRDevT, on: c_int) -> c_int;
174    fn rtlsdr_get_offset_tuning(dev: *mut RTLSDRDevT) -> c_int;
175    fn rtlsdr_reset_buffer(dev: *mut RTLSDRDevT) -> c_int;
176    fn rtlsdr_read_sync(dev: *mut RTLSDRDevT,
177                        buf: *mut c_void,
178                        len: c_int,
179                        n_read: *mut c_int)
180                        -> c_int;
181    fn rtlsdr_wait_async(dev: *mut RTLSDRDevT, cb: ReadAsyncCbT, ctx: *mut c_void) -> c_int;
182    fn rtlsdr_read_async(dev: *mut RTLSDRDevT,
183                         cb: ReadAsyncCbT,
184                         ctx: *mut c_void,
185                         buf_num: u32,
186                         buf_len: u32)
187                         -> c_int;
188    fn rtlsdr_cancel_async(dev: *mut RTLSDRDevT) -> c_int;
189}
190
191// FIXME: there has to be a better way...
192fn get_err_msg(e: c_int) -> Error {
193    match e {
194        0 => Error::NoError,
195        -1 => Error::Io,
196        -2 => Error::InvalidParam,
197        -3 => Error::Access,
198        -4 => Error::NoDevice,
199        -5 => Error::NotFound,
200        -6 => Error::Busy,
201        -7 => Error::Timeout,
202        -8 => Error::Overflow,
203        -9 => Error::Pipe,
204        -10 => Error::Interrupted,
205        -11 => Error::NoMem,
206        -12 => Error::NotSupported,
207        NO_VALID_EEPROM_HEADER => Error::NoValidEEPROMHeader,
208        STRING_VALUE_TOO_LONG => Error::StringValueTooLong,
209        STRING_DESCRIPTOR_INVALID => Error::StringDescriptorInvalid,
210        STRING__DESCRIPTOR_TOO_LONG => Error::StringDescriptorTooLong,
211        _ => Error::Unknown,
212    }
213}
214
215fn from_tuner_type(t: RTLSDRTuner) -> String {
216    match t {
217        RTLSDRTuner::Unknown => String::from("Unknown"),
218        RTLSDRTuner::E4000 => String::from("E4000"),
219        RTLSDRTuner::FC0012 => String::from("FC0012"),
220        RTLSDRTuner::FC0013 => String::from("FC0013"),
221        RTLSDRTuner::FC2580 => String::from("FC2580"),
222        RTLSDRTuner::R820T => String::from("R820T"),
223        RTLSDRTuner::R828D => String::from("R828D"),
224    }
225}
226
227fn from_pchar(p: *const c_char) -> String {
228    let c_str = unsafe { CStr::from_ptr(p) };
229    String::from(str::from_utf8(c_str.to_bytes()).unwrap())
230}
231
232
233/// Returns the number of devices detected.
234pub fn get_device_count() -> i32 {
235    unsafe { rtlsdr_get_device_count() as i32 }
236}
237
238/// Returns the name of the device by index.
239pub fn get_device_name(index: i32) -> String {
240    unsafe { CStr::from_ptr(rtlsdr_get_device_name(index as u32)).to_string_lossy().into_owned() }
241}
242
243/// Returns the information of a device by index.
244pub fn get_device_usb_strings(index: i32) -> (String, String, String, Error) {
245    unsafe {
246        let m: [c_char; 256] = [0; 256];
247        let p: [c_char; 256] = [0; 256];
248        let s: [c_char; 256] = [0; 256];
249        let err = rtlsdr_get_device_usb_strings(index as u32,
250                                                m.as_ptr() as *mut c_char,
251                                                p.as_ptr() as *mut c_char,
252                                                s.as_ptr() as *mut c_char);
253        (from_pchar(m.as_ptr()), from_pchar(p.as_ptr()), from_pchar(s.as_ptr()), get_err_msg(err))
254    }
255}
256
257/// Returns a device index by serial id.
258pub fn get_index_by_serial(serial: String) -> i32 {
259    unsafe { rtlsdr_get_index_by_serial(serial.as_ptr() as *const c_char) as i32 }
260}
261
262/// Returns an opened device by index.
263pub fn open(index: i32) -> (Arc<Device>, Error) {
264    unsafe {
265        let mut dev: *mut RTLSDRDevT = std::ptr::null_mut();
266        let err = rtlsdr_open(&mut dev as *mut *mut RTLSDRDevT, index as u32);
267        (Arc::new(Device { dev: dev }), get_err_msg(err))
268    }
269}
270
271/// Gets the manufacturer, product, and serial strings from data.
272fn get_string_descriptors(data: &Vec<u8>) -> (String, String, String, Error) {
273    let mut pos = STR_OFFSET_START;
274    let mut strings: Vec<String> = Vec::new();
275
276    for _ in 0..3 {
277        let l = data[pos] as usize;
278        if l > (MAX_STR_SIZE * 2) as usize + 2 {
279            return ("".to_string(),
280                    "".to_string(),
281                    "".to_string(),
282                    get_err_msg(STRING_VALUE_TOO_LONG));
283        }
284        if data[pos + 1] != 0x03 {
285            return ("".to_string(),
286                    "".to_string(),
287                    "".to_string(),
288                    get_err_msg(STRING_DESCRIPTOR_INVALID));
289        }
290
291        let mut j: usize = 2;
292        let mut s = String::new();
293        while j < l {
294            s.push(data[pos + j] as char);
295            j += 2;
296        }
297        strings.push(s);
298        pos += j;
299    }
300    (strings[0].clone(), strings[1].clone(), strings[2].clone(), get_err_msg(0))
301}
302
303/// Sets the manufacturer, product, and serial strings in vec format.
304fn set_string_descriptors(info: &HwInfo, data: &mut Vec<u8>) -> Error {
305    let mlen = info.manufact.len();
306    let plen = info.product.len();
307    let slen = info.serial.len();
308
309    if mlen > MAX_STR_SIZE || plen > MAX_STR_SIZE || slen > MAX_STR_SIZE {
310        return get_err_msg(STRING__DESCRIPTOR_TOO_LONG);
311    }
312
313    let mut pos = STR_OFFSET_START;
314    let strings = [&info.manufact, &info.product, &info.serial];
315    for s in strings.iter() {
316        data[pos] = ((s.len() * 2) + 2) as u8;
317        data[pos + 1] = 0x03u8;
318        pos += 2;
319
320        for b in s.as_bytes().iter() {
321            data[pos] = *b;
322            data[pos + 1] = 0x00u8;
323            pos += 2;
324        }
325    }
326
327    return get_err_msg(0);
328}
329
330impl Device {
331    /// Close the device.
332    pub fn close(&self) -> Error {
333        unsafe { get_err_msg(rtlsdr_close(self.dev)) }
334    }
335
336    /// Sets the crystal oscillator frequencies.
337    ///
338    /// Typically both ICs (rtlsdr and tuner) use the same clock. Changing the
339    /// clock may make sense if you are applying an external clock to the tuner
340    /// or to compensate the frequency (and sample rate) error caused by the
341    /// original (cheap) crystal.
342    ///
343    /// Note, call this function only if you fully understand the implications.
344    pub fn set_xtal_freq(&self, rtl_freq_hz: i32, tuner_freq_hz: i32) -> Error {
345        unsafe {
346            get_err_msg(rtlsdr_set_xtal_freq(self.dev, rtl_freq_hz as u32, tuner_freq_hz as u32))
347        }
348    }
349
350    /// Returns the crystal oscillator frequencies.
351    /// Typically both ICs (rtlsdr and tuner) use the same clock.
352    pub fn get_xtal_freq(&self) -> (i32, i32, Error) {
353        let mut rtl_freq_hz: u32 = 0;
354        let mut tuner_freq_hz: u32 = 0;
355        unsafe {
356            let err = rtlsdr_get_xtal_freq(self.dev,
357                                           &mut rtl_freq_hz as *mut u32,
358                                           &mut tuner_freq_hz as *mut u32);
359            (rtl_freq_hz as i32, tuner_freq_hz as i32, get_err_msg(err))
360        }
361    }
362
363    /// Returns the device information (manufact, product, serial).
364    /// Note, strings may be empty.
365    pub fn get_usb_strings(&self) -> (String, String, String, Error) {
366        let m: [c_char; 256] = [0; 256];
367        let p: [c_char; 256] = [0; 256];
368        let s: [c_char; 256] = [0; 256];
369        unsafe {
370            let err = rtlsdr_get_usb_strings(self.dev,
371                                             m.as_ptr() as *mut c_char,
372                                             p.as_ptr() as *mut c_char,
373                                             s.as_ptr() as *mut c_char);
374            (from_pchar(m.as_ptr()),
375             from_pchar(p.as_ptr()),
376             from_pchar(s.as_ptr()),
377             get_err_msg(err))
378        }
379    }
380
381    /// Writes information data to the EEPROM.
382    pub fn write_eeprom(&self, data: Vec<u8>, offset: u8) -> Error {
383        unsafe {
384            let mut err = rtlsdr_write_eeprom(self.dev,
385                                              data.as_ptr() as *mut u8,
386                                              offset,
387                                              data.len() as u16);
388            if err >= 0 {
389                err = 0;
390            }
391            get_err_msg(err)
392        }
393    }
394
395    /// Returns information data read from the EEPROM.
396    pub fn read_eeprom(&self, offset: u8, len: u16) -> (Vec<u8>, Error) {
397        let mut v = vec![0u8; len as usize];
398        unsafe {
399            let mut err = rtlsdr_read_eeprom(self.dev, v.as_mut_ptr() as *mut u8, offset, len);
400            if err >= 0 {
401                err = 0;
402            }
403            (v, get_err_msg(err))
404        }
405
406    }
407
408    /// Sets the center frequency.
409    pub fn set_center_freq(&self, freq_hz: i32) -> Error {
410        unsafe { get_err_msg(rtlsdr_set_center_freq(self.dev, freq_hz as u32)) }
411    }
412
413    /// Returns the tuned frequency or zero on error.
414    pub fn get_center_freq(&self) -> i32 {
415        unsafe { rtlsdr_get_center_freq(self.dev) as i32 }
416    }
417
418    /// Sets the frequency correction.
419    pub fn set_freq_correction(&self, ppm: i32) -> Error {
420        unsafe { get_err_msg(rtlsdr_set_freq_correction(self.dev, ppm)) }
421    }
422
423    /// Returns the frequency correction value.
424    pub fn get_freq_correction(&self) -> i32 {
425        unsafe { rtlsdr_get_freq_correction(self.dev) }
426    }
427
428    /// Returns the tuner type.
429    pub fn get_tuner_type(&self) -> String {
430        unsafe { from_tuner_type(rtlsdr_get_tuner_type(self.dev)) }
431    }
432
433    /// Returns a list of supported tuner gains.
434    /// Values are in tenths of dB, e.g. 115 means 11.5 dB.
435    pub fn get_tuner_gains(&self) -> (Vec<i32>, Error) {
436        unsafe {
437            let mut i = rtlsdr_get_tuner_gains(self.dev, ptr::null_mut());
438            if i <= 0 {
439                // println!("error rtlsdr_get_tuner_gains <= 0: {}", i);
440                return (Vec::new(), get_err_msg(i));
441            }
442            println!("rtlsdr_get_tuner_gains count: {}", i);
443            let mut v = vec![0; i as usize];
444            i = rtlsdr_get_tuner_gains(self.dev, v.as_mut_ptr());
445            let err = if i <= 0 {
446                Error::Unknown
447            } else {
448                Error::NoError
449            };
450            (v, err)
451        }
452    }
453
454    /// Sets the tuner gain. Note, manual gain mode
455    /// must be enabled for this to work. Valid gain values may be
456    /// queried using get_tuner_gains.
457    ///
458    /// Valid values (in tenths of a dB) are:
459    /// -10, 15, 40, 65, 90, 115, 140, 165, 190, 215, 240, 290,
460    /// 340, 420, 430, 450, 470, 490
461    ///
462    /// Gain values are in tenths of dB, e.g. 115 means 11.5 dB.
463    pub fn set_tuner_gain(&self, gain: i32) -> Error {
464        unsafe { get_err_msg(rtlsdr_set_tuner_gain(self.dev, gain)) }
465    }
466
467    /// Returns the tuner gain.
468    ///
469    /// Gain values are in tenths of dB, e.g. 115 means 11.5 dB.
470    pub fn get_tuner_gain(&self) -> i32 {
471        unsafe { rtlsdr_get_tuner_gain(self.dev) }
472    }
473
474    /// Sets the device bandwidth.
475    pub fn set_tuner_bandwidth(&self, bw_hz: i32) -> Error {
476        unsafe { get_err_msg(rtlsdr_set_tuner_bandwidth(self.dev, bw_hz as u32)) }
477    }
478
479    /// Sets the intermediate frequency gain.
480    ///
481    /// Intermediate frequency gain stage number 1 to 6.
482    /// Gain values are in tenths of dB, e.g. -30 means -3.0 dB.
483    pub fn set_tuner_if_gain(&self, stage: i32, gains_tenths_db: i32) -> Error {
484        unsafe { get_err_msg(rtlsdr_set_tuner_if_gain(self.dev, stage, gains_tenths_db)) }
485
486    }
487
488    /// Sets the gain mode, automatic or manual.
489    /// Manual gain mode must be enabled for the gain setter function to work.
490    pub fn set_tuner_gain_mode(&self, manual_mode: bool) -> Error {
491        unsafe { get_err_msg(rtlsdr_set_tuner_gain_mode(self.dev, manual_mode as i32)) }
492
493    }
494
495    /// Sets the sample rate.
496    ///
497    /// When applicable, the baseband filters are also selected based
498    /// on the requested sample rate.
499    pub fn set_sample_rate(&self, rate_hz: i32) -> Error {
500        unsafe { get_err_msg(rtlsdr_set_sample_rate(self.dev, rate_hz as u32)) }
501    }
502
503    /// Returns the sample rate.
504    pub fn get_sample_rate(&self) -> i32 {
505        unsafe { rtlsdr_get_sample_rate(self.dev) }
506    }
507
508    /// Sets device to test mode.
509    ///
510    /// Test mode returns 8 bit counters instead of samples. Note,
511    /// the counter is generated inside the device.
512    pub fn set_testmode(&self, test_mode: bool) -> Error {
513        unsafe { get_err_msg(rtlsdr_set_testmode(self.dev, test_mode as i32)) }
514    }
515
516    /// Sets the AGC mode.
517    pub fn set_agc_mode(&self, agc_mode: bool) -> Error {
518        unsafe { get_err_msg(rtlsdr_set_agc_mode(self.dev, agc_mode as i32)) }
519    }
520
521    /// Sets the direct sampling mode.
522    ///
523    /// When enabled, the IF mode of the device is activated, and
524    /// set_center_freq() will control the IF-frequency of the DDC, which
525    /// can be used to tune from 0 to 28.8 MHz (xtal frequency of the device).
526    pub fn set_direct_sampling(&self, mode: SamplingMode) -> Error {
527        unsafe { get_err_msg(rtlsdr_set_direct_sampling(self.dev, mode as i32)) }
528    }
529
530    /// Returns the state of direct sampling mode.
531    pub fn get_direct_sampling(&self) -> SamplingMode {
532        unsafe {
533            match rtlsdr_get_direct_sampling(self.dev) {
534                0 => SamplingMode::None,
535                1 => SamplingMode::IADC,
536                2 => SamplingMode::QADC,
537                _ => SamplingMode::Error,
538            }
539        }
540    }
541
542    /// Sets the offset tuning mode for zero-IF tuners, which
543    /// avoids problems caused by the DC offset of the ADCs and 1/f noise.
544    pub fn set_offset_tuning(&self, enable: bool) -> Error {
545        unsafe { get_err_msg(rtlsdr_set_offset_tuning(self.dev, enable as i32)) }
546    }
547
548    /// Returns the offset tuning mode.
549    pub fn get_offset_tuning(&self) -> Error {
550        unsafe { get_err_msg(rtlsdr_get_offset_tuning(self.dev)) }
551    }
552
553    /// Resets the streaming buffer.
554    pub fn reset_buffer(&self) -> Error {
555        unsafe { get_err_msg(rtlsdr_reset_buffer(self.dev)) }
556    }
557
558    /// Performs a synchronous read of samples and returns
559    /// the number of samples read.
560    pub fn read_sync(&self, len: i32) -> (Vec<u8>, i32, Error) {
561        let mut buf = vec![0u8; len as usize];
562        let mut n_read: i32 = 0;
563        unsafe {
564            let err = rtlsdr_read_sync(self.dev,
565                                       buf.as_mut_ptr() as *mut c_void,
566                                       len,
567                                       &mut n_read as *mut c_int);
568            (buf, n_read, get_err_msg(err))
569        }
570
571    }
572
573    /// Reads samples asynchronously. Note, this function will block until
574    /// canceled using cancel_async. ReadAsyncCbT is a package global variable.
575    ///
576    /// Optional buf_num buffer count, buf_num * buf_len = overall buffer size,
577    /// set to 0 for default buffer count of 32.
578    ///
579    /// Optional buf_len buffer length, must be multiple of 512, set to 0 for
580    /// default buffer length of 262,144 (16 * 32 * 512).
581    pub fn read_async(&self,
582                      f: ReadAsyncCbT,
583                      ctx: *mut c_void,
584                      buf_num: i32,
585                      buf_len: i32)
586                      -> Error {
587        unsafe { get_err_msg(rtlsdr_read_async(self.dev, f, ctx, buf_num as u32, buf_len as u32)) }
588    }
589
590    /// Cancels all pending asynchronous operations.
591    pub fn cancel_async(&self) -> Error {
592        unsafe { get_err_msg(rtlsdr_cancel_async(self.dev)) }
593
594    }
595
596    /// Reads the dongle's information items from the EEPROM.
597    pub fn get_hw_info(&self) -> (HwInfo, Error) {
598        let mut have_serial = false;
599        let mut remote_wakeup = false;
600        let mut enable_ir = false;
601        let mut vendor_id = 0u16;
602        let mut product_id = 0u16;
603        let mut m: String = "".to_string();
604        let mut p: String = "".to_string();
605        let mut s: String = "".to_string();
606
607        let (data, mut err) = self.read_eeprom(0, EEPROM_SIZE as u16);
608        // println!("eeprom data: {:?}, error: {:?}", data, err);
609
610        if let Some(Error::NoError) = Some(err) {
611            if (data[0] != 0x28) || (data[1] != 0x32) {
612                err = get_err_msg(NO_VALID_EEPROM_HEADER);
613            } else {
614                vendor_id = (data[3] as u16) << 8 | data[2] as u16;
615                product_id = (data[5] as u16) << 8 | data[4] as u16;
616                // println!("vendor_id {}, product_id {}", vendor_id, product_id);
617
618                if data[6] == 0xA5 {
619                    have_serial = true;
620                }
621                if (data[7] & 0x01) == 0x01 {
622                    remote_wakeup = true;
623                }
624                if (data[7] & 0x02) == 0x02 {
625                    enable_ir = true;
626                }
627
628                let (mm, pp, ss, e) = get_string_descriptors(&data);
629                m = mm;
630                p = pp;
631                s = ss;
632                err = e;
633            }
634        }
635
636        let info = HwInfo {
637            have_serial: have_serial,
638            vendor_id: vendor_id,
639            product_id: product_id,
640            remote_wakeup: remote_wakeup,
641            enable_ir: enable_ir,
642            manufact: m,
643            product: p,
644            serial: s,
645        };
646
647        (info, err)
648    }
649
650    /// Write the dongle's information items to the EEPROM.
651    pub fn set_hw_info(&self, info: &HwInfo) -> Error {
652        let mlen = info.manufact.len();
653        let plen = info.product.len();
654        let slen = info.serial.len();
655        let stored_len = STR_OFFSET_START + ((2 * mlen) + 2) + ((2 * plen) + 2) + ((2 * slen) + 2);
656        let mut data = vec![0u8; stored_len];
657
658        data[0] = 0x28u8;
659        data[1] = 0x32u8;
660        data[2] = info.vendor_id as u8;
661        data[3] = (info.vendor_id >> 8) as u8;
662        data[4] = info.product_id as u8;
663        data[5] = (info.product_id >> 8) as u8;
664
665        if info.have_serial == true {
666            data[6] = 0xA5u8;
667        }
668        if info.remote_wakeup == true {
669            data[7] = data[7] | 0x01;
670        }
671        if info.enable_ir == true {
672            data[7] = data[7] | 0x02;
673        }
674
675        let mut err = set_string_descriptors(&info, &mut data);
676        if let Some(Error::NoError) = Some(err) {
677            err = self.write_eeprom(data, 0);
678        }
679
680        return err;
681    }
682}