operacake: add get/set switching mode functions

This commit is contained in:
Mike Walters
2021-07-31 02:50:35 +01:00
parent 7fd3db9b2b
commit 790b5d35cf
8 changed files with 217 additions and 14 deletions

View File

@ -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<range_idx; i++) {
if((freq_mhz >= ranges[i].freq_min)
&& (freq_mhz <= ranges[i].freq_max)) {
int range;
for(range=0; range<range_idx; range++) {
if((freq_mhz >= 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;
}

View File

@ -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);

View File

@ -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 =

View File

@ -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;
}

View File

@ -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__ */

View File

@ -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 <n>: specify a particular device by serial number\n");
printf("\t-o, --address <n>: specify a particular operacake by address [default: 0x00]\n");
printf("\t-m, --mode <mode>: specify switching mode [options: manual, frequency]\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");
@ -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++;
}
}

View File

@ -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,

View File

@ -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,