Skip to content

Commit

Permalink
Opera glasses: allow user specified ranges for operacake ports
Browse files Browse the repository at this point in the history
 - 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
  • Loading branch information
dominicgs committed May 16, 2017
1 parent 9bbbbbf commit 8c7941b
Show file tree
Hide file tree
Showing 11 changed files with 208 additions and 5 deletions.
49 changes: 49 additions & 0 deletions firmware/common/operacake.c
Original file line number Diff line number Diff line change
Expand Up @@ -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<range_idx; i++) {
if((freq_mhz >= 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;
}
4 changes: 4 additions & 0 deletions firmware/common/operacake.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
2 changes: 2 additions & 0 deletions firmware/common/tuning.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <mixer.h>
#include <max2837.h>
#include <sgpio.h>
#include <operacake.h>

#define FREQ_ONE_MHZ (1000*1000)

Expand Down Expand Up @@ -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;
}
Expand Down
3 changes: 2 additions & 1 deletion firmware/hackrf_usb/hackrf_usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
27 changes: 27 additions & 0 deletions firmware/hackrf_usb/usb_api_operacake.c
Original file line number Diff line number Diff line change
Expand Up @@ -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; i<endpoint->setup.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;
}
3 changes: 3 additions & 0 deletions firmware/hackrf_usb/usb_api_operacake.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__ */
4 changes: 3 additions & 1 deletion firmware/hackrf_usb/usb_descriptor.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions host/hackrf-tools/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ SET(TOOLS
hackrf_info
hackrf_debug
hackrf_sweep
hackrf_operacake
)

if(MSVC)
Expand Down
92 changes: 89 additions & 3 deletions host/hackrf-tools/src/hackrf_operacake.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,26 @@
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <string.h>

#ifndef bool
typedef int bool;
#define true 1
#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");
printf("\t-d, --device <n>: specify a particular device by serial number\n");
printf("\t-o, --address <n>: specify a particular operacake by address [default: 0x00]\n");
printf("\t-a <n>: set port A connection\n");
printf("\t-b <n>: set port B connection\n");
printf("\t-f <min:max:port>: automatically assign <port> for range <min:max> in MHz\n");
printf("\t-l, --list: list available operacake boards\n");
}

Expand All @@ -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) ) {
Expand All @@ -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;
Expand All @@ -73,14 +113,16 @@ 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 ) {
printf("hackrf_init() failed: %s (%d)\n", hackrf_error_name(result), result);
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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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<range_idx; i++) {
ptr = 5*i;
range_bytes[ptr] = ranges[i].freq_min >> 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);
Expand Down
24 changes: 24 additions & 0 deletions host/libhackrf/src/hackrf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions host/libhackrf/src/hackrf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 8c7941b

Please sign in to comment.