1extern crate num;
6
7use std::ffi::CStr;
8use std::result;
9use std::str;
10use std::sync::mpsc::Sender;
11use num::Complex;
12
13mod ffi;
14
15pub struct Airspy {
17 ptr: *mut ffi::airspy_device
18}
19
20impl Drop for Airspy {
22 #[inline(never)]
23 fn drop(&mut self) {
24 unsafe { ffi::airspy_close(self.ptr); }
25 }
26}
27
28pub struct LibVersion {
30 pub major: u32,
31 pub minor: u32,
32 pub revision: u32
33}
34
35pub struct PartID {
37 pub part_id: [u32; 2],
38 pub serial_no: u64
39}
40
41pub type IQ<T> = Complex<T>;
43
44pub type Real<T> = T;
46
47pub trait SampleType: Clone { fn get_type() -> ffi::airspy_sample_type; }
50impl SampleType for IQ<f32> { fn get_type() -> ffi::airspy_sample_type {
51 ffi::airspy_sample_type::AIRSPY_SAMPLE_FLOAT32_IQ } }
52impl SampleType for IQ<i16> { fn get_type() -> ffi::airspy_sample_type {
53 ffi::airspy_sample_type::AIRSPY_SAMPLE_INT16_IQ } }
54impl SampleType for Real<f32> { fn get_type() -> ffi::airspy_sample_type {
55 ffi::airspy_sample_type::AIRSPY_SAMPLE_FLOAT32_REAL } }
56impl SampleType for Real<i16> { fn get_type() -> ffi::airspy_sample_type {
57 ffi::airspy_sample_type::AIRSPY_SAMPLE_INT16_REAL } }
58impl SampleType for Real<u16> { fn get_type() -> ffi::airspy_sample_type {
59 ffi::airspy_sample_type::AIRSPY_SAMPLE_UINT16_REAL } }
60
61pub enum GPIOPort {
63 Port0, Port1, Port2, Port3, Port4, Port5, Port6, Port7
64}
65
66pub enum GPIOPin {
68 Pin0, Pin1, Pin2, Pin3, Pin4, Pin5, Pin6, Pin7,
69 Pin8, Pin9, Pin10, Pin11, Pin12, Pin13, Pin14, Pin15,
70 Pin16, Pin17, Pin18, Pin19, Pin20, Pin21, Pin22, Pin23,
71 Pin24, Pin25, Pin26, Pin27, Pin28, Pin29, Pin30, Pin31
72}
73
74pub enum GPIODirection {
76 Input, Output
77}
78
79#[derive(Debug)]
81pub struct FFIError {
82 errno: ffi::airspy_error
83}
84
85impl FFIError {
86 fn new(err: ffi::airspy_error) -> FFIError {
87 FFIError { errno: err }
88 }
89
90 fn errstr(&self) -> &str {
91 let cstr = unsafe {
92 CStr::from_ptr(ffi::airspy_error_name(self.errno))
93 };
94 str::from_utf8(cstr.to_bytes()).unwrap()
95 }
96}
97
98impl std::fmt::Display for FFIError {
99 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
100 write!(f, "Airspy Error: {}", self.errstr())
101 }
102}
103
104impl std::error::Error for FFIError {
105 fn description(&self) -> &str {
106 self.errstr()
107 }
108}
109
110pub type Result<T> = result::Result<T, FFIError>;
112
113pub fn lib_version() -> LibVersion {
115 let mut v = ffi::airspy_lib_version_t {
116 major_version: 0, minor_version: 0, revision: 0};
117 unsafe { ffi::airspy_lib_version(&mut v); }
118
119 LibVersion {
120 major: v.major_version, minor: v.minor_version, revision: v.revision}
121}
122
123macro_rules! ffifn {
124 ($f:expr, $r:expr) => (
125 match unsafe { $f } {
126 ffi::airspy_error::AIRSPY_SUCCESS => Ok($r),
127 err => Err(FFIError::new(err))
128 }
129 );
130 ($f:expr) => (
131 ffifn!($f, ())
132 );
133}
134
135extern fn rx_cb<T>(transfer: *mut ffi::airspy_transfer_t) -> ffi::c_int
138 where T: SampleType
139{
140 let transfer = unsafe { &*transfer };
141 let sample_count = transfer.sample_count as usize;
142 let buffer = unsafe {
143 std::slice::from_raw_parts(transfer.samples as *const T, sample_count)
144 }.to_vec();
145
146 let sender: &Sender<Vec<T>> = unsafe { &*(transfer.ctx as *const _)};
149 match sender.send(buffer) {
150 Ok(_) => 0,
151 Err(_) => {
152 let boxed: Box<Sender<Vec<T>>> = unsafe {
155 std::mem::transmute(transfer.ctx as *const _) };
156 std::mem::drop(boxed);
157 1
158 }
159 }
160}
161
162
163pub fn init() -> Result<()> {
165 ffifn!(ffi::airspy_init())
166}
167
168pub fn exit() -> Result<()> {
170 ffifn!(ffi::airspy_exit())
171}
172
173impl Airspy {
174 pub fn new() -> Result<Airspy> {
176 let mut device: Airspy = Airspy{ ptr: unsafe { std::mem::zeroed() }};
177 ffifn!(ffi::airspy_open(&mut device.ptr), device)
178 }
179
180 pub fn from_serial(serial_number: u64) -> Result<Airspy> {
182 let mut device: Airspy = Airspy{ ptr: unsafe { std::mem::zeroed() }};
183 ffifn!(ffi::airspy_open_sn(&mut device.ptr, serial_number), device)
184 }
185
186 pub fn get_sample_rates(&mut self) -> Result<Vec<u32>> {
188 let mut len: u32 = 0;
189 let lenp = &mut len as *mut u32;
190 try!(ffifn!(ffi::airspy_get_samplerates(self.ptr, lenp, 0)));
191 let mut rates: Vec<u32> = Vec::with_capacity(len as usize);
192 let ratesp = rates.as_mut_ptr();
193 try!(ffifn!(ffi::airspy_get_samplerates(self.ptr, ratesp, len)));
194 unsafe { rates.set_len(len as usize); }
195 Ok(rates)
196 }
197
198 pub fn set_sample_rate(&mut self, target_rate: u32) -> Result<()> {
202 let rates = try!(self.get_sample_rates());
203 for (idx, rate) in rates.iter().enumerate() {
204 if *rate == target_rate {
205 return ffifn!(ffi::airspy_set_samplerate(
206 self.ptr, idx as u32));
207 }
208 }
209 Err(FFIError::new(ffi::airspy_error::AIRSPY_ERROR_INVALID_PARAM))
210 }
211
212 pub fn start_rx<T>(&mut self, sender: Sender<Vec<T>>) -> Result<()>
221 where T: SampleType
222 {
223 try!(ffifn!(ffi::airspy_set_sample_type(self.ptr, T::get_type())));
225
226 let boxed_sender = Box::new(sender);
228 let ctx = &*boxed_sender as *const _ as *mut ffi::c_void;
229
230 std::mem::forget(boxed_sender);
232
233 ffifn!(ffi::airspy_start_rx(self.ptr, rx_cb::<T>, ctx))
235 }
236
237 pub fn is_streaming(&mut self) -> bool {
239 unsafe { ffi::airspy_is_streaming(self.ptr) == 1 }
240 }
241
242 pub fn si5351c_write(&mut self, register: u8, value: u8) -> Result<()> {
244 ffifn!(ffi::airspy_si5351c_write(self.ptr, register, value))
245 }
246
247 pub fn si5351c_read(&mut self, register: u8) -> Result<u8> {
249 let mut val: u8 = 0;
250 try!(ffifn!(ffi::airspy_si5351c_read(
251 self.ptr, register, &mut val as *mut u8)));
252 Ok(val)
253 }
254
255 pub fn r820t_write(&mut self, register: u8, value: u8) -> Result<()> {
257 ffifn!(ffi::airspy_r820t_write(self.ptr, register, value))
258 }
259
260 pub fn r820t_read(&mut self, register: u8) -> Result<u8> {
262 let mut val: u8 = 0;
263 try!(ffifn!(ffi::airspy_r820t_read(
264 self.ptr, register, &mut val as *mut u8)));
265 Ok(val)
266 }
267
268 fn map_gpio_port_pin(port: GPIOPort, pin: GPIOPin)
269 -> (ffi::airspy_gpio_port_t, ffi::airspy_gpio_pin_t) {
270 (match port {
271 GPIOPort::Port0 => ffi::airspy_gpio_port_t::GPIO_PORT0,
272 GPIOPort::Port1 => ffi::airspy_gpio_port_t::GPIO_PORT1,
273 GPIOPort::Port2 => ffi::airspy_gpio_port_t::GPIO_PORT2,
274 GPIOPort::Port3 => ffi::airspy_gpio_port_t::GPIO_PORT3,
275 GPIOPort::Port4 => ffi::airspy_gpio_port_t::GPIO_PORT4,
276 GPIOPort::Port5 => ffi::airspy_gpio_port_t::GPIO_PORT5,
277 GPIOPort::Port6 => ffi::airspy_gpio_port_t::GPIO_PORT6,
278 GPIOPort::Port7 => ffi::airspy_gpio_port_t::GPIO_PORT7,
279 }, match pin {
280 GPIOPin::Pin0 => ffi::airspy_gpio_pin_t::GPIO_PIN0,
281 GPIOPin::Pin1 => ffi::airspy_gpio_pin_t::GPIO_PIN1,
282 GPIOPin::Pin2 => ffi::airspy_gpio_pin_t::GPIO_PIN2,
283 GPIOPin::Pin3 => ffi::airspy_gpio_pin_t::GPIO_PIN3,
284 GPIOPin::Pin4 => ffi::airspy_gpio_pin_t::GPIO_PIN4,
285 GPIOPin::Pin5 => ffi::airspy_gpio_pin_t::GPIO_PIN5,
286 GPIOPin::Pin6 => ffi::airspy_gpio_pin_t::GPIO_PIN6,
287 GPIOPin::Pin7 => ffi::airspy_gpio_pin_t::GPIO_PIN7,
288 GPIOPin::Pin8 => ffi::airspy_gpio_pin_t::GPIO_PIN8,
289 GPIOPin::Pin9 => ffi::airspy_gpio_pin_t::GPIO_PIN9,
290 GPIOPin::Pin10 => ffi::airspy_gpio_pin_t::GPIO_PIN10,
291 GPIOPin::Pin11 => ffi::airspy_gpio_pin_t::GPIO_PIN11,
292 GPIOPin::Pin12 => ffi::airspy_gpio_pin_t::GPIO_PIN12,
293 GPIOPin::Pin13 => ffi::airspy_gpio_pin_t::GPIO_PIN13,
294 GPIOPin::Pin14 => ffi::airspy_gpio_pin_t::GPIO_PIN14,
295 GPIOPin::Pin15 => ffi::airspy_gpio_pin_t::GPIO_PIN15,
296 GPIOPin::Pin16 => ffi::airspy_gpio_pin_t::GPIO_PIN16,
297 GPIOPin::Pin17 => ffi::airspy_gpio_pin_t::GPIO_PIN17,
298 GPIOPin::Pin18 => ffi::airspy_gpio_pin_t::GPIO_PIN18,
299 GPIOPin::Pin19 => ffi::airspy_gpio_pin_t::GPIO_PIN19,
300 GPIOPin::Pin20 => ffi::airspy_gpio_pin_t::GPIO_PIN20,
301 GPIOPin::Pin21 => ffi::airspy_gpio_pin_t::GPIO_PIN21,
302 GPIOPin::Pin22 => ffi::airspy_gpio_pin_t::GPIO_PIN22,
303 GPIOPin::Pin23 => ffi::airspy_gpio_pin_t::GPIO_PIN23,
304 GPIOPin::Pin24 => ffi::airspy_gpio_pin_t::GPIO_PIN24,
305 GPIOPin::Pin25 => ffi::airspy_gpio_pin_t::GPIO_PIN25,
306 GPIOPin::Pin26 => ffi::airspy_gpio_pin_t::GPIO_PIN26,
307 GPIOPin::Pin27 => ffi::airspy_gpio_pin_t::GPIO_PIN27,
308 GPIOPin::Pin28 => ffi::airspy_gpio_pin_t::GPIO_PIN28,
309 GPIOPin::Pin29 => ffi::airspy_gpio_pin_t::GPIO_PIN29,
310 GPIOPin::Pin30 => ffi::airspy_gpio_pin_t::GPIO_PIN30,
311 GPIOPin::Pin31 => ffi::airspy_gpio_pin_t::GPIO_PIN31,
312 })
313 }
314
315 pub fn gpio_write(&mut self, port: GPIOPort, pin: GPIOPin, val: bool)
317 -> Result<()>
318 {
319 let (port, pin) = Airspy::map_gpio_port_pin(port, pin);
320 ffifn!(ffi::airspy_gpio_write(self.ptr, port, pin, val as u8))
321 }
322
323 pub fn gpio_read(&mut self, port: GPIOPort, pin: GPIOPin) -> Result<bool> {
325 let mut val: u8 = 0;
326 let (port, pin) = Airspy::map_gpio_port_pin(port, pin);
327 try!(ffifn!(ffi::airspy_gpio_read(
328 self.ptr, port, pin, &mut val as *mut u8)));
329 Ok(match val {
330 0 => false,
331 1 => true,
332 _ => unreachable!()
333 })
334 }
335
336 pub fn gpio_set_direction(&mut self, port: GPIOPort, pin: GPIOPin,
338 dir: GPIODirection) -> Result<()>
339 {
340 let (port, pin) = Airspy::map_gpio_port_pin(port, pin);
341 let dir: u8 = match dir {
342 GPIODirection::Input => 0,
343 GPIODirection::Output => 1
344 };
345 ffifn!(ffi::airspy_gpiodir_write(self.ptr, port, pin, dir))
346 }
347
348 pub fn gpio_get_direction(&mut self, port: GPIOPort, pin: GPIOPin)
350 -> Result<GPIODirection>
351 {
352 let mut dir: u8 = 0;
353 let (port, pin) = Airspy::map_gpio_port_pin(port, pin);
354 try!(ffifn!(ffi::airspy_gpiodir_read(
355 self.ptr, port, pin, &mut dir as *mut u8)));
356 Ok(match dir {
357 0 => GPIODirection::Input,
358 1 => GPIODirection::Output,
359 _ => unreachable!()
360 })
361 }
362
363 pub fn get_board_id(&mut self) -> Result<&str> {
365 let mut id: u8 = 0;
366 try!(ffifn!(ffi::airspy_board_id_read(self.ptr, &mut id as *mut u8)));
367 let cstr = unsafe {
368 CStr::from_ptr(ffi::airspy_board_id_name(id))
369 };
370 Ok(str::from_utf8(cstr.to_bytes()).unwrap())
371 }
372
373 pub fn get_version(&mut self) -> Result<String> {
375 let mut buf: Vec<i8> = Vec::with_capacity(255);
376 let bufp = buf.as_mut_ptr();
377 try!(ffifn!(ffi::airspy_version_string_read(self.ptr, bufp, 255)));
378 let cstr = unsafe { CStr::from_ptr(buf.as_ptr()) };
379 Ok(String::from(str::from_utf8(cstr.to_bytes()).unwrap()))
380 }
381
382 pub fn get_partid_serial(&mut self) -> Result<PartID> {
384 let mut v = ffi::airspy_read_partid_serialno_t {
385 part_id: [0u32; 2],
386 serial_no: [0u32; 4]
387 };
388 try!(ffifn!(ffi::airspy_board_partid_serialno_read(self.ptr, &mut v)));
389 Ok(PartID {
390 part_id: v.part_id,
391 serial_no: (v.serial_no[2] as u64) << 32 | v.serial_no[3] as u64
392 })
393 }
394
395 pub fn set_freq(&mut self, freq: u32) -> Result<()> {
397 ffifn!(ffi::airspy_set_freq(self.ptr, freq))
398 }
399
400 pub fn set_lna_gain(&mut self, gain: u8) -> Result<()> {
402 ffifn!(ffi::airspy_set_lna_gain(self.ptr, gain))
403 }
404
405 pub fn set_mixer_gain(&mut self, gain: u8) -> Result<()> {
407 ffifn!(ffi::airspy_set_mixer_gain(self.ptr, gain))
408 }
409
410 pub fn set_vga_gain(&mut self, gain: u8) -> Result<()> {
412 ffifn!(ffi::airspy_set_vga_gain(self.ptr, gain))
413 }
414
415 pub fn set_lna_agc(&mut self, enable: bool) -> Result<()> {
417 ffifn!(ffi::airspy_set_lna_agc(self.ptr, enable as u8))
418 }
419
420 pub fn set_mixer_agc(&mut self, enable: bool) -> Result<()> {
422 ffifn!(ffi::airspy_set_mixer_agc(self.ptr, enable as u8))
423 }
424
425 pub fn set_rf_bias(&mut self, enable: bool) -> Result<()> {
427 ffifn!(ffi::airspy_set_rf_bias(self.ptr, enable as u8))
428 }
429}
430
431#[cfg(test)]
432mod tests {
433 use super::*;
434
435 #[test]
436 fn test_lib_version() {
437 let v = lib_version();
438 assert!(v.major == 1);
439 assert!(v.minor == 0);
440 assert!(v.revision >= 6);
441 }
442
443 #[test]
444 fn test_init() {
445 assert!(init().is_ok());
446 let _ = exit();
447 }
448
449 #[test]
450 fn test_exit() {
451 let _ = init();
452 assert!(exit().is_ok());
453 }
454
455 #[test]
456 fn test_new() {
457 let _ = init();
458 let airspy = Airspy::new();
459 assert!(airspy.is_ok());
460 let _ = exit();
461 }
462
463 #[test]
464 fn test_from_serial() {
465 let _ = init();
466 let mut serial: u64;
467 {
468 let mut airspy = Airspy::new().unwrap();
469 let v = airspy.get_partid_serial().unwrap();
470 serial = v.serial_no;
471 }
472 let airspy = Airspy::from_serial(serial);
473 assert!(airspy.is_ok());
474 let _ = exit();
475 }
476
477 #[test]
478 fn test_get_sample_rates() {
479 let _ = init();
480 let mut airspy = Airspy::new().unwrap();
481 let rates = airspy.get_sample_rates();
482 assert!(rates.is_ok());
483 let rates = rates.unwrap();
484 assert!(rates.len() == 2);
485 assert!(rates.contains(&2500000));
486 assert!(rates.contains(&10000000));
487 let _ = exit();
488 }
489
490 #[test]
491 fn test_set_sample_rate() {
492 let _ = init();
493 let mut airspy = Airspy::new().unwrap();
494 assert!(airspy.set_sample_rate(10_000_000).is_ok());
495 }
496
497 #[test]
498 fn test_start_rx() {
499 let _ = init();
500 let mut airspy = Airspy::new().unwrap();
501 let (tx, _) = ::std::sync::mpsc::channel();
502 assert!(airspy.start_rx::<IQ<f32>>(tx).is_ok());
503 }
504
505 #[test]
506 fn test_is_streaming() {
507 let _ = init();
508 let mut airspy = Airspy::new().unwrap();
509 assert!(airspy.is_streaming() == false);
510 }
511
512 #[test]
513 fn test_si5351c_read() {
514 let mut airspy = Airspy::new().unwrap();
515 assert!(airspy.si5351c_read(16).is_ok());
516 }
517
518 #[test]
519 fn test_si5351c_write() {
520 let mut airspy = Airspy::new().unwrap();
521 let val = airspy.si5351c_read(16).unwrap();
522 assert!(airspy.si5351c_write(16, val).is_ok());
523 }
524
525 #[test]
526 fn test_r820t_read() {
527 let mut airspy = Airspy::new().unwrap();
528 assert!(airspy.r820t_read(0x0F).is_ok());
529 }
530
531 #[test]
532 fn test_r820t_write() {
533 let mut airspy = Airspy::new().unwrap();
534 let val = airspy.r820t_read(0x0F).unwrap();
535 assert!(airspy.r820t_write(0x0F, val).is_ok());
536 }
537
538 #[test]
539 fn test_gpio_read() {
540 let mut airspy = Airspy::new().unwrap();
541 assert!(airspy.gpio_read(GPIOPort::Port0, GPIOPin::Pin0).is_ok());
542 }
543
544 #[test]
545 fn test_gpio_write() {
546 let mut airspy = Airspy::new().unwrap();
547 let val = airspy.gpio_read(GPIOPort::Port0, GPIOPin::Pin0).unwrap();
548 assert!(airspy.gpio_write(
549 GPIOPort::Port0, GPIOPin::Pin0, val).is_ok());
550 }
551
552 #[test]
553 fn test_gpio_get_dir() {
554 let mut airspy = Airspy::new().unwrap();
555 assert!(airspy.gpio_get_direction(
556 GPIOPort::Port0, GPIOPin::Pin0).is_ok());
557 }
558
559 #[test]
560 fn test_gpio_set_dir() {
561 let mut airspy = Airspy::new().unwrap();
562 let dir = airspy.gpio_get_direction(
563 GPIOPort::Port0, GPIOPin::Pin0).unwrap();
564 assert!(airspy.gpio_set_direction(
565 GPIOPort::Port0, GPIOPin::Pin0, dir).is_ok());
566 }
567
568 #[test]
569 fn test_get_board() {
570 let _ = init();
571 let mut airspy = Airspy::new().unwrap();
572 assert!(airspy.get_board_id().unwrap() == "AIRSPY");
573 }
574
575 #[test]
576 fn test_get_version() {
577 let _ = init();
578 let mut airspy = Airspy::new().unwrap();
579 assert!(airspy.get_version().is_ok());
580 }
582
583 #[test]
584 fn test_get_partid_serial() {
585 let _ = init();
586 let mut airspy = Airspy::new().unwrap();
587 assert!(airspy.get_partid_serial().is_ok());
588 }
590
591 #[test]
592 fn test_set_freq() {
593 let _ = init();
594 let mut airspy = Airspy::new().unwrap();
595 assert!(airspy.set_freq(434000000).is_ok());
596 }
597
598 #[test]
599 fn test_set_lna_gain() {
600 let _ = init();
601 let mut airspy = Airspy::new().unwrap();
602 assert!(airspy.set_lna_gain(7).is_ok());
603 }
604
605 #[test]
606 fn test_set_mixer_gain() {
607 let _ = init();
608 let mut airspy = Airspy::new().unwrap();
609 assert!(airspy.set_mixer_gain(7).is_ok());
610 }
611
612 #[test]
613 fn test_set_vga_gain() {
614 let _ = init();
615 let mut airspy = Airspy::new().unwrap();
616 assert!(airspy.set_vga_gain(7).is_ok());
617 }
618
619 #[test]
620 fn test_set_lna_agc() {
621 let _ = init();
622 let mut airspy = Airspy::new().unwrap();
623 assert!(airspy.set_lna_agc(true).is_ok());
624 }
625
626 #[test]
627 fn test_set_mixer_agc() {
628 let _ = init();
629 let mut airspy = Airspy::new().unwrap();
630 assert!(airspy.set_mixer_agc(true).is_ok());
631 }
632
633 #[test]
634 fn test_set_rf_bias() {
635 let _ = init();
636 let mut airspy = Airspy::new().unwrap();
637 assert!(airspy.set_rf_bias(true).is_ok());
638 }
639}