use nusb::transfer::{ControlOut, ControlType, Recipient, RequestBuffer};
use crate::{
Buffer, Error, HackRf, baseband_filter_bw,
consts::{ControlRequest, TransceiverMode},
error::StateChangeError,
};
pub struct SweepParams {
pub sample_rate_hz: u32,
pub freq_mhz: Vec<(u16, u16)>,
pub blocks_per_tuning: u16,
pub step_width_hz: u32,
pub offset_hz: u32,
pub mode: SweepMode,
}
impl SweepParams {
pub fn init_sample_rate(sample_rate_hz: u32) -> Self {
let filter_bw = baseband_filter_bw(sample_rate_hz * 3 / 4);
let offset_hz = filter_bw / 2;
let step_width_hz = filter_bw * 4 / 3;
Self {
sample_rate_hz,
freq_mhz: Vec::new(),
blocks_per_tuning: 1,
step_width_hz,
offset_hz,
mode: SweepMode::Interleaved,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SweepMode {
Linear,
Interleaved,
}
const SWEEP_BUF_SIZE: usize = 16384;
pub struct SweepBuf {
freq_hz: u64,
buf: Buffer,
}
impl SweepBuf {
pub fn freq_hz(&self) -> u64 {
self.freq_hz
}
pub fn samples(&self) -> &[num_complex::Complex<i8>] {
unsafe { self.buf.samples().get_unchecked(5..) }
}
pub fn samples_mut(&mut self) -> &mut [num_complex::Complex<i8>] {
unsafe { self.buf.samples_mut().get_unchecked_mut(5..) }
}
fn parse(buf: Buffer) -> Result<Self, Error> {
let bytes = buf.bytes();
if bytes.len() != SWEEP_BUF_SIZE {
return Err(Error::ReturnData);
}
let header: &[u8; 2] = unsafe { &*(bytes.as_ptr() as *const [u8; 2]) };
let freq: [u8; 8] = unsafe { *(bytes.as_ptr().add(2) as *const [u8; 8]) };
if header != &[0x7f, 0x7f] {
return Err(Error::ReturnData);
}
let freq_hz = u64::from_le_bytes(freq);
if !(100_000..=7_100_000_000).contains(&freq_hz) {
return Err(Error::ReturnData);
}
Ok(Self { freq_hz, buf })
}
}
pub struct Sweep {
rf: HackRf,
}
impl Sweep {
pub async fn new(rf: HackRf, params: &SweepParams) -> Result<Self, StateChangeError> {
if let Err(err) = rf.set_sample_rate(params.sample_rate_hz as f64).await {
return Err(StateChangeError { err, rf });
}
Self::new_with_custom_sample_rate(rf, params).await
}
pub async fn new_with_custom_sample_rate(
rf: HackRf,
params: &SweepParams,
) -> Result<Self, StateChangeError> {
const MAX_SWEEP_RANGES: usize = 10;
const TUNING_BLOCK_BYTES: usize = 16384;
if params.freq_mhz.is_empty()
|| params.freq_mhz.len() > MAX_SWEEP_RANGES
|| params.blocks_per_tuning < 1
|| params.step_width_hz < 1
{
return Err(StateChangeError {
rf,
err: Error::InvalidParameter("Invalid sweep parameters"),
});
}
let mut data = Vec::with_capacity(params.freq_mhz.len() * 4 + 9);
data.extend_from_slice(¶ms.step_width_hz.to_le_bytes());
data.extend_from_slice(¶ms.offset_hz.to_be_bytes());
data.push(match params.mode {
SweepMode::Linear => 0,
SweepMode::Interleaved => 1,
});
for (lo, hi) in params.freq_mhz.iter().copied() {
if lo >= hi
|| lo > (crate::consts::FREQ_MAX_MHZ as u16)
|| hi > (crate::consts::FREQ_MAX_MHZ as u16)
{
return Err(StateChangeError {
rf,
err: Error::InvalidParameter("Invalid frequency range"),
});
}
let lo_hz = lo as u32 * 1_000_000;
let hi_hz = hi as u32 * 1_000_000;
let steps = (hi_hz - lo_hz).div_ceil(params.step_width_hz);
let full_hi = (steps * params.step_width_hz).div_ceil(1_000_000);
data.extend_from_slice(&lo.to_le_bytes());
data.extend_from_slice(&full_hi.to_le_bytes());
}
let num_bytes = (params.blocks_per_tuning as u32) * (TUNING_BLOCK_BYTES as u32);
if let Err(e) = rf
.interface
.control_out(ControlOut {
control_type: ControlType::Vendor,
recipient: Recipient::Device,
request: ControlRequest::InitSweep as u8,
value: (num_bytes & 0xffff) as u16,
index: (num_bytes >> 16) as u16,
data: &data,
})
.await
.into_result()
{
return Err(StateChangeError { rf, err: e.into() });
}
if let Err(err) = rf.set_transceiver_mode(TransceiverMode::RxSweep).await {
return Err(StateChangeError { rf, err });
}
Ok(Self { rf })
}
pub fn submit(&mut self) {
let req = if let Ok(buf) = self.rf.rx.buf_pool.try_recv() {
RequestBuffer::reuse(buf, SWEEP_BUF_SIZE)
} else {
RequestBuffer::new(SWEEP_BUF_SIZE)
};
self.rf.rx.queue.submit(req);
}
pub async fn next_complete(&mut self) -> Result<SweepBuf, Error> {
let result = self.rf.rx.queue.next_complete().await;
match result.status {
Ok(_) => {
let buf = Buffer::new(result.data, self.rf.rx.buf_pool_send.clone());
SweepBuf::parse(buf)
}
Err(e) => {
let _ = self.rf.rx.buf_pool_send.send(result.data);
Err(e.into())
}
}
}
pub fn pending(&self) -> usize {
self.rf.rx.queue.pending()
}
pub async fn stop(mut self) -> Result<HackRf, StateChangeError> {
self.rf.rx.queue.cancel_all();
while self.pending() > 0 {
let _ = self.next_complete().await;
}
match self.rf.set_transceiver_mode(TransceiverMode::Off).await {
Ok(_) => Ok(self.rf),
Err(err) => Err(StateChangeError { err, rf: self.rf }),
}
}
}