@ -31,31 +31,53 @@
|
|||||||
#define MIN(x,y) ((x)<(y)?(x):(y))
|
#define MIN(x,y) ((x)<(y)?(x):(y))
|
||||||
#define MAX(x,y) ((x)>(y)?(x):(y))
|
#define MAX(x,y) ((x)>(y)?(x):(y))
|
||||||
#define FREQ_GRANULARITY 1000000
|
#define FREQ_GRANULARITY 1000000
|
||||||
#define MIN_FREQ 1
|
#define MAX_RANGES 10
|
||||||
#define MAX_FREQ 6000
|
|
||||||
#define MAX_FREQ_COUNT 1000
|
|
||||||
#define THROWAWAY_BUFFERS 2
|
#define THROWAWAY_BUFFERS 2
|
||||||
|
|
||||||
volatile bool start_sweep_mode = false;
|
volatile bool start_sweep_mode = false;
|
||||||
static uint64_t sweep_freq;
|
static uint64_t sweep_freq;
|
||||||
bool odd = true;
|
static uint16_t frequencies[MAX_RANGES * 2];
|
||||||
static uint16_t frequencies[MAX_FREQ_COUNT];
|
static unsigned char data[9 + MAX_RANGES * 2 * sizeof(frequencies[0])];
|
||||||
static uint16_t frequency_count = 0;
|
static uint16_t num_ranges = 0;
|
||||||
static uint32_t dwell_blocks = 0;
|
static uint32_t dwell_blocks = 0;
|
||||||
|
static uint32_t step_width = 0;
|
||||||
|
static uint32_t offset = 0;
|
||||||
|
static enum sweep_style style = LINEAR;
|
||||||
|
|
||||||
usb_request_status_t usb_vendor_request_init_sweep(
|
usb_request_status_t usb_vendor_request_init_sweep(
|
||||||
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage)
|
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage)
|
||||||
{
|
{
|
||||||
uint32_t dwell_time;
|
uint32_t num_samples;
|
||||||
|
int i;
|
||||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||||
dwell_time = (endpoint->setup.index << 16) | endpoint->setup.value;
|
num_samples = (endpoint->setup.index << 16) | endpoint->setup.value;
|
||||||
dwell_blocks = dwell_time / 0x4000;
|
dwell_blocks = num_samples / 0x4000;
|
||||||
frequency_count = endpoint->setup.length / sizeof(uint16_t);
|
if(1 > dwell_blocks) {
|
||||||
usb_transfer_schedule_block(endpoint->out, &frequencies,
|
return USB_REQUEST_STATUS_STALL;
|
||||||
endpoint->setup.length, NULL, NULL);
|
}
|
||||||
|
num_ranges = (endpoint->setup.length - 9) / (2 * sizeof(frequencies[0]));
|
||||||
|
if((1 > num_ranges) || (MAX_RANGES < num_ranges)) {
|
||||||
|
return USB_REQUEST_STATUS_STALL;
|
||||||
|
}
|
||||||
|
usb_transfer_schedule_block(endpoint->out, &data,
|
||||||
|
endpoint->setup.length, NULL, NULL);
|
||||||
} else if (stage == USB_TRANSFER_STAGE_DATA) {
|
} else if (stage == USB_TRANSFER_STAGE_DATA) {
|
||||||
sweep_freq = frequencies[0];
|
step_width = ((uint32_t)(data[3]) << 24) | ((uint32_t)(data[2]) << 16)
|
||||||
set_freq(sweep_freq*FREQ_GRANULARITY);
|
| ((uint32_t)(data[1]) << 8) | data[0];
|
||||||
|
if(1 > step_width) {
|
||||||
|
return USB_REQUEST_STATUS_STALL;
|
||||||
|
}
|
||||||
|
offset = ((uint32_t)(data[7]) << 24) | ((uint32_t)(data[6]) << 16)
|
||||||
|
| ((uint32_t)(data[5]) << 8) | data[4];
|
||||||
|
style = data[8];
|
||||||
|
if(INTERLEAVED < style) {
|
||||||
|
return USB_REQUEST_STATUS_STALL;
|
||||||
|
}
|
||||||
|
for(i=0; i<(num_ranges*2); i++) {
|
||||||
|
frequencies[i] = ((uint16_t)(data[10+i*2]) << 8) + data[9+i*2];
|
||||||
|
}
|
||||||
|
sweep_freq = (uint64_t)frequencies[0] * FREQ_GRANULARITY;
|
||||||
|
set_freq(sweep_freq + offset);
|
||||||
start_sweep_mode = true;
|
start_sweep_mode = true;
|
||||||
usb_transfer_schedule_ack(endpoint->in);
|
usb_transfer_schedule_ack(endpoint->in);
|
||||||
}
|
}
|
||||||
@ -64,8 +86,9 @@ usb_request_status_t usb_vendor_request_init_sweep(
|
|||||||
|
|
||||||
void sweep_mode(void) {
|
void sweep_mode(void) {
|
||||||
unsigned int blocks_queued = 0;
|
unsigned int blocks_queued = 0;
|
||||||
unsigned int phase = 0;
|
unsigned int phase = 1;
|
||||||
unsigned int ifreq = 0;
|
bool odd = true;
|
||||||
|
uint16_t range = 0;
|
||||||
|
|
||||||
uint8_t *buffer;
|
uint8_t *buffer;
|
||||||
bool transfer = false;
|
bool transfer = false;
|
||||||
@ -88,8 +111,16 @@ void sweep_mode(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (transfer) {
|
if (transfer) {
|
||||||
*(uint16_t*)buffer = 0x7F7F;
|
*buffer = 0x7f;
|
||||||
*(uint16_t*)(buffer+2) = sweep_freq;
|
*(buffer+1) = 0x7f;
|
||||||
|
*(buffer+2) = sweep_freq & 0xff;
|
||||||
|
*(buffer+3) = (sweep_freq >> 8) & 0xff;
|
||||||
|
*(buffer+4) = (sweep_freq >> 16) & 0xff;
|
||||||
|
*(buffer+5) = (sweep_freq >> 24) & 0xff;
|
||||||
|
*(buffer+6) = (sweep_freq >> 32) & 0xff;
|
||||||
|
*(buffer+7) = (sweep_freq >> 40) & 0xff;
|
||||||
|
*(buffer+8) = (sweep_freq >> 48) & 0xff;
|
||||||
|
*(buffer+9) = (sweep_freq >> 56) & 0xff;
|
||||||
if (blocks_queued > THROWAWAY_BUFFERS) {
|
if (blocks_queued > THROWAWAY_BUFFERS) {
|
||||||
usb_transfer_schedule_block(
|
usb_transfer_schedule_block(
|
||||||
&usb_endpoint_bulk_in,
|
&usb_endpoint_bulk_in,
|
||||||
@ -102,10 +133,27 @@ void sweep_mode(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((dwell_blocks + THROWAWAY_BUFFERS) <= blocks_queued) {
|
if ((dwell_blocks + THROWAWAY_BUFFERS) <= blocks_queued) {
|
||||||
if(++ifreq >= frequency_count)
|
if(INTERLEAVED == style) {
|
||||||
ifreq = 0;
|
if(!odd && ((sweep_freq + step_width) >= ((uint64_t)frequencies[1+range*2] * FREQ_GRANULARITY))) {
|
||||||
sweep_freq = frequencies[ifreq];
|
range = (range + 1) % num_ranges;
|
||||||
set_freq(sweep_freq*FREQ_GRANULARITY);
|
sweep_freq = (uint64_t)frequencies[range*2] * FREQ_GRANULARITY;
|
||||||
|
} else {
|
||||||
|
if(odd) {
|
||||||
|
sweep_freq += step_width/4;
|
||||||
|
} else {
|
||||||
|
sweep_freq += 3*step_width/4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
odd = !odd;
|
||||||
|
} else {
|
||||||
|
if((sweep_freq + step_width) >= ((uint64_t)frequencies[1+range*2] * FREQ_GRANULARITY)) {
|
||||||
|
range = (range + 1) % num_ranges;
|
||||||
|
sweep_freq = (uint64_t)frequencies[range*2] * FREQ_GRANULARITY;
|
||||||
|
} else {
|
||||||
|
sweep_freq += step_width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set_freq(sweep_freq + offset);
|
||||||
blocks_queued = 0;
|
blocks_queued = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,8 @@
|
|||||||
* Boston, MA 02110-1301, USA.
|
* Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __USB_API_SCAN_H__
|
#ifndef __USB_API_SWEEP_H__
|
||||||
#define __USB_API_SCAN_H__
|
#define __USB_API_SWEEP_H__
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <usb_type.h>
|
#include <usb_type.h>
|
||||||
@ -28,9 +28,14 @@
|
|||||||
|
|
||||||
extern volatile bool start_sweep_mode;
|
extern volatile bool start_sweep_mode;
|
||||||
|
|
||||||
|
enum sweep_style {
|
||||||
|
LINEAR = 0,
|
||||||
|
INTERLEAVED = 1,
|
||||||
|
};
|
||||||
|
|
||||||
usb_request_status_t usb_vendor_request_init_sweep(
|
usb_request_status_t usb_vendor_request_init_sweep(
|
||||||
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
|
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
|
||||||
|
|
||||||
void sweep_mode(void);
|
void sweep_mode(void);
|
||||||
|
|
||||||
#endif /* __USB_API_SPCAN_H__ */
|
#endif /* __USB_API_SWEEP_H__ */
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Dominic Spill <dominicgs@gmail.com>
|
* Copyright 2016 Dominic Spill <dominicgs@gmail.com>
|
||||||
* Copyright 2016 Mike Walters <mike@flomp.net>
|
* Copyright 2016 Mike Walters <mike@flomp.net>
|
||||||
|
* Copyright 2017 Michael Ossmann <mike@ossmann.com>
|
||||||
*
|
*
|
||||||
* This file is part of HackRF.
|
* This file is part of HackRF.
|
||||||
*
|
*
|
||||||
@ -34,6 +35,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fftw3.h>
|
#include <fftw3.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
#define _FILE_OFFSET_BITS 64
|
#define _FILE_OFFSET_BITS 64
|
||||||
|
|
||||||
@ -87,21 +89,25 @@ int gettimeofday(struct timeval *tv, void* ignored) {
|
|||||||
|
|
||||||
#define FREQ_ONE_MHZ (1000000ull)
|
#define FREQ_ONE_MHZ (1000000ull)
|
||||||
|
|
||||||
#define FREQ_MIN_HZ (0ull) /* 0 Hz */
|
#define FREQ_MIN_MHZ (0) /* 0 MHz */
|
||||||
#define FREQ_MAX_HZ (7250000000ull) /* 7250MHz */
|
#define FREQ_MAX_MHZ (7250) /* 7250 MHz */
|
||||||
|
|
||||||
#define DEFAULT_SAMPLE_RATE_HZ (20000000) /* 20MHz default sample rate */
|
#define DEFAULT_SAMPLE_RATE_HZ (20000000) /* 20MHz default sample rate */
|
||||||
#define DEFAULT_BASEBAND_FILTER_BANDWIDTH (15000000) /* 5MHz default */
|
#define DEFAULT_BASEBAND_FILTER_BANDWIDTH (15000000) /* 5MHz default */
|
||||||
|
|
||||||
#define FREQ_STEP (DEFAULT_SAMPLE_RATE_HZ / FREQ_ONE_MHZ)
|
#define TUNE_STEP (DEFAULT_SAMPLE_RATE_HZ / FREQ_ONE_MHZ)
|
||||||
#define MAX_FREQ_COUNT 1000
|
#define OFFSET 7500000
|
||||||
|
|
||||||
#define DEFAULT_SAMPLE_COUNT 0x4000
|
#define DEFAULT_SAMPLE_COUNT 0x4000
|
||||||
|
#define BLOCKS_PER_TRANSFER 16
|
||||||
|
|
||||||
#if defined _WIN32
|
#if defined _WIN32
|
||||||
#define sleep(a) Sleep( (a*1000) )
|
#define sleep(a) Sleep( (a*1000) )
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int num_ranges = 0;
|
||||||
|
uint16_t frequencies[MAX_SWEEP_RANGES*2];
|
||||||
|
|
||||||
static float TimevalDiff(const struct timeval *a, const struct timeval *b) {
|
static float TimevalDiff(const struct timeval *a, const struct timeval *b) {
|
||||||
return (a->tv_sec - b->tv_sec) + 1e-6f * (a->tv_usec - b->tv_usec);
|
return (a->tv_sec - b->tv_sec) + 1e-6f * (a->tv_usec - b->tv_usec);
|
||||||
}
|
}
|
||||||
@ -166,15 +172,20 @@ uint32_t amp_enable;
|
|||||||
bool antenna = false;
|
bool antenna = false;
|
||||||
uint32_t antenna_enable;
|
uint32_t antenna_enable;
|
||||||
|
|
||||||
uint32_t freq_min;
|
bool binary_output = false;
|
||||||
uint32_t freq_max;
|
bool one_shot = false;
|
||||||
|
volatile bool sweep_started = false;
|
||||||
|
|
||||||
int fftSize;
|
int fftSize = 20;
|
||||||
|
uint32_t fft_bin_width;
|
||||||
fftwf_complex *fftwIn = NULL;
|
fftwf_complex *fftwIn = NULL;
|
||||||
fftwf_complex *fftwOut = NULL;
|
fftwf_complex *fftwOut = NULL;
|
||||||
fftwf_plan fftwPlan = NULL;
|
fftwf_plan fftwPlan = NULL;
|
||||||
float* pwr;
|
float* pwr;
|
||||||
float* window;
|
float* window;
|
||||||
|
time_t time_now;
|
||||||
|
struct tm *fft_time;
|
||||||
|
char time_str[50];
|
||||||
|
|
||||||
float logPower(fftwf_complex in, float scale)
|
float logPower(fftwf_complex in, float scale)
|
||||||
{
|
{
|
||||||
@ -185,64 +196,112 @@ float logPower(fftwf_complex in, float scale)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int rx_callback(hackrf_transfer* transfer) {
|
int rx_callback(hackrf_transfer* transfer) {
|
||||||
/* This is where we need to do interesting things with the samples
|
|
||||||
* FFT
|
|
||||||
* Throw away unused bins
|
|
||||||
* write output to pipe
|
|
||||||
*/
|
|
||||||
ssize_t bytes_to_write;
|
|
||||||
ssize_t bytes_written;
|
|
||||||
int8_t* buf;
|
int8_t* buf;
|
||||||
float frequency;
|
uint8_t* ubuf;
|
||||||
|
uint64_t frequency; /* in Hz */
|
||||||
|
float float_freq;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
if( fd != NULL ) {
|
if(NULL == fd) {
|
||||||
byte_count += transfer->valid_length;
|
|
||||||
bytes_to_write = transfer->valid_length;
|
|
||||||
buf = (int8_t*) transfer->buffer;
|
|
||||||
for(j=0; j<16; j++) {
|
|
||||||
if(buf[0] == 0x7F && buf[1] == 0x7F) {
|
|
||||||
frequency = *(uint16_t*)&buf[2];
|
|
||||||
}
|
|
||||||
/* copy to fftwIn as floats */
|
|
||||||
buf += 16384 - (fftSize * 2);
|
|
||||||
for(i=0; i < fftSize; i++) {
|
|
||||||
fftwIn[i][0] = buf[i*2] * window[i] * 1.0f / 128.0f;
|
|
||||||
fftwIn[i][1] = buf[i*2+1] * window[i] * 1.0f / 128.0f;
|
|
||||||
}
|
|
||||||
buf += fftSize * 2;
|
|
||||||
fftwf_execute(fftwPlan);
|
|
||||||
for (i=0; i < fftSize; i++) {
|
|
||||||
// Start from the middle of the FFTW array and wrap
|
|
||||||
// to rearrange the data
|
|
||||||
int k = i ^ (fftSize >> 1);
|
|
||||||
pwr[i] = logPower(fftwOut[k], 1.0f / fftSize);
|
|
||||||
}
|
|
||||||
fwrite(&frequency, sizeof(float), 1, stdout);
|
|
||||||
fwrite(pwr, sizeof(float), fftSize, stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes_written = fwrite(transfer->buffer, 1, bytes_to_write, fd);
|
|
||||||
if (bytes_written != bytes_to_write) {
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
byte_count += transfer->valid_length;
|
||||||
|
buf = (int8_t*) transfer->buffer;
|
||||||
|
for(j=0; j<BLOCKS_PER_TRANSFER; j++) {
|
||||||
|
if(do_exit) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ubuf = (uint8_t*) buf;
|
||||||
|
if(ubuf[0] == 0x7F && ubuf[1] == 0x7F) {
|
||||||
|
frequency = ((uint64_t)(ubuf[9]) << 56) | ((uint64_t)(ubuf[8]) << 48) | ((uint64_t)(ubuf[7]) << 40)
|
||||||
|
| ((uint64_t)(ubuf[6]) << 32) | ((uint64_t)(ubuf[5]) << 24) | ((uint64_t)(ubuf[4]) << 16)
|
||||||
|
| ((uint64_t)(ubuf[3]) << 8) | ubuf[2];
|
||||||
|
} else {
|
||||||
|
buf += SAMPLES_PER_BLOCK;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(!sweep_started) {
|
||||||
|
if (frequency == (uint64_t)(FREQ_ONE_MHZ*frequencies[0])) {
|
||||||
|
sweep_started = true;
|
||||||
|
} else {
|
||||||
|
buf += SAMPLES_PER_BLOCK;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if((FREQ_MAX_MHZ * FREQ_ONE_MHZ) < frequency) {
|
||||||
|
buf += SAMPLES_PER_BLOCK;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* copy to fftwIn as floats */
|
||||||
|
buf += SAMPLES_PER_BLOCK - (fftSize * 2);
|
||||||
|
for(i=0; i < fftSize; i++) {
|
||||||
|
fftwIn[i][0] = buf[i*2] * window[i] * 1.0f / 128.0f;
|
||||||
|
fftwIn[i][1] = buf[i*2+1] * window[i] * 1.0f / 128.0f;
|
||||||
|
}
|
||||||
|
buf += fftSize * 2;
|
||||||
|
fftwf_execute(fftwPlan);
|
||||||
|
for (i=0; i < fftSize; i++) {
|
||||||
|
pwr[i] = logPower(fftwOut[i], 1.0f / fftSize);
|
||||||
|
}
|
||||||
|
if(binary_output) {
|
||||||
|
float_freq = frequency + DEFAULT_SAMPLE_RATE_HZ / 4;
|
||||||
|
float_freq /= FREQ_ONE_MHZ;
|
||||||
|
fwrite(&float_freq, sizeof(float), 1, stdout);
|
||||||
|
fwrite(&pwr[1+(fftSize*5)/8], sizeof(float), fftSize/4, stdout);
|
||||||
|
float_freq = frequency + DEFAULT_SAMPLE_RATE_HZ / 2;
|
||||||
|
float_freq /= FREQ_ONE_MHZ;
|
||||||
|
fwrite(&float_freq, sizeof(float), 1, stdout);
|
||||||
|
fwrite(&pwr[1+fftSize/8], sizeof(float), fftSize/4, stdout);
|
||||||
|
} else {
|
||||||
|
time_now = time(NULL);
|
||||||
|
fft_time = localtime(&time_now);
|
||||||
|
strftime(time_str, 50, "%Y-%m-%d, %H:%M:%S", fft_time);
|
||||||
|
printf("%s, %" PRIu64 ", %" PRIu64 ", %.2f, %u",
|
||||||
|
time_str,
|
||||||
|
(uint64_t)(frequency),
|
||||||
|
(uint64_t)(frequency+DEFAULT_SAMPLE_RATE_HZ/4),
|
||||||
|
(float)fft_bin_width,
|
||||||
|
fftSize);
|
||||||
|
for(i=1+(fftSize*5)/8; (1+(fftSize*7)/8) > i; i++) {
|
||||||
|
printf(", %.2f", pwr[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
printf("%s, %" PRIu64 ", %" PRIu64 ", %.2f, %u",
|
||||||
|
time_str,
|
||||||
|
(uint64_t)(frequency+(DEFAULT_SAMPLE_RATE_HZ/2)),
|
||||||
|
(uint64_t)(frequency+((DEFAULT_SAMPLE_RATE_HZ*3)/4)),
|
||||||
|
(float)fft_bin_width,
|
||||||
|
fftSize);
|
||||||
|
for(i=1+fftSize/8; (1+(fftSize*3)/8) > i; i++) {
|
||||||
|
printf(", %.2f", pwr[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
if(one_shot && ((uint64_t)(frequency+((DEFAULT_SAMPLE_RATE_HZ*3)/4))
|
||||||
|
>= (uint64_t)(FREQ_ONE_MHZ*frequencies[num_ranges*2-1]))) {
|
||||||
|
do_exit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void usage() {
|
static void usage() {
|
||||||
fprintf(stderr, "Usage:\n");
|
fprintf(stderr, "Usage:\n");
|
||||||
fprintf(stderr, "\t[-h] # this help\n");
|
fprintf(stderr, "\t[-h] # this help\n");
|
||||||
fprintf(stderr, "\t[-d serial_number] # Serial number of desired HackRF.\n");
|
fprintf(stderr, "\t[-d serial_number] # Serial number of desired HackRF\n");
|
||||||
fprintf(stderr, "\t[-a amp_enable] # RX RF amplifier 1=Enable, 0=Disable.\n");
|
fprintf(stderr, "\t[-a amp_enable] # RX RF amplifier 1=Enable, 0=Disable\n");
|
||||||
fprintf(stderr, "\t[-f freq_min:freq_max # Specify minimum & maximum sweep frequencies (MHz).\n");
|
fprintf(stderr, "\t[-f freq_min:freq_max] # minimum and maximum frequencies in MHz\n");
|
||||||
fprintf(stderr, "\t[-p antenna_enable] # Antenna port power, 1=Enable, 0=Disable.\n");
|
fprintf(stderr, "\t[-p antenna_enable] # Antenna port power, 1=Enable, 0=Disable\n");
|
||||||
fprintf(stderr, "\t[-l gain_db] # RX LNA (IF) gain, 0-40dB, 8dB steps\n");
|
fprintf(stderr, "\t[-l gain_db] # RX LNA (IF) gain, 0-40dB, 8dB steps\n");
|
||||||
fprintf(stderr, "\t[-g gain_db] # RX VGA (baseband) gain, 0-62dB, 2dB steps\n");
|
fprintf(stderr, "\t[-g gain_db] # RX VGA (baseband) gain, 0-62dB, 2dB steps\n");
|
||||||
fprintf(stderr, "\t[-n num_samples] # Number of samples per frequency, 16384-4294967296\n");
|
fprintf(stderr, "\t[-n num_samples] # Number of samples per frequency, 16384-4294967296\n");
|
||||||
|
fprintf(stderr, "\t[-w bin_width] # FFT bin width (frequency resolution) in Hz\n");
|
||||||
|
fprintf(stderr, "\t[-1] # one shot mode\n");
|
||||||
|
fprintf(stderr, "\t[-B] # binary output\n");
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
fprintf(stderr, "Output fields:\n");
|
||||||
|
fprintf(stderr, "\tdate, time, hz_low, hz_high, hz_bin_width, num_samples, dB, dB, . . .\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static hackrf_device* device = NULL;
|
static hackrf_device* device = NULL;
|
||||||
@ -265,18 +324,20 @@ void sigint_callback_handler(int signum) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
int opt, i, result, ifreq = 0;
|
int opt, i, result = 0;
|
||||||
bool odd;
|
|
||||||
const char* path = "/dev/null";
|
const char* path = "/dev/null";
|
||||||
const char* serial_number = NULL;
|
const char* serial_number = NULL;
|
||||||
int exit_code = EXIT_SUCCESS;
|
int exit_code = EXIT_SUCCESS;
|
||||||
struct timeval t_end;
|
struct timeval t_end;
|
||||||
float time_diff;
|
float time_diff;
|
||||||
unsigned int lna_gain=16, vga_gain=20;
|
unsigned int lna_gain=16, vga_gain=20;
|
||||||
uint16_t frequencies[MAX_FREQ_COUNT];
|
|
||||||
uint32_t num_samples = DEFAULT_SAMPLE_COUNT;
|
uint32_t num_samples = DEFAULT_SAMPLE_COUNT;
|
||||||
|
int step_count;
|
||||||
|
uint32_t freq_min = 0;
|
||||||
|
uint32_t freq_max = 6000;
|
||||||
|
|
||||||
while( (opt = getopt(argc, argv, "a:f:p:l:g:d:n:h?")) != EOF ) {
|
|
||||||
|
while( (opt = getopt(argc, argv, "a:f:p:l:g:d:n:w:1Bh?")) != EOF ) {
|
||||||
result = HACKRF_SUCCESS;
|
result = HACKRF_SUCCESS;
|
||||||
switch( opt )
|
switch( opt )
|
||||||
{
|
{
|
||||||
@ -291,17 +352,29 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
result = parse_u32_range(optarg, &freq_min, &freq_max);
|
result = parse_u32_range(optarg, &freq_min, &freq_max);
|
||||||
fprintf(stderr, "Scanning %uMHz to %uMHz\n", freq_min, freq_max);
|
if(freq_min >= freq_max) {
|
||||||
frequencies[ifreq++] = freq_min;
|
fprintf(stderr,
|
||||||
odd = true;
|
"argument error: freq_max must be greater than freq_min.\n");
|
||||||
while(frequencies[ifreq-1] <= freq_max) {
|
usage();
|
||||||
if (odd)
|
return EXIT_FAILURE;
|
||||||
frequencies[ifreq] = frequencies[ifreq-1] + FREQ_STEP / 4;
|
|
||||||
else
|
|
||||||
frequencies[ifreq] = frequencies[ifreq-1] + 3*(FREQ_STEP/4);
|
|
||||||
ifreq++;
|
|
||||||
odd = !odd;
|
|
||||||
}
|
}
|
||||||
|
if(FREQ_MAX_MHZ <freq_max) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"argument error: freq_max may not be higher than %u.\n",
|
||||||
|
FREQ_MAX_MHZ);
|
||||||
|
usage();
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
if(MAX_SWEEP_RANGES <= num_ranges) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"argument error: specify a maximum of %u frequency ranges.\n",
|
||||||
|
MAX_SWEEP_RANGES);
|
||||||
|
usage();
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
frequencies[2*num_ranges] = (uint16_t)freq_min;
|
||||||
|
frequencies[2*num_ranges+1] = (uint16_t)freq_max;
|
||||||
|
num_ranges++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
@ -321,6 +394,19 @@ int main(int argc, char** argv) {
|
|||||||
result = parse_u32(optarg, &num_samples);
|
result = parse_u32(optarg, &num_samples);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'w':
|
||||||
|
result = parse_u32(optarg, &fft_bin_width);
|
||||||
|
fftSize = DEFAULT_SAMPLE_RATE_HZ / fft_bin_width;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '1':
|
||||||
|
one_shot = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'B':
|
||||||
|
binary_output = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
case '?':
|
case '?':
|
||||||
usage();
|
usage();
|
||||||
@ -345,12 +431,12 @@ int main(int argc, char** argv) {
|
|||||||
if (vga_gain % 2)
|
if (vga_gain % 2)
|
||||||
fprintf(stderr, "warning: vga_gain (-g) must be a multiple of 2\n");
|
fprintf(stderr, "warning: vga_gain (-g) must be a multiple of 2\n");
|
||||||
|
|
||||||
if (num_samples % 0x4000) {
|
if (num_samples % SAMPLES_PER_BLOCK) {
|
||||||
fprintf(stderr, "warning: num_samples (-n) must be a multiple of 16384\n");
|
fprintf(stderr, "warning: num_samples (-n) must be a multiple of 16384\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num_samples < 0x4000) {
|
if (num_samples < SAMPLES_PER_BLOCK) {
|
||||||
fprintf(stderr, "warning: num_samples (-n) must be at least 16384\n");
|
fprintf(stderr, "warning: num_samples (-n) must be at least 16384\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@ -371,16 +457,36 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ifreq == 0) {
|
if (0 == num_ranges) {
|
||||||
fprintf(stderr, "argument error: must specify sweep frequency range (-f).\n");
|
frequencies[0] = (uint16_t)freq_min;
|
||||||
usage();
|
frequencies[1] = (uint16_t)freq_max;
|
||||||
|
num_ranges++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(4 > fftSize) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"argument error: FFT bin width (-w) must be no more than one quarter the sample rate\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
fftSize = 64;
|
if(16368 < fftSize) {
|
||||||
fftwIn = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fftSize);
|
fprintf(stderr,
|
||||||
fftwOut = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fftSize);
|
"argument error: FFT bin width (-w) too small, resulted in more than 16368 FFT bins\n");
|
||||||
fftwPlan = fftwf_plan_dft_1d(fftSize, fftwIn, fftwOut, FFTW_FORWARD, FFTW_MEASURE);
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In interleaved mode, the FFT bin selection works best if the total
|
||||||
|
* number of FFT bins is equal to an odd multiple of four.
|
||||||
|
* (e.g. 4, 12, 20, 28, 36, . . .)
|
||||||
|
*/
|
||||||
|
while((fftSize + 4) % 8) {
|
||||||
|
fftSize++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fft_bin_width = DEFAULT_SAMPLE_RATE_HZ / fftSize;
|
||||||
|
fftwIn = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fftSize);
|
||||||
|
fftwOut = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fftSize);
|
||||||
|
fftwPlan = fftwf_plan_dft_1d(fftSize, fftwIn, fftwOut, FFTW_FORWARD, FFTW_MEASURE);
|
||||||
pwr = (float*)fftwf_malloc(sizeof(float) * fftSize);
|
pwr = (float*)fftwf_malloc(sizeof(float) * fftSize);
|
||||||
window = (float*)fftwf_malloc(sizeof(float) * fftSize);
|
window = (float*)fftwf_malloc(sizeof(float) * fftSize);
|
||||||
for (i = 0; i < fftSize; i++) {
|
for (i = 0; i < fftSize; i++) {
|
||||||
@ -453,7 +559,21 @@ int main(int argc, char** argv) {
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = hackrf_init_sweep(device, frequencies, ifreq, num_samples);
|
/*
|
||||||
|
* For each range, plan a whole number of tuning steps of a certain
|
||||||
|
* bandwidth. Increase high end of range if necessary to accommodate a
|
||||||
|
* whole number of steps, minimum 1.
|
||||||
|
*/
|
||||||
|
for(i = 0; i < num_ranges; i++) {
|
||||||
|
step_count = 1 + (frequencies[2*i+1] - frequencies[2*i] - 1)
|
||||||
|
/ TUNE_STEP;
|
||||||
|
frequencies[2*i+1] = frequencies[2*i] + step_count * TUNE_STEP;
|
||||||
|
fprintf(stderr, "Sweeping from %u MHz to %u MHz\n",
|
||||||
|
frequencies[2*i], frequencies[2*i+1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = hackrf_init_sweep(device, frequencies, num_ranges, num_samples,
|
||||||
|
TUNE_STEP * FREQ_ONE_MHZ, OFFSET, INTERLEAVED);
|
||||||
if( result != HACKRF_SUCCESS ) {
|
if( result != HACKRF_SUCCESS ) {
|
||||||
fprintf(stderr, "hackrf_init_sweep() failed: %s (%d)\n",
|
fprintf(stderr, "hackrf_init_sweep() failed: %s (%d)\n",
|
||||||
hackrf_error_name(result), result);
|
hackrf_error_name(result), result);
|
||||||
|
@ -1810,23 +1810,70 @@ int ADDCALL hackrf_set_hw_sync_mode(hackrf_device* device, const uint8_t value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialise sweep mode with alist of frequencies and dwell time in samples */
|
/*
|
||||||
int ADDCALL hackrf_init_sweep(hackrf_device* device, uint16_t* frequency_list, int length, uint32_t dwell_time)
|
* Initialize sweep mode:
|
||||||
{
|
* frequency_list is a list of start/stop pairs of frequencies in MHz.
|
||||||
|
* num_ranges is the number of pairs in frequency_list (1 to 10)
|
||||||
|
* num_samples is the number of samples to capture after each tuning.
|
||||||
|
* step_width is the width in Hz of the tuning step.
|
||||||
|
* offset is a number of Hz added to every tuning frequency.
|
||||||
|
* Use to select center frequency based on the expected usable bandwidth.
|
||||||
|
* sweep_mode
|
||||||
|
* LINEAR means step_width is added to the current frequency at each step.
|
||||||
|
* INTERLEAVED invokes a scheme in which each step is divided into two
|
||||||
|
* interleaved sub-steps, allowing the host to select the best portions
|
||||||
|
* of the FFT of each sub-step and discard the rest.
|
||||||
|
*/
|
||||||
|
int ADDCALL hackrf_init_sweep(hackrf_device* device,
|
||||||
|
const uint16_t* frequency_list, const int num_ranges,
|
||||||
|
const uint32_t num_samples, const uint32_t step_width,
|
||||||
|
const uint32_t offset, const enum sweep_style style) {
|
||||||
USB_API_REQUIRED(device, 0x0102)
|
USB_API_REQUIRED(device, 0x0102)
|
||||||
int result, i;
|
int result, i;
|
||||||
int size = length * sizeof(frequency_list[0]);
|
unsigned char data[9 + MAX_SWEEP_RANGES * 2 * sizeof(frequency_list[0])];
|
||||||
|
int size = 9 + num_ranges * 2 * sizeof(frequency_list[0]);
|
||||||
|
|
||||||
for(i=0; i<length; i++)
|
if((num_ranges < 1) || (num_ranges > MAX_SWEEP_RANGES)){
|
||||||
frequency_list[i] = TO_LE(frequency_list[i]);
|
return HACKRF_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(num_samples % SAMPLES_PER_BLOCK) {
|
||||||
|
return HACKRF_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(SAMPLES_PER_BLOCK < num_samples) {
|
||||||
|
return HACKRF_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(1 > step_width) {
|
||||||
|
return HACKRF_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(INTERLEAVED < style) {
|
||||||
|
return HACKRF_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
data[0] = step_width & 0xff;
|
||||||
|
data[1] = (step_width >> 8) & 0xff;
|
||||||
|
data[2] = (step_width >> 16) & 0xff;
|
||||||
|
data[3] = (step_width >> 24) & 0xff;
|
||||||
|
data[4] = offset & 0xff;
|
||||||
|
data[5] = (offset >> 8) & 0xff;
|
||||||
|
data[6] = (offset >> 16) & 0xff;
|
||||||
|
data[7] = (offset >> 24) & 0xff;
|
||||||
|
data[8] = style;
|
||||||
|
for(i=0; i<(num_ranges*2); i++) {
|
||||||
|
data[9+i*2] = frequency_list[i] & 0xff;
|
||||||
|
data[10+i*2] = (frequency_list[i] >> 8) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
result = libusb_control_transfer(
|
result = libusb_control_transfer(
|
||||||
device->usb_device,
|
device->usb_device,
|
||||||
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
|
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
|
||||||
HACKRF_VENDOR_REQUEST_INIT_SWEEP,
|
HACKRF_VENDOR_REQUEST_INIT_SWEEP,
|
||||||
dwell_time & 0xffff,
|
num_samples & 0xffff,
|
||||||
(dwell_time >> 16) & 0xffff,
|
(num_samples >> 16) & 0xffff,
|
||||||
(unsigned char*)frequency_list,
|
data,
|
||||||
size,
|
size,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
@ -47,6 +47,9 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSI
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define SAMPLES_PER_BLOCK 16384
|
||||||
|
#define MAX_SWEEP_RANGES 10
|
||||||
|
|
||||||
enum hackrf_error {
|
enum hackrf_error {
|
||||||
HACKRF_SUCCESS = 0,
|
HACKRF_SUCCESS = 0,
|
||||||
HACKRF_TRUE = 1,
|
HACKRF_TRUE = 1,
|
||||||
@ -95,6 +98,11 @@ enum operacake_ports {
|
|||||||
OPERACAKE_PB4 = 7,
|
OPERACAKE_PB4 = 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum sweep_style {
|
||||||
|
LINEAR = 0,
|
||||||
|
INTERLEAVED = 1,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct hackrf_device hackrf_device;
|
typedef struct hackrf_device hackrf_device;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -218,10 +226,11 @@ extern ADDAPI uint32_t ADDCALL hackrf_compute_baseband_filter_bw(const uint32_t
|
|||||||
/* set hardware sync mode */
|
/* set hardware sync mode */
|
||||||
extern ADDAPI int ADDCALL hackrf_set_hw_sync_mode(hackrf_device* device, const uint8_t value);
|
extern ADDAPI int ADDCALL hackrf_set_hw_sync_mode(hackrf_device* device, const uint8_t value);
|
||||||
|
|
||||||
/* Start scan mode */
|
/* Start sweep mode */
|
||||||
extern ADDAPI int ADDCALL hackrf_init_sweep(hackrf_device* device,
|
extern ADDAPI int ADDCALL hackrf_init_sweep(hackrf_device* device,
|
||||||
uint16_t* frequency_list,
|
const uint16_t* frequency_list, const int num_ranges,
|
||||||
int length, uint32_t dwell_time);
|
const uint32_t num_samples, const uint32_t step_width,
|
||||||
|
const uint32_t offset, const enum sweep_style style);
|
||||||
|
|
||||||
/* Operacake functions */
|
/* Operacake functions */
|
||||||
extern ADDAPI int ADDCALL hackrf_get_operacake_boards(hackrf_device* device, uint8_t* boards);
|
extern ADDAPI int ADDCALL hackrf_get_operacake_boards(hackrf_device* device, uint8_t* boards);
|
||||||
|
Reference in New Issue
Block a user