Firmware updates to allow fine-grained control of biast from command line (#1314)

* Initial commit of hackrf_biast

* Cleaned up hackrf_biast

* Cleaned up usage info

* Include getopt.h for non-GNU systems

* Add support for overriding HackRF's default antenna power behavior in firmware.  Add support for specifying antenna power behavior in libhackrf.

* Moved bias tee config routines into user_config.c, cleaned up operation of hackrf_biast

* hackrf_biast now calls usage() and exits when invoked with no arguments

* Fixed minor documentation error in usage()

* minor syntax cleanup

* Add some documentation to the host API call

* Add proper declaration magic in hackrf.h to hackrf_set_user_bias_t_opts() to appease Visual Studio

* Documentation changes suggested by @martinling

* Moved bias t setting above switch statement, removed line that explicit turned bias t off when entering OFF mode

* Change hackrf_set_user_bias_t_opts() to use a friendly struct() instead of a bitmask.  User friendliness fixes to hackrf_biast options.  More clang-format appeasement.

* Removed support for integer mode args from hackrf_biast

* clang-format error fixes

* Tweaked position of comment for clang-format v14

* Reformat files with clang-format v14 instead of 16

* Remove internal numeric modes for bias T settings

Co-authored-by: Martin Ling <martin-github@earth.li>

* Fix documentation error in hackrf_biast.c

---------

Co-authored-by: Martin Ling <martin-github@earth.li>
This commit is contained in:
Jonathan Suite
2023-09-13 08:15:30 -07:00
committed by GitHub
parent 13dacd81e6
commit dab548bf29
12 changed files with 495 additions and 8 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -22,7 +22,7 @@
*/
#include "usb_api_register.h"
#include <user_config.h>
#include <hackrf_core.h>
#include <usb_queue.h>
#include <max283x.h>
@ -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;
}

View File

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

View File

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

View File

@ -37,6 +37,7 @@ SET(TOOLS
hackrf_clock
hackrf_sweep
hackrf_operacake
hackrf_biast
)
if(MSVC)

View File

@ -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 <hackrf.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <string.h>
#if defined(__GNUC__)
#include <unistd.h>
#include <sys/time.h>
#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;
}

View File

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

View File

@ -26,7 +26,7 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSI
#include <stdint.h>
#include <sys/types.h>
#include <stdbool.h> // 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