diff --git a/firmware/common/rf_path.c b/firmware/common/rf_path.c index ba8ef69ba..0a82ea7fa 100644 --- a/firmware/common/rf_path.c +++ b/firmware/common/rf_path.c @@ -34,6 +34,7 @@ #include "max283x.h" #include "max5864.h" #include "sgpio.h" +#include "user_config.h" #if (defined JAWBREAKER || defined HACKRF_ONE || defined RAD1O) /* @@ -386,6 +387,10 @@ void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t d { /* Turn off TX and RX amplifiers, then enable based on direction and bypass state. */ rf_path->switchctrl |= SWITCHCTRL_NO_TX_AMP_PWR | SWITCHCTRL_NO_RX_AMP_PWR; + + // Perform any user-requested actions for mode switch + user_config_on_rf_path_direction_change(rf_path, direction); + switch (direction) { case RF_PATH_DIRECTION_TX: rf_path->switchctrl |= SWITCHCTRL_TX; @@ -427,9 +432,6 @@ void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t d case RF_PATH_DIRECTION_OFF: default: -#ifdef HACKRF_ONE - rf_path_set_antenna(rf_path, 0); -#endif rf_path_set_lna(rf_path, 0); /* Set RF path to receive direction when "off" */ rf_path->switchctrl &= ~SWITCHCTRL_TX; @@ -510,4 +512,4 @@ void rf_path_set_antenna(rf_path_t* const rf_path, const uint_fast8_t enable) switchctrl_set(rf_path, rf_path->switchctrl); hackrf_ui()->set_antenna_bias(enable); -} +} \ No newline at end of file diff --git a/firmware/common/user_config.c b/firmware/common/user_config.c new file mode 100644 index 000000000..6c1ba419b --- /dev/null +++ b/firmware/common/user_config.c @@ -0,0 +1,112 @@ +/* + * Copyright 2023 Jonathan Suite (GitHub: @ai6aj) + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "user_config.h" + +static user_config_user_opt_t user_direction_rx_bias_t_opts = RF_DIRECTION_USER_OPT_NOP; +static user_config_user_opt_t user_direction_tx_bias_t_opts = RF_DIRECTION_USER_OPT_NOP; +static user_config_user_opt_t user_direction_off_bias_t_opts = + RF_DIRECTION_USER_OPT_CLEAR; + +// Perform user-specified actions to Bias T power when transitioning modes +static void _rf_path_handle_user_bias_t_action(rf_path_t* const rf_path, int action) +{ + switch (action) { + case RF_DIRECTION_USER_OPT_SET: + rf_path_set_antenna(rf_path, 1); + break; + + case RF_DIRECTION_USER_OPT_CLEAR: + rf_path_set_antenna(rf_path, 0); + break; + + case RF_DIRECTION_USER_OPT_NOP: + default: + break; + } +} + +void user_config_on_rf_path_direction_change( + rf_path_t* const rf_path, + const rf_path_direction_t direction) +{ + switch (direction) { + case RF_PATH_DIRECTION_RX: + _rf_path_handle_user_bias_t_action(rf_path, user_direction_rx_bias_t_opts); + break; + + case RF_PATH_DIRECTION_TX: + _rf_path_handle_user_bias_t_action(rf_path, user_direction_tx_bias_t_opts); + break; + + case RF_PATH_DIRECTION_OFF: + default: + _rf_path_handle_user_bias_t_action( + rf_path, + user_direction_off_bias_t_opts); + break; + } +} + +void user_config_set_bias_t_opt( + const rf_path_direction_t direction, + const user_config_user_opt_t option) +{ + switch (direction) { + case RF_PATH_DIRECTION_RX: + user_direction_rx_bias_t_opts = option; + break; + + case RF_PATH_DIRECTION_TX: + user_direction_tx_bias_t_opts = option; + break; + + case RF_PATH_DIRECTION_OFF: + user_direction_off_bias_t_opts = option; + break; + + default: + break; + } +} + +/* + Bias T options are set as follows: + Bits 0,1: One of NOP (0), CLEAR (0b10), or SET (0b11) + Bit 2: 1=Set OFF behavior according to bits 0,1 0=Don't change + Bits 3,4: One of NOP (0), CLEAR (0b10), or SET (0b11) + Bit 5: 1=Set RX behavior according to bits 0,1 0=Don't change + Bits 6,7: One of NOP (0), CLEAR (0b10), or SET (0b11) + Bit 8: 1=Set TX behavior according to bits 0,1 0=Don't change + Bits 9-15: Ignored; set to 0 +*/ +void user_config_set_bias_t_opts(uint16_t value) +{ + if (value & 0x4) { + user_config_set_bias_t_opt(RF_PATH_DIRECTION_OFF, value & 0x3); + } + if (value & 0x20) { + user_config_set_bias_t_opt(RF_PATH_DIRECTION_RX, (value & 0x18) >> 3); + } + if (value & 0x100) { + user_config_set_bias_t_opt(RF_PATH_DIRECTION_TX, (value & 0xC0) >> 6); + } +} diff --git a/firmware/common/user_config.h b/firmware/common/user_config.h new file mode 100644 index 000000000..114ba0f35 --- /dev/null +++ b/firmware/common/user_config.h @@ -0,0 +1,43 @@ +/* + * Copyright 2023 Jonathan Suite (GitHub: @ai6aj) + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __USER_CONFIG_H__ +#define __USER_CONFIG_H__ + +#include "rf_path.h" + +typedef enum { + RF_DIRECTION_USER_OPT_NOP, // No OPeration / Ignore the thing + RF_DIRECTION_USER_OPT_RESERVED, // Currently a NOP + RF_DIRECTION_USER_OPT_CLEAR, // Clear/Disable the thing + RF_DIRECTION_USER_OPT_SET, // Set/Enable the thing +} user_config_user_opt_t; + +void user_config_set_bias_t_opt( + const rf_path_direction_t direction, + const user_config_user_opt_t action); +void user_config_set_bias_t_opts(uint16_t value); + +void user_config_on_rf_path_direction_change( + rf_path_t* const rf_path, + const rf_path_direction_t direction); + +#endif \ No newline at end of file diff --git a/firmware/hackrf-common.cmake b/firmware/hackrf-common.cmake index 83250c89f..90e3e9463 100644 --- a/firmware/hackrf-common.cmake +++ b/firmware/hackrf-common.cmake @@ -190,7 +190,8 @@ macro(DeclareTargets) ${PATH_HACKRF_FIRMWARE_COMMON}/firmware_info.c ${PATH_HACKRF_FIRMWARE_COMMON}/clkin.c ${PATH_HACKRF_FIRMWARE_COMMON}/gpdma.c - ) + ${PATH_HACKRF_FIRMWARE_COMMON}/user_config.c + ) if(BOARD STREQUAL "RAD1O") SET(SRC_M4 diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index 4b7856835..e6536795e 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -125,6 +125,7 @@ static usb_request_handler_fn vendor_request_handler[] = { usb_vendor_request_read_board_rev, usb_vendor_request_read_supported_platform, usb_vendor_request_set_leds, + usb_vendor_request_user_config_set_bias_t_opts, }; static const uint32_t vendor_request_handler_count = diff --git a/firmware/hackrf_usb/usb_api_register.c b/firmware/hackrf_usb/usb_api_register.c index b3aa241be..8058fb5e5 100644 --- a/firmware/hackrf_usb/usb_api_register.c +++ b/firmware/hackrf_usb/usb_api_register.c @@ -22,7 +22,7 @@ */ #include "usb_api_register.h" - +#include #include #include #include @@ -208,3 +208,14 @@ usb_request_status_t usb_vendor_request_set_leds( } return USB_REQUEST_STATUS_OK; } + +usb_request_status_t usb_vendor_request_user_config_set_bias_t_opts( + usb_endpoint_t* const endpoint, + const usb_transfer_stage_t stage) +{ + if (stage == USB_TRANSFER_STAGE_SETUP) { + user_config_set_bias_t_opts(endpoint->setup.value); + usb_transfer_schedule_ack(endpoint->in); + } + return USB_REQUEST_STATUS_OK; +} diff --git a/firmware/hackrf_usb/usb_api_register.h b/firmware/hackrf_usb/usb_api_register.h index 7f26283a1..cb3a2f775 100644 --- a/firmware/hackrf_usb/usb_api_register.h +++ b/firmware/hackrf_usb/usb_api_register.h @@ -54,5 +54,8 @@ usb_request_status_t usb_vendor_request_get_clkin_status( usb_request_status_t usb_vendor_request_set_leds( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); +usb_request_status_t usb_vendor_request_user_config_set_bias_t_opts( + usb_endpoint_t* const endpoint, + const usb_transfer_stage_t stage); #endif /* end of include guard: __USB_API_REGISTER_H__ */ diff --git a/firmware/hackrf_usb/usb_descriptor.c b/firmware/hackrf_usb/usb_descriptor.c index ecf094d9d..ed388859e 100644 --- a/firmware/hackrf_usb/usb_descriptor.c +++ b/firmware/hackrf_usb/usb_descriptor.c @@ -37,7 +37,7 @@ #define USB_PRODUCT_ID (0xFFFF) #endif -#define USB_API_VERSION (0x0107) +#define USB_API_VERSION (0x0108) #define USB_WORD(x) (x & 0xFF), ((x >> 8) & 0xFF) diff --git a/host/hackrf-tools/src/CMakeLists.txt b/host/hackrf-tools/src/CMakeLists.txt index 7115151c4..9cfac7cfd 100644 --- a/host/hackrf-tools/src/CMakeLists.txt +++ b/host/hackrf-tools/src/CMakeLists.txt @@ -37,6 +37,7 @@ SET(TOOLS hackrf_clock hackrf_sweep hackrf_operacake + hackrf_biast ) if(MSVC) diff --git a/host/hackrf-tools/src/hackrf_biast.c b/host/hackrf-tools/src/hackrf_biast.c new file mode 100644 index 000000000..2231257fd --- /dev/null +++ b/host/hackrf-tools/src/hackrf_biast.c @@ -0,0 +1,216 @@ +/* + * Copyright 2023 Jonathan Suite (GitHub: @ai6aj) + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include +#include +#include + +#if defined(__GNUC__) + #include + #include +#endif + +#define USAGE 1 +#define INVALID_BIAST_MODE 2 + +void usage() +{ + fprintf(stderr, + "\nhackrf_biast - enable/disable antenna power on the HackRF for compatibility\n"); + fprintf(stderr, + " with software that does not support this function\n\n"); + fprintf(stderr, "Usage: \n"); + fprintf(stderr, " -h Display this help\n"); + fprintf(stderr, + " -R Reset all bias tee settings to device default. When combined\n"); + fprintf(stderr, + " with -r/-t/-o, those settings will take precedence.\n\n"); + + fprintf(stderr, + " [-b mode] 1=Enable bias tee immediately, 0=disable immediately\n"); + fprintf(stderr, + " [-r mode] Set default bias tee power when device enters RX mode\n"); + fprintf(stderr, + " [-t mode] Set default bias tee power when device enters TX mode\n"); + fprintf(stderr, + " [-o mode] Set default bias tee power when device enters OFF mode\n"); + + fprintf(stderr, + " [-d serial_number] Specify serial number of HackRF device to configure\n\n\n"); + fprintf(stderr, "The -r/-t/-o options support the following mode settings:\n\n"); + fprintf(stderr, " leave do nothing when entering mode\n"); + fprintf(stderr, " on enable bias tee when entering mode\n"); + fprintf(stderr, " off disable bias tee when entering mode\n\n"); + exit(USAGE); +} + +void update_user_mode( + const char* direction_str, + const char* strarg, + hackrf_bool_user_settting* setting) +{ + if (strcmp("off", strarg) == 0) { + setting->do_update = true; + setting->change_on_mode_entry = true; + setting->enabled = false; + } else if (strcmp("on", strarg) == 0) { + setting->do_update = true; + setting->change_on_mode_entry = true; + setting->enabled = true; + } else if (strcmp("leave", strarg) == 0) { + setting->do_update = true; + setting->change_on_mode_entry = false; + setting->enabled = false; + } else { + fprintf(stderr, "Invalid mode '%s' for %s\n", strarg, direction_str); + exit(INVALID_BIAST_MODE); + } +} + +int main(int argc, char** argv) +{ + int opt; + int result = HACKRF_SUCCESS; + hackrf_device* device; + + int biast_enable = -1; + int do_user_opts_update = 0; + hackrf_bias_t_user_settting_req req; + + req.off.do_update = false; + req.off.change_on_mode_entry = false; + req.off.enabled = false; + req.rx.do_update = false; + req.rx.change_on_mode_entry = false; + req.rx.enabled = false; + req.tx.do_update = false; + req.tx.change_on_mode_entry = false; + req.tx.enabled = false; + + const char* serial_number = NULL; + + while ((opt = getopt(argc, argv, "d:b:h?Rr:t:o:")) != EOF) { + result = HACKRF_SUCCESS; + + switch (opt) { + case 'b': + biast_enable = atoi(optarg) ? 1 : 0; + break; + + case 'd': + serial_number = optarg; + break; + + case 'r': + do_user_opts_update = 1; + update_user_mode("RX", optarg, &req.rx); + break; + + case 't': + do_user_opts_update = 1; + update_user_mode("TX", optarg, &req.tx); + break; + + case 'o': + do_user_opts_update = 1; + update_user_mode("OFF", optarg, &req.off); + break; + + case 'R': + do_user_opts_update = 1; + req.rx.do_update = true; + req.rx.change_on_mode_entry = false; + req.rx.enabled = false; + req.tx.do_update = true; + req.tx.change_on_mode_entry = false; + req.tx.enabled = false; + req.off.do_update = true; + req.off.change_on_mode_entry = true; + req.off.enabled = false; + break; + + case 'h': + case '?': + usage(); + return EXIT_FAILURE; + } + } + + result = hackrf_init(); + if (result != HACKRF_SUCCESS) { + fprintf(stderr, + "hackrf_init() failed: %s (%d)\n", + hackrf_error_name(result), + result); + return EXIT_FAILURE; + } + + result = hackrf_open_by_serial(serial_number, &device); + if (result != HACKRF_SUCCESS) { + fprintf(stderr, + "hackrf_open() failed: %s (%d)\n", + hackrf_error_name(result), + result); + usage(); + return EXIT_FAILURE; + } + + if (!(biast_enable >= 0 || do_user_opts_update)) { + usage(); + } + + if (biast_enable >= 0) { + result = hackrf_set_antenna_enable(device, (uint8_t) biast_enable); + if (result != HACKRF_SUCCESS) { + fprintf(stderr, + "hackrf_set_antenna_enable() failed: %s (%d)\n", + hackrf_error_name(result), + result); + return EXIT_FAILURE; + } + } + + if (do_user_opts_update) { + result = hackrf_set_user_bias_t_opts(device, &req); + if (result != HACKRF_SUCCESS) { + fprintf(stderr, + "hackrf_set_user_bias_t_opts() failed: %s (%d)\n", + hackrf_error_name(result), + result); + return EXIT_FAILURE; + } + } + + result = hackrf_close(device); + if (result != HACKRF_SUCCESS) { + fprintf(stderr, + "hackrf_close() failed: %s (%d)\n", + hackrf_error_name(result), + result); + } + + hackrf_exit(); + + return EXIT_SUCCESS; +} diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index c75ec5a48..7b909861e 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -103,6 +103,7 @@ typedef enum { HACKRF_VENDOR_REQUEST_BOARD_REV_READ = 45, HACKRF_VENDOR_REQUEST_SUPPORTED_PLATFORM_READ = 46, HACKRF_VENDOR_REQUEST_SET_LEDS = 47, + HACKRF_VENDOR_REQUEST_SET_USER_BIAS_T_OPTS = 48, } hackrf_vendor_request; #define USB_CONFIG_STANDARD 0x1 @@ -2954,6 +2955,52 @@ int ADDCALL hackrf_set_leds(hackrf_device* device, const uint8_t state) } } +int ADDCALL hackrf_set_user_bias_t_opts( + hackrf_device* device, + hackrf_bias_t_user_settting_req* req) +{ + USB_API_REQUIRED(device, 0x0108) + uint16_t state = 0; // Assume no modifications + if (req->off.do_update) { + state |= 0x4; + if (req->off.change_on_mode_entry) { + state |= 0x2 + req->off.enabled; + } + } + + if (req->rx.do_update) { + state |= 0x20; + if (req->rx.change_on_mode_entry) { + state |= 0x10 + (req->rx.enabled << 3); + } + } + + if (req->tx.do_update) { + state |= 0x100; + if (req->tx.change_on_mode_entry) { + state |= 0x80 + (req->tx.enabled << 6); + } + } + + int result = libusb_control_transfer( + device->usb_device, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | + LIBUSB_RECIPIENT_DEVICE, + HACKRF_VENDOR_REQUEST_SET_USER_BIAS_T_OPTS, + state, + 0, + NULL, + 0, + 0); + + if (result != 0) { + 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 8c592b448..b856eed24 100644 --- a/host/libhackrf/src/hackrf.h +++ b/host/libhackrf/src/hackrf.h @@ -26,7 +26,7 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSI #include #include - +#include // for bool #ifdef _WIN32 #define ADD_EXPORTS @@ -885,6 +885,28 @@ typedef struct { uint8_t port; } hackrf_operacake_freq_range; +/** + * Helper struct for hackrf_bias_t_user_setting. If 'do_update' is true, then the values of 'change_on_mode_entry' + * and 'enabled' will be used as the new default. If 'do_update' is false, the current default will not change. +*/ +typedef struct { + bool do_update; + bool change_on_mode_entry; + bool enabled; +} hackrf_bool_user_settting; + +/** + * User settings for user-supplied bias tee defaults. + * + * @ingroup device + * +*/ +typedef struct { + hackrf_bool_user_settting tx; + hackrf_bool_user_settting rx; + hackrf_bool_user_settting off; +} hackrf_bias_t_user_settting_req; + /** * State of the SGPIO loop running on the M0 core. * @ingroup debug @@ -1984,6 +2006,34 @@ extern ADDAPI int ADDCALL hackrf_supported_platform_read( */ extern ADDAPI int ADDCALL hackrf_set_leds(hackrf_device* device, const uint8_t state); +/** + * Configure bias tee behavior of the HackRF device when changing RF states + * + * This function allows the user to configure bias tee behavior so that it can be turned on or off automatically by the HackRF when entering the RX, TX, or OFF state. By default, the HackRF switches off the bias tee when the RF path switches to OFF mode. + * + * The bias tee configuration is specified via a bitfield: + * + * 0000000TmmRmmOmm + * + * Where setting T/R/O bits indicates that the TX/RX/Off behavior should be set to mode 'mm', 0=don't modify + * + * mm specifies the bias tee mode: + * + * 00 - do nothing + * 01 - reserved, do not use + * 10 - disable bias tee + * 11 - enable bias tee + * + * @param device device to configure + * @param state Bias tee states, as a bitfield + * @return @ref HACKRF_SUCCESS on success or @ref hackrf_error variant + * @ingroup device + * +*/ +extern ADDAPI int ADDCALL hackrf_set_user_bias_t_opts( + hackrf_device* device, + hackrf_bias_t_user_settting_req* req); + #ifdef __cplusplus } // __cplusplus defined. #endif