1#![deny(unsafe_code)]
2
3#![cfg_attr(docsrs, feature(doc_cfg))]
46#![warn(missing_docs)]
47
48mod types;
49
50use futures_lite::future::block_on;
51use log::*;
52use nusb::{
53 DeviceInfo,
54 transfer::{ControlIn, ControlOut, ControlType, Queue, Recipient, RequestBuffer},
55};
56use std::{
57 collections::VecDeque,
58 sync::{Arc, Mutex},
59};
60pub use types::*;
61
62const HACKRF_USB_VID: u16 = 0x1D50;
64const HACKRF_ONE_USB_PID: u16 = 0x6089;
66
67pub struct HackRf {
72 interface: nusb::Interface,
73 version: UsbVersion,
74 inner: Mutex<Inner>,
77}
78
79struct Inner {
80 mode: Mode,
81 streamer_active: bool,
82}
83
84impl Inner {
85 fn ensure_mode(&self, expected: Mode) -> Result<()> {
86 let actual = self.mode;
87 if actual != expected {
88 return Err(Error::WrongMode {
89 required: expected,
90 actual,
91 });
92 }
93 Ok(())
94 }
95}
96
97impl HackRf {
98 pub fn open(info: DeviceInfo) -> Result<Self> {
100 let device = info.open()?;
101
102 let interface = device
103 .detach_and_claim_interface(0)
104 .inspect_err(|e| warn!("detach_and_claim_interface failed: {e:?}"))?;
105
106 let this = HackRf {
107 interface,
108 version: UsbVersion::from_bcd(info.device_version()),
109 inner: Mutex::new(Inner {
110 mode: Mode::Off,
111 streamer_active: false,
112 }),
113 };
114
115 this.stop()?;
116
117 Ok(this)
118 }
119
120 #[cfg(any(target_os = "android", target_os = "linux"))]
124 pub fn from_fd(fd: std::os::fd::OwnedFd) -> Result<Self> {
125 use std::os::fd::AsRawFd;
126
127 info!("Wrapping hackrf fd={}", fd.as_raw_fd());
128 let device = nusb::Device::from_fd(fd)?;
129
130 let interface = device
131 .detach_and_claim_interface(0)
132 .expect("claim interface");
133
134 Ok(HackRf {
135 interface,
136 version: UsbVersion::from_bcd(0x0102),
138 inner: Mutex::new(Inner {
139 mode: Mode::Off,
140 streamer_active: false,
141 }),
142 })
143 }
144
145 pub fn open_first() -> Result<HackRf> {
147 for device in nusb::list_devices()? {
148 if device.vendor_id() == HACKRF_USB_VID && device.product_id() == HACKRF_ONE_USB_PID {
149 match Self::open(device) {
150 Ok(dev) => return Ok(dev),
151 Err(_) => continue,
152 }
153 }
154 }
155
156 Err(Error::NotFound)
157 }
158
159 pub fn scan() -> Result<Vec<(u8, u8)>> {
162 let mut res = vec![];
163 for device in nusb::list_devices()? {
164 if device.vendor_id() == HACKRF_USB_VID && device.product_id() == HACKRF_ONE_USB_PID {
165 res.push((device.bus_number(), device.device_address()));
166 }
167 }
168 Ok(res)
169 }
170
171 pub fn open_bus(bus_number: u8, address: u8) -> Result<HackRf> {
173 for device in nusb::list_devices()? {
174 if device.vendor_id() == HACKRF_USB_VID
175 && device.product_id() == HACKRF_ONE_USB_PID
176 && device.bus_number() == bus_number
177 && device.device_address() == address
178 {
179 return Self::open(device);
180 }
181 }
182
183 Err(Error::NotFound)
184 }
185
186 pub fn reset(self) -> Result<()> {
188 self.check_api_version(UsbVersion::from_bcd(0x0102))?;
189 self.write_control(Request::Reset, 0, 0, &[])?;
190
191 Ok(())
192 }
193
194 pub fn device_version(&self) -> UsbVersion {
196 self.version
197 }
198
199 pub fn board_id(&self) -> Result<u8> {
201 let data: [u8; 1] = self.read_control(Request::BoardIdRead, 0, 0)?;
202 Ok(data[0])
203 }
204
205 pub fn version(&self) -> Result<String> {
207 let buf = block_on(self.interface.control_in(ControlIn {
208 control_type: ControlType::Vendor,
209 recipient: Recipient::Device,
210 request: Request::VersionStringRead as u8,
211 value: 0x0,
212 index: 0x0,
213 length: 64,
214 }))
215 .into_result()?;
216
217 Ok(String::from_utf8_lossy(&buf).into())
218 }
219
220 fn apply_config(&self, config: &Config) -> Result<()> {
221 self.set_lna_gain(config.lna_db)?;
222 self.set_vga_gain(config.vga_db)?;
223 self.set_txvga_gain(config.txvga_db)?;
224 self.set_freq(config.frequency_hz)?;
225 self.set_amp_enable(config.amp_enable)?;
226 self.set_antenna_enable(config.antenna_enable)?;
227 self.set_sample_rate(config.sample_rate_hz, config.sample_rate_div)?;
228
229 Ok(())
230 }
231
232 pub fn start_tx(&self, config: &Config) -> Result<()> {
241 let mut inner = self.inner.lock().unwrap();
242 inner.ensure_mode(Mode::Off)?;
243
244 self.apply_config(config)?;
245
246 self.write_control(Request::SetTransceiverMode, Mode::Transmit as u16, 0, &[])?;
247 inner.mode = Mode::Transmit;
248
249 Ok(())
250 }
251
252 pub fn start_rx(&self, config: &Config) -> Result<()> {
261 let mut inner = self.inner.lock().unwrap();
262 inner.ensure_mode(Mode::Off)?;
263
264 self.apply_config(config)?;
265
266 self.write_control(Request::SetTransceiverMode, Mode::Receive as u16, 0, &[])?;
267 inner.mode = Mode::Receive;
268
269 Ok(())
270 }
271
272 pub fn stop(&self) -> Result<()> {
274 let mut inner = self.inner.lock().unwrap();
275 self.write_control(Request::SetTransceiverMode, Mode::Off as u16, 0, &[])?;
276 inner.mode = Mode::Off;
277
278 Ok(())
279 }
280
281 pub fn read(&self, samples: &mut [u8]) -> Result<usize> {
286 let inner = self.inner.lock().unwrap();
287 inner.ensure_mode(Mode::Receive)?;
288
289 if !samples.len().is_multiple_of(512) {
290 panic!("samples must be a multiple of 512");
291 }
292
293 const ENDPOINT: u8 = 0x81;
294 let buf = block_on(
295 self.interface
296 .bulk_in(ENDPOINT, RequestBuffer::new(samples.len())),
297 )
298 .into_result()?;
299 samples[..buf.len()].copy_from_slice(&buf);
300
301 Ok(buf.len())
302 }
303
304 pub fn write(&self, samples: &[u8]) -> Result<usize> {
309 let inner = self.inner.lock().unwrap();
310 inner.ensure_mode(Mode::Transmit)?;
311
312 if !samples.len().is_multiple_of(512) {
313 panic!("samples must be a multiple of 512");
314 }
315
316 const ENDPOINT: u8 = 0x02;
317 let buf = Vec::from(samples);
318 let n = block_on(self.interface.bulk_out(ENDPOINT, buf)).into_result()?;
320
321 Ok(n.actual_length())
322 }
323
324 pub fn start_rx_stream(self: &Arc<Self>, transfer_size: usize) -> Result<RxStream> {
329 if !transfer_size.is_multiple_of(512) {
330 panic!("transfer_size must be a multiple of 512");
331 }
332
333 let mut inner = self.inner.lock().unwrap();
334 inner.ensure_mode(Mode::Receive)?;
335 if inner.streamer_active {
336 return Err(Error::StreamerExists);
337 }
338 inner.streamer_active = true;
339
340 const ENDPOINT: u8 = 0x81;
341 Ok(RxStream {
342 queue: self.interface.bulk_in_queue(ENDPOINT),
343 in_flight_transfers: 3,
344 transfer_size,
345 buf_pos: transfer_size,
346 buf: vec![0u8; transfer_size],
347 hackrf: Arc::clone(self),
348 })
349 }
350
351 pub fn start_tx_stream(self: &Arc<Self>) -> Result<TxStream> {
356 let mut inner = self.inner.lock().unwrap();
357 inner.ensure_mode(Mode::Transmit)?;
358 if inner.streamer_active {
359 return Err(Error::StreamerExists);
360 }
361 inner.streamer_active = true;
362
363 const ENDPOINT: u8 = 0x02;
364 Ok(TxStream {
365 queue: self.interface.bulk_out_queue(ENDPOINT),
366 in_flight_transfers: 3,
367 expected_length: VecDeque::new(),
368 hackrf: Arc::clone(self),
369 })
370 }
371
372 fn stop_streamer(&self) -> Result<()> {
373 if let Err(e) = self.stop() {
374 warn!("Failed to stop tx: {e:?}");
375 }
376
377 let mut inner = self.inner.lock().unwrap();
378 if !inner.streamer_active {
379 warn!("Streamer not active");
380 }
381 inner.streamer_active = false;
382
383 Ok(())
384 }
385}
386
387pub struct RxStream {
391 queue: Queue<RequestBuffer>,
392 in_flight_transfers: usize,
393 transfer_size: usize,
394 buf_pos: usize,
395 buf: Vec<u8>,
396 hackrf: Arc<HackRf>,
397}
398
399impl RxStream {
400 pub fn read_sync(&mut self, count: usize) -> Result<&[u8]> {
402 let buffered_remaining = self.buf.len() - self.buf_pos;
403 if buffered_remaining > 0 {
404 let to_consume = std::cmp::min(count, buffered_remaining);
405 let ret = &self.buf[self.buf_pos..self.buf_pos + to_consume];
406 self.buf_pos += ret.len();
407 return Ok(ret);
408 }
409
410 while self.queue.pending() < self.in_flight_transfers {
411 self.queue.submit(RequestBuffer::new(self.transfer_size));
412 }
413 let completion = block_on(self.queue.next_complete());
414
415 if let Err(e) = completion.status {
416 return Err(e.into());
417 }
418
419 let reuse = std::mem::replace(&mut self.buf, completion.data);
420 self.buf_pos = 0;
421
422 self.queue
423 .submit(RequestBuffer::reuse(reuse, self.transfer_size));
424
425 self.read_sync(count)
427 }
428}
429
430impl Drop for RxStream {
431 fn drop(&mut self) {
432 if let Err(e) = self.hackrf.stop_streamer() {
433 warn!("Failed to stop streamer in drop: {e:?}");
434 }
435 }
436}
437
438pub struct TxStream {
442 queue: Queue<Vec<u8>>,
443 in_flight_transfers: usize,
444 expected_length: VecDeque<usize>,
445 hackrf: Arc<HackRf>,
446}
447
448impl TxStream {
449 pub fn write_sync(&mut self, bytes: &[u8]) -> Result<()> {
451 let mut buf = if self.queue.pending() < self.in_flight_transfers {
452 Vec::new()
453 } else {
454 let a = block_on(self.queue.next_complete());
455 let expected = self.expected_length.pop_front().unwrap();
456 let actual = a.data.actual_length();
457 if expected != actual {
458 warn!(
459 "Failed to write all bytes to device. Expected: {expected}, wrote: {}",
460 a.data.actual_length(),
461 );
462 return Err(Error::TransferTruncated { actual, expected });
463 }
464 a.into_result()?.reuse()
465 };
466 buf.clear();
467 buf.extend_from_slice(bytes);
468
469 self.queue.submit(buf);
470 self.expected_length.push_back(bytes.len());
471
472 Ok(())
473 }
474}
475
476impl Drop for TxStream {
477 fn drop(&mut self) {
478 if let Err(e) = self.hackrf.stop_streamer() {
479 warn!("Failed to stop streamer in drop: {e:?}");
480 }
481 }
482}
483
484impl Drop for HackRf {
485 fn drop(&mut self) {
486 if let Err(e) = self.stop() {
487 warn!("Failed to stop tx: {e:?}");
488 }
489 }
490}
491
492impl HackRf {
493 fn read_control<const N: usize>(
494 &self,
495 request: Request,
496 value: u16,
497 index: u16,
498 ) -> Result<[u8; N]> {
499 let mut res: [u8; N] = [0; N];
500 let buf = block_on(self.interface.control_in(ControlIn {
501 control_type: ControlType::Vendor,
502 recipient: Recipient::Device,
503 request: request as u8,
504 value,
505 index,
506 length: N as u16,
507 }))
508 .into_result()?;
509
510 if buf.len() != N {
511 return Err(Error::TransferTruncated {
512 actual: buf.len(),
513 expected: N,
514 });
515 }
516
517 res.copy_from_slice(&buf);
518 Ok(res)
519 }
520
521 fn write_control(&self, request: Request, value: u16, index: u16, buf: &[u8]) -> Result<()> {
522 let out = block_on(self.interface.control_out(ControlOut {
523 control_type: ControlType::Vendor,
524 recipient: Recipient::Device,
525 request: request as u8,
526 value,
527 index,
528 data: buf,
529 }))
530 .into_result()?;
531
532 if out.actual_length() != buf.len() {
533 Err(Error::TransferTruncated {
534 actual: out.actual_length(),
535 expected: buf.len(),
536 })
537 } else {
538 Ok(())
539 }
540 }
541
542 fn check_api_version(&self, min: UsbVersion) -> Result<()> {
543 fn version_to_u32(v: UsbVersion) -> u32 {
544 ((v.major() as u32) << 16) | ((v.minor() as u32) << 8) | (v.sub_minor() as u32)
545 }
546
547 if version_to_u32(self.version) >= version_to_u32(min) {
548 Ok(())
549 } else {
550 Err(Error::NoApi {
551 device: self.version,
552 min,
553 })
554 }
555 }
556
557 pub fn set_freq(&self, hz: u64) -> Result<()> {
559 let buf: [u8; 8] = freq_params(hz);
560 self.write_control(Request::SetFreq, 0, 0, &buf)
561 }
562
563 pub fn set_amp_enable(&self, enable: bool) -> Result<()> {
568 self.write_control(Request::AmpEnable, enable.into(), 0, &[])
569 }
570
571 pub fn set_baseband_filter_bandwidth(&self, hz: u32) -> Result<()> {
576 self.write_control(
577 Request::BasebandFilterBandwidthSet,
578 (hz & 0xFFFF) as u16,
579 (hz >> 16) as u16,
580 &[],
581 )
582 }
583
584 pub fn set_sample_rate(&self, hz: u32, div: u32) -> Result<()> {
595 let hz: u32 = hz.to_le();
596 let div: u32 = div.to_le();
597 let buf: [u8; 8] = [
598 (hz & 0xFF) as u8,
599 ((hz >> 8) & 0xFF) as u8,
600 ((hz >> 16) & 0xFF) as u8,
601 ((hz >> 24) & 0xFF) as u8,
602 (div & 0xFF) as u8,
603 ((div >> 8) & 0xFF) as u8,
604 ((div >> 16) & 0xFF) as u8,
605 ((div >> 24) & 0xFF) as u8,
606 ];
607 self.write_control(Request::SampleRateSet, 0, 0, &buf)?;
608 self.set_baseband_filter_bandwidth((0.75 * (hz as f32) / (div as f32)) as u32)
609 }
610
611 pub fn set_lna_gain(&self, gain: u16) -> Result<()> {
617 if gain > 40 {
618 Err(Error::Argument("lna gain must be less than 40"))
619 } else {
620 let buf: [u8; 1] = self.read_control(Request::SetLnaGain, 0, gain & !0x07)?;
621 if buf[0] == 0 {
622 panic!("Unexpected return value from read_control(SetLnaGain)");
623 } else {
624 Ok(())
625 }
626 }
627 }
628
629 pub fn set_vga_gain(&self, gain: u16) -> Result<()> {
635 if gain > 62 || gain % 2 == 1 {
636 Err(Error::Argument(
637 "gain parameter out of range. must be even and less than or equal to 62",
638 ))
639 } else {
640 let buf: [u8; 1] = self.read_control(Request::SetVgaGain, 0, gain & !0b1)?;
641 if buf[0] == 0 {
642 panic!("What is this return value?")
643 } else {
644 Ok(())
645 }
646 }
647 }
648
649 pub fn set_txvga_gain(&self, gain: u16) -> Result<()> {
653 if gain > 47 {
654 Err(Error::Argument("gain parameter out of range. max is 47"))
655 } else {
656 let buf: [u8; 1] = self.read_control(Request::SetTxvgaGain, 0, gain)?;
657 if buf[0] == 0 {
658 panic!("What is this return value?")
659 } else {
660 Ok(())
661 }
662 }
663 }
664
665 pub fn set_antenna_enable(&self, value: bool) -> Result<()> {
669 let value = if value { 1 } else { 0 };
670 self.write_control(Request::AntennaEnable, value, 0, &[])
671 }
672}
673
674fn freq_params(hz: u64) -> [u8; 8] {
676 const MHZ: u64 = 1_000_000;
677
678 let l_freq_mhz: u32 = u32::try_from(hz / MHZ).unwrap_or(u32::MAX).to_le();
679 let l_freq_hz: u32 = u32::try_from(hz - u64::from(l_freq_mhz) * MHZ)
680 .unwrap_or(u32::MAX)
681 .to_le();
682
683 [
684 (l_freq_mhz & 0xFF) as u8,
685 ((l_freq_mhz >> 8) & 0xFF) as u8,
686 ((l_freq_mhz >> 16) & 0xFF) as u8,
687 ((l_freq_mhz >> 24) & 0xFF) as u8,
688 (l_freq_hz & 0xFF) as u8,
689 ((l_freq_hz >> 8) & 0xFF) as u8,
690 ((l_freq_hz >> 16) & 0xFF) as u8,
691 ((l_freq_hz >> 24) & 0xFF) as u8,
692 ]
693}
694
695#[cfg(test)]
696mod test {
697 use std::time::Duration;
698
699 use super::*;
700
701 #[test]
702 fn test_freq_params() {
703 assert_eq!(freq_params(915_000_000), [0x93, 0x03, 0, 0, 0, 0, 0, 0]);
704 assert_eq!(freq_params(915_000_001), [0x93, 0x03, 0, 0, 1, 0, 0, 0]);
705 assert_eq!(
706 freq_params(123456789),
707 [0x7B, 0, 0, 0, 0x55, 0xF8, 0x06, 0x00]
708 );
709
710 assert_eq!(freq_params(0), [0; 8]);
711
712 assert_eq!(freq_params(u64::MAX), [0xFF; 8]);
713 }
714
715 #[allow(dead_code)]
719 fn device_states() {
720 let radio = HackRf::open_first().expect("Failed to open hackrf");
721
722 radio
723 .start_tx(&Config {
724 vga_db: 0,
725 txvga_db: 0,
726 lna_db: 0,
727 amp_enable: false,
728 antenna_enable: false,
729 frequency_hz: 915_000_000,
730 sample_rate_hz: 2_000_000,
731 sample_rate_div: 1,
732 })
733 .unwrap();
734 std::thread::sleep(Duration::from_millis(50));
735
736 radio.stop().unwrap();
737 assert!(radio.stop().is_err());
738 assert!(radio.stop().is_err());
739 assert!(radio.stop().is_err());
740 assert!(radio.stop().is_err());
741
742 std::thread::sleep(Duration::from_millis(50));
743
744 radio
745 .start_rx(&Config {
746 vga_db: 0,
747 txvga_db: 0,
748 lna_db: 0,
749 amp_enable: false,
750 antenna_enable: false,
751 frequency_hz: 915_000_000,
752 sample_rate_hz: 2_000_000,
753 sample_rate_div: 1,
754 })
755 .unwrap();
756 std::thread::sleep(Duration::from_millis(50));
757
758 radio.stop().unwrap();
759 assert!(radio.stop().is_err());
760 assert!(radio.stop().is_err());
761 assert!(radio.stop().is_err());
762 assert!(radio.stop().is_err());
763 }
764}