Merge pull request #1018 from greatscottgadgets/oc-bugs

Fix Opera Cake bugs
This commit is contained in:
Mike Walters
2022-01-12 17:37:58 +00:00
committed by GitHub
6 changed files with 95 additions and 65 deletions

View File

@ -74,6 +74,9 @@
#define OPERACAKE_MAX_BOARDS 8 #define OPERACAKE_MAX_BOARDS 8
#define INVALID_RANGE 0xFF;
static uint8_t current_range = INVALID_RANGE;
i2c_bus_t* const oc_bus = &i2c0; i2c_bus_t* const oc_bus = &i2c0;
enum operacake_switching_mode { enum operacake_switching_mode {
@ -151,38 +154,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) { uint8_t port_to_pins(uint8_t port) {
switch(port) { switch(port) {
case OPERACAKE_PA1: case OPERACAKE_PA1:
@ -206,16 +177,17 @@ uint8_t port_to_pins(uint8_t port) {
return 0xFF; return 0xFF;
} }
uint8_t operacake_set_ports(uint8_t address, uint8_t PA, uint8_t PB) { /*
uint8_t side, pa, pb, reg; * Issue I2C command to activate ports.
/* Start with some error checking,
* which should have been done either
* on the host or elsewhere in firmware
*/ */
uint8_t operacake_activate_ports(uint8_t address, uint8_t PA, uint8_t PB)
{
uint8_t side, pa, pb, reg;
/* Ensure PA and PB are within the valid range. */
if ((PA > OPERACAKE_PB4) || (PB > OPERACAKE_PB4)) { if ((PA > OPERACAKE_PB4) || (PB > OPERACAKE_PB4)) {
return 1; return 1;
} }
/* Check which side PA and PB are on */ /* Ensure PA and PB are on opposite sides. */
if (((PA <= OPERACAKE_PA4) && (PB <= OPERACAKE_PA4)) if (((PA <= OPERACAKE_PA4) && (PB <= OPERACAKE_PA4))
|| ((PA > OPERACAKE_PA4) && (PB > OPERACAKE_PA4))) { || ((PA > OPERACAKE_PA4) && (PB > OPERACAKE_PA4))) {
return 1; return 1;
@ -227,25 +199,76 @@ uint8_t operacake_set_ports(uint8_t address, uint8_t PA, uint8_t PB) {
side = OPERACAKE_SAMESIDE; side = OPERACAKE_SAMESIDE;
} }
// 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;
pa = port_to_pins(PA); pa = port_to_pins(PA);
pb = port_to_pins(PB); pb = port_to_pins(PB);
reg = (OPERACAKE_GPIO_DISABLE | side reg = (OPERACAKE_GPIO_DISABLE | side | pa | pb | OPERACAKE_EN_LEDS);
| pa | pb | OPERACAKE_EN_LEDS);
operacake_write_reg(oc_bus, address, OPERACAKE_REG_OUTPUT, reg); operacake_write_reg(oc_bus, address, OPERACAKE_REG_OUTPUT, reg);
return 0; return 0;
} }
void operacake_set_mode(uint8_t address, uint8_t mode) {
if (address >= OPERACAKE_MAX_BOARDS)
return;
operacake_boards[address].mode = mode;
current_range = INVALID_RANGE;
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;
}
/* /*
* Opera Glasses * 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;
// 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);
}
return 0;
}
/*
* frequency mode aka "Opera Glasses"
*/ */
typedef struct { typedef struct {
uint16_t freq_min; uint16_t freq_min;
@ -264,18 +287,19 @@ 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_min = freq_min;
ranges[range_idx].freq_max = freq_max; ranges[range_idx].freq_max = freq_max;
ranges[range_idx].portA = port; ranges[range_idx].portA = port;
ranges[range_idx].portB = 7; /* Make the B port mirror the A port. */
if(port <= OPERACAKE_PA4) { ranges[range_idx].portB = (port + 4) % 8;
ranges[range_idx].portB = range_idx+4;
} else {
ranges[range_idx].portB = OPERACAKE_PA1;
}
range_idx++; range_idx++;
current_range = INVALID_RANGE;
return 0; return 0;
} }
void operacake_clear_ranges(void)
{
range_idx = 0;
}
#define FREQ_ONE_MHZ (1000000ull) #define FREQ_ONE_MHZ (1000000ull)
static uint8_t current_range = 0xFF;
uint8_t operacake_set_range(uint32_t freq_mhz) { uint8_t operacake_set_range(uint32_t freq_mhz) {
if(range_idx == 0) { if(range_idx == 0) {
@ -289,13 +313,17 @@ uint8_t operacake_set_range(uint32_t freq_mhz) {
break; break;
} }
} }
/* Use the last range if there was no match. */
if (range == range_idx) {
range--;
}
if(range == current_range) { if(range == current_range) {
return 1; return 1;
} }
for (int i = 0; i < OPERACAKE_MAX_BOARDS; i++) { for (int i = 0; i < OPERACAKE_MAX_BOARDS; i++) {
if (operacake_is_board_present(i) && operacake_get_mode(i) == MODE_FREQUENCY) { 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; break;
} }
} }

View File

@ -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_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_add_range(uint16_t freq_min, uint16_t freq_max, uint8_t port);
uint8_t operacake_set_range(uint32_t freq_mhz); uint8_t operacake_set_range(uint32_t freq_mhz);
void operacake_clear_ranges(void);
uint16_t gpio_test(uint8_t address); uint16_t gpio_test(uint8_t address);
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -65,6 +65,7 @@ usb_request_status_t usb_vendor_request_operacake_set_ranges(
if((num_ranges == 0) || (num_ranges > MAX_OPERACAKE_RANGES)) { if((num_ranges == 0) || (num_ranges > MAX_OPERACAKE_RANGES)) {
return USB_REQUEST_STATUS_STALL; return USB_REQUEST_STATUS_STALL;
} }
operacake_clear_ranges();
usb_transfer_schedule_block(endpoint->out, &data, usb_transfer_schedule_block(endpoint->out, &data,
endpoint->setup.length, NULL, NULL); endpoint->setup.length, NULL, NULL);
} else if (stage == USB_TRANSFER_STAGE_DATA) { } else if (stage == USB_TRANSFER_STAGE_DATA) {

View File

@ -57,9 +57,9 @@ static void usage() {
} }
static struct option long_options[] = { static struct option long_options[] = {
{ "device", no_argument, 0, 'd' }, { "device", required_argument, 0, 'd' },
{ "address", no_argument, 0, 'o' }, { "address", required_argument, 0, 'o' },
{ "mode", no_argument, 0, 'm' }, { "mode", required_argument, 0, 'm' },
{ "list", no_argument, 0, 'l' }, { "list", no_argument, 0, 'l' },
{ "gpio_test", no_argument, 0, 'g' }, { "gpio_test", no_argument, 0, 'g' },
{ "help", no_argument, 0, 'h' }, { "help", no_argument, 0, 'h' },

View File

@ -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, int ADDCALL hackrf_set_operacake_ports(hackrf_device* device,
uint8_t address, uint8_t address,
uint8_t port_a, uint8_t port_a,

View File

@ -110,7 +110,7 @@ enum operacake_switching_mode {
*/ */
OPERACAKE_MODE_MANUAL, 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, OPERACAKE_MODE_FREQUENCY,
/** /**