Moved sweep mode frequency computation into firmware.
Changed from long list of tuning frequencies to short list of ranges.
This commit is contained in:
@ -31,31 +31,55 @@
|
||||
#define MIN(x,y) ((x)<(y)?(x):(y))
|
||||
#define MAX(x,y) ((x)>(y)?(x):(y))
|
||||
#define FREQ_GRANULARITY 1000000
|
||||
#define MIN_FREQ 1
|
||||
#define MAX_FREQ 6000
|
||||
#define MAX_FREQ_COUNT 1000
|
||||
#define MAX_RANGES 10
|
||||
#define THROWAWAY_BUFFERS 2
|
||||
|
||||
volatile bool start_sweep_mode = false;
|
||||
static uint64_t sweep_freq;
|
||||
bool odd = true;
|
||||
static uint16_t frequencies[MAX_FREQ_COUNT];
|
||||
static uint16_t frequency_count = 0;
|
||||
static bool odd = true;
|
||||
static uint16_t frequencies[MAX_RANGES * 2];
|
||||
static unsigned char data[9 + MAX_RANGES * 2 * sizeof(frequencies[0])];
|
||||
static uint16_t num_ranges = 0;
|
||||
static uint32_t dwell_blocks = 0;
|
||||
static uint32_t step_width = 0;
|
||||
static uint32_t offset = 0;
|
||||
static enum sweep_style style = LINEAR;
|
||||
static uint16_t range = 0;
|
||||
|
||||
usb_request_status_t usb_vendor_request_init_sweep(
|
||||
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) {
|
||||
dwell_time = (endpoint->setup.index << 16) | endpoint->setup.value;
|
||||
dwell_blocks = dwell_time / 0x4000;
|
||||
frequency_count = endpoint->setup.length / sizeof(uint16_t);
|
||||
usb_transfer_schedule_block(endpoint->out, &frequencies,
|
||||
num_samples = (endpoint->setup.index << 16) | endpoint->setup.value;
|
||||
dwell_blocks = num_samples / 0x4000;
|
||||
if(1 > dwell_blocks) {
|
||||
return USB_REQUEST_STATUS_STALL;
|
||||
}
|
||||
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) {
|
||||
sweep_freq = frequencies[0];
|
||||
set_freq(sweep_freq*FREQ_GRANULARITY);
|
||||
step_width = ((uint32_t)(data[3]) << 24) | ((uint32_t)(data[2]) << 16)
|
||||
| ((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 = frequencies[0] * FREQ_GRANULARITY;
|
||||
set_freq(sweep_freq + offset);
|
||||
start_sweep_mode = true;
|
||||
usb_transfer_schedule_ack(endpoint->in);
|
||||
}
|
||||
@ -65,7 +89,6 @@ usb_request_status_t usb_vendor_request_init_sweep(
|
||||
void sweep_mode(void) {
|
||||
unsigned int blocks_queued = 0;
|
||||
unsigned int phase = 0;
|
||||
unsigned int ifreq = 0;
|
||||
|
||||
uint8_t *buffer;
|
||||
bool transfer = false;
|
||||
@ -88,8 +111,16 @@ void sweep_mode(void) {
|
||||
}
|
||||
|
||||
if (transfer) {
|
||||
*(uint16_t*)buffer = 0x7F7F;
|
||||
*(uint16_t*)(buffer+2) = sweep_freq;
|
||||
*buffer = 0x7f;
|
||||
*(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) {
|
||||
usb_transfer_schedule_block(
|
||||
&usb_endpoint_bulk_in,
|
||||
@ -102,10 +133,27 @@ void sweep_mode(void) {
|
||||
}
|
||||
|
||||
if ((dwell_blocks + THROWAWAY_BUFFERS) <= blocks_queued) {
|
||||
if(++ifreq >= frequency_count)
|
||||
ifreq = 0;
|
||||
sweep_freq = frequencies[ifreq];
|
||||
set_freq(sweep_freq*FREQ_GRANULARITY);
|
||||
if(INTERLEAVED == style) {
|
||||
if(!odd && ((sweep_freq + step_width) >= ((uint64_t)frequencies[1+range*2] * FREQ_GRANULARITY))) {
|
||||
range = (range + 1) % num_ranges;
|
||||
sweep_freq = 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 = frequencies[range*2] * FREQ_GRANULARITY;
|
||||
} else {
|
||||
sweep_freq += step_width;
|
||||
}
|
||||
}
|
||||
set_freq(sweep_freq + offset);
|
||||
blocks_queued = 0;
|
||||
}
|
||||
}
|
||||
|
@ -19,8 +19,8 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __USB_API_SCAN_H__
|
||||
#define __USB_API_SCAN_H__
|
||||
#ifndef __USB_API_SWEEP_H__
|
||||
#define __USB_API_SWEEP_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <usb_type.h>
|
||||
@ -28,6 +28,11 @@
|
||||
|
||||
extern volatile bool start_sweep_mode;
|
||||
|
||||
enum sweep_style {
|
||||
LINEAR = 0,
|
||||
INTERLEAVED = 1,
|
||||
};
|
||||
|
||||
usb_request_status_t usb_vendor_request_init_sweep(
|
||||
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
|
||||
|
||||
|
@ -37,10 +37,6 @@
|
||||
#include <inttypes.h>
|
||||
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#define BLOCKS_PER_TRANSFER 16
|
||||
#define SAMPLES_PER_BLOCK 16384
|
||||
#define STEP_SIZE_IN_HZ 312500
|
||||
#define FFT_SIZE 64
|
||||
|
||||
#ifndef bool
|
||||
typedef int bool;
|
||||
@ -99,9 +95,12 @@ int gettimeofday(struct timeval *tv, void* ignored) {
|
||||
#define DEFAULT_BASEBAND_FILTER_BANDWIDTH (15000000) /* 5MHz default */
|
||||
|
||||
#define TUNE_STEP (DEFAULT_SAMPLE_RATE_HZ / FREQ_ONE_MHZ)
|
||||
#define MAX_FREQ_COUNT 1000
|
||||
#define OFFSET 7500000
|
||||
|
||||
#define DEFAULT_SAMPLE_COUNT 0x4000
|
||||
#define BLOCKS_PER_TRANSFER 16
|
||||
#define FFT_BIN_WIDTH_HZ 312500
|
||||
#define FFT_SIZE 64
|
||||
|
||||
#if defined _WIN32
|
||||
#define sleep(a) Sleep( (a*1000) )
|
||||
@ -201,7 +200,8 @@ int rx_callback(hackrf_transfer* transfer) {
|
||||
* write output to pipe
|
||||
*/
|
||||
int8_t* buf;
|
||||
uint16_t frequency; /* in MHz */
|
||||
uint8_t* ubuf;
|
||||
uint64_t frequency; /* in Hz */
|
||||
float float_freq;
|
||||
int i, j;
|
||||
|
||||
@ -209,13 +209,16 @@ int rx_callback(hackrf_transfer* transfer) {
|
||||
byte_count += transfer->valid_length;
|
||||
buf = (int8_t*) transfer->buffer;
|
||||
for(j=0; j<BLOCKS_PER_TRANSFER; j++) {
|
||||
if(buf[0] == 0x7F && buf[1] == 0x7F) {
|
||||
frequency = *(uint16_t*)&buf[2];
|
||||
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;
|
||||
break;
|
||||
}
|
||||
if(FREQ_MAX_MHZ < frequency) {
|
||||
if((FREQ_MAX_MHZ * FREQ_ONE_MHZ) < frequency) {
|
||||
buf += SAMPLES_PER_BLOCK;
|
||||
break;
|
||||
}
|
||||
@ -236,6 +239,7 @@ int rx_callback(hackrf_transfer* transfer) {
|
||||
}
|
||||
if(binary_output) {
|
||||
float_freq = frequency;
|
||||
float_freq /= FREQ_ONE_MHZ;
|
||||
fwrite(&float_freq, sizeof(float), 1, stdout);
|
||||
fwrite(pwr, sizeof(float), fftSize, stdout);
|
||||
} else {
|
||||
@ -244,9 +248,9 @@ int rx_callback(hackrf_transfer* transfer) {
|
||||
strftime(time_str, 50, "%Y-%m-%d, %H:%M:%S", fft_time);
|
||||
printf("%s, %" PRIu64 ", %" PRIu64 ", %.2f, %u",
|
||||
time_str,
|
||||
(uint64_t)((FREQ_ONE_MHZ*frequency)-((DEFAULT_SAMPLE_RATE_HZ*3)/8)),
|
||||
(uint64_t)((FREQ_ONE_MHZ*frequency)-(DEFAULT_SAMPLE_RATE_HZ/8)),
|
||||
(float)STEP_SIZE_IN_HZ,
|
||||
(uint64_t)(frequency),
|
||||
(uint64_t)(frequency+DEFAULT_SAMPLE_RATE_HZ/4),
|
||||
(float)FFT_BIN_WIDTH_HZ,
|
||||
FFT_SIZE);
|
||||
for(i=fftSize/8; (fftSize*3)/8 > i; i++) {
|
||||
printf(", %.2f", pwr[i]);
|
||||
@ -254,9 +258,9 @@ int rx_callback(hackrf_transfer* transfer) {
|
||||
printf("\n");
|
||||
printf("%s, %" PRIu64 ", %" PRIu64 ", %.2f, %u",
|
||||
time_str,
|
||||
(uint64_t)((FREQ_ONE_MHZ*frequency)+(DEFAULT_SAMPLE_RATE_HZ/8)),
|
||||
(uint64_t)((FREQ_ONE_MHZ*frequency)+((DEFAULT_SAMPLE_RATE_HZ*3)/8)),
|
||||
(float)STEP_SIZE_IN_HZ,
|
||||
(uint64_t)(frequency+(DEFAULT_SAMPLE_RATE_HZ/2)),
|
||||
(uint64_t)(frequency+((DEFAULT_SAMPLE_RATE_HZ*3)/4)),
|
||||
(float)FFT_BIN_WIDTH_HZ,
|
||||
FFT_SIZE);
|
||||
for(i=(fftSize*5)/8; (fftSize*7)/8 > i; i++) {
|
||||
printf(", %.2f", pwr[i]);
|
||||
@ -303,15 +307,14 @@ void sigint_callback_handler(int signum) {
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int opt, i, result, ifreq = 0;
|
||||
bool odd;
|
||||
int opt, i, result = 0;
|
||||
const char* path = "/dev/null";
|
||||
const char* serial_number = NULL;
|
||||
int exit_code = EXIT_SUCCESS;
|
||||
struct timeval t_end;
|
||||
float time_diff;
|
||||
unsigned int lna_gain=16, vga_gain=20;
|
||||
uint16_t frequencies[MAX_FREQ_COUNT];
|
||||
uint16_t frequencies[MAX_SWEEP_RANGES*2];
|
||||
uint32_t num_samples = DEFAULT_SAMPLE_COUNT;
|
||||
int step_count;
|
||||
|
||||
@ -409,10 +412,6 @@ int main(int argc, char** argv) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Plan a whole number of steps with bandwidth equal to the sample rate. */
|
||||
step_count = 1 + (freq_max - freq_min - 1) / TUNE_STEP;
|
||||
freq_max = freq_min + step_count * TUNE_STEP;
|
||||
|
||||
if (FREQ_MAX_MHZ <freq_max) {
|
||||
fprintf(stderr, "argument error: freq_max may not be higher than %u.\n",
|
||||
FREQ_MAX_MHZ);
|
||||
@ -420,18 +419,6 @@ int main(int argc, char** argv) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Sweeping from %u MHz to %u MHz\n", freq_min, freq_max);
|
||||
frequencies[0] = freq_min;
|
||||
odd = true;
|
||||
for(ifreq = 1; ifreq < step_count*2; ifreq++) {
|
||||
if (odd) {
|
||||
frequencies[ifreq] = frequencies[ifreq-1] + TUNE_STEP / 4;
|
||||
} else {
|
||||
frequencies[ifreq] = frequencies[ifreq-1] + 3*(TUNE_STEP/4);
|
||||
}
|
||||
odd = !odd;
|
||||
}
|
||||
|
||||
fftSize = FFT_SIZE;
|
||||
fftwIn = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fftSize);
|
||||
fftwOut = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fftSize);
|
||||
@ -508,7 +495,20 @@ int main(int argc, char** argv) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
result = hackrf_init_sweep(device, frequencies, ifreq, num_samples);
|
||||
/*
|
||||
* Plan a whole number of tuning steps of a certain bandwidth.
|
||||
* Increase freq_max if necessary to accomodate a whole number of steps,
|
||||
* minimum 1.
|
||||
*/
|
||||
step_count = 1 + (freq_max - freq_min - 1) / TUNE_STEP;
|
||||
freq_max = freq_min + step_count * TUNE_STEP;
|
||||
|
||||
fprintf(stderr, "Sweeping from %u MHz to %u MHz\n", freq_min, freq_max);
|
||||
frequencies[0] = freq_min;
|
||||
frequencies[1] = freq_max;
|
||||
|
||||
result = hackrf_init_sweep(device, frequencies, 1, num_samples,
|
||||
TUNE_STEP * FREQ_ONE_MHZ, OFFSET, INTERLEAVED);
|
||||
if( result != HACKRF_SUCCESS ) {
|
||||
fprintf(stderr, "hackrf_init_sweep() failed: %s (%d)\n",
|
||||
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)
|
||||
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++)
|
||||
frequency_list[i] = TO_LE(frequency_list[i]);
|
||||
if((num_ranges < 1) || (num_ranges > MAX_SWEEP_RANGES)){
|
||||
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(
|
||||
device->usb_device,
|
||||
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
|
||||
HACKRF_VENDOR_REQUEST_INIT_SWEEP,
|
||||
dwell_time & 0xffff,
|
||||
(dwell_time >> 16) & 0xffff,
|
||||
(unsigned char*)frequency_list,
|
||||
num_samples & 0xffff,
|
||||
(num_samples >> 16) & 0xffff,
|
||||
data,
|
||||
size,
|
||||
0
|
||||
);
|
||||
|
@ -47,6 +47,9 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSI
|
||||
|
||||
#endif
|
||||
|
||||
#define SAMPLES_PER_BLOCK 16384
|
||||
#define MAX_SWEEP_RANGES 10
|
||||
|
||||
enum hackrf_error {
|
||||
HACKRF_SUCCESS = 0,
|
||||
HACKRF_TRUE = 1,
|
||||
@ -95,6 +98,11 @@ enum operacake_ports {
|
||||
OPERACAKE_PB4 = 7,
|
||||
};
|
||||
|
||||
enum sweep_style {
|
||||
LINEAR = 0,
|
||||
INTERLEAVED = 1,
|
||||
};
|
||||
|
||||
typedef struct hackrf_device hackrf_device;
|
||||
|
||||
typedef struct {
|
||||
@ -218,10 +226,11 @@ extern ADDAPI uint32_t ADDCALL hackrf_compute_baseband_filter_bw(const uint32_t
|
||||
/* set hardware sync mode */
|
||||
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,
|
||||
uint16_t* frequency_list,
|
||||
int length, uint32_t dwell_time);
|
||||
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);
|
||||
|
||||
/* Operacake functions */
|
||||
extern ADDAPI int ADDCALL hackrf_get_operacake_boards(hackrf_device* device, uint8_t* boards);
|
||||
|
Reference in New Issue
Block a user