From 3b8c317800d0452173ac2636569ce71bbe343705 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Sat, 11 Dec 2021 17:37:36 -0700 Subject: [PATCH 1/6] hackrf_operacake: fix long options with arguments --- host/hackrf-tools/src/hackrf_operacake.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/host/hackrf-tools/src/hackrf_operacake.c b/host/hackrf-tools/src/hackrf_operacake.c index 2a8664f1..ca0a114a 100644 --- a/host/hackrf-tools/src/hackrf_operacake.c +++ b/host/hackrf-tools/src/hackrf_operacake.c @@ -57,9 +57,9 @@ static void usage() { } static struct option long_options[] = { - { "device", no_argument, 0, 'd' }, - { "address", no_argument, 0, 'o' }, - { "mode", no_argument, 0, 'm' }, + { "device", required_argument, 0, 'd' }, + { "address", required_argument, 0, 'o' }, + { "mode", required_argument, 0, 'm' }, { "list", no_argument, 0, 'l' }, { "gpio_test", no_argument, 0, 'g' }, { "help", no_argument, 0, 'h' }, From 083f502413db604ebf0cf4b755e0f718dc98218c Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Sat, 11 Dec 2021 17:51:51 -0700 Subject: [PATCH 2/6] mirror Opera Cake port selection in frequency mode --- firmware/common/operacake.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/firmware/common/operacake.c b/firmware/common/operacake.c index 6230cb39..a75a7907 100644 --- a/firmware/common/operacake.c +++ b/firmware/common/operacake.c @@ -264,12 +264,8 @@ uint8_t operacake_add_range(uint16_t freq_min, uint16_t freq_max, uint8_t port) 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; - } + /* Make the B port mirror the A port. */ + ranges[range_idx].portB = (port + 4) % 8; range_idx++; return 0; } From e25096b17a97b77a3cf2a0e7824c22a56aa26813 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Sun, 12 Dec 2021 11:56:57 -0700 Subject: [PATCH 3/6] firmware: add operacake_activate_ports() Fixes frequency mode which had been broken by operacake_set_ports() only activating the selected ports when in manual mode (at my suggestion). --- firmware/common/operacake.c | 125 +++++++++++++++++++++--------------- host/libhackrf/src/hackrf.c | 2 +- host/libhackrf/src/hackrf.h | 2 +- 3 files changed, 74 insertions(+), 55 deletions(-) diff --git a/firmware/common/operacake.c b/firmware/common/operacake.c index a75a7907..4ed757db 100644 --- a/firmware/common/operacake.c +++ b/firmware/common/operacake.c @@ -151,38 +151,6 @@ 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; - - if (mode == MODE_TIME) { - // Switch Opera Cake to pin-control mode - uint8_t config_pins = (uint8_t)~(OPERACAKE_PIN_OE(1) | OPERACAKE_PIN_LEDEN(1) | OPERACAKE_PIN_LEDEN2(1)); - operacake_write_reg(oc_bus, address, OPERACAKE_REG_CONFIG, config_pins); - operacake_write_reg(oc_bus, address, OPERACAKE_REG_OUTPUT, OPERACAKE_GPIO_ENABLE | OPERACAKE_EN_LEDS); - } else { - operacake_write_reg(oc_bus, address, OPERACAKE_REG_CONFIG, OPERACAKE_CONFIG_ALL_OUTPUT); - operacake_set_ports(address, operacake_boards[address].PA, operacake_boards[address].PB); - } - - // If any boards are in MODE_TIME, enable the sctimer events. - bool enable_sctimer = false; - for (int i = 0; i < OPERACAKE_MAX_BOARDS; i++) { - if (operacake_boards[i].mode == MODE_TIME) - enable_sctimer = true; - } - operacake_sctimer_enable(enable_sctimer); -} - -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: @@ -206,46 +174,97 @@ uint8_t port_to_pins(uint8_t port) { return 0xFF; } -uint8_t operacake_set_ports(uint8_t address, uint8_t PA, uint8_t PB) { +/* + * Issue I2C command to activate ports. + */ +uint8_t operacake_activate_ports(uint8_t address, uint8_t PA, uint8_t PB) +{ uint8_t side, pa, pb, reg; - /* Start with some error checking, - * which should have been done either - * on the host or elsewhere in firmware - */ - if((PA > OPERACAKE_PB4) || (PB > OPERACAKE_PB4)) { + /* Ensure PA and PB are within the valid range. */ + if ((PA > OPERACAKE_PB4) || (PB > OPERACAKE_PB4)) { return 1; } - /* Check which side PA and PB are on */ - if(((PA <= OPERACAKE_PA4) && (PB <= OPERACAKE_PA4)) - || ((PA > OPERACAKE_PA4) && (PB > OPERACAKE_PA4))) { + /* Ensure PA and PB are on opposite sides. */ + if (((PA <= OPERACAKE_PA4) && (PB <= OPERACAKE_PA4)) + || ((PA > OPERACAKE_PA4) && (PB > OPERACAKE_PA4))) { return 1; } - if(PA > OPERACAKE_PA4) { + if (PA > OPERACAKE_PA4) { side = OPERACAKE_CROSSOVER; } else { side = OPERACAKE_SAMESIDE; } + pa = port_to_pins(PA); + pb = port_to_pins(PB); + + reg = (OPERACAKE_GPIO_DISABLE | side | pa | pb | OPERACAKE_EN_LEDS); + operacake_write_reg(oc_bus, address, OPERACAKE_REG_OUTPUT, reg); + return 0; +} + +void operacake_set_mode(uint8_t address, uint8_t mode) { + if (address >= OPERACAKE_MAX_BOARDS) + return; + + operacake_boards[address].mode = mode; + + if (mode == MODE_TIME) { + // Switch Opera Cake to pin-control mode + uint8_t config_pins = (uint8_t)~(OPERACAKE_PIN_OE(1) | OPERACAKE_PIN_LEDEN(1) | OPERACAKE_PIN_LEDEN2(1)); + operacake_write_reg(oc_bus, address, OPERACAKE_REG_CONFIG, config_pins); + operacake_write_reg(oc_bus, address, OPERACAKE_REG_OUTPUT, OPERACAKE_GPIO_ENABLE | OPERACAKE_EN_LEDS); + } else { + operacake_write_reg(oc_bus, address, OPERACAKE_REG_CONFIG, OPERACAKE_CONFIG_ALL_OUTPUT); + operacake_activate_ports(address, operacake_boards[address].PA, operacake_boards[address].PB); + } + + // If any boards are in MODE_TIME, enable the sctimer events. + bool enable_sctimer = false; + for (int i = 0; i < OPERACAKE_MAX_BOARDS; i++) { + if (operacake_boards[i].mode == MODE_TIME) + enable_sctimer = true; + } + operacake_sctimer_enable(enable_sctimer); +} + +uint8_t operacake_get_mode(uint8_t address) { + if (address >= OPERACAKE_MAX_BOARDS) + return 0; + + return operacake_boards[address].mode; +} + +/* + * Set manual mode ports. + */ +uint8_t operacake_set_ports(uint8_t address, uint8_t PA, uint8_t PB) +{ + /* Ensure PA and PB are within the valid range. */ + if ((PA > OPERACAKE_PB4) || (PB > OPERACAKE_PB4)) { + return 1; + } + /* Ensure PA and PB are on opposite sides. */ + if (((PA <= OPERACAKE_PA4) && (PB <= OPERACAKE_PA4)) + || ((PA > OPERACAKE_PA4) && (PB > OPERACAKE_PA4))) { + return 1; + } + // Keep track of manual settings for when we switch in/out of time/frequency modes. operacake_boards[address].PA = PA; operacake_boards[address].PB = PB; - // Only apply register settings if the board is in manual mode. - if (operacake_boards[address].mode != MODE_MANUAL) - return 0; + // Immediately apply register settings if the board is in manual mode. + if (operacake_boards[address].mode == MODE_MANUAL) { + return operacake_activate_ports(address, PA, PB); + } - pa = port_to_pins(PA); - pb = port_to_pins(PB); - - reg = (OPERACAKE_GPIO_DISABLE | side - | pa | pb | OPERACAKE_EN_LEDS); - operacake_write_reg(oc_bus, address, OPERACAKE_REG_OUTPUT, reg); return 0; } /* - * Opera Glasses + * frequency mode aka "Opera Glasses" */ typedef struct { uint16_t freq_min; @@ -291,7 +310,7 @@ uint8_t operacake_set_range(uint32_t freq_mhz) { 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); + operacake_activate_ports(i, ranges[range].portA, ranges[range].portB); break; } } diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index 5be23d6f..025c2d59 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -2204,7 +2204,7 @@ int ADDCALL hackrf_get_operacake_mode(hackrf_device* device, uint8_t address, en } } -/* Set Operacake ports */ +/* Set Operacake manual mode ports. */ int ADDCALL hackrf_set_operacake_ports(hackrf_device* device, uint8_t address, uint8_t port_a, diff --git a/host/libhackrf/src/hackrf.h b/host/libhackrf/src/hackrf.h index 70acec8c..4fb56363 100644 --- a/host/libhackrf/src/hackrf.h +++ b/host/libhackrf/src/hackrf.h @@ -110,7 +110,7 @@ enum operacake_switching_mode { */ OPERACAKE_MODE_MANUAL, /** - * Port connections are switched automatically when the frequency is changed. Frequency ranges can be set using @ref hackrf_set_operacake_ranges. + * Port connections are switched automatically when the frequency is changed. Frequency ranges can be set using @ref hackrf_set_operacake_freq_ranges. */ OPERACAKE_MODE_FREQUENCY, /** From 66de65e6b44573d65334ed7d059755de84c27327 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Sun, 12 Dec 2021 13:18:29 -0700 Subject: [PATCH 4/6] start Opera Cake frequency mode correctly When switching to frequency mode or modifying the frequency ranges, ensure that the Opera Cake is switched to the correct port on the very next tuning. --- firmware/common/operacake.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/firmware/common/operacake.c b/firmware/common/operacake.c index 4ed757db..4999b19b 100644 --- a/firmware/common/operacake.c +++ b/firmware/common/operacake.c @@ -74,6 +74,9 @@ #define OPERACAKE_MAX_BOARDS 8 +#define INVALID_RANGE 0xFF; +static uint8_t current_range = INVALID_RANGE; + i2c_bus_t* const oc_bus = &i2c0; enum operacake_switching_mode { @@ -209,6 +212,7 @@ void operacake_set_mode(uint8_t address, uint8_t mode) { return; operacake_boards[address].mode = mode; + current_range = INVALID_RANGE; if (mode == MODE_TIME) { // Switch Opera Cake to pin-control mode @@ -286,11 +290,11 @@ uint8_t operacake_add_range(uint16_t freq_min, uint16_t freq_max, uint8_t port) /* Make the B port mirror the A port. */ ranges[range_idx].portB = (port + 4) % 8; range_idx++; + current_range = INVALID_RANGE; 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) { From d0c0270b9c8038ed7cb6f260052d111db73ee9b6 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Sun, 12 Dec 2021 13:25:44 -0700 Subject: [PATCH 5/6] clear frequency ranges before adding new ones --- firmware/common/operacake.c | 5 +++++ firmware/common/operacake.h | 1 + firmware/hackrf_usb/usb_api_operacake.c | 1 + 3 files changed, 7 insertions(+) diff --git a/firmware/common/operacake.c b/firmware/common/operacake.c index 4999b19b..f4acd306 100644 --- a/firmware/common/operacake.c +++ b/firmware/common/operacake.c @@ -294,6 +294,11 @@ uint8_t operacake_add_range(uint16_t freq_min, uint16_t freq_max, uint8_t port) return 0; } +void operacake_clear_ranges(void) +{ + range_idx = 0; +} + #define FREQ_ONE_MHZ (1000000ull) uint8_t operacake_set_range(uint32_t freq_mhz) { diff --git a/firmware/common/operacake.h b/firmware/common/operacake.h index 88bb135c..3b2621bb 100644 --- a/firmware/common/operacake.h +++ b/firmware/common/operacake.h @@ -50,6 +50,7 @@ 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); +void operacake_clear_ranges(void); uint16_t gpio_test(uint8_t address); #ifdef __cplusplus diff --git a/firmware/hackrf_usb/usb_api_operacake.c b/firmware/hackrf_usb/usb_api_operacake.c index 00374522..43f14a52 100644 --- a/firmware/hackrf_usb/usb_api_operacake.c +++ b/firmware/hackrf_usb/usb_api_operacake.c @@ -65,6 +65,7 @@ usb_request_status_t usb_vendor_request_operacake_set_ranges( if((num_ranges == 0) || (num_ranges > MAX_OPERACAKE_RANGES)) { return USB_REQUEST_STATUS_STALL; } + operacake_clear_ranges(); usb_transfer_schedule_block(endpoint->out, &data, endpoint->setup.length, NULL, NULL); } else if (stage == USB_TRANSFER_STAGE_DATA) { From 8cd5d682b8beff65c1cc48388e4a8290e5b8723c Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Sun, 12 Dec 2021 13:29:25 -0700 Subject: [PATCH 6/6] default to the last specified frequency range This was supposed to be the default, but there was a bug that looked past the last range. --- firmware/common/operacake.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/firmware/common/operacake.c b/firmware/common/operacake.c index f4acd306..3a19c4cd 100644 --- a/firmware/common/operacake.c +++ b/firmware/common/operacake.c @@ -313,6 +313,10 @@ uint8_t operacake_set_range(uint32_t freq_mhz) { break; } } + /* Use the last range if there was no match. */ + if (range == range_idx) { + range--; + } if(range == current_range) { return 1; }