From 82656b8f147d1779ee9e653d9c5d77ea6a5fa521 Mon Sep 17 00:00:00 2001 From: Dominic Spill Date: Fri, 9 Nov 2018 22:10:16 -0700 Subject: [PATCH] HackRF Opera Cake - GPIO test mode --- firmware/common/operacake.c | 94 +++++++++++++++++++++++- firmware/common/operacake.h | 1 + firmware/hackrf_usb/hackrf_usb.c | 3 +- firmware/hackrf_usb/usb_api_operacake.c | 15 ++++ firmware/hackrf_usb/usb_api_operacake.h | 3 + host/hackrf-tools/src/hackrf_operacake.c | 94 ++++++++++++++++++++++-- host/libhackrf/src/hackrf.c | 25 +++++++ host/libhackrf/src/hackrf.h | 4 + 8 files changed, 230 insertions(+), 9 deletions(-) diff --git a/firmware/common/operacake.c b/firmware/common/operacake.c index 5154a890..8a047e14 100644 --- a/firmware/common/operacake.c +++ b/firmware/common/operacake.c @@ -21,7 +21,13 @@ #include "operacake.h" #include "hackrf_core.h" +#include "gpio.h" +#include "gpio_lpc.h" +#include +/* + * I2C Mode + */ #define OPERACAKE_PIN_OE(x) (x<<7) #define OPERACAKE_PIN_U2CTRL1(x) (x<<6) #define OPERACAKE_PIN_U2CTRL0(x) (x<<5) @@ -44,7 +50,7 @@ #define OPERACAKE_SAMESIDE OPERACAKE_PIN_U1CTRL(1) #define OPERACAKE_CROSSOVER OPERACAKE_PIN_U1CTRL(0) #define OPERACAKE_EN_LEDS (OPERACAKE_PIN_LEDEN2(1) | OPERACAKE_PIN_LEDEN2(0)) -#define OPERACAKE_GPIO_EN OPERACAKE_PIN_OE(0) +#define OPERACAKE_GPIO_ENABLE OPERACAKE_PIN_OE(0) #define OPERACAKE_GPIO_DISABLE OPERACAKE_PIN_OE(1) #define OPERACAKE_REG_INPUT 0x00 @@ -56,6 +62,10 @@ | OPERACAKE_PORT_A1 | OPERACAKE_PORT_B1 \ | OPERACAKE_EN_LEDS) #define OPERACAKE_CONFIG_ALL_OUTPUT (0x00) +// Leave LED bits as outputs +#define OPERACAKE_CONFIG_GPIO_INPUTS (0x7C) + +#define OPERACAKE_POLARITY_NORMAL (0x00) #define OPERACAKE_DEFAULT_ADDRESS 0x18 @@ -145,6 +155,9 @@ uint8_t operacake_set_ports(uint8_t address, uint8_t PA, uint8_t PB) { return 0; } +/* + * Opera Glasses + */ typedef struct { uint16_t freq_min; uint16_t freq_max; @@ -194,3 +207,82 @@ uint8_t operacake_set_range(uint32_t freq_mhz) { current_range = i; return 0; } + +/* + * GPIO + */ +uint16_t gpio_test(uint8_t address) +{ + uint8_t i, reg, bit_mask, gpio_mask = 0x1F; + uint16_t result = 0; + operacake_init(); + scu_pinmux(SCU_PINMUX_GPIO3_8, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_GPIO3_12, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_GPIO3_13, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_GPIO3_14, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_GPIO3_15, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); + + static struct gpio_t gpio_pins[] = { + GPIO(3, 8), // u1ctrl IO2 + GPIO(3, 14), // u3ctrl0 IO3 + GPIO(3, 15), // u3ctrl1 IO4 + GPIO(3, 12), // u2ctrl0 IO5 + GPIO(3, 13) // u2ctrl1 IO6 + }; + // Setup I2C to put it in GPIO mode + reg = (OPERACAKE_GPIO_ENABLE | OPERACAKE_EN_LEDS); + operacake_write_reg(oc_bus, address, OPERACAKE_REG_OUTPUT, reg); + operacake_write_reg(oc_bus, address, OPERACAKE_REG_CONFIG, + OPERACAKE_CONFIG_GPIO_INPUTS); + operacake_write_reg(oc_bus, address, OPERACAKE_REG_POLARITY, + OPERACAKE_POLARITY_NORMAL); + // clear state + for(i=0; i<5; i++) { + gpio_output(&gpio_pins[i]); + gpio_write(&gpio_pins[i], 0); + } + // Test each pin separately + for(i=0; i<5; i++) { + // Set pin high + gpio_write(&gpio_pins[i], 1); + // check input + reg = operacake_read_reg(oc_bus, address, OPERACAKE_REG_INPUT); + reg >>= 2; + reg &= gpio_mask; + bit_mask = 1 << i; + result <<= 1; + if(!(reg & bit_mask)) { + // Is the correct bit set? + result |= 1; + } + result <<= 1; + if(reg & ~bit_mask) { + // Are any other bits set? + result |= 1; + } + result <<= 1; + // set pin low + gpio_write(&gpio_pins[i], 0); + // check input + reg = operacake_read_reg(oc_bus, address, OPERACAKE_REG_INPUT); + reg >>= 2; + reg &= gpio_mask; + bit_mask = 1 << i; + if(reg & bit_mask) { + // Is the correct bit clear? + result |= 1; + } + } + + // clean up + for(i=0; i<5; i++) { + gpio_input(&gpio_pins[i]); + } + + // Put it back in to I2C mode and set default pins + operacake_write_reg(oc_bus, address, OPERACAKE_REG_CONFIG, + OPERACAKE_CONFIG_ALL_OUTPUT); + operacake_write_reg(oc_bus, address, OPERACAKE_REG_OUTPUT, + OPERACAKE_DEFAULT_OUTPUT); + return result; +} diff --git a/firmware/common/operacake.h b/firmware/common/operacake.h index a07988cf..77acf08f 100644 --- a/firmware/common/operacake.h +++ b/firmware/common/operacake.h @@ -49,6 +49,7 @@ 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); +uint16_t gpio_test(uint8_t address); #ifdef __cplusplus } diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index 5d0c6ea4..280ad4b2 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -92,7 +92,8 @@ static const usb_request_handler_fn vendor_request_handler[] = { usb_vendor_request_operacake_set_ranges, usb_vendor_request_set_clkout_enable, usb_vendor_request_spiflash_status, - usb_vendor_request_spiflash_clear_status + usb_vendor_request_spiflash_clear_status, + usb_vendor_request_operacake_gpio_test }; 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 4901d900..ef49dc6f 100644 --- a/firmware/hackrf_usb/usb_api_operacake.c +++ b/firmware/hackrf_usb/usb_api_operacake.c @@ -74,3 +74,18 @@ usb_request_status_t usb_vendor_request_operacake_set_ranges( } return USB_REQUEST_STATUS_OK; } + +usb_request_status_t usb_vendor_request_operacake_gpio_test( + usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) +{ + uint16_t test_result; + uint8_t address = endpoint->setup.value & 0xFF; + if (stage == USB_TRANSFER_STAGE_SETUP) { + test_result = gpio_test(address); + endpoint->buffer[0] = test_result & 0xff; + endpoint->buffer[1] = test_result >> 8; + usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 2, 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 73259aca..e6dfbec1 100644 --- a/firmware/hackrf_usb/usb_api_operacake.h +++ b/firmware/hackrf_usb/usb_api_operacake.h @@ -34,4 +34,7 @@ usb_request_status_t usb_vendor_request_operacake_set_ports( usb_request_status_t usb_vendor_request_operacake_set_ranges( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); +usb_request_status_t usb_vendor_request_operacake_gpio_test( + 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 810f2147..53bd754a 100644 --- a/host/hackrf-tools/src/hackrf_operacake.c +++ b/host/hackrf-tools/src/hackrf_operacake.c @@ -36,6 +36,9 @@ typedef int bool; #define FREQ_MAX_MHZ (7250) /* 7250 MHz */ #define MAX_FREQ_RANGES 8 +#define INVALID_ADDRESS 0xFF +#define INVALID_PORT 0xFF + static void usage() { printf("\nUsage:\n"); printf("\t-h, --help: this help\n"); @@ -45,12 +48,14 @@ static void usage() { 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"); + printf("\t-g, --gpio_test: test GPIO functionality of an opera cake\n"); } static struct option long_options[] = { { "device", no_argument, 0, 'd' }, { "address", no_argument, 0, 'o' }, { "list", no_argument, 0, 'l' }, + { "gpio_test", no_argument, 0, 'g' }, { "help", no_argument, 0, 'h' }, { 0, 0, 0, 0 }, }; @@ -135,11 +140,12 @@ int parse_range(char* s, hackrf_oc_range* range) { int main(int argc, char** argv) { int opt; const char* serial_number = NULL; - uint8_t operacake_address = 0; - uint8_t port_a = 0; - uint8_t port_b = 0; + uint8_t operacake_address = INVALID_ADDRESS; + uint8_t port_a = INVALID_PORT; + uint8_t port_b = INVALID_PORT; bool set_ports = false; bool list = false; + bool gpio_test = false; uint8_t operacakes[8]; uint8_t operacake_count = 0; int i = 0; @@ -154,7 +160,7 @@ int main(int argc, char** argv) { return -1; } - while( (opt = getopt_long(argc, argv, "d:o:a:b:lf:h?", long_options, &option_index)) != EOF ) { + while( (opt = getopt_long(argc, argv, "d:o:a:b:lf:hg?", long_options, &option_index)) != EOF ) { switch( opt ) { case 'd': serial_number = optarg; @@ -162,7 +168,6 @@ int main(int argc, char** argv) { case 'o': operacake_address = atoi(optarg); - set_ports = true; break; case 'f': @@ -200,6 +205,7 @@ int main(int argc, char** argv) { fprintf(stderr, "failed to parse port\n"); return EXIT_FAILURE; } + set_ports = true; break; case 'b': @@ -208,11 +214,17 @@ int main(int argc, char** argv) { fprintf(stderr, "failed to parse port\n"); return EXIT_FAILURE; } + set_ports = true; break; case 'l': list = true; break; + + case 'g': + gpio_test = true; + break; + case 'h': case '?': usage(); @@ -225,8 +237,14 @@ int main(int argc, char** argv) { } } - if(!(list || set_ports || range_idx)) { - fprintf(stderr, "Specify either list or address option.\n"); + if(!(list || set_ports || range_idx || gpio_test)) { + fprintf(stderr, "Specify either list, address, or GPIO test option.\n"); + usage(); + return EXIT_FAILURE; + } + + if((set_ports || gpio_test) && (operacake_address == INVALID_ADDRESS)) { + fprintf(stderr, "An address is required.\n"); usage(); return EXIT_FAILURE; } @@ -257,7 +275,69 @@ int main(int argc, char** argv) { printf("\n"); } + if(gpio_test) { + uint16_t test_result; + uint8_t reg, mask = 0x7; + result = hackrf_operacake_gpio_test(device, operacake_address, &test_result); + if (result != HACKRF_SUCCESS) { + fprintf(stderr, "hackrf_operacake_gpio_test() failed: %s (%d)\n", + hackrf_error_name(result), result); + return EXIT_FAILURE; + } + + if(test_result) { + fprintf(stderr, "GPIO test failed\n"); + fprintf(stderr, "Pin\tHigh\tShorts\tLow\n"); + reg = test_result & mask; + fprintf(stderr, "u2ctrl1\t%d\t%d\t%d\n", + (reg>>2) & 1, + (reg>>1) & 1, + reg & 1); + test_result >>= 3; + reg = test_result & mask; + fprintf(stderr, "u2ctrl0\t%d\t%d\t%d\n", + (reg>>2) & 1, + (reg>>1) & 1, + reg & 1); + test_result >>= 3; + reg = test_result & mask; + fprintf(stderr, "u3ctrl1\t%d\t%d\t%d\n", + (reg>>2) & 1, + (reg>>1) & 1, + reg & 1); + test_result >>= 3; + reg = test_result & mask; + fprintf(stderr, "u3ctrl0\t%d\t%d\t%d\n", + (reg>>2) & 1, + (reg>>1) & 1, + reg & 1); + test_result >>= 3; + reg = test_result & mask; + fprintf(stderr, "u1ctrl \t%d\t%d\t%d\n", + (reg>>2) & 1, + (reg>>1) & 1, + reg & 1); + } else { + fprintf(stderr, "GPIO test passed\n"); + } + } + if(set_ports) { + // Set other port to "don't care" if not set + if(port_a == INVALID_PORT) { + if(port_b >= 4) { + port_a = 0; + } else { + port_a = 4; + } + } + if(port_b == INVALID_PORT) { + if(port_a >= 4) { + port_b = 0; + } else { + port_b = 4; + } + } if(((port_a<=3) && (port_b<=3)) || ((port_a>=4) && (port_b>=4))) { fprintf(stderr, "Port A and B cannot be connected to the same side\n"); return EXIT_FAILURE; diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index 3da23019..a062e545 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -83,6 +83,7 @@ typedef enum { HACKRF_VENDOR_REQUEST_CLKOUT_ENABLE = 32, HACKRF_VENDOR_REQUEST_SPIFLASH_STATUS = 33, HACKRF_VENDOR_REQUEST_SPIFLASH_CLEAR_STATUS = 34, + HACKRF_VENDOR_REQUEST_OPERACAKE_GPIO_TEST = 35, } hackrf_vendor_request; #define USB_CONFIG_STANDARD 0x1 @@ -2080,6 +2081,30 @@ int ADDCALL hackrf_set_clkout_enable(hackrf_device* device, const uint8_t value) } } +int ADDCALL hackrf_operacake_gpio_test(hackrf_device* device, const uint8_t address, + uint16_t* test_result) +{ + USB_API_REQUIRED(device, 0x0103) + int result; + result = libusb_control_transfer( + device->usb_device, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + HACKRF_VENDOR_REQUEST_OPERACAKE_GPIO_TEST, + address, + 0, + (unsigned char*)test_result, + 2, + 0 + ); + + if (result < 1) { + 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 476cc571..abd7debd 100644 --- a/host/libhackrf/src/hackrf.h +++ b/host/libhackrf/src/hackrf.h @@ -251,6 +251,10 @@ extern ADDAPI int ADDCALL hackrf_set_operacake_ranges(hackrf_device* device, extern ADDAPI int ADDCALL hackrf_set_clkout_enable(hackrf_device* device, const uint8_t value); +extern ADDAPI int ADDCALL hackrf_operacake_gpio_test(hackrf_device* device, + uint8_t address, + uint16_t* test_result); + #ifdef __cplusplus } // __cplusplus defined. #endif