From 790b5d35cf53312915df13090ad9e422b59cbe06 Mon Sep 17 00:00:00 2001 From: Mike Walters Date: Sat, 31 Jul 2021 02:50:35 +0100 Subject: [PATCH] operacake: add get/set switching mode functions --- firmware/common/operacake.c | 40 +++++++--- firmware/common/operacake.h | 2 + firmware/hackrf_usb/hackrf_usb.c | 2 + firmware/hackrf_usb/usb_api_operacake.c | 26 +++++++ firmware/hackrf_usb/usb_api_operacake.h | 6 ++ host/hackrf-tools/src/hackrf_operacake.c | 47 +++++++++++- host/libhackrf/src/hackrf.c | 94 +++++++++++++++++++++++- host/libhackrf/src/hackrf.h | 14 ++++ 8 files changed, 217 insertions(+), 14 deletions(-) diff --git a/firmware/common/operacake.c b/firmware/common/operacake.c index f62cd5cf..0ad97ee5 100644 --- a/firmware/common/operacake.c +++ b/firmware/common/operacake.c @@ -75,8 +75,14 @@ i2c_bus_t* const oc_bus = &i2c0; +enum operacake_switching_mode { + MODE_MANUAL = 0, + MODE_FREQUENCY = 1, +}; + struct operacake_state { bool present; + enum operacake_switching_mode mode; }; struct operacake_state operacake_boards[OPERACAKE_MAX_BOARDS]; @@ -112,6 +118,7 @@ uint8_t operacake_init(bool allow_gpio) { uint8_t reg = operacake_read_reg(oc_bus, addr, OPERACAKE_REG_CONFIG); operacake_boards[addr].present = (reg == OPERACAKE_CONFIG_ALL_OUTPUT); + operacake_boards[addr].mode = MODE_MANUAL; } allow_gpio_mode = allow_gpio; return 0; @@ -135,6 +142,20 @@ void operacake_get_boards(uint8_t *addresses) { } } +void operacake_set_mode(uint8_t address, uint8_t mode) { + if (address >= OPERACAKE_MAX_BOARDS) + return; + + operacake_boards[address].mode = mode; +} + +uint8_t operacake_get_mode(uint8_t address) { + if (address >= OPERACAKE_MAX_BOARDS) + return 0; + + return operacake_boards[address].mode; +} + uint8_t port_to_pins(uint8_t port) { switch(port) { case OPERACAKE_PA1: @@ -225,25 +246,26 @@ 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)) { + + int range; + for(range=0; range= ranges[range].freq_min) + && (freq_mhz <= ranges[range].freq_max)) { break; } } - if(i == current_range) { + if(range == current_range) { return 1; } - for (i = 0; i < OPERACAKE_MAX_BOARDS; i++) { - if (operacake_is_board_present(i)) { - operacake_set_ports(i, ranges[i].portA, ranges[i].portB); + for (int i = 0; i < OPERACAKE_MAX_BOARDS; i++) { + if (operacake_is_board_present(i) && operacake_get_mode(i) == MODE_FREQUENCY) { + operacake_set_ports(i, ranges[range].portA, ranges[range].portB); break; } } - current_range = i; + current_range = range; return 0; } diff --git a/firmware/common/operacake.h b/firmware/common/operacake.h index c48e9f21..88bb135c 100644 --- a/firmware/common/operacake.h +++ b/firmware/common/operacake.h @@ -45,6 +45,8 @@ extern "C" uint8_t operacake_init(bool allow_gpio); bool operacake_is_board_present(uint8_t address); void operacake_get_boards(uint8_t *addresses); +void operacake_set_mode(uint8_t address, uint8_t mode); +uint8_t operacake_get_mode(uint8_t address); 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); diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index b7b8c01e..8e3e2840 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -111,6 +111,8 @@ static usb_request_handler_fn vendor_request_handler[] = { NULL, #endif usb_vendor_request_set_ui_enable, + usb_vendor_request_operacake_set_mode, + usb_vendor_request_operacake_get_mode, }; 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 50619d0a..a04beab2 100644 --- a/firmware/hackrf_usb/usb_api_operacake.c +++ b/firmware/hackrf_usb/usb_api_operacake.c @@ -92,3 +92,29 @@ usb_request_status_t usb_vendor_request_operacake_gpio_test( } return USB_REQUEST_STATUS_OK; } + +usb_request_status_t usb_vendor_request_operacake_set_mode( + usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) +{ + uint8_t address, mode; + address = endpoint->setup.value & 0xFF; + mode = endpoint->setup.index & 0xFF; + if (stage == USB_TRANSFER_STAGE_SETUP) { + operacake_set_mode(address, mode); + usb_transfer_schedule_ack(endpoint->in); + } + return USB_REQUEST_STATUS_OK; +} + +usb_request_status_t usb_vendor_request_operacake_get_mode( + usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) +{ + uint8_t address; + address = endpoint->setup.value & 0xFF; + if (stage == USB_TRANSFER_STAGE_SETUP) { + endpoint->buffer[0] = operacake_get_mode(address); + usb_transfer_schedule_block(endpoint->in, endpoint->buffer, 1, NULL, NULL); + usb_transfer_schedule_ack(endpoint->out); + } + return USB_REQUEST_STATUS_OK; +} diff --git a/firmware/hackrf_usb/usb_api_operacake.h b/firmware/hackrf_usb/usb_api_operacake.h index e6dfbec1..d41d4b12 100644 --- a/firmware/hackrf_usb/usb_api_operacake.h +++ b/firmware/hackrf_usb/usb_api_operacake.h @@ -37,4 +37,10 @@ usb_request_status_t usb_vendor_request_operacake_set_ranges( usb_request_status_t usb_vendor_request_operacake_gpio_test( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); +usb_request_status_t usb_vendor_request_operacake_set_mode( + usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); + +usb_request_status_t usb_vendor_request_operacake_get_mode( + usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); + #endif /* end of include guard: __USB_API_OPERACAKE_H__ */ diff --git a/host/hackrf-tools/src/hackrf_operacake.c b/host/hackrf-tools/src/hackrf_operacake.c index a597c29e..8c6e3ec8 100644 --- a/host/hackrf-tools/src/hackrf_operacake.c +++ b/host/hackrf-tools/src/hackrf_operacake.c @@ -37,6 +37,7 @@ typedef int bool; #define MAX_FREQ_RANGES 8 #define INVALID_ADDRESS 0xFF +#define INVALID_MODE 0xFF #define INVALID_PORT 0xFF #define GPIO_TEST_DISABLED 0xFFFF @@ -46,6 +47,7 @@ static void usage() { printf("\t-h, --help: this help\n"); printf("\t-d, --device : specify a particular device by serial number\n"); printf("\t-o, --address : specify a particular operacake by address [default: 0x00]\n"); + printf("\t-m, --mode : specify switching mode [options: manual, frequency]\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"); @@ -56,6 +58,7 @@ static void usage() { static struct option long_options[] = { { "device", no_argument, 0, 'd' }, { "address", no_argument, 0, 'o' }, + { "mode", no_argument, 0, 'm' }, { "list", no_argument, 0, 'l' }, { "gpio_test", no_argument, 0, 'g' }, { "help", no_argument, 0, 'h' }, @@ -143,6 +146,8 @@ int main(int argc, char** argv) { int opt; const char* serial_number = NULL; uint8_t operacake_address = INVALID_ADDRESS; + bool set_mode = false; + uint8_t mode; uint8_t port_a = INVALID_PORT; uint8_t port_b = INVALID_PORT; bool set_ports = false; @@ -162,7 +167,7 @@ int main(int argc, char** argv) { return -1; } - while( (opt = getopt_long(argc, argv, "d:o:a:b:lf:hg?", long_options, &option_index)) != EOF ) { + while( (opt = getopt_long(argc, argv, "d:o:a:m:b:lf:hg?", long_options, &option_index)) != EOF ) { switch( opt ) { case 'd': serial_number = optarg; @@ -172,6 +177,21 @@ int main(int argc, char** argv) { operacake_address = atoi(optarg); break; + case 'm': + if (strcmp(optarg, "manual") == 0) { + mode = OPERACAKE_MODE_MANUAL; + set_mode = true; + } else if (strcmp(optarg, "frequency") == 0) { + mode = OPERACAKE_MODE_FREQUENCY; + set_mode = true; + } else { + fprintf(stderr, + "argument error: mode must be one of [manual, frequency].\n"); + usage(); + return EXIT_FAILURE; + } + break; + case 'f': if(MAX_FREQ_RANGES == range_idx) { fprintf(stderr, @@ -239,13 +259,13 @@ int main(int argc, char** argv) { } } - if(!(list || set_ports || range_idx || gpio_test)) { - fprintf(stderr, "Specify either list, address, or GPIO test option.\n"); + if(!(list || set_mode || set_ports || range_idx || gpio_test)) { + fprintf(stderr, "Specify either list, mode, address, or GPIO test option.\n"); usage(); return EXIT_FAILURE; } - if((set_ports || gpio_test) && (operacake_address == INVALID_ADDRESS)) { + if((set_mode || set_ports || gpio_test) && (operacake_address == INVALID_ADDRESS)) { fprintf(stderr, "An address is required.\n"); usage(); return EXIT_FAILURE; @@ -258,6 +278,15 @@ int main(int argc, char** argv) { return EXIT_FAILURE; } + if (set_mode) { + result = hackrf_set_operacake_mode(device, operacake_address, mode); + if (result != HACKRF_SUCCESS) { + fprintf(stderr, "hackrf_set_operacake_mode() failed: %s (%d)\n", + hackrf_error_name(result), result); + return EXIT_FAILURE; + } + } + if(list) { result = hackrf_get_operacake_boards(device, operacakes); if (result != HACKRF_SUCCESS) { @@ -269,6 +298,16 @@ int main(int argc, char** argv) { for(i=0; i<8; i++) { if(operacakes[i] != HACKRF_OPERACAKE_ADDRESS_INVALID) { printf("\n\tAddress: %d", operacakes[i]); + enum operacake_switching_mode mode; + hackrf_get_operacake_mode(device, i, &mode); + printf("\tSwitching mode: "); + if (mode == OPERACAKE_MODE_MANUAL) { + printf("manual\n"); + } else if (mode == OPERACAKE_MODE_FREQUENCY) { + printf("frequency\n"); + } else { + printf("unknown\n"); + } operacake_count++; } } diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index aebceb9e..15549d4e 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -89,6 +89,8 @@ typedef enum { HACKRF_VENDOR_REQUEST_OPERACAKE_GPIO_TEST = 35, HACKRF_VENDOR_REQUEST_CPLD_CHECKSUM = 36, HACKRF_VENDOR_REQUEST_UI_ENABLE = 37, + HACKRF_VENDOR_REQUEST_OPERACAKE_SET_MODE = 38, + HACKRF_VENDOR_REQUEST_OPERACAKE_GET_MODE = 39, } hackrf_vendor_request; #define USB_CONFIG_STANDARD 0x1 @@ -2090,6 +2092,10 @@ int ADDCALL hackrf_init_sweep(hackrf_device* device, } } +bool hackrf_operacake_valid_address(uint8_t address) { + return address < HACKRF_OPERACAKE_MAX_BOARDS; +} + /** * Retrieve list of Opera Cake board addresses * @param[in] device @@ -2121,6 +2127,82 @@ int ADDCALL hackrf_get_operacake_boards(hackrf_device* device, uint8_t* boards) } } +/** + * Set Opera Cake switching mode. + * @param[in] device + * @param[in] address Opera Cake address. + * @param[in] mode Switching mode. + * @return @ref HACKRF_SUCCESS + * @return @ref HACKRF_ERROR_LIBUSB + */ +int ADDCALL hackrf_set_operacake_mode(hackrf_device* device, uint8_t address, enum operacake_switching_mode mode) +{ + USB_API_REQUIRED(device, 0x0105) + + if (!hackrf_operacake_valid_address(address)) { + return HACKRF_ERROR_INVALID_PARAM; + } + + int result; + result = libusb_control_transfer( + device->usb_device, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + HACKRF_VENDOR_REQUEST_OPERACAKE_SET_MODE, + address, + (uint8_t)mode, + NULL, + 0, + 0 + ); + + if (result != 0) + { + last_libusb_error = result; + return HACKRF_ERROR_LIBUSB; + } else { + return HACKRF_SUCCESS; + } +} + +/** + * Get Opera Cake switching mode. + * @param[in] device + * @param[in] address Opera Cake address. + * @param[out] mode Switching mode. + * @return @ref HACKRF_SUCCESS + * @return @ref HACKRF_ERROR_LIBUSB + */ +int ADDCALL hackrf_get_operacake_mode(hackrf_device* device, uint8_t address, enum operacake_switching_mode *mode) +{ + USB_API_REQUIRED(device, 0x0105) + + if (!hackrf_operacake_valid_address(address)) { + return HACKRF_ERROR_INVALID_PARAM; + } + + int result; + uint8_t buf; + result = libusb_control_transfer( + device->usb_device, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + HACKRF_VENDOR_REQUEST_OPERACAKE_GET_MODE, + address, + 0, + &buf, + 1, + 0 + ); + + if (result < 1) + { + last_libusb_error = result; + return HACKRF_ERROR_LIBUSB; + } else { + *mode = buf; + return HACKRF_SUCCESS; + } +} + /* Set Operacake ports */ int ADDCALL hackrf_set_operacake_ports(hackrf_device* device, uint8_t address, @@ -2128,6 +2210,11 @@ int ADDCALL hackrf_set_operacake_ports(hackrf_device* device, uint8_t port_b) { USB_API_REQUIRED(device, 0x0102) + + if (!hackrf_operacake_valid_address(address)) { + return HACKRF_ERROR_INVALID_PARAM; + } + int result; /* Error checking */ if((port_a > OPERACAKE_PB4) || (port_b > OPERACAKE_PB4)) { @@ -2181,8 +2268,8 @@ 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; + int result; result = libusb_control_transfer( device->usb_device, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, @@ -2230,6 +2317,11 @@ int ADDCALL hackrf_operacake_gpio_test(hackrf_device* device, const uint8_t addr uint16_t* test_result) { USB_API_REQUIRED(device, 0x0103) + + if (!hackrf_operacake_valid_address(address)) { + return HACKRF_ERROR_INVALID_PARAM; + } + int result; result = libusb_control_transfer( device->usb_device, diff --git a/host/libhackrf/src/hackrf.h b/host/libhackrf/src/hackrf.h index d1cbaea8..7a9d69e1 100644 --- a/host/libhackrf/src/hackrf.h +++ b/host/libhackrf/src/hackrf.h @@ -51,6 +51,7 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSI #define BYTES_PER_BLOCK 16384 #define MAX_SWEEP_RANGES 10 #define HACKRF_OPERACAKE_ADDRESS_INVALID 0xFF +#define HACKRF_OPERACAKE_MAX_BOARDS 8 enum hackrf_error { HACKRF_SUCCESS = 0, @@ -101,6 +102,17 @@ enum operacake_ports { OPERACAKE_PB4 = 7, }; +enum operacake_switching_mode { + /** + * Port connections are set manually using @ref hackrf_set_operacake_ports. + */ + OPERACAKE_MODE_MANUAL, + /** + * Port connections are switched automatically when the frequency is changed. Frequency ranges can be set using @ref hackrf_set_operacake_ranges. + */ + OPERACAKE_MODE_FREQUENCY, +}; + enum sweep_style { LINEAR = 0, INTERLEAVED = 1, @@ -238,6 +250,8 @@ extern ADDAPI int ADDCALL hackrf_init_sweep(hackrf_device* device, /* Operacake functions */ extern ADDAPI int ADDCALL hackrf_get_operacake_boards(hackrf_device* device, uint8_t* boards); +extern ADDAPI int ADDCALL hackrf_set_operacake_mode(hackrf_device* device, uint8_t address, enum operacake_switching_mode mode); +extern ADDAPI int ADDCALL hackrf_get_operacake_mode(hackrf_device* device, uint8_t address, enum operacake_switching_mode *mode); extern ADDAPI int ADDCALL hackrf_set_operacake_ports(hackrf_device* device, uint8_t address, uint8_t port_a,