Initial commit of libhackrf.
This commit is contained in:
41
host/libhackrf/CMakeLists.txt
Normal file
41
host/libhackrf/CMakeLists.txt
Normal file
@ -0,0 +1,41 @@
|
||||
# Copyright 2012 Jared Boone
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# Based heavily upon the libftdi cmake setup.
|
||||
|
||||
project(libhackrf)
|
||||
set(MAJOR_VERSION 0)
|
||||
set(MINOR_VERSION 1)
|
||||
set(PACKAGE libhackrf)
|
||||
set(VERSION_STRING ${MAJOR_VERSION}.${MINOR_VERSION})
|
||||
set(VERSION ${VERSION_STRING})
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}")
|
||||
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
add_definitions(-Wall)
|
||||
add_definitions(-std=c99)
|
||||
|
||||
find_package(USB1 REQUIRED)
|
||||
include_directories(${LIBUSB_INCLUDE_DIR})
|
||||
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(examples)
|
||||
|
38
host/libhackrf/FindUSB1.cmake
Normal file
38
host/libhackrf/FindUSB1.cmake
Normal file
@ -0,0 +1,38 @@
|
||||
# - Try to find the freetype library
|
||||
# Once done this defines
|
||||
#
|
||||
# LIBUSB_FOUND - system has libusb
|
||||
# LIBUSB_INCLUDE_DIR - the libusb include directory
|
||||
# LIBUSB_LIBRARIES - Link these to use libusb
|
||||
|
||||
# Copyright (c) 2006, 2008 Laurent Montel, <montel@kde.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
|
||||
if (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
|
||||
|
||||
# in cache already
|
||||
set(LIBUSB_FOUND TRUE)
|
||||
|
||||
else (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
|
||||
IF (NOT WIN32)
|
||||
# use pkg-config to get the directories and then use these values
|
||||
# in the FIND_PATH() and FIND_LIBRARY() calls
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(PC_LIBUSB libusb-1.0)
|
||||
ENDIF(NOT WIN32)
|
||||
|
||||
FIND_PATH(LIBUSB_INCLUDE_DIR libusb.h
|
||||
PATHS ${PC_LIBUSB_INCLUDEDIR} ${PC_LIBUSB_INCLUDE_DIRS})
|
||||
|
||||
FIND_LIBRARY(LIBUSB_LIBRARIES NAMES usb-1.0
|
||||
PATHS ${PC_LIBUSB_LIBDIR} ${PC_LIBUSB_LIBRARY_DIRS})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBUSB DEFAULT_MSG LIBUSB_LIBRARIES LIBUSB_INCLUDE_DIR)
|
||||
|
||||
MARK_AS_ADVANCED(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES)
|
||||
|
||||
endif (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
|
33
host/libhackrf/examples/CMakeLists.txt
Normal file
33
host/libhackrf/examples/CMakeLists.txt
Normal file
@ -0,0 +1,33 @@
|
||||
# Copyright 2012 Jared Boone
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# Based heavily upon the libftdi cmake setup.
|
||||
|
||||
option(EXAMPLES "Build example programs" ON)
|
||||
|
||||
IF( EXAMPLES )
|
||||
add_executable(hackrf_max2837 hackrf_max2837.c)
|
||||
add_executable(hackrf_transfer hackrf_transfer.c)
|
||||
|
||||
target_link_libraries(hackrf_max2837 hackrf)
|
||||
target_link_libraries(hackrf_transfer hackrf)
|
||||
|
||||
include_directories(BEFORE ${CMAKE_SOURCE_DIR}/src)
|
||||
endif(EXAMPLES)
|
161
host/libhackrf/examples/hackrf_max2837.c
Normal file
161
host/libhackrf/examples/hackrf_max2837.c
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||
*
|
||||
* 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>
|
||||
|
||||
static void usage() {
|
||||
printf("\nUsage:\n");
|
||||
printf("\t-n, --register <n>: set register number for subsequent read/write operations\n");
|
||||
printf("\t-r, --read: read register specified by last -n argument, or all registers\n");
|
||||
printf("\t-w, --write <v>: write register specified by last -n argument with value <v>\n");
|
||||
printf("\nExamples:\n");
|
||||
printf("\t<command> -n 12 -r # reads from register 12\n");
|
||||
printf("\t<command> -r # reads all registers\n");
|
||||
printf("\t<command> -n 10 -w 22 # writes register 10 with 22 decimal\n");
|
||||
}
|
||||
|
||||
static struct option long_options[] = {
|
||||
{ "register", required_argument, 0, 'n' },
|
||||
{ "write", required_argument, 0, 'w' },
|
||||
{ "read", no_argument, 0, 'r' },
|
||||
{ 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
int parse_int(char* const s, uint16_t* const value) {
|
||||
char* s_end = s;
|
||||
const long long_value = strtol(s, &s_end, 10);
|
||||
if( (s != s_end) && (*s_end == 0) ) {
|
||||
*value = long_value;
|
||||
return HACKRF_SUCCESS;
|
||||
} else {
|
||||
return HACKRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
int dump_register(hackrf_device* device, const uint16_t register_number) {
|
||||
uint16_t register_value;
|
||||
int result = hackrf_max2837_read(device, register_number, ®ister_value);
|
||||
|
||||
if( result == HACKRF_SUCCESS ) {
|
||||
printf("[%2d] -> 0x%03x\n", register_number, register_value);
|
||||
} else {
|
||||
printf("hackrf_max2837_read() failed: %s (%d)\n", hackrf_error_name(result), result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int dump_registers(hackrf_device* device) {
|
||||
int result = HACKRF_SUCCESS;
|
||||
|
||||
for(uint16_t register_number=0; register_number<32; register_number++) {
|
||||
result = dump_register(device, register_number);
|
||||
if( result != HACKRF_SUCCESS ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int write_register(
|
||||
hackrf_device* device,
|
||||
const uint16_t register_number,
|
||||
const uint16_t register_value
|
||||
) {
|
||||
int result = HACKRF_SUCCESS;
|
||||
result = hackrf_max2837_write(device, register_number, register_value);
|
||||
|
||||
if( result == HACKRF_SUCCESS ) {
|
||||
printf("0x%03x -> [%2d]\n", register_value, register_number);
|
||||
} else {
|
||||
printf("hackrf_max2837_write() failed: %s (%d)\n", hackrf_error_name(result), result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define REGISTER_INVALID 32767
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int opt;
|
||||
uint16_t register_number = REGISTER_INVALID;
|
||||
uint16_t register_value;
|
||||
|
||||
int result = hackrf_init();
|
||||
if( result ) {
|
||||
printf("hackrf_init() failed: %s (%d)\n", hackrf_error_name(result), result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hackrf_device* device = NULL;
|
||||
result = hackrf_open(&device);
|
||||
if( result ) {
|
||||
printf("hackrf_open() failed: %s (%d)\n", hackrf_error_name(result), result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int option_index = 0;
|
||||
while( (opt = getopt_long(argc, argv, "n:rw:", long_options, &option_index)) != EOF ) {
|
||||
switch( opt ) {
|
||||
case 'n':
|
||||
result = parse_int(optarg, ®ister_number);
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
result = parse_int(optarg, ®ister_value);
|
||||
if( result == HACKRF_SUCCESS ) {
|
||||
result = write_register(device, register_number, register_value);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
if( register_number == REGISTER_INVALID ) {
|
||||
result = dump_registers(device);
|
||||
} else {
|
||||
result = dump_register(device, register_number);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
|
||||
if( result != HACKRF_SUCCESS ) {
|
||||
printf("argument error: %s (%d)\n", hackrf_error_name(result), result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
result = hackrf_close(device);
|
||||
if( result ) {
|
||||
printf("hackrf_close() failed: %s (%d)\n", hackrf_error_name(result), result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hackrf_exit();
|
||||
|
||||
return 0;
|
||||
}
|
210
host/libhackrf/examples/hackrf_transfer.c
Normal file
210
host/libhackrf/examples/hackrf_transfer.c
Normal file
@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||
*
|
||||
* 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 <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <signal.h>
|
||||
|
||||
typedef enum {
|
||||
TRANSCEIVER_MODE_RX,
|
||||
TRANSCEIVER_MODE_TX,
|
||||
} transceiver_mode_t;
|
||||
static transceiver_mode_t transceiver_mode = TRANSCEIVER_MODE_RX;
|
||||
|
||||
static float
|
||||
TimevalDiff(const struct timeval *a, const struct timeval *b)
|
||||
{
|
||||
return (a->tv_sec - b->tv_sec) + 1e-6f * (a->tv_usec - b->tv_usec);
|
||||
}
|
||||
|
||||
int fd = -1;
|
||||
volatile uint32_t byte_count = 0;
|
||||
|
||||
int rx_callback(hackrf_transfer* transfer) {
|
||||
if( fd != -1 ) {
|
||||
byte_count += transfer->valid_length;
|
||||
const ssize_t bytes_written = write(fd, transfer->buffer, transfer->valid_length);
|
||||
if( bytes_written == transfer->valid_length ) {
|
||||
return 0;
|
||||
} else {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int tx_callback(hackrf_transfer* transfer) {
|
||||
if( fd != -1 ) {
|
||||
byte_count += transfer->valid_length;
|
||||
const ssize_t bytes_read = read(fd, transfer->buffer, transfer->valid_length);
|
||||
if( bytes_read == transfer->valid_length ) {
|
||||
return 0;
|
||||
} else {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void usage() {
|
||||
printf("Usage:\n");
|
||||
printf("\t-r <filename> # Receive data into file.\n");
|
||||
printf("\t-t <filename> # Transmit data from file.\n");
|
||||
}
|
||||
|
||||
static hackrf_device* device = NULL;
|
||||
|
||||
void sigint_callback_handler(int signum) {
|
||||
hackrf_stop_rx(device);
|
||||
hackrf_stop_tx(device);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int opt;
|
||||
bool receive = false;
|
||||
bool transmit = false;
|
||||
const char* path = NULL;
|
||||
|
||||
while( (opt = getopt(argc, argv, "r:t:")) != EOF ) {
|
||||
switch( opt ) {
|
||||
case 'r':
|
||||
receive = true;
|
||||
path = optarg;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
transmit = true;
|
||||
path = optarg;
|
||||
break;
|
||||
|
||||
default:
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if( transmit == receive ) {
|
||||
if( transmit == true ) {
|
||||
fprintf(stderr, "receive and transmit options are mutually exclusive\n");
|
||||
} else {
|
||||
fprintf(stderr, "specify either transmit or receive option\n");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if( receive ) {
|
||||
transceiver_mode = TRANSCEIVER_MODE_RX;
|
||||
}
|
||||
|
||||
if( transmit ) {
|
||||
transceiver_mode = TRANSCEIVER_MODE_TX;
|
||||
}
|
||||
|
||||
if( path == NULL ) {
|
||||
fprintf(stderr, "specify a path to a file to transmit/receive\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int result = hackrf_init();
|
||||
if( result ) {
|
||||
printf("hackrf_init() failed: %s (%d)\n", hackrf_error_name(result), result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = hackrf_open(&device);
|
||||
if( result ) {
|
||||
printf("hackrf_open() failed: %s (%d)\n", hackrf_error_name(result), result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = -1;
|
||||
if( transceiver_mode == TRANSCEIVER_MODE_RX ) {
|
||||
fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
} else {
|
||||
fd = open(path, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
}
|
||||
|
||||
if( fd == -1 ) {
|
||||
printf("Failed to open file: errno %d\n", errno);
|
||||
return fd;
|
||||
}
|
||||
|
||||
signal(SIGINT, sigint_callback_handler);
|
||||
|
||||
if( transceiver_mode == TRANSCEIVER_MODE_RX ) {
|
||||
result = hackrf_start_rx(device, rx_callback);
|
||||
} else {
|
||||
result = hackrf_start_tx(device, tx_callback);
|
||||
}
|
||||
if( result ) {
|
||||
printf("hackrf_start_?x() failed: %s (%d)\n", hackrf_error_name(result), result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct timeval time_start;
|
||||
gettimeofday(&time_start, NULL);
|
||||
|
||||
while( hackrf_is_streaming(device) ) {
|
||||
sleep(1);
|
||||
|
||||
struct timeval time_now;
|
||||
gettimeofday(&time_now, NULL);
|
||||
|
||||
uint32_t byte_count_now = byte_count;
|
||||
byte_count = 0;
|
||||
|
||||
const float time_difference = TimevalDiff(&time_now, &time_start);
|
||||
const float rate = (float)byte_count_now / time_difference;
|
||||
printf("%4.1f MiB / %5.3f sec = %4.1f MiB/second\n",
|
||||
byte_count_now / 1e6f,
|
||||
time_difference,
|
||||
rate / 1e6f
|
||||
);
|
||||
|
||||
time_start = time_now;
|
||||
}
|
||||
|
||||
result = hackrf_close(device);
|
||||
if( result ) {
|
||||
printf("hackrf_close() failed: %s (%d)\n", hackrf_error_name(result), result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hackrf_exit();
|
||||
|
||||
return 0;
|
||||
}
|
69
host/libhackrf/src/CMakeLists.txt
Normal file
69
host/libhackrf/src/CMakeLists.txt
Normal file
@ -0,0 +1,69 @@
|
||||
# Copyright 2012 Jared Boone
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# Based heavily upon the libftdi cmake setup.
|
||||
|
||||
# Targets
|
||||
set(c_sources ${CMAKE_CURRENT_SOURCE_DIR}/hackrf.c CACHE INTERNAL "List of C sources")
|
||||
set(c_headers ${CMAKE_CURRENT_SOURCE_DIR}/hackrf.h CACHE INTERNAL "List of C headers")
|
||||
|
||||
# Dynamic library
|
||||
add_library(hackrf SHARED ${c_sources})
|
||||
set_target_properties(hackrf PROPERTIES VERSION ${MAJOR_VERSION}.${MINOR_VERSION}.0 SOVERSION 0)
|
||||
|
||||
# Static library
|
||||
add_library(hackrf-static STATIC ${c_sources})
|
||||
set_target_properties(hackrf-static PROPERTIES OUTPUT_NAME "hackrf")
|
||||
|
||||
set_target_properties(hackrf PROPERTIES CLEAN_DIRECT_OUTPUT 1)
|
||||
set_target_properties(hackrf-static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
|
||||
|
||||
# Dependencies
|
||||
target_link_libraries(hackrf ${LIBUSB_LIBRARIES})
|
||||
|
||||
if( ${UNIX} )
|
||||
install(TARGETS hackrf
|
||||
LIBRARY DESTINATION lib${LIB_SUFFIX}
|
||||
COMPONENT sharedlibs
|
||||
)
|
||||
install(TARGETS hackrf-static
|
||||
ARCHIVE DESTINATION lib${LIB_SUFFIX}
|
||||
COMPONENT staticlibs
|
||||
)
|
||||
install(FILES ${c_headers}
|
||||
DESTINATION include/${PROJECT_NAME}
|
||||
COMPONENT headers
|
||||
)
|
||||
endif( ${UNIX} )
|
||||
|
||||
if( ${WIN32} )
|
||||
install(TARGETS hackrf
|
||||
DESTINATION bin
|
||||
COMPONENT sharedlibs
|
||||
)
|
||||
install(TARGETS hackrf-static
|
||||
DESTINATION bin
|
||||
COMPONENT staticlibs
|
||||
)
|
||||
install(FILES ${c_headers}
|
||||
DESTINATION include/${PROJECT_NAME}
|
||||
COMPONENT headers
|
||||
)
|
||||
endif( ${WIN32} )
|
451
host/libhackrf/src/hackrf.c
Normal file
451
host/libhackrf/src/hackrf.c
Normal file
@ -0,0 +1,451 @@
|
||||
/*
|
||||
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
|
||||
#include <libusb.h>
|
||||
#include <pthread.h>
|
||||
|
||||
// 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;
|
||||
|
||||
typedef enum {
|
||||
HACKRF_TRANSCEIVER_MODE_RECEIVE = 1,
|
||||
HACKRF_TRANSCEIVER_MODE_TRANSMIT = 2,
|
||||
} hackrf_transceiver_mode;
|
||||
|
||||
struct hackrf_device {
|
||||
libusb_device_handle* usb_device;
|
||||
struct libusb_transfer** transfers;
|
||||
hackrf_sample_block_cb_fn callback;
|
||||
pthread_t transfer_thread;
|
||||
uint32_t transfer_count;
|
||||
uint32_t buffer_size;
|
||||
bool streaming;
|
||||
};
|
||||
|
||||
static const uint16_t hackrf_usb_vid = 0x1d50;
|
||||
static const uint16_t hackrf_usb_pid = 0x604b;
|
||||
|
||||
static libusb_context* g_libusb_context = NULL;
|
||||
|
||||
static int free_transfers(hackrf_device* device) {
|
||||
if( device->transfers != NULL ) {
|
||||
// libusb_close() should free all transfers referenced from this array.
|
||||
for(uint32_t transfer_index=0; transfer_index<device->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 ) {
|
||||
device->transfers = calloc(device->transfer_count, sizeof(struct libusb_transfer));
|
||||
if( device->transfers == NULL ) {
|
||||
return HACKRF_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
for(uint32_t transfer_index=0; transfer_index<device->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,
|
||||
(unsigned char*)malloc(device->buffer_size),
|
||||
device->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
|
||||
) {
|
||||
if( device->transfers != NULL ) {
|
||||
for(uint32_t transfer_index=0; transfer_index<device->transfer_count; transfer_index++) {
|
||||
device->transfers[transfer_index]->endpoint = endpoint_address;
|
||||
device->transfers[transfer_index]->callback = callback;
|
||||
|
||||
int error = libusb_submit_transfer(device->transfers[transfer_index]);
|
||||
if( error != 0 ) {
|
||||
return HACKRF_ERROR_LIBUSB;
|
||||
}
|
||||
}
|
||||
return HACKRF_SUCCESS;
|
||||
} else {
|
||||
// This shouldn't happen.
|
||||
return HACKRF_ERROR_OTHER;
|
||||
}
|
||||
}
|
||||
/*
|
||||
static int cancel_transfers(hackrf_device* device) {
|
||||
if( device->transfers != NULL ) {
|
||||
for(uint32_t transfer_index=0; transfer_index<device->transfer_count; transfer_index++) {
|
||||
libusb_cancel_transfer(device->transfers[transfer_index]);
|
||||
}
|
||||
return HACKRF_SUCCESS;
|
||||
} else {
|
||||
// This shouldn't happen.
|
||||
return HACKRF_ERROR_OTHER;
|
||||
}
|
||||
}
|
||||
*/
|
||||
int hackrf_init() {
|
||||
const int libusb_error = libusb_init(&g_libusb_context);
|
||||
if( libusb_error != 0 ) {
|
||||
return HACKRF_ERROR_LIBUSB;
|
||||
} else {
|
||||
return HACKRF_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
int hackrf_exit() {
|
||||
if( g_libusb_context != NULL ) {
|
||||
libusb_exit(g_libusb_context);
|
||||
g_libusb_context = NULL;
|
||||
}
|
||||
|
||||
return HACKRF_SUCCESS;
|
||||
}
|
||||
|
||||
int hackrf_open(hackrf_device** device) {
|
||||
if( device == NULL ) {
|
||||
return HACKRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
// TODO: Do proper scanning of available devices, searching for
|
||||
// unit serial number (if specified?).
|
||||
libusb_device_handle* usb_device = libusb_open_device_with_vid_pid(g_libusb_context, hackrf_usb_vid, hackrf_usb_pid);
|
||||
if( usb_device == NULL ) {
|
||||
return HACKRF_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
//int speed = libusb_get_device_speed(usb_device);
|
||||
// TODO: Error or warning if not high speed USB?
|
||||
|
||||
int result = libusb_set_configuration(usb_device, 1);
|
||||
if( result != 0 ) {
|
||||
libusb_close(usb_device);
|
||||
return HACKRF_ERROR_LIBUSB;
|
||||
}
|
||||
|
||||
result = libusb_claim_interface(usb_device, 0);
|
||||
if( result != 0 ) {
|
||||
libusb_close(usb_device);
|
||||
return HACKRF_ERROR_LIBUSB;
|
||||
}
|
||||
|
||||
hackrf_device* lib_device = NULL;
|
||||
lib_device = malloc(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 = 0;
|
||||
lib_device->transfer_count = 1024;
|
||||
lib_device->buffer_size = 16384;
|
||||
lib_device->streaming = false;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
*device = lib_device;
|
||||
|
||||
return HACKRF_SUCCESS;
|
||||
}
|
||||
|
||||
static int hackrf_set_transceiver_mode(hackrf_device* device, hackrf_transceiver_mode value) {
|
||||
int 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 ) {
|
||||
return HACKRF_ERROR_LIBUSB;
|
||||
} else {
|
||||
return HACKRF_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
int hackrf_max2837_read(hackrf_device* device, uint8_t register_number, uint16_t* value) {
|
||||
if( register_number >= 32 ) {
|
||||
return HACKRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
int 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 ) {
|
||||
return HACKRF_ERROR_LIBUSB;
|
||||
} else {
|
||||
return HACKRF_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
int hackrf_max2837_write(hackrf_device* device, uint8_t register_number, uint16_t value) {
|
||||
if( register_number >= 32 ) {
|
||||
return HACKRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
if( value >= 0x400 ) {
|
||||
return HACKRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
int 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 ) {
|
||||
return HACKRF_ERROR_LIBUSB;
|
||||
} else {
|
||||
return HACKRF_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
static void* transfer_threadproc(void* arg) {
|
||||
hackrf_device* device = (hackrf_device*)arg;
|
||||
|
||||
struct timeval timeout = { 0, 500000 };
|
||||
|
||||
while( device->streaming ) {
|
||||
int error = libusb_handle_events_timeout(g_libusb_context, &timeout);
|
||||
if( error != 0 ) {
|
||||
device->streaming = false;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void hackrf_libusb_transfer_callback(struct libusb_transfer* usb_transfer) {
|
||||
hackrf_device* device = (hackrf_device*)usb_transfer->user_data;
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
if( device->callback(&transfer) == 0 ) {
|
||||
libusb_submit_transfer(usb_transfer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
device->streaming = false;
|
||||
}
|
||||
|
||||
static int kill_transfer_thread(hackrf_device* device) {
|
||||
device->streaming = false;
|
||||
|
||||
if( device->transfer_thread != 0 ) {
|
||||
void* value = NULL;
|
||||
int result = pthread_join(device->transfer_thread, &value);
|
||||
if( result != 0 ) {
|
||||
return HACKRF_ERROR_THREAD;
|
||||
}
|
||||
device->transfer_thread = 0;
|
||||
}
|
||||
|
||||
return HACKRF_SUCCESS;
|
||||
}
|
||||
|
||||
static int create_transfer_thread(
|
||||
hackrf_device* device,
|
||||
const uint8_t endpoint_address,
|
||||
hackrf_sample_block_cb_fn callback
|
||||
) {
|
||||
if( device->transfer_thread == 0 ) {
|
||||
int result = prepare_transfers(
|
||||
device, endpoint_address,
|
||||
hackrf_libusb_transfer_callback
|
||||
);
|
||||
if( result != HACKRF_SUCCESS ) {
|
||||
return result;
|
||||
}
|
||||
|
||||
device->callback = callback;
|
||||
device->streaming = true;
|
||||
|
||||
result = pthread_create(&device->transfer_thread, 0, transfer_threadproc, device);
|
||||
if( result != 0 ) {
|
||||
return HACKRF_ERROR_THREAD;
|
||||
}
|
||||
} else {
|
||||
return HACKRF_ERROR_BUSY;
|
||||
}
|
||||
|
||||
return HACKRF_SUCCESS;
|
||||
}
|
||||
|
||||
bool hackrf_is_streaming(hackrf_device* device) {
|
||||
return device->streaming;
|
||||
}
|
||||
|
||||
int hackrf_start_rx(hackrf_device* device, hackrf_sample_block_cb_fn callback) {
|
||||
const uint8_t endpoint_address = LIBUSB_ENDPOINT_IN | 1;
|
||||
int result = hackrf_set_transceiver_mode(device, HACKRF_TRANSCEIVER_MODE_RECEIVE);
|
||||
if( result == HACKRF_SUCCESS ) {
|
||||
create_transfer_thread(device, endpoint_address, callback);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int hackrf_stop_rx(hackrf_device* device) {
|
||||
return kill_transfer_thread(device);
|
||||
}
|
||||
|
||||
int hackrf_start_tx(hackrf_device* device, hackrf_sample_block_cb_fn callback) {
|
||||
const uint8_t endpoint_address = LIBUSB_ENDPOINT_OUT | 2;
|
||||
int result = hackrf_set_transceiver_mode(device, HACKRF_TRANSCEIVER_MODE_TRANSMIT);
|
||||
if( result == HACKRF_SUCCESS ) {
|
||||
result = create_transfer_thread(device, endpoint_address, callback);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int hackrf_stop_tx(hackrf_device* device) {
|
||||
return kill_transfer_thread(device);
|
||||
}
|
||||
|
||||
int hackrf_close(hackrf_device* device) {
|
||||
if( device != NULL ) {
|
||||
int result = hackrf_stop_rx(device);
|
||||
if( result ) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = hackrf_stop_tx(device);
|
||||
if( result ) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if( device->usb_device != NULL ) {
|
||||
result = libusb_release_interface(device->usb_device, 0);
|
||||
if( result ) {
|
||||
return HACKRF_ERROR_LIBUSB;
|
||||
}
|
||||
|
||||
libusb_close(device->usb_device);
|
||||
|
||||
device->usb_device = NULL;
|
||||
}
|
||||
|
||||
free_transfers(device);
|
||||
|
||||
free(device);
|
||||
}
|
||||
|
||||
return HACKRF_SUCCESS;
|
||||
}
|
||||
|
||||
const char* hackrf_error_name(enum hackrf_error errcode) {
|
||||
switch(errcode) {
|
||||
case HACKRF_SUCCESS:
|
||||
return "HACKRF_SUCCESS";
|
||||
|
||||
case HACKRF_ERROR_INVALID_PARAM:
|
||||
return "HACKRF_ERROR_INVALID_PARAM";
|
||||
|
||||
case HACKRF_ERROR_NOT_FOUND:
|
||||
return "HACKRF_ERROR_NOT_FOUND";
|
||||
|
||||
case HACKRF_ERROR_BUSY:
|
||||
return "HACKRF_ERROR_BUSY";
|
||||
|
||||
case HACKRF_ERROR_NO_MEM:
|
||||
return "HACKRF_ERROR_NO_MEM";
|
||||
|
||||
case HACKRF_ERROR_LIBUSB:
|
||||
return "HACKRF_ERROR_LIBUSB";
|
||||
|
||||
case HACKRF_ERROR_THREAD:
|
||||
return "HACKRF_ERROR_THREAD";
|
||||
|
||||
case HACKRF_ERROR_OTHER:
|
||||
return "HACKRF_ERROR_OTHER";
|
||||
|
||||
default:
|
||||
return "HACKRF unknown error";
|
||||
}
|
||||
}
|
71
host/libhackrf/src/hackrf.h
Normal file
71
host/libhackrf/src/hackrf.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||
*
|
||||
* 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 __HACKRF_H__
|
||||
#define __HACKRF_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
enum hackrf_error {
|
||||
HACKRF_SUCCESS = 0,
|
||||
HACKRF_ERROR_INVALID_PARAM = -2,
|
||||
HACKRF_ERROR_NOT_FOUND = -5,
|
||||
HACKRF_ERROR_BUSY = -6,
|
||||
HACKRF_ERROR_NO_MEM = -11,
|
||||
HACKRF_ERROR_LIBUSB = -1000,
|
||||
HACKRF_ERROR_THREAD = -1001,
|
||||
HACKRF_ERROR_OTHER = -9999,
|
||||
};
|
||||
|
||||
typedef struct hackrf_device hackrf_device;
|
||||
|
||||
typedef struct {
|
||||
hackrf_device* device;
|
||||
uint8_t* buffer;
|
||||
int buffer_length;
|
||||
int valid_length;
|
||||
} hackrf_transfer;
|
||||
|
||||
typedef int (*hackrf_sample_block_cb_fn)(hackrf_transfer* transfer);
|
||||
|
||||
int hackrf_init();
|
||||
int hackrf_exit();
|
||||
|
||||
int hackrf_open(hackrf_device** device);
|
||||
int hackrf_close(hackrf_device* device);
|
||||
|
||||
//int hackrf_set_sampling_rate(float sampling_rate_hz);
|
||||
|
||||
int hackrf_start_rx(hackrf_device* device, hackrf_sample_block_cb_fn callback);
|
||||
int hackrf_stop_rx(hackrf_device* device);
|
||||
|
||||
int hackrf_start_tx(hackrf_device* device, hackrf_sample_block_cb_fn callback);
|
||||
int hackrf_stop_tx(hackrf_device* device);
|
||||
|
||||
bool hackrf_is_streaming(hackrf_device* device);
|
||||
|
||||
int hackrf_max2837_read(hackrf_device* device, uint8_t register_number, uint16_t* value);
|
||||
int hackrf_max2837_write(hackrf_device* device, uint8_t register_number, uint16_t value);
|
||||
|
||||
const char* hackrf_error_name(enum hackrf_error errcode);
|
||||
|
||||
#endif//__HACKRF_H__
|
Reference in New Issue
Block a user