Files
HackRF-Treasure-Chest/Software/portapack-mayhem/hackrf/host/libhackrf/src/hackrf.c
2022-09-22 09:26:57 -07:00

2696 lines
62 KiB
C

/*
Copyright (c) 2012, Jared Boone <jared@sharebrained.com>
Copyright (c) 2013, Benjamin Vernoux <titanmkd@gmail.com>
Copyright (c) 2013, Michael Ossmann <mike@ossmann.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of Great Scott Gadgets nor the names of its contributors may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "hackrf.h"
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <libusb.h>
#ifdef _WIN32
/* Avoid redefinition of timespec from time.h (included by libusb.h) */
#define HAVE_STRUCT_TIMESPEC 1
#define strdup _strdup
#endif
#include <pthread.h>
#ifndef bool
typedef int bool;
#define true 1
#define false 0
#endif
#ifdef HACKRF_BIG_ENDIAN
#define TO_LE(x) __builtin_bswap32(x)
#define TO_LE64(x) __builtin_bswap64(x)
#define FROM_LE16(x) __builtin_bswap16(x)
#define FROM_LE32(x) __builtin_bswap32(x)
#else
#define TO_LE(x) x
#define TO_LE64(x) x
#define FROM_LE16(x) x
#define FROM_LE32(x) x
#endif
// TODO: Factor this into a shared #include so that firmware can use
// the same values.
typedef enum {
HACKRF_VENDOR_REQUEST_SET_TRANSCEIVER_MODE = 1,
HACKRF_VENDOR_REQUEST_MAX2837_WRITE = 2,
HACKRF_VENDOR_REQUEST_MAX2837_READ = 3,
HACKRF_VENDOR_REQUEST_SI5351C_WRITE = 4,
HACKRF_VENDOR_REQUEST_SI5351C_READ = 5,
HACKRF_VENDOR_REQUEST_SAMPLE_RATE_SET = 6,
HACKRF_VENDOR_REQUEST_BASEBAND_FILTER_BANDWIDTH_SET = 7,
HACKRF_VENDOR_REQUEST_RFFC5071_WRITE = 8,
HACKRF_VENDOR_REQUEST_RFFC5071_READ = 9,
HACKRF_VENDOR_REQUEST_SPIFLASH_ERASE = 10,
HACKRF_VENDOR_REQUEST_SPIFLASH_WRITE = 11,
HACKRF_VENDOR_REQUEST_SPIFLASH_READ = 12,
HACKRF_VENDOR_REQUEST_BOARD_ID_READ = 14,
HACKRF_VENDOR_REQUEST_VERSION_STRING_READ = 15,
HACKRF_VENDOR_REQUEST_SET_FREQ = 16,
HACKRF_VENDOR_REQUEST_AMP_ENABLE = 17,
HACKRF_VENDOR_REQUEST_BOARD_PARTID_SERIALNO_READ = 18,
HACKRF_VENDOR_REQUEST_SET_LNA_GAIN = 19,
HACKRF_VENDOR_REQUEST_SET_VGA_GAIN = 20,
HACKRF_VENDOR_REQUEST_SET_TXVGA_GAIN = 21,
HACKRF_VENDOR_REQUEST_ANTENNA_ENABLE = 23,
HACKRF_VENDOR_REQUEST_SET_FREQ_EXPLICIT = 24,
HACKRF_VENDOR_REQUEST_USB_WCID_VENDOR_REQ = 25,
HACKRF_VENDOR_REQUEST_INIT_SWEEP = 26,
HACKRF_VENDOR_REQUEST_OPERACAKE_GET_BOARDS = 27,
HACKRF_VENDOR_REQUEST_OPERACAKE_SET_PORTS = 28,
HACKRF_VENDOR_REQUEST_SET_HW_SYNC_MODE = 29,
HACKRF_VENDOR_REQUEST_RESET = 30,
HACKRF_VENDOR_REQUEST_OPERACAKE_SET_RANGES = 31,
HACKRF_VENDOR_REQUEST_CLKOUT_ENABLE = 32,
HACKRF_VENDOR_REQUEST_SPIFLASH_STATUS = 33,
HACKRF_VENDOR_REQUEST_SPIFLASH_CLEAR_STATUS = 34,
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_OPERACAKE_SET_DWELL_TIMES = 40,
HACKRF_VENDOR_REQUEST_GET_M0_STATE = 41,
HACKRF_VENDOR_REQUEST_SET_TX_UNDERRUN_LIMIT = 42,
HACKRF_VENDOR_REQUEST_SET_RX_OVERRUN_LIMIT = 43,
} hackrf_vendor_request;
#define USB_CONFIG_STANDARD 0x1
typedef enum {
HACKRF_TRANSCEIVER_MODE_OFF = 0,
HACKRF_TRANSCEIVER_MODE_RECEIVE = 1,
HACKRF_TRANSCEIVER_MODE_TRANSMIT = 2,
HACKRF_TRANSCEIVER_MODE_SS = 3,
TRANSCEIVER_MODE_CPLD_UPDATE = 4,
TRANSCEIVER_MODE_RX_SWEEP = 5,
} hackrf_transceiver_mode;
typedef enum {
HACKRF_HW_SYNC_MODE_OFF = 0,
HACKRF_HW_SYNC_MODE_ON = 1,
} hackrf_hw_sync_mode;
#define TRANSFER_COUNT 4
#define TRANSFER_BUFFER_SIZE 262144
#define USB_MAX_SERIAL_LENGTH 32
struct hackrf_device {
libusb_device_handle* usb_device;
struct libusb_transfer** transfers;
hackrf_sample_block_cb_fn callback;
volatile bool transfer_thread_started; /* volatile shared between threads (read only) */
pthread_t transfer_thread;
volatile bool streaming; /* volatile shared between threads (read only) */
void* rx_ctx;
void* tx_ctx;
volatile bool do_exit;
unsigned char buffer[TRANSFER_COUNT * TRANSFER_BUFFER_SIZE];
bool transfers_setup; /* true if the USB transfers have been setup */
pthread_mutex_t transfer_lock; /* must be held to cancel or restart transfers */
bool transfer_finished[TRANSFER_COUNT]; /* which transfers have finished */
volatile bool all_finished; /* whether all transfers have finished */
pthread_cond_t all_finished_cv; /* signalled when all transfers have finished */
pthread_mutex_t all_finished_lock; /* used to protect all_finished */
};
typedef struct {
uint32_t bandwidth_hz;
} max2837_ft_t;
static const max2837_ft_t max2837_ft[] = {
{ 1750000 },
{ 2500000 },
{ 3500000 },
{ 5000000 },
{ 5500000 },
{ 6000000 },
{ 7000000 },
{ 8000000 },
{ 9000000 },
{ 10000000 },
{ 12000000 },
{ 14000000 },
{ 15000000 },
{ 20000000 },
{ 24000000 },
{ 28000000 },
{ 0 }
};
#define USB_API_REQUIRED(device, version) \
uint16_t usb_version = 0; \
hackrf_usb_api_version_read(device, &usb_version); \
if(usb_version < version) \
return HACKRF_ERROR_USB_API_VERSION;
static const uint16_t hackrf_usb_vid = 0x1d50;
static const uint16_t hackrf_jawbreaker_usb_pid = 0x604b;
static const uint16_t hackrf_one_usb_pid = 0x6089;
static const uint16_t rad1o_usb_pid = 0xcc15;
static uint16_t open_devices = 0;
static int create_transfer_thread(hackrf_device* device);
static libusb_context* g_libusb_context = NULL;
int last_libusb_error = LIBUSB_SUCCESS;
static void request_exit(hackrf_device* device)
{
device->do_exit = true;
}
/*
* Check if the transfers are setup and owned by libusb.
*
* Returns true if the device transfers are currently setup
* in libusb, false otherwise.
*/
static int transfers_check_setup(hackrf_device* device)
{
if( (device->transfers != NULL) && (device->transfers_setup == true) )
return true;
return false;
}
/*
* Cancel any transfers that are in-flight.
*
* This cancels any transfers that hvae been given to libusb for
* either transmit or receive.
*
* This must be done whilst the libusb thread is running, as
* on some platforms cancelling transfers requires some work
* to be done inside the libusb thread to completely cancel
* pending transfers.
*
* Returns HACKRF_SUCCESS if OK, HACKRF_ERROR_OTHER if the
* transfers aren't currently setup.
*/
static int cancel_transfers(hackrf_device* device)
{
uint32_t transfer_index;
int i;
if(transfers_check_setup(device) == true)
{
// Take lock while cancelling transfers. This blocks the
// transfer completion callback from restarting a transfer
// while we're in the middle of trying to cancel them all.
pthread_mutex_lock(&device->transfer_lock);
for(transfer_index=0; transfer_index<TRANSFER_COUNT; transfer_index++)
{
if( device->transfers[transfer_index] != NULL )
{
libusb_cancel_transfer(device->transfers[transfer_index]);
}
}
device->transfers_setup = false;
// Now release the lock. It's possible that some transfers were
// already complete when we called libusb_cancel_transfer() on
// them, and they may still get a callback. But the callback
// won't restart a transfer now that the transfers_setup flag
// is set to false.
pthread_mutex_unlock(&device->transfer_lock);
// Now wait for the transfer thread to signal that all transfers
// have finished, either by completing or being fully cancelled.
pthread_mutex_lock(&device->all_finished_lock);
while (!device->all_finished) {
pthread_cond_wait(&device->all_finished_cv, &device->all_finished_lock);
}
pthread_mutex_unlock(&device->all_finished_lock);
// Now that all waiting and handling is completed, it's safe to
// reset these flags ready for the next time.
for (i = 0; i < TRANSFER_COUNT; i++)
device->transfer_finished[i] = false;
device->all_finished = false;
return HACKRF_SUCCESS;
} else {
return HACKRF_ERROR_OTHER;
}
}
static int free_transfers(hackrf_device* device)
{
uint32_t transfer_index;
if( device->transfers != NULL )
{
// libusb_close() should free all transfers referenced from this array.
for(transfer_index=0; transfer_index<TRANSFER_COUNT; transfer_index++)
{
if( device->transfers[transfer_index] != NULL )
{
libusb_free_transfer(device->transfers[transfer_index]);
device->transfers[transfer_index] = NULL;
}
}
free(device->transfers);
device->transfers = NULL;
}
return HACKRF_SUCCESS;
}
static int allocate_transfers(hackrf_device* const device)
{
if( device->transfers == NULL )
{
uint32_t transfer_index;
device->transfers = (struct libusb_transfer**) calloc(TRANSFER_COUNT, sizeof(struct libusb_transfer));
if( device->transfers == NULL )
{
return HACKRF_ERROR_NO_MEM;
}
memset(device->buffer, 0, TRANSFER_COUNT * TRANSFER_BUFFER_SIZE);
for(transfer_index=0; transfer_index<TRANSFER_COUNT; transfer_index++)
{
device->transfers[transfer_index] = libusb_alloc_transfer(0);
if( device->transfers[transfer_index] == NULL )
{
return HACKRF_ERROR_LIBUSB;
}
libusb_fill_bulk_transfer(
device->transfers[transfer_index],
device->usb_device,
0,
&device->buffer[transfer_index * TRANSFER_BUFFER_SIZE],
TRANSFER_BUFFER_SIZE,
NULL,
device,
0
);
if( device->transfers[transfer_index]->buffer == NULL )
{
return HACKRF_ERROR_NO_MEM;
}
}
return HACKRF_SUCCESS;
} else {
return HACKRF_ERROR_BUSY;
}
}
static int prepare_transfers(
hackrf_device* device,
const uint_fast8_t endpoint_address,
libusb_transfer_cb_fn callback)
{
int error;
uint32_t transfer_index;
if( device->transfers != NULL )
{
for(transfer_index=0; transfer_index<TRANSFER_COUNT; transfer_index++)
{
device->transfers[transfer_index]->endpoint = endpoint_address;
device->transfers[transfer_index]->callback = callback;
error = libusb_submit_transfer(device->transfers[transfer_index]);
if( error != 0 )
{
last_libusb_error = error;
return HACKRF_ERROR_LIBUSB;
}
}
device->transfers_setup = true;
return HACKRF_SUCCESS;
} else {
// This shouldn't happen.
return HACKRF_ERROR_OTHER;
}
}
static int detach_kernel_drivers(libusb_device_handle* usb_device_handle)
{
int i, num_interfaces, result;
libusb_device* dev;
struct libusb_config_descriptor* config;
dev = libusb_get_device(usb_device_handle);
result = libusb_get_active_config_descriptor(dev, &config);
if( result < 0 )
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
}
num_interfaces = config->bNumInterfaces;
libusb_free_config_descriptor(config);
for(i=0; i<num_interfaces; i++)
{
result = libusb_kernel_driver_active(usb_device_handle, i);
if( result < 0 )
{
if( result == LIBUSB_ERROR_NOT_SUPPORTED ) {
return 0;
}
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else if( result == 1 ) {
result = libusb_detach_kernel_driver(usb_device_handle, i);
if( result != 0 )
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
}
}
}
return HACKRF_SUCCESS;
}
static int set_hackrf_configuration(libusb_device_handle* usb_device, int config)
{
int result, curr_config;
result = libusb_get_configuration(usb_device, &curr_config);
if( result != 0 )
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
}
if(curr_config != config)
{
result = detach_kernel_drivers(usb_device);
if( result != 0 )
{
return result;
}
result = libusb_set_configuration(usb_device, config);
if( result != 0 )
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
}
}
result = detach_kernel_drivers(usb_device);
if( result != 0 )
{
return result;
}
return LIBUSB_SUCCESS;
}
#ifdef __cplusplus
extern "C"
{
#endif
int ADDCALL hackrf_init(void)
{
int libusb_error;
if (g_libusb_context != NULL) {
return HACKRF_SUCCESS;
}
libusb_error = libusb_init(&g_libusb_context);
if( libusb_error != 0 )
{
last_libusb_error = libusb_error;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_exit(void)
{
if( open_devices == 0)
{
if( g_libusb_context != NULL )
{
libusb_exit(g_libusb_context);
g_libusb_context = NULL;
}
return HACKRF_SUCCESS;
} else {
return HACKRF_ERROR_NOT_LAST_DEVICE;
}
}
#ifndef LIBRARY_VERSION
#define LIBRARY_VERSION "unknown"
#endif
const char* ADDCALL hackrf_library_version()
{
return LIBRARY_VERSION;
}
#ifndef LIBRARY_RELEASE
#define LIBRARY_RELEASE "unknown"
#endif
const char* ADDCALL hackrf_library_release()
{
return LIBRARY_RELEASE;
}
hackrf_device_list_t* ADDCALL hackrf_device_list()
{
int i;
libusb_device_handle* usb_device = NULL;
uint8_t serial_descriptor_index;
char serial_number[64];
uint8_t idx, serial_number_length;
hackrf_device_list_t* list = calloc(1, sizeof(*list));
if ( list == NULL )
return NULL;
list->usb_devicecount = (int) libusb_get_device_list(g_libusb_context, (libusb_device ***)&list->usb_devices);
list->serial_numbers = calloc(list->usb_devicecount, sizeof(void *));
list->usb_board_ids = calloc(list->usb_devicecount, sizeof(enum hackrf_usb_board_id));
list->usb_device_index = calloc(list->usb_devicecount, sizeof(int));
if ( list->serial_numbers == NULL || list->usb_board_ids == NULL || list->usb_device_index == NULL) {
hackrf_device_list_free(list);
return NULL;
}
for (i=0; i<list->usb_devicecount; i++) {
struct libusb_device_descriptor device_descriptor;
libusb_get_device_descriptor(list->usb_devices[i], &device_descriptor);
if( device_descriptor.idVendor == hackrf_usb_vid ) {
if((device_descriptor.idProduct == hackrf_one_usb_pid) ||
(device_descriptor.idProduct == hackrf_jawbreaker_usb_pid) ||
(device_descriptor.idProduct == rad1o_usb_pid)) {
idx = list->devicecount++;
list->usb_board_ids[idx] = device_descriptor.idProduct;
list->usb_device_index[idx] = i;
serial_descriptor_index = device_descriptor.iSerialNumber;
if( serial_descriptor_index > 0 ) {
if( libusb_open(list->usb_devices[i], &usb_device) != 0 ) {
usb_device = NULL;
continue;
}
serial_number_length = libusb_get_string_descriptor_ascii(usb_device, serial_descriptor_index, (unsigned char*)serial_number, sizeof(serial_number));
if( serial_number_length >= USB_MAX_SERIAL_LENGTH )
serial_number_length = USB_MAX_SERIAL_LENGTH;
serial_number[serial_number_length] = 0;
list->serial_numbers[idx] = strdup(serial_number);
libusb_close(usb_device);
usb_device = NULL;
}
}
}
}
return list;
}
void ADDCALL hackrf_device_list_free(hackrf_device_list_t *list)
{
int i;
libusb_free_device_list((libusb_device **)list->usb_devices, 1);
for (i = 0; i < list->devicecount; i++) {
if (list->serial_numbers[i])
free(list->serial_numbers[i]);
}
free(list->serial_numbers);
free(list->usb_board_ids);
free(list->usb_device_index);
free(list);
}
libusb_device_handle* hackrf_open_usb(const char* const desired_serial_number)
{
libusb_device_handle* usb_device = NULL;
libusb_device** devices = NULL;
const ssize_t list_length = libusb_get_device_list(g_libusb_context, &devices);
ssize_t match_len = 0;
ssize_t i;
char serial_number[64];
int serial_number_length;
if( desired_serial_number ) {
/* If a shorter serial number is specified, only match against the suffix.
* Should probably complain if the match is not unique, currently doesn't.
*/
match_len = strlen(desired_serial_number);
if ( match_len > 32 )
return NULL;
}
for (i=0; i<list_length; i++) {
struct libusb_device_descriptor device_descriptor;
libusb_get_device_descriptor(devices[i], &device_descriptor);
if( device_descriptor.idVendor == hackrf_usb_vid ) {
if((device_descriptor.idProduct == hackrf_one_usb_pid) ||
(device_descriptor.idProduct == hackrf_jawbreaker_usb_pid) ||
(device_descriptor.idProduct == rad1o_usb_pid)) {
if( desired_serial_number != NULL ) {
const uint_fast8_t serial_descriptor_index = device_descriptor.iSerialNumber;
if( serial_descriptor_index > 0 ) {
if( libusb_open(devices[i], &usb_device) != 0 ) {
usb_device = NULL;
continue;
}
serial_number_length = libusb_get_string_descriptor_ascii(usb_device, serial_descriptor_index, (unsigned char*)serial_number, sizeof(serial_number));
if( serial_number_length >= USB_MAX_SERIAL_LENGTH )
serial_number_length = USB_MAX_SERIAL_LENGTH;
serial_number[serial_number_length] = 0;
if( strncmp(serial_number + serial_number_length-match_len, desired_serial_number, match_len) == 0 ) {
break;
} else {
libusb_close(usb_device);
usb_device = NULL;
}
}
} else {
libusb_open(devices[i], &usb_device);
break;
}
}
}
}
libusb_free_device_list(devices, 1);
return usb_device;
}
static int hackrf_open_setup(libusb_device_handle* usb_device, hackrf_device** device)
{
int result, i;
hackrf_device* lib_device;
//int speed = libusb_get_device_speed(usb_device);
// TODO: Error or warning if not high speed USB?
result = set_hackrf_configuration(usb_device, USB_CONFIG_STANDARD);
if( result != LIBUSB_SUCCESS )
{
libusb_close(usb_device);
return result;
}
result = libusb_claim_interface(usb_device, 0);
if( result != LIBUSB_SUCCESS )
{
last_libusb_error = result;
libusb_close(usb_device);
return HACKRF_ERROR_LIBUSB;
}
lib_device = NULL;
lib_device = (hackrf_device*)calloc(1, sizeof(*lib_device));
if( lib_device == NULL )
{
libusb_release_interface(usb_device, 0);
libusb_close(usb_device);
return HACKRF_ERROR_NO_MEM;
}
lib_device->usb_device = usb_device;
lib_device->transfers = NULL;
lib_device->callback = NULL;
lib_device->transfer_thread_started = false;
lib_device->streaming = false;
lib_device->do_exit = false;
for (i = 0; i < TRANSFER_COUNT; i++)
lib_device->transfer_finished[i] = false;
lib_device->all_finished = false;
result = pthread_mutex_init(&lib_device->transfer_lock, NULL);
if( result != 0 )
{
free(lib_device);
libusb_release_interface(usb_device, 0);
libusb_close(usb_device);
return HACKRF_ERROR_THREAD;
}
result = pthread_mutex_init(&lib_device->all_finished_lock, NULL);
if( result != 0 )
{
free(lib_device);
libusb_release_interface(usb_device, 0);
libusb_close(usb_device);
return HACKRF_ERROR_THREAD;
}
result = pthread_cond_init(&lib_device->all_finished_cv, NULL);
if( result != 0 )
{
free(lib_device);
libusb_release_interface(usb_device, 0);
libusb_close(usb_device);
return HACKRF_ERROR_THREAD;
}
result = allocate_transfers(lib_device);
if( result != 0 )
{
free(lib_device);
libusb_release_interface(usb_device, 0);
libusb_close(usb_device);
return HACKRF_ERROR_NO_MEM;
}
result = create_transfer_thread(lib_device);
if (result != 0) {
free(lib_device);
libusb_release_interface(usb_device, 0);
libusb_close(usb_device);
return result;
}
*device = lib_device;
open_devices++;
return HACKRF_SUCCESS;
}
int ADDCALL hackrf_open(hackrf_device** device)
{
libusb_device_handle* usb_device;
if( device == NULL )
{
return HACKRF_ERROR_INVALID_PARAM;
}
usb_device = libusb_open_device_with_vid_pid(g_libusb_context, hackrf_usb_vid, hackrf_one_usb_pid);
if( usb_device == NULL )
{
usb_device = libusb_open_device_with_vid_pid(g_libusb_context, hackrf_usb_vid, hackrf_jawbreaker_usb_pid);
}
if( usb_device == NULL )
{
usb_device = libusb_open_device_with_vid_pid(g_libusb_context, hackrf_usb_vid, rad1o_usb_pid);
}
if( usb_device == NULL )
{
return HACKRF_ERROR_NOT_FOUND;
}
return hackrf_open_setup(usb_device, device);
}
int ADDCALL hackrf_open_by_serial(const char* const desired_serial_number, hackrf_device** device)
{
libusb_device_handle* usb_device;
if( desired_serial_number == NULL )
{
return hackrf_open(device);
}
if( device == NULL )
{
return HACKRF_ERROR_INVALID_PARAM;
}
usb_device = hackrf_open_usb(desired_serial_number);
if( usb_device == NULL )
{
return HACKRF_ERROR_NOT_FOUND;
}
return hackrf_open_setup(usb_device, device);
}
int ADDCALL hackrf_device_list_open(hackrf_device_list_t *list, int idx, hackrf_device** device)
{
libusb_device_handle* usb_device;
int i, result;
if( device == NULL || list == NULL || idx < 0 || idx >= list->devicecount )
{
return HACKRF_ERROR_INVALID_PARAM;
}
i = list->usb_device_index[idx];
result = libusb_open(list->usb_devices[i], &usb_device);
if(result != 0) {
usb_device = NULL;
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
}
return hackrf_open_setup(usb_device, device);
}
int ADDCALL hackrf_set_transceiver_mode(hackrf_device* device, hackrf_transceiver_mode value)
{
int result;
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_SET_TRANSCEIVER_MODE,
value,
0,
NULL,
0,
0
);
if( result != 0 )
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_max2837_read(hackrf_device* device, uint8_t register_number, uint16_t* value)
{
int result;
if( register_number >= 32 )
{
return HACKRF_ERROR_INVALID_PARAM;
}
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_MAX2837_READ,
0,
register_number,
(unsigned char*)value,
2,
0
);
if( result < 2 )
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_max2837_write(hackrf_device* device, uint8_t register_number, uint16_t value)
{
int result;
if( register_number >= 32 )
{
return HACKRF_ERROR_INVALID_PARAM;
}
if( value >= 0x400 )
{
return HACKRF_ERROR_INVALID_PARAM;
}
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_MAX2837_WRITE,
value,
register_number,
NULL,
0,
0
);
if( result != 0 )
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_si5351c_read(hackrf_device* device, uint16_t register_number, uint16_t* value)
{
uint8_t temp_value;
int result;
if( register_number >= 256 )
{
return HACKRF_ERROR_INVALID_PARAM;
}
temp_value = 0;
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_SI5351C_READ,
0,
register_number,
(unsigned char*)&temp_value,
1,
0
);
if( result < 1 )
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
*value = temp_value;
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_si5351c_write(hackrf_device* device, uint16_t register_number, uint16_t value)
{
int result;
if( register_number >= 256 )
{
return HACKRF_ERROR_INVALID_PARAM;
}
if( value >= 256 ) {
return HACKRF_ERROR_INVALID_PARAM;
}
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_SI5351C_WRITE,
value,
register_number,
NULL,
0,
0
);
if( result != 0 )
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_set_baseband_filter_bandwidth(hackrf_device* device, const uint32_t bandwidth_hz)
{
int result;
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_BASEBAND_FILTER_BANDWIDTH_SET,
bandwidth_hz & 0xffff,
bandwidth_hz >> 16,
NULL,
0,
0
);
if( result != 0 )
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_rffc5071_read(hackrf_device* device, uint8_t register_number, uint16_t* value)
{
int result;
if( register_number >= 31 )
{
return HACKRF_ERROR_INVALID_PARAM;
}
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_RFFC5071_READ,
0,
register_number,
(unsigned char*)value,
2,
0
);
if( result < 2 )
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_rffc5071_write(hackrf_device* device, uint8_t register_number, uint16_t value)
{
int result;
if( register_number >= 31 )
{
return HACKRF_ERROR_INVALID_PARAM;
}
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_RFFC5071_WRITE,
value,
register_number,
NULL,
0,
0
);
if( result != 0 )
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_get_m0_state(hackrf_device* device, hackrf_m0_state* state)
{
USB_API_REQUIRED(device, 0x0106)
int result;
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_GET_M0_STATE,
0,
0,
(unsigned char*)state,
sizeof(hackrf_m0_state),
0
);
if( result < sizeof(hackrf_m0_state) )
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
state->request_flag = FROM_LE16(state->request_flag);
state->requested_mode = FROM_LE16(state->requested_mode);
state->active_mode = FROM_LE32(state->active_mode);
state->m0_count = FROM_LE32(state->m0_count);
state->m4_count = FROM_LE32(state->m4_count);
state->num_shortfalls = FROM_LE32(state->num_shortfalls);
state->longest_shortfall = FROM_LE32(state->longest_shortfall);
state->shortfall_limit = FROM_LE32(state->shortfall_limit);
state->threshold = FROM_LE32(state->threshold);
state->next_mode = FROM_LE32(state->next_mode);
state->error = FROM_LE32(state->error);
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_set_tx_underrun_limit(hackrf_device* device, uint32_t value)
{
USB_API_REQUIRED(device, 0x0106)
int result;
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_SET_TX_UNDERRUN_LIMIT,
value & 0xffff,
value >> 16,
NULL,
0,
0
);
if( result != 0 )
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_set_rx_overrun_limit(hackrf_device* device, uint32_t value)
{
USB_API_REQUIRED(device, 0x0106)
int result;
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_SET_RX_OVERRUN_LIMIT,
value & 0xffff,
value >> 16,
NULL,
0,
0
);
if( result != 0 )
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_spiflash_erase(hackrf_device* device)
{
int result;
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_SPIFLASH_ERASE,
0,
0,
NULL,
0,
0
);
if (result != 0)
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_spiflash_write(hackrf_device* device, const uint32_t address,
const uint16_t length, unsigned char* const data)
{
int result;
if (address > 0x0FFFFF)
{
return HACKRF_ERROR_INVALID_PARAM;
}
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_SPIFLASH_WRITE,
address >> 16,
address & 0xFFFF,
data,
length,
0
);
if (result < length)
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_spiflash_read(hackrf_device* device, const uint32_t address,
const uint16_t length, unsigned char* data)
{
int result;
if (address > 0x0FFFFF)
{
return HACKRF_ERROR_INVALID_PARAM;
}
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_SPIFLASH_READ,
address >> 16,
address & 0xFFFF,
data,
length,
0
);
if (result < length)
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_spiflash_status(hackrf_device* device, uint8_t* data)
{
USB_API_REQUIRED(device, 0x0103)
int result;
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_SPIFLASH_STATUS,
0,
0,
data,
2,
0
);
if (result < 1)
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_spiflash_clear_status(hackrf_device* device)
{
USB_API_REQUIRED(device, 0x0103)
int result;
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_SPIFLASH_CLEAR_STATUS,
0,
0,
NULL,
0,
0
);
if( result != 0 )
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_cpld_write(hackrf_device* device,
unsigned char* const data, const unsigned int total_length)
{
const unsigned int chunk_size = 512;
unsigned int i;
int result, transferred = 0;
result = hackrf_set_transceiver_mode(device, TRANSCEIVER_MODE_CPLD_UPDATE);
if (result != 0)
return result;
for (i = 0; i < total_length; i += chunk_size)
{
result = libusb_bulk_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | 2,
&data[i],
chunk_size,
&transferred,
10000 // long timeout to allow for CPLD programming
);
if (result != LIBUSB_SUCCESS) {
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
}
}
return HACKRF_SUCCESS;
}
int ADDCALL hackrf_board_id_read(hackrf_device* device, uint8_t* value)
{
int result;
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_BOARD_ID_READ,
0,
0,
value,
1,
0
);
if (result < 1)
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_version_string_read(hackrf_device* device, char* version,
uint8_t length)
{
int result;
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_VERSION_STRING_READ,
0,
0,
(unsigned char*)version,
length,
0
);
if (result < 0)
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
version[result] = '\0';
return HACKRF_SUCCESS;
}
}
extern ADDAPI int ADDCALL hackrf_usb_api_version_read(hackrf_device* device,
uint16_t* version)
{
int result;
libusb_device* dev;
struct libusb_device_descriptor desc;
dev = libusb_get_device(device->usb_device);
result = libusb_get_device_descriptor(dev, &desc);
if (result < 0) {
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
}
*version = desc.bcdDevice;
return HACKRF_SUCCESS;
}
typedef struct {
uint32_t freq_mhz; /* From 0 to 6000+MHz */
uint32_t freq_hz; /* From 0 to 999999Hz */
/* Final Freq = freq_mhz+freq_hz */
} set_freq_params_t;
#define FREQ_ONE_MHZ (1000*1000ull)
int ADDCALL hackrf_set_freq(hackrf_device* device, const uint64_t freq_hz)
{
uint32_t l_freq_mhz;
uint32_t l_freq_hz;
set_freq_params_t set_freq_params;
uint8_t length;
int result;
/* Convert Freq Hz 64bits to Freq MHz (32bits) & Freq Hz (32bits) */
l_freq_mhz = (uint32_t)(freq_hz / FREQ_ONE_MHZ);
l_freq_hz = (uint32_t)(freq_hz - (((uint64_t)l_freq_mhz) * FREQ_ONE_MHZ));
set_freq_params.freq_mhz = TO_LE(l_freq_mhz);
set_freq_params.freq_hz = TO_LE(l_freq_hz);
length = sizeof(set_freq_params_t);
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_SET_FREQ,
0,
0,
(unsigned char*)&set_freq_params,
length,
0
);
if (result < length)
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
struct set_freq_explicit_params {
uint64_t if_freq_hz; /* intermediate frequency */
uint64_t lo_freq_hz; /* front-end local oscillator frequency */
uint8_t path; /* image rejection filter path */
};
int ADDCALL hackrf_set_freq_explicit(hackrf_device* device,
const uint64_t if_freq_hz, const uint64_t lo_freq_hz,
const enum rf_path_filter path)
{
struct set_freq_explicit_params params;
uint8_t length;
int result;
if (if_freq_hz < 2150000000 || if_freq_hz > 2750000000) {
return HACKRF_ERROR_INVALID_PARAM;
}
if ((path != RF_PATH_FILTER_BYPASS) &&
(lo_freq_hz < 84375000 || lo_freq_hz > 5400000000)) {
return HACKRF_ERROR_INVALID_PARAM;
}
if (path > 2) {
return HACKRF_ERROR_INVALID_PARAM;
}
params.if_freq_hz = TO_LE(if_freq_hz);
params.lo_freq_hz = TO_LE(lo_freq_hz);
params.path = (uint8_t)path;
length = sizeof(struct set_freq_explicit_params);
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_SET_FREQ_EXPLICIT,
0,
0,
(unsigned char*)&params,
length,
0
);
if (result < length)
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
typedef struct {
uint32_t freq_hz;
uint32_t divider;
} set_fracrate_params_t;
/*
* You should probably use hackrf_set_sample_rate() below instead of this
* function. They both result in automatic baseband filter selection as
* described below.
*/
int ADDCALL hackrf_set_sample_rate_manual(hackrf_device* device,
const uint32_t freq_hz,
const uint32_t divider)
{
set_fracrate_params_t set_fracrate_params;
uint8_t length;
int result;
set_fracrate_params.freq_hz = TO_LE(freq_hz);
set_fracrate_params.divider = TO_LE(divider);
length = sizeof(set_fracrate_params_t);
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_SAMPLE_RATE_SET,
0,
0,
(unsigned char*)&set_fracrate_params,
length,
0
);
if (result < length)
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return hackrf_set_baseband_filter_bandwidth(device,
hackrf_compute_baseband_filter_bw((uint32_t)(0.75*freq_hz/divider)));
}
}
/*
* For anti-aliasing, the baseband filter bandwidth is automatically set to the
* widest available setting that is no more than 75% of the sample rate. This
* happens every time the sample rate is set. If you want to override the
* baseband filter selection, you must do so after setting the sample rate.
*/
int ADDCALL hackrf_set_sample_rate(hackrf_device* device, const double freq)
{
const int MAX_N = 32;
uint32_t freq_hz, divider;
double freq_frac = 1.0 + freq - (int)freq;
uint64_t a, m;
int i, e;
union {
uint64_t u64;
double d;
} v;
v.d = freq;
e = (v.u64 >> 52) - 1023;
m = ((1ULL << 52) - 1);
v.d = freq_frac;
v.u64 &= m;
m &= ~((1 << (e+4)) - 1);
a = 0;
for (i=1; i<MAX_N; i++) {
a += v.u64;
if (!(a & m) || !(~a & m))
break;
}
if (i == MAX_N)
i = 1;
freq_hz = (uint32_t)(freq * i + 0.5);
divider = i;
return hackrf_set_sample_rate_manual(device, freq_hz, divider);
}
int ADDCALL hackrf_set_amp_enable(hackrf_device* device, const uint8_t value)
{
int result;
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_AMP_ENABLE,
value,
0,
NULL,
0,
0
);
if (result != 0)
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_board_partid_serialno_read(hackrf_device* device, read_partid_serialno_t* read_partid_serialno)
{
uint8_t length;
int result;
length = sizeof(read_partid_serialno_t);
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_BOARD_PARTID_SERIALNO_READ,
0,
0,
(unsigned char*)read_partid_serialno,
length,
0
);
if (result < length)
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
read_partid_serialno->part_id[0] = TO_LE(read_partid_serialno->part_id[0]);
read_partid_serialno->part_id[1] = TO_LE(read_partid_serialno->part_id[1]);
read_partid_serialno->serial_no[0] = TO_LE(read_partid_serialno->serial_no[0]);
read_partid_serialno->serial_no[1] = TO_LE(read_partid_serialno->serial_no[1]);
read_partid_serialno->serial_no[2] = TO_LE(read_partid_serialno->serial_no[2]);
read_partid_serialno->serial_no[3] = TO_LE(read_partid_serialno->serial_no[3]);
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_set_lna_gain(hackrf_device* device, uint32_t value)
{
int result;
uint8_t retval;
if( value > 40 )
{
return HACKRF_ERROR_INVALID_PARAM;
}
value &= ~0x07;
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_SET_LNA_GAIN,
0,
value,
&retval,
1,
0
);
if( result != 1 || !retval )
{
return HACKRF_ERROR_INVALID_PARAM;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_set_vga_gain(hackrf_device* device, uint32_t value)
{
int result;
uint8_t retval;
if( value > 62 )
{
return HACKRF_ERROR_INVALID_PARAM;
}
value &= ~0x01;
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_SET_VGA_GAIN,
0,
value,
&retval,
1,
0
);
if( result != 1 || !retval )
{
return HACKRF_ERROR_INVALID_PARAM;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_set_txvga_gain(hackrf_device* device, uint32_t value)
{
int result;
uint8_t retval;
if( value > 47 )
{
return HACKRF_ERROR_INVALID_PARAM;
}
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_SET_TXVGA_GAIN,
0,
value,
&retval,
1,
0
);
if( result != 1 || !retval )
{
return HACKRF_ERROR_INVALID_PARAM;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_set_antenna_enable(hackrf_device* device, const uint8_t value)
{
int result;
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_ANTENNA_ENABLE,
value,
0,
NULL,
0,
0
);
if (result != 0)
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
static void* transfer_threadproc(void* arg)
{
hackrf_device* device = (hackrf_device*)arg;
int error;
struct timeval timeout = { 0, 500000 };
while(device->do_exit == false )
{
error = libusb_handle_events_timeout(g_libusb_context, &timeout);
if( (error != 0) && (error != LIBUSB_ERROR_INTERRUPTED) )
{
device->streaming = false;
}
}
return NULL;
}
static void transfer_finished(struct hackrf_device* device, struct libusb_transfer* finished_transfer)
{
int i;
bool all_finished = true;
for (i = 0; i < TRANSFER_COUNT; i++) {
if (device->transfers[i] == finished_transfer) {
device->transfer_finished[i] = true;
} else {
all_finished &= device->transfer_finished[i];
}
}
if (all_finished) {
pthread_mutex_lock(&device->all_finished_lock);
device->all_finished = true;
pthread_cond_signal(&device->all_finished_cv);
pthread_mutex_unlock(&device->all_finished_lock);
}
}
static void LIBUSB_CALL hackrf_libusb_transfer_callback(struct libusb_transfer* usb_transfer)
{
hackrf_device* device = (hackrf_device*)usb_transfer->user_data;
bool resubmit;
int result;
if(usb_transfer->status == LIBUSB_TRANSFER_COMPLETED)
{
hackrf_transfer transfer = {
.device = device,
.buffer = usb_transfer->buffer,
.buffer_length = usb_transfer->length,
.valid_length = usb_transfer->actual_length,
.rx_ctx = device->rx_ctx,
.tx_ctx = device->tx_ctx
};
if( device->callback(&transfer) == 0 )
{
// Take lock to make sure that we don't restart a
// transfer whilst cancel_transfers() is in the middle
// of stopping them.
pthread_mutex_lock(&device->transfer_lock);
if ((resubmit = device->transfers_setup)) {
result = libusb_submit_transfer(usb_transfer);
}
// Now we can release the lock. Our transfer was either
// cancelled or restarted, not both.
pthread_mutex_unlock(&device->transfer_lock);
if (!resubmit || result < 0) {
transfer_finished(device, usb_transfer);
}
} else {
transfer_finished(device, usb_transfer);
device->streaming = false;
}
} else if(usb_transfer->status == LIBUSB_TRANSFER_CANCELLED) {
transfer_finished(device, usb_transfer);
} else {
/* Other cases LIBUSB_TRANSFER_NO_DEVICE
LIBUSB_TRANSFER_ERROR, LIBUSB_TRANSFER_TIMED_OUT
LIBUSB_TRANSFER_STALL, LIBUSB_TRANSFER_OVERFLOW ....
*/
request_exit(device); /* Fatal error stop transfer */
device->streaming = false;
}
}
static int kill_transfer_thread(hackrf_device* device)
{
void* value;
int result;
if( device->transfer_thread_started != false )
{
/*
* Cancel transfers. This call will block until the transfer
* thread has handled all completion callbacks.
*/
cancel_transfers(device);
/*
* Now call request_exit() to halt the main loop.
*/
request_exit(device);
/*
* Interrupt the event handling thread instead of
* waiting for timeout.
*/
libusb_interrupt_event_handler(g_libusb_context);
value = NULL;
result = pthread_join(device->transfer_thread, &value);
if( result != 0 )
{
return HACKRF_ERROR_THREAD;
}
device->transfer_thread_started = false;
}
/*
* Reset do_exit; we're now done here and the thread was
* already dead or is now dead.
*/
device->do_exit = false;
return HACKRF_SUCCESS;
}
static int prepare_setup_transfers(hackrf_device* device,
const uint8_t endpoint_address,
hackrf_sample_block_cb_fn callback)
{
int result;
if( device->transfers_setup == true )
{
return HACKRF_ERROR_BUSY;
}
device->callback = callback;
result = prepare_transfers(
device, endpoint_address,
hackrf_libusb_transfer_callback
);
if( result != HACKRF_SUCCESS )
{
return result;
}
return HACKRF_SUCCESS;
}
static int create_transfer_thread(hackrf_device* device)
{
int result, i;
if( device->transfer_thread_started == false )
{
device->streaming = false;
device->do_exit = false;
for (i = 0; i < TRANSFER_COUNT; i++)
device->transfer_finished[i] = false;
device->all_finished = false;
result = pthread_create(&device->transfer_thread, 0, transfer_threadproc, device);
if( result == 0 )
{
device->transfer_thread_started = true;
}else {
return HACKRF_ERROR_THREAD;
}
} else {
return HACKRF_ERROR_BUSY;
}
return HACKRF_SUCCESS;
}
int ADDCALL hackrf_is_streaming(hackrf_device* device)
{
/* return hackrf is streaming only when streaming, transfer_thread_started are true and do_exit equal false */
if( (device->transfer_thread_started == true) &&
(device->streaming == true) &&
(device->do_exit == false) )
{
return HACKRF_TRUE;
} else {
if(device->transfer_thread_started == false)
{
return HACKRF_ERROR_STREAMING_THREAD_ERR;
}
if(device->streaming == false)
{
return HACKRF_ERROR_STREAMING_STOPPED;
}
return HACKRF_ERROR_STREAMING_EXIT_CALLED;
}
}
int ADDCALL hackrf_start_rx(hackrf_device* device, hackrf_sample_block_cb_fn callback, void* rx_ctx)
{
int result;
const uint8_t endpoint_address = LIBUSB_ENDPOINT_IN | 1;
device->rx_ctx = rx_ctx;
result = hackrf_set_transceiver_mode(device, HACKRF_TRANSCEIVER_MODE_RECEIVE);
if( result == HACKRF_SUCCESS )
{
result = prepare_setup_transfers(device, endpoint_address, callback);
}
if (result == HACKRF_SUCCESS) {
device->streaming = true;
}
return result;
}
static int hackrf_stop_rx_cmd(hackrf_device* device)
{
int result;
result = hackrf_set_transceiver_mode(device, HACKRF_TRANSCEIVER_MODE_OFF);
#ifdef _WIN32
Sleep(10);
#else
usleep(10 * 1000);
#endif
return result;
}
/*
* Stop any pending receive.
*
* This call stops transfers and halts recieve if it is enabled.
*
* It returns HACKRF_SUCCESS if receive was started and it was
* properly stopped, an error otherwise.
*/
int ADDCALL hackrf_stop_rx(hackrf_device* device)
{
int result;
device->streaming = false;
result = cancel_transfers(device);
if (result != HACKRF_SUCCESS)
{
return result;
}
return hackrf_stop_rx_cmd(device);
}
int ADDCALL hackrf_start_tx(hackrf_device* device, hackrf_sample_block_cb_fn callback, void* tx_ctx)
{
int result;
const uint8_t endpoint_address = LIBUSB_ENDPOINT_OUT | 2;
result = hackrf_set_transceiver_mode(device, HACKRF_TRANSCEIVER_MODE_TRANSMIT);
if( result == HACKRF_SUCCESS )
{
device->tx_ctx = tx_ctx;
result = prepare_setup_transfers(device, endpoint_address, callback);
}
if (result == HACKRF_SUCCESS) {
device->streaming = true;
}
return result;
}
static int hackrf_stop_tx_cmd(hackrf_device* device)
{
int result;
result = hackrf_set_transceiver_mode(device, HACKRF_TRANSCEIVER_MODE_OFF);
#ifdef _WIN32
Sleep(10);
#else
usleep(10 * 1000);
#endif
return result;
}
/*
* Stop any pending transmit.
*
* This call stops transfers and halts transmit if it is enabled.
*
* It returns HACKRF_SUCCESS if receive was started and it was
* properly stopped, an error otherwise.
*/
int ADDCALL hackrf_stop_tx(hackrf_device* device)
{
int result;
device->streaming = false;
result = cancel_transfers(device);
if (result != HACKRF_SUCCESS)
{
return result;
}
return hackrf_stop_tx_cmd(device);
}
int ADDCALL hackrf_close(hackrf_device* device)
{
int result1, result2, result3;
result1 = HACKRF_SUCCESS;
result2 = HACKRF_SUCCESS;
result3 = HACKRF_SUCCESS;
if( device != NULL )
{
result1 = hackrf_stop_rx_cmd(device);
result2 = hackrf_stop_tx_cmd(device);
/*
* Finally kill the transfer thread, which will
* also cancel any pending transmit/receive transfers.
*/
result3 = kill_transfer_thread(device);
if( device->usb_device != NULL )
{
libusb_release_interface(device->usb_device, 0);
libusb_close(device->usb_device);
device->usb_device = NULL;
}
free_transfers(device);
pthread_mutex_destroy(&device->transfer_lock);
pthread_cond_destroy(&device->all_finished_cv);
pthread_mutex_destroy(&device->all_finished_lock);
free(device);
}
open_devices--;
if (result3 != HACKRF_SUCCESS)
{
return result3;
}
if (result2 != HACKRF_SUCCESS)
{
return result2;
}
return result1;
}
const char* ADDCALL hackrf_error_name(enum hackrf_error errcode)
{
switch(errcode)
{
case HACKRF_SUCCESS:
return "HACKRF_SUCCESS";
case HACKRF_TRUE:
return "HACKRF_TRUE";
case HACKRF_ERROR_INVALID_PARAM:
return "invalid parameter(s)";
case HACKRF_ERROR_NOT_FOUND:
return "HackRF not found";
case HACKRF_ERROR_BUSY:
return "HackRF busy";
case HACKRF_ERROR_NO_MEM:
return "insufficient memory";
case HACKRF_ERROR_LIBUSB:
#if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000103)
if(last_libusb_error != LIBUSB_SUCCESS)
return libusb_strerror(last_libusb_error);
#endif
return "USB error";
case HACKRF_ERROR_THREAD:
return "transfer thread error";
case HACKRF_ERROR_STREAMING_THREAD_ERR:
return "streaming thread encountered an error";
case HACKRF_ERROR_STREAMING_STOPPED:
return "streaming stopped";
case HACKRF_ERROR_STREAMING_EXIT_CALLED:
return "streaming terminated";
case HACKRF_ERROR_USB_API_VERSION:
return "feature not supported by installed firmware";
case HACKRF_ERROR_NOT_LAST_DEVICE:
return "one or more HackRFs still in use";
case HACKRF_ERROR_OTHER:
return "unspecified error";
default:
return "unknown error code";
}
}
const char* ADDCALL hackrf_board_id_name(enum hackrf_board_id board_id)
{
switch(board_id)
{
case BOARD_ID_JELLYBEAN:
return "Jellybean";
case BOARD_ID_JAWBREAKER:
return "Jawbreaker";
case BOARD_ID_HACKRF_ONE:
return "HackRF One";
case BOARD_ID_RAD1O:
return "rad1o";
case BOARD_ID_INVALID:
return "Invalid Board ID";
default:
return "Unknown Board ID";
}
}
extern ADDAPI const char* ADDCALL hackrf_usb_board_id_name(enum hackrf_usb_board_id usb_board_id)
{
switch(usb_board_id)
{
case USB_BOARD_ID_JAWBREAKER:
return "Jawbreaker";
case USB_BOARD_ID_HACKRF_ONE:
return "HackRF One";
case USB_BOARD_ID_RAD1O:
return "rad1o";
case USB_BOARD_ID_INVALID:
return "Invalid Board ID";
default:
return "Unknown Board ID";
}
}
const char* ADDCALL hackrf_filter_path_name(const enum rf_path_filter path)
{
switch(path) {
case RF_PATH_FILTER_BYPASS:
return "mixer bypass";
case RF_PATH_FILTER_LOW_PASS:
return "low pass filter";
case RF_PATH_FILTER_HIGH_PASS:
return "high pass filter";
default:
return "invalid filter path";
}
}
/* Return final bw round down and less than expected bw. */
uint32_t ADDCALL hackrf_compute_baseband_filter_bw_round_down_lt(const uint32_t bandwidth_hz)
{
const max2837_ft_t* p = max2837_ft;
while( p->bandwidth_hz != 0 )
{
if( p->bandwidth_hz >= bandwidth_hz )
{
break;
}
p++;
}
/* Round down (if no equal to first entry) */
if(p != max2837_ft)
{
p--;
}
return p->bandwidth_hz;
}
/* Return final bw. */
uint32_t ADDCALL hackrf_compute_baseband_filter_bw(const uint32_t bandwidth_hz)
{
const max2837_ft_t* p = max2837_ft;
while( p->bandwidth_hz != 0 )
{
if( p->bandwidth_hz >= bandwidth_hz )
{
break;
}
p++;
}
/* Round down (if no equal to first entry) and if > bandwidth_hz */
if(p != max2837_ft)
{
if(p->bandwidth_hz > bandwidth_hz)
p--;
}
return p->bandwidth_hz;
}
/* All features below require USB API version 0x0102 or higher) */
int ADDCALL hackrf_set_hw_sync_mode(hackrf_device* device, const uint8_t value) {
USB_API_REQUIRED(device, 0x0102)
int result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_SET_HW_SYNC_MODE,
value,
0,
NULL,
0,
0
);
if( result != 0 )
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
/*
* Initialize sweep mode:
* frequency_list is a list of start/stop pairs of frequencies in MHz.
* num_ranges is the number of pairs in frequency_list (1 to 10)
* num_bytes is the number of sample bytes to capture after each tuning.
* step_width is the width in Hz of the tuning step.
* offset is a number of Hz added to every tuning frequency.
* Use to select center frequency based on the expected usable bandwidth.
* sweep_mode
* LINEAR means step_width is added to the current frequency at each step.
* INTERLEAVED invokes a scheme in which each step is divided into two
* interleaved sub-steps, allowing the host to select the best portions
* of the FFT of each sub-step and discard the rest.
*/
int ADDCALL hackrf_init_sweep(hackrf_device* device,
const uint16_t* frequency_list, const int num_ranges,
const uint32_t num_bytes, const uint32_t step_width,
const uint32_t offset, const enum sweep_style style) {
USB_API_REQUIRED(device, 0x0102)
int result, i;
unsigned char data[9 + MAX_SWEEP_RANGES * 2 * sizeof(frequency_list[0])];
int size = 9 + num_ranges * 2 * sizeof(frequency_list[0]);
if((num_ranges < 1) || (num_ranges > MAX_SWEEP_RANGES)){
return HACKRF_ERROR_INVALID_PARAM;
}
if(num_bytes % BYTES_PER_BLOCK) {
return HACKRF_ERROR_INVALID_PARAM;
}
if(BYTES_PER_BLOCK > num_bytes) {
return HACKRF_ERROR_INVALID_PARAM;
}
if(1 > step_width) {
return HACKRF_ERROR_INVALID_PARAM;
}
if(INTERLEAVED < style) {
return HACKRF_ERROR_INVALID_PARAM;
}
data[0] = step_width & 0xff;
data[1] = (step_width >> 8) & 0xff;
data[2] = (step_width >> 16) & 0xff;
data[3] = (step_width >> 24) & 0xff;
data[4] = offset & 0xff;
data[5] = (offset >> 8) & 0xff;
data[6] = (offset >> 16) & 0xff;
data[7] = (offset >> 24) & 0xff;
data[8] = style;
for(i=0; i<(num_ranges*2); i++) {
data[9+i*2] = frequency_list[i] & 0xff;
data[10+i*2] = (frequency_list[i] >> 8) & 0xff;
}
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_INIT_SWEEP,
num_bytes & 0xffff,
(num_bytes >> 16) & 0xffff,
data,
size,
0
);
if (result < size) {
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
bool hackrf_operacake_valid_address(uint8_t address) {
return address < HACKRF_OPERACAKE_MAX_BOARDS;
}
/**
* Retrieve list of Opera Cake board addresses
* @param[in] device
* @param[out] boards List of board addresses. Must point to a `uint8_t[8]`. If the number of boards is less than 8, extra entries are filled with @ref HACKRF_OPERACAKE_ADDRESS_INVALID.
* @return @ref HACKRF_SUCCESS
* @return @ref HACKRF_ERROR_LIBUSB
*/
int ADDCALL hackrf_get_operacake_boards(hackrf_device* device, uint8_t* boards)
{
USB_API_REQUIRED(device, 0x0105)
int result;
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_OPERACAKE_GET_BOARDS,
0,
0,
boards,
8,
0
);
if (result < 8)
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
/**
* 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 manual mode ports. */
int ADDCALL hackrf_set_operacake_ports(hackrf_device* device,
uint8_t address,
uint8_t port_a,
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)) {
return HACKRF_ERROR_INVALID_PARAM;
}
/* Check which side PA and PB are on */
if(((port_a <= OPERACAKE_PA4) && (port_b <= OPERACAKE_PA4))
|| ((port_a > OPERACAKE_PA4) && (port_b > OPERACAKE_PA4))) {
return HACKRF_ERROR_INVALID_PARAM;
}
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_OPERACAKE_SET_PORTS,
address,
port_a | (port_b<<8),
NULL,
0,
0
);
if (result != 0) {
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_reset(hackrf_device* device) {
USB_API_REQUIRED(device, 0x0102)
int result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_RESET,
0,
0,
NULL,
0,
0
);
if( result != 0 ) {
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
/**
* @deprecated This has been replaced by @ref hackrf_set_operacake_freq_ranges
*/
int ADDCALL hackrf_set_operacake_ranges(hackrf_device* device, uint8_t* ranges, uint8_t len_ranges)
{
USB_API_REQUIRED(device, 0x0103)
int result;
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_OPERACAKE_SET_RANGES,
0,
0,
ranges,
len_ranges,
0
);
if (result < len_ranges) {
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_set_operacake_freq_ranges(hackrf_device* device, hackrf_operacake_freq_range* freq_ranges, uint8_t count)
{
USB_API_REQUIRED(device, 0x0103)
uint8_t range_bytes[HACKRF_OPERACAKE_MAX_FREQ_RANGES * sizeof(hackrf_operacake_freq_range)];
uint8_t ptr;
int i;
for (i = 0; i < count; i++) {
ptr = 5*i;
range_bytes[ptr] = freq_ranges[i].freq_min >> 8;
range_bytes[ptr+1] = freq_ranges[i].freq_min & 0xFF;
range_bytes[ptr+2] = freq_ranges[i].freq_max >> 8;
range_bytes[ptr+3] = freq_ranges[i].freq_max & 0xFF;
range_bytes[ptr+4] = freq_ranges[i].port;
}
int result;
int len_ranges = count*5;
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_OPERACAKE_SET_RANGES,
0,
0,
range_bytes,
len_ranges,
0
);
if (result < len_ranges) {
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
#define DWELL_TIME_SIZE 5
static uint8_t dwell_data[DWELL_TIME_SIZE*HACKRF_OPERACAKE_MAX_DWELL_TIMES];
int ADDCALL hackrf_set_operacake_dwell_times(hackrf_device* device, hackrf_operacake_dwell_time *dwell_times, uint8_t count)
{
USB_API_REQUIRED(device, 0x0105)
if (count > HACKRF_OPERACAKE_MAX_DWELL_TIMES) {
return HACKRF_ERROR_INVALID_PARAM;
}
int i;
for (i = 0; i < count; i++) {
*(uint32_t*)&dwell_data[i*DWELL_TIME_SIZE] = TO_LE(dwell_times[i].dwell);
dwell_data[(i*DWELL_TIME_SIZE)+4] = dwell_times[i].port;
}
int data_len = count * DWELL_TIME_SIZE;
int result;
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_OPERACAKE_SET_DWELL_TIMES,
0,
0,
dwell_data,
data_len,
0
);
if (result < data_len) {
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_set_clkout_enable(hackrf_device* device, const uint8_t value)
{
USB_API_REQUIRED(device, 0x0103)
int result;
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_CLKOUT_ENABLE,
value,
0,
NULL,
0,
0
);
if (result != 0)
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_operacake_gpio_test(hackrf_device* device, const uint8_t address,
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,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_OPERACAKE_GPIO_TEST,
address,
0,
(unsigned char*)test_result,
2,
0
);
if (result < 1) {
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
#ifdef HACKRF_ISSUE_609_IS_FIXED
int ADDCALL hackrf_cpld_checksum(hackrf_device* device,
uint32_t* crc)
{
USB_API_REQUIRED(device, 0x0103)
uint8_t length;
int result;
length = sizeof(*crc);
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_CPLD_CHECKSUM,
0,
0,
(unsigned char*)crc,
length,
0
);
if (result < length)
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
*crc = TO_LE(*crc);
return HACKRF_SUCCESS;
}
}
#endif /* HACKRF_ISSUE_609_IS_FIXED */
int ADDCALL hackrf_set_ui_enable(hackrf_device* device, const uint8_t value)
{
USB_API_REQUIRED(device, 0x0104)
int result;
result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_UI_ENABLE,
value,
0,
NULL,
0,
0
);
if (result != 0)
{
last_libusb_error = result;
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int ADDCALL hackrf_start_rx_sweep(hackrf_device* device, hackrf_sample_block_cb_fn callback, void* rx_ctx)
{
USB_API_REQUIRED(device, 0x0104)
int result;
const uint8_t endpoint_address = LIBUSB_ENDPOINT_IN | 1;
result = hackrf_set_transceiver_mode(device, TRANSCEIVER_MODE_RX_SWEEP);
if (HACKRF_SUCCESS == result)
{
device->rx_ctx = rx_ctx;
result = prepare_setup_transfers(device, endpoint_address, callback);
}
if (result == HACKRF_SUCCESS) {
device->streaming = true;
}
return result;
}
#ifdef __cplusplus
} // __cplusplus defined.
#endif