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