From 8c7941b0efe5ba9dbe390a40130ac5ece5057bd1 Mon Sep 17 00:00:00 2001 From: Dominic Spill Date: Tue, 16 May 2017 17:18:54 -0600 Subject: [PATCH] Opera glasses: allow user specified ranges for operacake ports - HackRF switches antenna when tuning - ports specified using hackrf_operacake cmdline tool hackrf_operacake -f 2350:2800:0 -f 0:400:1 -f 400:700:2 -f 700:6000:3 --- firmware/common/operacake.c | 49 +++++++++++++ firmware/common/operacake.h | 4 ++ firmware/common/tuning.c | 2 + firmware/hackrf_usb/hackrf_usb.c | 3 +- firmware/hackrf_usb/usb_api_operacake.c | 27 +++++++ firmware/hackrf_usb/usb_api_operacake.h | 3 + firmware/hackrf_usb/usb_descriptor.c | 4 +- host/hackrf-tools/src/CMakeLists.txt | 1 + host/hackrf-tools/src/hackrf_operacake.c | 92 +++++++++++++++++++++++- host/libhackrf/src/hackrf.c | 24 +++++++ host/libhackrf/src/hackrf.h | 4 ++ 11 files changed, 208 insertions(+), 5 deletions(-) diff --git a/firmware/common/operacake.c b/firmware/common/operacake.c index eecf298f..5154a890 100644 --- a/firmware/common/operacake.c +++ b/firmware/common/operacake.c @@ -145,3 +145,52 @@ uint8_t operacake_set_ports(uint8_t address, uint8_t PA, uint8_t PB) { return 0; } +typedef struct { + uint16_t freq_min; + uint16_t freq_max; + uint8_t portA; + uint8_t portB; +} operacake_range; + +static operacake_range ranges[MAX_OPERACAKE_RANGES * sizeof(operacake_range)]; +static uint8_t range_idx = 0; + +uint8_t operacake_add_range(uint16_t freq_min, uint16_t freq_max, uint8_t port) { + if(range_idx >= MAX_OPERACAKE_RANGES) { + return 1; + } + ranges[range_idx].freq_min = freq_min; + ranges[range_idx].freq_max = freq_max; + ranges[range_idx].portA = port; + ranges[range_idx].portB = 7; + if(port <= OPERACAKE_PA4) { + ranges[range_idx].portB = range_idx+4; + } else { + ranges[range_idx].portB = OPERACAKE_PA1; + } + range_idx++; + return 0; +} + +#define FREQ_ONE_MHZ (1000000ull) +static uint8_t current_range = 0xFF; + +uint8_t operacake_set_range(uint32_t freq_mhz) { + if(range_idx == 0) { + return 1; + } + int i; + for(i=0; i= ranges[i].freq_min) + && (freq_mhz <= ranges[i].freq_max)) { + break; + } + } + if(i == current_range) { + return 1; + } + + operacake_set_ports(operacake_boards[0], ranges[i].portA, ranges[i].portB); + current_range = i; + return 0; +} diff --git a/firmware/common/operacake.h b/firmware/common/operacake.h index 0fda1f2b..a07988cf 100644 --- a/firmware/common/operacake.h +++ b/firmware/common/operacake.h @@ -40,11 +40,15 @@ extern "C" #define OPERACAKE_PB3 6 #define OPERACAKE_PB4 7 +#define MAX_OPERACAKE_RANGES 8 + /* Up to 8 Operacake boards can be used with one HackRF */ extern uint8_t operacake_boards[8]; uint8_t operacake_init(void); uint8_t operacake_set_ports(uint8_t address, uint8_t PA, uint8_t PB); +uint8_t operacake_add_range(uint16_t freq_min, uint16_t freq_max, uint8_t port); +uint8_t operacake_set_range(uint32_t freq_mhz); #ifdef __cplusplus } diff --git a/firmware/common/tuning.c b/firmware/common/tuning.c index b33b90d3..d4c27a5c 100644 --- a/firmware/common/tuning.c +++ b/firmware/common/tuning.c @@ -28,6 +28,7 @@ #include #include #include +#include #define FREQ_ONE_MHZ (1000*1000) @@ -115,6 +116,7 @@ bool set_freq(const uint64_t freq) if( success ) { freq_cache = freq; hackrf_ui_setFrequency(freq); + operacake_set_range(freq_mhz); } return success; } diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index 51d8a088..0bc4eb86 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -88,7 +88,8 @@ static const usb_request_handler_fn vendor_request_handler[] = { usb_vendor_request_operacake_get_boards, usb_vendor_request_operacake_set_ports, usb_vendor_request_set_hw_sync_mode, - usb_vendor_request_reset + usb_vendor_request_reset, + usb_vendor_request_operacake_set_ranges }; static const uint32_t vendor_request_handler_count = diff --git a/firmware/hackrf_usb/usb_api_operacake.c b/firmware/hackrf_usb/usb_api_operacake.c index d9e5affa..4901d900 100644 --- a/firmware/hackrf_usb/usb_api_operacake.c +++ b/firmware/hackrf_usb/usb_api_operacake.c @@ -47,3 +47,30 @@ usb_request_status_t usb_vendor_request_operacake_set_ports( } return USB_REQUEST_STATUS_OK; } + +static unsigned char data[MAX_OPERACAKE_RANGES * 5]; +usb_request_status_t usb_vendor_request_operacake_set_ranges( + usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) +{ + uint16_t i, freq_min, freq_max, num_ranges = 0; + uint8_t port; + + if (stage == USB_TRANSFER_STAGE_SETUP) { + num_ranges = endpoint->setup.length / 5; + if((num_ranges == 0) || (num_ranges > MAX_OPERACAKE_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) { + + for(i=0; isetup.length; i+=5) { + freq_min = data[i] << 8 | data[i+1]; + freq_max = data[i+2] << 8 | data[i+3]; + port = data[i+4]; + operacake_add_range(freq_min, freq_max, port); + } + usb_transfer_schedule_ack(endpoint->in); + } + return USB_REQUEST_STATUS_OK; +} diff --git a/firmware/hackrf_usb/usb_api_operacake.h b/firmware/hackrf_usb/usb_api_operacake.h index 4339488d..73259aca 100644 --- a/firmware/hackrf_usb/usb_api_operacake.h +++ b/firmware/hackrf_usb/usb_api_operacake.h @@ -31,4 +31,7 @@ usb_request_status_t usb_vendor_request_operacake_get_boards( usb_request_status_t usb_vendor_request_operacake_set_ports( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); +usb_request_status_t usb_vendor_request_operacake_set_ranges( + usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); + #endif /* end of include guard: __USB_API_OPERACAKE_H__ */ diff --git a/firmware/hackrf_usb/usb_descriptor.c b/firmware/hackrf_usb/usb_descriptor.c index f11ce887..dd365405 100644 --- a/firmware/hackrf_usb/usb_descriptor.c +++ b/firmware/hackrf_usb/usb_descriptor.c @@ -36,6 +36,8 @@ #define USB_PRODUCT_ID (0xFFFF) #endif +#define USB_API_VERSION (0x0103) + #define USB_WORD(x) (x & 0xFF), ((x >> 8) & 0xFF) #define USB_MAX_PACKET0 (64) @@ -57,7 +59,7 @@ uint8_t usb_descriptor_device[] = { USB_MAX_PACKET0, // bMaxPacketSize0 USB_WORD(USB_VENDOR_ID), // idVendor USB_WORD(USB_PRODUCT_ID), // idProduct - USB_WORD(0x0102), // bcdDevice + USB_WORD(USB_API_VERSION), // bcdDevice 0x01, // iManufacturer 0x02, // iProduct 0x04, // iSerialNumber diff --git a/host/hackrf-tools/src/CMakeLists.txt b/host/hackrf-tools/src/CMakeLists.txt index bc8270f3..ea396455 100644 --- a/host/hackrf-tools/src/CMakeLists.txt +++ b/host/hackrf-tools/src/CMakeLists.txt @@ -32,6 +32,7 @@ SET(TOOLS hackrf_info hackrf_debug hackrf_sweep + hackrf_operacake ) if(MSVC) diff --git a/host/hackrf-tools/src/hackrf_operacake.c b/host/hackrf-tools/src/hackrf_operacake.c index 3a77c8ab..1d28f288 100644 --- a/host/hackrf-tools/src/hackrf_operacake.c +++ b/host/hackrf-tools/src/hackrf_operacake.c @@ -24,6 +24,7 @@ #include #include #include +#include #ifndef bool typedef int bool; @@ -31,6 +32,10 @@ typedef int bool; #define false 0 #endif +#define FREQ_MIN_MHZ (0) /* 0 MHz */ +#define FREQ_MAX_MHZ (7250) /* 7250 MHz */ +#define MAX_FREQ_RANGES 8 + static void usage() { printf("\nUsage:\n"); printf("\t-h, --help: this help\n"); @@ -38,6 +43,7 @@ static void usage() { printf("\t-o, --address : specify a particular operacake by address [default: 0x00]\n"); printf("\t-a : set port A connection\n"); printf("\t-b : set port B connection\n"); + printf("\t-f : automatically assign for range in MHz\n"); printf("\t-l, --list: list available operacake boards\n"); } @@ -49,7 +55,13 @@ static struct option long_options[] = { { 0, 0, 0, 0 }, }; -int parse_int(char* const s, uint16_t* const value) { +typedef struct { + uint16_t freq_min; + uint16_t freq_max; + uint8_t port; +} hackrf_oc_range; + +int parse_uint16(char* const s, uint16_t* const value) { char* s_end = s; const long long_value = strtol(s, &s_end, 10); if( (s != s_end) && (*s_end == 0) ) { @@ -60,6 +72,34 @@ int parse_int(char* const s, uint16_t* const value) { } } +int parse_u16_range(char* s, hackrf_oc_range* range) { + int result; + uint16_t port; + + char *sep = strchr(s, ':'); + if (!sep) + return HACKRF_ERROR_INVALID_PARAM; + *sep = 0; + + char *sep2 = strchr(sep+1, ':'); + if (!sep2) + return HACKRF_ERROR_INVALID_PARAM; + *sep2 = 0; + + result = parse_uint16(s, &range->freq_min); + if (result != HACKRF_SUCCESS) + return result; + result = parse_uint16(sep + 1, &range->freq_max); + if (result != HACKRF_SUCCESS) + return result; + result = parse_uint16(sep2 + 1, &port); + if (result != HACKRF_SUCCESS) + return result; + range->port = port; + + return HACKRF_SUCCESS; +} + int main(int argc, char** argv) { int opt; const char* serial_number = NULL; @@ -73,6 +113,8 @@ int main(int argc, char** argv) { int i = 0; hackrf_device* device = NULL; int option_index = 0; + hackrf_oc_range ranges[MAX_FREQ_RANGES]; + uint8_t range_idx = 0; int result = hackrf_init(); if( result ) { @@ -80,7 +122,7 @@ int main(int argc, char** argv) { return -1; } - while( (opt = getopt_long(argc, argv, "d:o:a:b:lh?", long_options, &option_index)) != EOF ) { + while( (opt = getopt_long(argc, argv, "d:o:a:b:lf:h?", long_options, &option_index)) != EOF ) { switch( opt ) { case 'd': serial_number = optarg; @@ -91,6 +133,31 @@ int main(int argc, char** argv) { set_ports = true; break; + case 'f': + result = parse_u16_range(optarg, &ranges[range_idx]); + if(ranges[range_idx].freq_min >= ranges[range_idx].freq_max) { + fprintf(stderr, + "argument error: freq_max must be greater than freq_min.\n"); + usage(); + return EXIT_FAILURE; + } + if(FREQ_MAX_MHZ < ranges[range_idx].freq_max) { + fprintf(stderr, + "argument error: freq_max may not be higher than %u.\n", + FREQ_MAX_MHZ); + usage(); + return EXIT_FAILURE; + } + range_idx++; + if(MAX_FREQ_RANGES <= range_idx) { + fprintf(stderr, + "argument error: specify a maximum of %u frequency ranges.\n", + MAX_FREQ_RANGES); + usage(); + return EXIT_FAILURE; + } + break; + case 'a': port_a = atoi(optarg); break; @@ -114,7 +181,7 @@ int main(int argc, char** argv) { } } - if(!(list || set_ports)) { + if(!(list || set_ports || range_idx)) { fprintf(stderr, "Specify either list or address option.\n"); usage(); return EXIT_FAILURE; @@ -154,6 +221,25 @@ int main(int argc, char** argv) { } } + if(range_idx) { + uint8_t range_bytes[MAX_FREQ_RANGES * 5]; + uint8_t ptr; + for(i=0; i> 8; + range_bytes[ptr+1] = ranges[i].freq_min; + range_bytes[ptr+2] = ranges[i].freq_max >> 8; + range_bytes[ptr+3] = ranges[i].freq_max; + range_bytes[ptr+4] = ranges[i].port; + } + + result = hackrf_set_operacake_ranges(device, range_bytes, range_idx*5); + if( result ) { + printf("hackrf_set_operacake_ranges() failed: %s (%d)\n", hackrf_error_name(result), result); + return -1; + } + } + result = hackrf_close(device); if( result ) { printf("hackrf_close() failed: %s (%d)\n", hackrf_error_name(result), result); diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index 1bdb754f..6117f2b9 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -78,6 +78,7 @@ typedef enum { HACKRF_VENDOR_REQUEST_OPERACAKE_SET_PORTS = 28, HACKRF_VENDOR_REQUEST_SET_HW_SYNC_MODE = 29, HACKRF_VENDOR_REQUEST_RESET = 30, + HACKRF_VENDOR_REQUEST_OPERACAKE_SET_RANGES = 31, } hackrf_vendor_request; #define USB_CONFIG_STANDARD 0x1 @@ -1967,6 +1968,29 @@ int ADDCALL hackrf_reset(hackrf_device* device) { } } +int ADDCALL hackrf_set_operacake_ranges(hackrf_device* device, uint8_t* ranges, uint8_t len_ranges) +{ + USB_API_REQUIRED(device, 0x0103) + int result; + + result = libusb_control_transfer( + device->usb_device, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + HACKRF_VENDOR_REQUEST_OPERACAKE_SET_RANGES, + 0, + 0, + ranges, + len_ranges, + 0 + ); + + if (result < len_ranges) { + last_libusb_error = result; + return HACKRF_ERROR_LIBUSB; + } else { + return HACKRF_SUCCESS; + } +} #ifdef __cplusplus } // __cplusplus defined. #endif diff --git a/host/libhackrf/src/hackrf.h b/host/libhackrf/src/hackrf.h index d54a9d05..c2b28206 100644 --- a/host/libhackrf/src/hackrf.h +++ b/host/libhackrf/src/hackrf.h @@ -242,6 +242,10 @@ extern ADDAPI int ADDCALL hackrf_set_operacake_ports(hackrf_device* device, extern ADDAPI int ADDCALL hackrf_reset(hackrf_device* device); +extern ADDAPI int ADDCALL hackrf_set_operacake_ranges(hackrf_device* device, + uint8_t* ranges, + uint8_t num_ranges); + #ifdef __cplusplus } // __cplusplus defined. #endif