Merge pull request #382 from dominicgs/operaglasses
Opera glasses: allow user specified ranges for operacake ports
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <mixer.h>
|
||||
#include <max2837.h>
|
||||
#include <sgpio.h>
|
||||
#include <operacake.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
@ -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 =
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
@ -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
|
||||
|
@ -32,6 +32,7 @@ SET(TOOLS
|
||||
hackrf_info
|
||||
hackrf_debug
|
||||
hackrf_sweep
|
||||
hackrf_operacake
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
|
||||
#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 <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");
|
||||
}
|
||||
|
||||
@ -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<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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user