From 4cc865de5480591587b9b1a6ac9eb5bab4ccb6d1 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Mon, 15 Oct 2012 15:55:44 -0700 Subject: [PATCH 01/17] Swapped constant names for HackRF VID and PID. Fortunately, I also had them backward in my call to libusb... Now the names are right! --- host/usb_test/usb_test.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/host/usb_test/usb_test.c b/host/usb_test/usb_test.c index c984898c..33bc9979 100644 --- a/host/usb_test/usb_test.c +++ b/host/usb_test/usb_test.c @@ -31,8 +31,8 @@ #include -const uint16_t hackrf_usb_pid = 0x1d50; -const uint16_t hackrf_usb_vid = 0x604b; +const uint16_t hackrf_usb_vid = 0x1d50; +const uint16_t hackrf_usb_pid = 0x604b; typedef enum { TRANSCEIVER_MODE_RX, @@ -77,7 +77,7 @@ libusb_device_handle* open_device(libusb_context* const context) { return NULL; } - libusb_device_handle* device = libusb_open_device_with_vid_pid(context, hackrf_usb_pid, hackrf_usb_vid); + libusb_device_handle* device = libusb_open_device_with_vid_pid(context, hackrf_usb_vid, hackrf_usb_pid); if( device == NULL ) { printf("libusb_open_device_with_vid_pid() failed\n"); return NULL; From 1391bfc61e067c4dbd6b5b56eeeb434d8e073525 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 16 Oct 2012 16:56:25 -0700 Subject: [PATCH 02/17] Flip endian-ness on USB MAX2837 register read request. --- firmware/usb_performance/usb_performance.c | 4 ++-- host/usb_test/max2837_dump.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/usb_performance/usb_performance.c b/firmware/usb_performance/usb_performance.c index 6d9e7145..94244300 100644 --- a/firmware/usb_performance/usb_performance.c +++ b/firmware/usb_performance/usb_performance.c @@ -240,8 +240,8 @@ bool usb_vendor_request_read_max2837( if( stage == USB_TRANSFER_STAGE_SETUP ) { if( endpoint->setup.index < 32 ) { const uint16_t value = max2837_reg_read(endpoint->setup.index); - endpoint->buffer[0] = value >> 8; - endpoint->buffer[1] = value & 0xff; + endpoint->buffer[0] = value & 0xff; + endpoint->buffer[1] = value >> 8; usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 2); usb_endpoint_schedule_ack(endpoint->out); return true; diff --git a/host/usb_test/max2837_dump.py b/host/usb_test/max2837_dump.py index 1bda15fc..3e85d6a7 100755 --- a/host/usb_test/max2837_dump.py +++ b/host/usb_test/max2837_dump.py @@ -27,7 +27,7 @@ device = usb.core.find(idVendor=0x1d50, idProduct=0x604b) device.set_configuration() def read_max2837_register(register_number): - return struct.unpack('>H', device.ctrl_transfer(0xC0, 3, 0, register_number, 2))[0] + return struct.unpack(' Date: Tue, 16 Oct 2012 16:57:35 -0700 Subject: [PATCH 03/17] Return of the hand-optimized assembly for SGPIO read and write interrupt. Reset only the one SGPIO slice flag that is actually causing the interrupt. --- firmware/usb_performance/usb_performance.c | 62 ++++++++++++++++------ 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/firmware/usb_performance/usb_performance.c b/firmware/usb_performance/usb_performance.c index 94244300..88766176 100644 --- a/firmware/usb_performance/usb_performance.c +++ b/firmware/usb_performance/usb_performance.c @@ -332,27 +332,55 @@ bool usb_set_configuration( }; void sgpio_irqhandler() { - SGPIO_CLR_STATUS_1 = 0xFFFFFFFF; + SGPIO_CLR_STATUS_1 = (1 << SGPIO_SLICE_A); uint32_t* const p = (uint32_t*)&usb_bulk_buffer[usb_bulk_buffer_offset]; if( transceiver_mode == TRANSCEIVER_MODE_RX ) { - p[7] = SGPIO_REG_SS(SGPIO_SLICE_A); - p[6] = SGPIO_REG_SS(SGPIO_SLICE_I); - p[5] = SGPIO_REG_SS(SGPIO_SLICE_E); - p[4] = SGPIO_REG_SS(SGPIO_SLICE_J); - p[3] = SGPIO_REG_SS(SGPIO_SLICE_C); - p[2] = SGPIO_REG_SS(SGPIO_SLICE_K); - p[1] = SGPIO_REG_SS(SGPIO_SLICE_F); - p[0] = SGPIO_REG_SS(SGPIO_SLICE_L); + __asm__( + "ldr r0, [%[SGPIO_REG_SS], #44]\n\t" + "str r0, [%[p], #0]\n\t" + "ldr r0, [%[SGPIO_REG_SS], #20]\n\t" + "str r0, [%[p], #4]\n\t" + "ldr r0, [%[SGPIO_REG_SS], #40]\n\t" + "str r0, [%[p], #8]\n\t" + "ldr r0, [%[SGPIO_REG_SS], #8]\n\t" + "str r0, [%[p], #12]\n\t" + "ldr r0, [%[SGPIO_REG_SS], #36]\n\t" + "str r0, [%[p], #16]\n\t" + "ldr r0, [%[SGPIO_REG_SS], #16]\n\t" + "str r0, [%[p], #20]\n\t" + "ldr r0, [%[SGPIO_REG_SS], #32]\n\t" + "str r0, [%[p], #24]\n\t" + "ldr r0, [%[SGPIO_REG_SS], #0]\n\t" + "str r0, [%[p], #28]\n\t" + : + : [SGPIO_REG_SS] "l" (SGPIO_PORT_BASE + 0x100), + [p] "l" (p) + : "r0" + ); } else { - SGPIO_REG_SS(SGPIO_SLICE_A) = p[7]; - SGPIO_REG_SS(SGPIO_SLICE_I) = p[6]; - SGPIO_REG_SS(SGPIO_SLICE_E) = p[5]; - SGPIO_REG_SS(SGPIO_SLICE_J) = p[4]; - SGPIO_REG_SS(SGPIO_SLICE_C) = p[3]; - SGPIO_REG_SS(SGPIO_SLICE_K) = p[2]; - SGPIO_REG_SS(SGPIO_SLICE_F) = p[1]; - SGPIO_REG_SS(SGPIO_SLICE_L) = p[0]; + __asm__( + "ldr r0, [%[p], #0]\n\t" + "str r0, [%[SGPIO_REG_SS], #44]\n\t" + "ldr r0, [%[p], #4]\n\t" + "str r0, [%[SGPIO_REG_SS], #20]\n\t" + "ldr r0, [%[p], #8]\n\t" + "str r0, [%[SGPIO_REG_SS], #40]\n\t" + "ldr r0, [%[p], #12]\n\t" + "str r0, [%[SGPIO_REG_SS], #8]\n\t" + "ldr r0, [%[p], #16]\n\t" + "str r0, [%[SGPIO_REG_SS], #36]\n\t" + "ldr r0, [%[p], #20]\n\t" + "str r0, [%[SGPIO_REG_SS], #16]\n\t" + "ldr r0, [%[p], #24]\n\t" + "str r0, [%[SGPIO_REG_SS], #32]\n\t" + "ldr r0, [%[p], #28]\n\t" + "str r0, [%[SGPIO_REG_SS], #0]\n\t" + : + : [SGPIO_REG_SS] "l" (SGPIO_PORT_BASE + 0x100), + [p] "l" (p) + : "r0" + ); } usb_bulk_buffer_offset = (usb_bulk_buffer_offset + 32) & usb_bulk_buffer_mask; From 38b6382c5adf86407403988df0d73ec0ebffa553 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 16 Oct 2012 16:58:36 -0700 Subject: [PATCH 04/17] Add a guard for stream data file read/write, to ensure fd is valid. --- host/usb_test/usb_test.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/host/usb_test/usb_test.c b/host/usb_test/usb_test.c index 33bc9979..52b8b7af 100644 --- a/host/usb_test/usb_test.c +++ b/host/usb_test/usb_test.c @@ -53,8 +53,16 @@ volatile uint32_t byte_count = 0; void write_callback(struct libusb_transfer* transfer) { if( transfer->status == LIBUSB_TRANSFER_COMPLETED ) { byte_count += transfer->actual_length; - write(fd, transfer->buffer, transfer->actual_length); - libusb_submit_transfer(transfer); + if( fd != -1 ) { + const ssize_t bytes_written = write(fd, transfer->buffer, transfer->actual_length); + if( bytes_written == transfer->actual_length ) { + libusb_submit_transfer(transfer); + } else { + printf("write failed: errno %d\n", errno); + close(fd); + fd = -1; + } + } } else { printf("transfer status was not 'completed'\n"); } @@ -63,8 +71,16 @@ void write_callback(struct libusb_transfer* transfer) { void read_callback(struct libusb_transfer* transfer) { if( transfer->status == LIBUSB_TRANSFER_COMPLETED ) { byte_count += transfer->actual_length; - read(fd, transfer->buffer, transfer->actual_length); - libusb_submit_transfer(transfer); + if( fd != -1 ) { + const ssize_t bytes_read = read(fd, transfer->buffer, transfer->length); + if( bytes_read == transfer->length ) { + libusb_submit_transfer(transfer); + } else { + printf("read failed: errno %d\n", errno); + close(fd); + fd = -1; + } + } } else { printf("transfer status was not 'completed'\n"); } From 91a9bf5ca373569c228723f344c342e2541e456f Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 16 Oct 2012 20:33:41 -0700 Subject: [PATCH 05/17] Initial commit of libhackrf. --- host/libhackrf/CMakeLists.txt | 41 ++ host/libhackrf/FindUSB1.cmake | 38 ++ host/libhackrf/examples/CMakeLists.txt | 33 ++ host/libhackrf/examples/hackrf_max2837.c | 161 ++++++++ host/libhackrf/examples/hackrf_transfer.c | 210 ++++++++++ host/libhackrf/src/CMakeLists.txt | 69 ++++ host/libhackrf/src/hackrf.c | 451 ++++++++++++++++++++++ host/libhackrf/src/hackrf.h | 71 ++++ 8 files changed, 1074 insertions(+) create mode 100644 host/libhackrf/CMakeLists.txt create mode 100644 host/libhackrf/FindUSB1.cmake create mode 100644 host/libhackrf/examples/CMakeLists.txt create mode 100644 host/libhackrf/examples/hackrf_max2837.c create mode 100644 host/libhackrf/examples/hackrf_transfer.c create mode 100644 host/libhackrf/src/CMakeLists.txt create mode 100644 host/libhackrf/src/hackrf.c create mode 100644 host/libhackrf/src/hackrf.h diff --git a/host/libhackrf/CMakeLists.txt b/host/libhackrf/CMakeLists.txt new file mode 100644 index 00000000..370a1c2d --- /dev/null +++ b/host/libhackrf/CMakeLists.txt @@ -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) + diff --git a/host/libhackrf/FindUSB1.cmake b/host/libhackrf/FindUSB1.cmake new file mode 100644 index 00000000..0cbf8022 --- /dev/null +++ b/host/libhackrf/FindUSB1.cmake @@ -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, +# +# 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) \ No newline at end of file diff --git a/host/libhackrf/examples/CMakeLists.txt b/host/libhackrf/examples/CMakeLists.txt new file mode 100644 index 00000000..fc3a198d --- /dev/null +++ b/host/libhackrf/examples/CMakeLists.txt @@ -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) diff --git a/host/libhackrf/examples/hackrf_max2837.c b/host/libhackrf/examples/hackrf_max2837.c new file mode 100644 index 00000000..f4fbdf2e --- /dev/null +++ b/host/libhackrf/examples/hackrf_max2837.c @@ -0,0 +1,161 @@ +/* + * 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. + */ + +#include + +#include +#include +#include + +static void usage() { + printf("\nUsage:\n"); + printf("\t-n, --register : 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 : write register specified by last -n argument with value \n"); + printf("\nExamples:\n"); + printf("\t -n 12 -r # reads from register 12\n"); + printf("\t -r # reads all registers\n"); + printf("\t -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; +} diff --git a/host/libhackrf/examples/hackrf_transfer.c b/host/libhackrf/examples/hackrf_transfer.c new file mode 100644 index 00000000..7bee7b51 --- /dev/null +++ b/host/libhackrf/examples/hackrf_transfer.c @@ -0,0 +1,210 @@ +/* + * 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. + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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 # Receive data into file.\n"); + printf("\t-t # 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; +} diff --git a/host/libhackrf/src/CMakeLists.txt b/host/libhackrf/src/CMakeLists.txt new file mode 100644 index 00000000..223d034c --- /dev/null +++ b/host/libhackrf/src/CMakeLists.txt @@ -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} ) diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c new file mode 100644 index 00000000..692580df --- /dev/null +++ b/host/libhackrf/src/hackrf.c @@ -0,0 +1,451 @@ +/* + * 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. + */ + +#include "hackrf.h" + +#include + +#include +#include + +// 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_indextransfer_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_indextransfer_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_indextransfer_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_indextransfer_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"; + } +} diff --git a/host/libhackrf/src/hackrf.h b/host/libhackrf/src/hackrf.h new file mode 100644 index 00000000..f06c6eec --- /dev/null +++ b/host/libhackrf/src/hackrf.h @@ -0,0 +1,71 @@ +/* + * 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. + */ + +#ifndef __HACKRF_H__ +#define __HACKRF_H__ + +#include +#include + +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__ From 34b4729cfeb04be9cdfa80f06ada3c8fbeba1187 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 16 Oct 2012 20:46:41 -0700 Subject: [PATCH 06/17] Whacked the usb_test project, which was transformed into libhackrf. Moved the Python utilities (such as they are) into a host/python directory. --- host/{usb_test => python}/max2837_dump.py | 0 .../set_transceiver_mode.py | 0 host/usb_test/Makefile | 77 ----- host/usb_test/usb_test.c | 308 ------------------ 4 files changed, 385 deletions(-) rename host/{usb_test => python}/max2837_dump.py (100%) rename host/{usb_test => python}/set_transceiver_mode.py (100%) delete mode 100644 host/usb_test/Makefile delete mode 100644 host/usb_test/usb_test.c diff --git a/host/usb_test/max2837_dump.py b/host/python/max2837_dump.py similarity index 100% rename from host/usb_test/max2837_dump.py rename to host/python/max2837_dump.py diff --git a/host/usb_test/set_transceiver_mode.py b/host/python/set_transceiver_mode.py similarity index 100% rename from host/usb_test/set_transceiver_mode.py rename to host/python/set_transceiver_mode.py diff --git a/host/usb_test/Makefile b/host/usb_test/Makefile deleted file mode 100644 index 138ca744..00000000 --- a/host/usb_test/Makefile +++ /dev/null @@ -1,77 +0,0 @@ -# Hey Emacs, this is a -*- makefile -*- -# -# Copyright 2010 Michael Ossmann -# 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. -# - -# derived primarily from Makefiles in Project Ubertooth - -CC ?= gcc -AR ?= ar -INSTALL ?= /usr/bin/install -LDCONFIG ?= /sbin/ldconfig - -OPTFLAGS = -O2 -ANGRYFLAGS = -Wall #-Wextra -pedantic -CFLAGS += $(OPTFLAGS) $(ANGRYFLAGS) - -LIB_DIR ?= /usr/lib -INCLUDE_DIR ?= /usr/include -INSTALL_DIR ?= /usr/bin - -OS = $(shell uname) -ifeq ($(OS), FreeBSD) - LIBUSB = usb - CFLAGS += -DFREEBSD -else - LIBUSB = usb-1.0 -endif - -LDFLAGS += -l$(LIBUSB) - -TOOLS = usb_test - -ifeq ($(OS), Darwin) - CFLAGS += -I/opt/local/include/ - LDFLAGS += -L/opt/local/lib/ -rpath,/opt/local/lib -else - # -endif - -TOOLS_SOURCE = $(TOOLS:%=%.c) - -all: $(TOOLS) - -$(TOOLS): $(TOOLS_SOURCE) - $(CC) $(CFLAGS) -o $@ $@.c $(LDFLAGS) - -install: $(TOOLS) - $(INSTALL) -m 0755 $(TOOLS) $(INSTALL_DIR) - -cygwin-install: $(LIB_FILE) $(STATIC_LIB_FILE) - $(INSTALL) -m 0755 $(TOOLS) $(INSTALL_DIR) - -osx-install: $(LIB_FILE) $(TOOLS) - $(INSTALL) -m 0755 $(TOOLS) $(INSTALL_DIR) - -clean: - rm -f $(TOOLS) - -.PHONY: all clean install cygwin-install osx-install \ No newline at end of file diff --git a/host/usb_test/usb_test.c b/host/usb_test/usb_test.c deleted file mode 100644 index 52b8b7af..00000000 --- a/host/usb_test/usb_test.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -const uint16_t hackrf_usb_vid = 0x1d50; -const uint16_t hackrf_usb_pid = 0x604b; - -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; -struct timeval time_start; -volatile uint32_t byte_count = 0; - -void write_callback(struct libusb_transfer* transfer) { - if( transfer->status == LIBUSB_TRANSFER_COMPLETED ) { - byte_count += transfer->actual_length; - if( fd != -1 ) { - const ssize_t bytes_written = write(fd, transfer->buffer, transfer->actual_length); - if( bytes_written == transfer->actual_length ) { - libusb_submit_transfer(transfer); - } else { - printf("write failed: errno %d\n", errno); - close(fd); - fd = -1; - } - } - } else { - printf("transfer status was not 'completed'\n"); - } -} - -void read_callback(struct libusb_transfer* transfer) { - if( transfer->status == LIBUSB_TRANSFER_COMPLETED ) { - byte_count += transfer->actual_length; - if( fd != -1 ) { - const ssize_t bytes_read = read(fd, transfer->buffer, transfer->length); - if( bytes_read == transfer->length ) { - libusb_submit_transfer(transfer); - } else { - printf("read failed: errno %d\n", errno); - close(fd); - fd = -1; - } - } - } else { - printf("transfer status was not 'completed'\n"); - } -} - -libusb_device_handle* open_device(libusb_context* const context) { - int result = libusb_init(NULL); - if( result != 0 ) { - printf("libusb_init() failed: %d\n", result); - return NULL; - } - - libusb_device_handle* device = libusb_open_device_with_vid_pid(context, hackrf_usb_vid, hackrf_usb_pid); - if( device == NULL ) { - printf("libusb_open_device_with_vid_pid() failed\n"); - return NULL; - } - - //int speed = libusb_get_device_speed(device); - //printf("device speed: %d\n", speed); - - result = libusb_set_configuration(device, 1); - if( result != 0 ) { - libusb_close(device); - printf("libusb_set_configuration() failed: %d\n", result); - return NULL; - } - - result = libusb_claim_interface(device, 0); - if( result != 0 ) { - libusb_close(device); - printf("libusb_claim_interface() failed: %d\n", result); - return NULL; - } - - return device; -} - -void free_transfers(struct libusb_transfer** const transfers, const uint32_t transfer_count) { - for(uint32_t transfer_index=0; transfer_indexbuffer == NULL ) { - free_transfers(transfers, transfer_count); - printf("malloc() failed\n"); - return NULL; - } - - int error = libusb_submit_transfer(transfers[transfer_index]); - if( error != 0 ) { - free_transfers(transfers, transfer_count); - printf("libusb_submit_transfer() failed: %d\n", error); - return NULL; - } - } - - return transfers; -} - -static void usage() { - printf("Usage:\n"); - printf("\tGo fish.\n"); -} - -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; - } - - fd = -1; - uint_fast8_t endpoint_address = 0; - libusb_transfer_cb_fn callback = NULL; - - if( transceiver_mode == TRANSCEIVER_MODE_RX ) { - fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO); - endpoint_address = 0x81; - callback = &write_callback; - } else { - fd = open(path, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO); - endpoint_address = 0x02; - callback = &read_callback; - } - - if( fd == -1 ) { - printf("Failed to open file: errno %d\n", errno); - return fd; - } - - libusb_context* const context = NULL; - libusb_device_handle* const device = open_device(context); - if( device == NULL ) { - return -3; - } - - const uint32_t transfer_count = 1024; - const uint32_t buffer_size = 16384; - struct libusb_transfer** const transfers = prepare_transfers( - device, endpoint_address, transfer_count, buffer_size, callback - ); - if( transfers == NULL ) { - return -4; - } - - ////////////////////////////////////////////////////////////// - - struct timeval timeout = { 0, 500000 }; - struct timeval time_now; - - const double progress_interval = 1.0; - gettimeofday(&time_start, NULL); - - uint32_t call_count = 0; - do { - int error = libusb_handle_events_timeout(context, &timeout); - if( error != 0 ) { - printf("libusb_handle_events_timeout() failed: %d\n", error); - return -10; - } - - if( (call_count & 0xFF) == 0 ) { - gettimeofday(&time_now, NULL); - const float time_difference = TimevalDiff(&time_now, &time_start); - if( time_difference >= progress_interval ) { - const float rate = (float)byte_count / time_difference; - printf("%.1f/%.3f = %.1f MiB/second\n", - byte_count / 1e6f, - time_difference, - rate / 1e6f - ); - time_start = time_now; - byte_count = 0; - } - } - call_count += 1; - } while(1); - - free_transfers(transfers, transfer_count); - - int result = libusb_release_interface(device, 0); - if( result != 0 ) { - printf("libusb_release_interface() failed: %d\n", result); - return -2000; - } - - libusb_close(device); - - libusb_exit(context); - - return 0; -} From 63b1a25979b4aff0d12eb55316b5b5066e5373a3 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 17 Oct 2012 11:45:30 -0700 Subject: [PATCH 07/17] Consolidate a few clock setup tasks that repeat among many projects into cpu_clock_init(). --- firmware/common/hackrf_core.c | 8 ++++++++ firmware/sgpio-rx/sgpio-rx.c | 7 ------- firmware/sgpio/sgpio.c | 6 ------ firmware/sgpio_passthrough_rom_to_ram/sgpio_passthrough.c | 7 ------- firmware/usb_performance/usb_performance.c | 6 ------ 5 files changed, 8 insertions(+), 26 deletions(-) diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index 3bca88df..fd3cd70b 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -194,6 +194,14 @@ void cpu_clock_init(void) /* use PLL0USB as clock source for USB0 */ CGU_BASE_USB0_CLK = CGU_BASE_USB0_CLK_AUTOBLOCK | CGU_BASE_USB0_CLK_CLK_SEL(CGU_SRC_PLL0USB); + + /* Switch peripheral clock over to use PLL1 (204MHz) */ + CGU_BASE_PERIPH_CLK = CGU_BASE_PERIPH_CLK_AUTOBLOCK + | CGU_BASE_PERIPH_CLK_CLK_SEL(CGU_SRC_PLL1); + + /* Switch APB1 clock over to use PLL1 (204MHz) */ + CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_AUTOBLOCK + | CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_PLL1); } void ssp1_init(void) diff --git a/firmware/sgpio-rx/sgpio-rx.c b/firmware/sgpio-rx/sgpio-rx.c index 62f29988..a9270a5c 100644 --- a/firmware/sgpio-rx/sgpio-rx.c +++ b/firmware/sgpio-rx/sgpio-rx.c @@ -96,13 +96,6 @@ int main(void) { pin_setup(); enable_1v8_power(); cpu_clock_init(); - - CGU_BASE_PERIPH_CLK = CGU_BASE_PERIPH_CLK_AUTOBLOCK - | CGU_BASE_PERIPH_CLK_CLK_SEL(CGU_SRC_PLL1); - - CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_AUTOBLOCK - | CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_PLL1); - ssp1_init(); ssp1_set_mode_max2837(); max2837_setup(); diff --git a/firmware/sgpio/sgpio.c b/firmware/sgpio/sgpio.c index fbf40ffd..e298c93e 100644 --- a/firmware/sgpio/sgpio.c +++ b/firmware/sgpio/sgpio.c @@ -72,12 +72,6 @@ int main(void) { cpu_clock_init(); ssp1_init(); - CGU_BASE_PERIPH_CLK = CGU_BASE_PERIPH_CLK_AUTOBLOCK - | CGU_BASE_PERIPH_CLK_CLK_SEL(CGU_SRC_PLL1); - - CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_AUTOBLOCK - | CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_PLL1); - gpio_set(PORT_LED1_3, PIN_LED1); ssp1_set_mode_max5864(); diff --git a/firmware/sgpio_passthrough_rom_to_ram/sgpio_passthrough.c b/firmware/sgpio_passthrough_rom_to_ram/sgpio_passthrough.c index afdf8a25..561aaa9d 100644 --- a/firmware/sgpio_passthrough_rom_to_ram/sgpio_passthrough.c +++ b/firmware/sgpio_passthrough_rom_to_ram/sgpio_passthrough.c @@ -354,13 +354,6 @@ int main(void) enable_1v8_power(); cpu_clock_init(); ssp1_init(); - - CGU_BASE_PERIPH_CLK = (CGU_BASE_CLK_AUTOBLOCK - | (CGU_SRC_PLL1 << CGU_BASE_CLK_SEL_SHIFT)); - - CGU_BASE_APB1_CLK = (CGU_BASE_CLK_AUTOBLOCK - | (CGU_SRC_PLL1 << CGU_BASE_CLK_SEL_SHIFT)); - gpio_set(PORT_LED1_3, PIN_LED1); //test_sgpio_sliceA_D(); diff --git a/firmware/usb_performance/usb_performance.c b/firmware/usb_performance/usb_performance.c index 88766176..32e3beef 100644 --- a/firmware/usb_performance/usb_performance.c +++ b/firmware/usb_performance/usb_performance.c @@ -394,12 +394,6 @@ int main(void) { enable_1v8_power(); cpu_clock_init(); - CGU_BASE_PERIPH_CLK = CGU_BASE_PERIPH_CLK_AUTOBLOCK - | CGU_BASE_PERIPH_CLK_CLK_SEL(CGU_SRC_PLL1); - - CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_AUTOBLOCK - | CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_PLL1); - usb_peripheral_reset(); usb_device_init(0, &usb_device); From 7fdfde9314736d20760682a0c7ab91cf11eefb6c Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 17 Oct 2012 11:48:35 -0700 Subject: [PATCH 08/17] Make use of i2c0_init() argument to control duty cycle, when APB1 clock shifts from IRC (~12MHz) to PLL1 (204MHz). --- firmware/common/hackrf_core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index fd3cd70b..4135f369 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -39,7 +39,10 @@ void delay(uint32_t duration) /* clock startup for Jellybean with Lemondrop attached */ void cpu_clock_init(void) { - i2c0_init(); + /* use IRC as clock source for APB1 (including I2C0) */ + CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_IRC); + + i2c0_init(15); si5351c_disable_all_outputs(); si5351c_disable_oeb_pin_control(); @@ -120,6 +123,8 @@ void cpu_clock_init(void) si5351c_enable_clock_outputs(); //FIXME disable I2C + /* Kick I2C0 down to 400kHz when we switch over to APB1 clock = 204MHz */ + i2c0_init(255); /* * 12MHz clock is entering LPC XTAL1/OSC input now. On From 6babcbe579d1151cdca545c4a59d1fb46ac77d1d Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 17 Oct 2012 11:57:44 -0700 Subject: [PATCH 09/17] Add USB vendor requests to read/write Si5351C registers. --- firmware/common/si5351c.h | 3 + firmware/usb_performance/usb_performance.c | 37 +++++ host/libhackrf/examples/CMakeLists.txt | 2 + host/libhackrf/examples/hackrf_si5351c.c | 161 +++++++++++++++++++++ host/libhackrf/src/hackrf.c | 53 +++++++ host/libhackrf/src/hackrf.h | 3 + 6 files changed, 259 insertions(+) create mode 100644 host/libhackrf/examples/hackrf_si5351c.c diff --git a/firmware/common/si5351c.h b/firmware/common/si5351c.h index 740da2f4..8cd583ed 100644 --- a/firmware/common/si5351c.h +++ b/firmware/common/si5351c.h @@ -45,6 +45,9 @@ void si5351c_configure_multisynth(const uint_fast8_t ms_number, void si5351c_configure_clock_control(); void si5351c_enable_clock_outputs(); +void si5351c_write_single(uint8_t reg, uint8_t val); +uint8_t si5351c_read_single(uint8_t reg); + #ifdef __cplusplus } #endif diff --git a/firmware/usb_performance/usb_performance.c b/firmware/usb_performance/usb_performance.c index 32e3beef..c681c625 100644 --- a/firmware/usb_performance/usb_performance.c +++ b/firmware/usb_performance/usb_performance.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -252,6 +253,42 @@ bool usb_vendor_request_read_max2837( } } +bool usb_vendor_request_write_si5351c( + usb_endpoint_t* const endpoint, + const usb_transfer_stage_t stage +) { + if( stage == USB_TRANSFER_STAGE_SETUP ) { + if( endpoint->setup.index < 256 ) { + if( endpoint->setup.value < 256 ) { + si5351c_write_single(endpoint->setup.index, endpoint->setup.value); + usb_endpoint_schedule_ack(endpoint->in); + return true; + } + } + return false; + } else { + return true; + } +} + +bool usb_vendor_request_read_si5351c( + usb_endpoint_t* const endpoint, + const usb_transfer_stage_t stage +) { + if( stage == USB_TRANSFER_STAGE_SETUP ) { + if( endpoint->setup.index < 256 ) { + const uint8_t value = si5351c_read_single(endpoint->setup.index); + endpoint->buffer[0] = value; + usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 1); + usb_endpoint_schedule_ack(endpoint->out); + return true; + } + return false; + } else { + return true; + } +} + void usb_vendor_request( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage diff --git a/host/libhackrf/examples/CMakeLists.txt b/host/libhackrf/examples/CMakeLists.txt index fc3a198d..3ab34119 100644 --- a/host/libhackrf/examples/CMakeLists.txt +++ b/host/libhackrf/examples/CMakeLists.txt @@ -24,9 +24,11 @@ option(EXAMPLES "Build example programs" ON) IF( EXAMPLES ) add_executable(hackrf_max2837 hackrf_max2837.c) + add_executable(hackrf_si5351c hackrf_si5351c.c) add_executable(hackrf_transfer hackrf_transfer.c) target_link_libraries(hackrf_max2837 hackrf) + target_link_libraries(hackrf_si5351c hackrf) target_link_libraries(hackrf_transfer hackrf) include_directories(BEFORE ${CMAKE_SOURCE_DIR}/src) diff --git a/host/libhackrf/examples/hackrf_si5351c.c b/host/libhackrf/examples/hackrf_si5351c.c new file mode 100644 index 00000000..dc9214cf --- /dev/null +++ b/host/libhackrf/examples/hackrf_si5351c.c @@ -0,0 +1,161 @@ +/* + * 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. + */ + +#include + +#include +#include +#include + +static void usage() { + printf("\nUsage:\n"); + printf("\t-n, --register : 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 : write register specified by last -n argument with value \n"); + printf("\nExamples:\n"); + printf("\t -n 12 -r # reads from register 12\n"); + printf("\t -r # reads all registers\n"); + printf("\t -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_si5351c_read(device, register_number, ®ister_value); + + if( result == HACKRF_SUCCESS ) { + printf("[%3d] -> 0x%02x\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<256; 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_si5351c_write(device, register_number, register_value); + + if( result == HACKRF_SUCCESS ) { + printf("0x%2x -> [%3d]\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; +} diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index 692580df..61730c84 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -32,6 +32,8 @@ 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; typedef enum { @@ -280,6 +282,57 @@ int hackrf_max2837_write(hackrf_device* device, uint8_t register_number, uint16_ } } +int hackrf_si5351c_read(hackrf_device* device, uint16_t register_number, uint16_t* value) { + if( register_number >= 256 ) { + return HACKRF_ERROR_INVALID_PARAM; + } + + uint8_t temp_value = 0; + int 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 ) { + return HACKRF_ERROR_LIBUSB; + } else { + *value = temp_value; + return HACKRF_SUCCESS; + } +} + +int hackrf_si5351c_write(hackrf_device* device, uint16_t register_number, uint16_t value) { + if( register_number >= 256 ) { + return HACKRF_ERROR_INVALID_PARAM; + } + if( value >= 256 ) { + 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_SI5351C_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; diff --git a/host/libhackrf/src/hackrf.h b/host/libhackrf/src/hackrf.h index f06c6eec..4bd37ac1 100644 --- a/host/libhackrf/src/hackrf.h +++ b/host/libhackrf/src/hackrf.h @@ -66,6 +66,9 @@ 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); +int hackrf_si5351c_read(hackrf_device* device, uint16_t register_number, uint16_t* value); +int hackrf_si5351c_write(hackrf_device* device, uint16_t register_number, uint16_t value); + const char* hackrf_error_name(enum hackrf_error errcode); #endif//__HACKRF_H__ From d4da08a3d7c0fbd7225f989c423d3cc4a4c935e4 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 17 Oct 2012 15:59:47 -0700 Subject: [PATCH 10/17] Oops! Forgot to change MAX2837 mode from RX to TX when transceiver mode is changed. Initialize MAX5864 earlier, in "transceiver" mode (where both ADC and DAC are active), and then shift SSP1 into MAX2837 mode and leave it there, for faster tuning and RX/TX switching. --- firmware/usb_performance/usb_performance.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/firmware/usb_performance/usb_performance.c b/firmware/usb_performance/usb_performance.c index c681c625..efa25151 100644 --- a/firmware/usb_performance/usb_performance.c +++ b/firmware/usb_performance/usb_performance.c @@ -178,9 +178,13 @@ void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) { if( transceiver_mode == TRANSCEIVER_MODE_RX ) { gpio_clear(PORT_LED1_3, PIN_LED3); usb_endpoint_init(&usb_endpoint_bulk_in); + + max2837_rx(); } else { gpio_set(PORT_LED1_3, PIN_LED3); usb_endpoint_init(&usb_endpoint_bulk_out); + + max2837_tx(); } sgpio_configure(transceiver_mode, true); @@ -443,6 +447,9 @@ int main(void) { usb_run(&usb_device); ssp1_init(); + ssp1_set_mode_max5864(); + max5864_xcvr(); + ssp1_set_mode_max2837(); max2837_setup(); @@ -456,8 +463,6 @@ int main(void) { max2837_set_frequency(freq); max2837_start(); max2837_rx(); - ssp1_set_mode_max5864(); - max5864_xcvr(); while(true) { // Wait until buffer 0 is transmitted/received. From 9c4a0e94b014460a08ec3acac7abd56647668acf Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 17 Oct 2012 16:57:26 -0700 Subject: [PATCH 11/17] Factor out sample_rate_set() from cpu_clock_init(). Implement switching between several supported sampling rates for Jellybean and Jawbreaker. Commit bits of the Si5351C USB request support that I apparently missed in a prior commit. --- firmware/common/hackrf_core.c | 114 +++++++++++++++++---- firmware/common/hackrf_core.h | 3 + firmware/usb_performance/usb_performance.c | 28 +++++ host/libhackrf/examples/hackrf_transfer.c | 6 ++ host/libhackrf/src/hackrf.c | 20 ++++ host/libhackrf/src/hackrf.h | 4 +- 6 files changed, 152 insertions(+), 23 deletions(-) diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index 4135f369..f32214b3 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -36,6 +36,96 @@ void delay(uint32_t duration) __asm__("nop"); } +bool sample_rate_set(const uint32_t sample_rate_hz) { +#ifdef JELLYBEAN + /* Due to design issues, Jellybean/Lemondrop frequency plan is limited. + * Long version of the story: The MAX2837 reference frequency + * originates from the same PLL as the sample clocks, and in order to + * keep the sample clocks in phase and keep jitter noise down, the MAX2837 + * and sample clocks must be integer-related. + */ + uint32_t r_div_sample = 2; + uint32_t r_div_sgpio = 1; + + switch( sample_rate_hz ) { + case 5000000: + r_div_sample = 3; /* 800 MHz / 20 / 8 = 5 MHz */ + r_div_sgpio = 2; /* 800 MHz / 20 / 4 = 10 MHz */ + break; + + case 10000000: + r_div_sample = 2; /* 800 MHz / 20 / 4 = 10 MHz */ + r_div_sgpio = 1; /* 800 MHz / 20 / 2 = 20 MHz */ + break; + + case 20000000: + r_div_sample = 1; /* 800 MHz / 20 / 2 = 20 MHz */ + r_div_sgpio = 0; /* 800 MHz / 20 / 1 = 40 MHz */ + break; + + default: + return false; + } + + /* NOTE: Because MS1, 2, 3 outputs are slaved to PLLA, the p1, p2, p3 + * values are irrelevant. */ + + /* MS0/CLK1 is the source for the MAX5864 codec. */ + si5351c_configure_multisynth(1, 4608, 0, 1, r_div_sample); + + /* MS0/CLK2 is the source for the CPLD codec clock (same as CLK1). */ + si5351c_configure_multisynth(2, 4608, 0, 1, r_div_sample); + + /* MS0/CLK3 is the source for the SGPIO clock. */ + si5351c_configure_multisynth(3, 4608, 0, 1, r_div_sgpio); + + return true; +#endif + +#ifdef JAWBREAKER + uint32_t p1 = 4608; + + switch(sample_rate_hz) { + case 5000000: + p1 = 9728; // 800MHz / 80 = 10 MHz (SGPIO), 5 MHz (codec) + break; + + case 10000000: + p1 = 4608; // 800MHz / 40 = 20 MHz (SGPIO), 10 MHz (codec) + break; + + case 12500000: + p1 = 3584; // 800MHz / 32 = 25 MHz (SGPIO), 12.5 MHz (codec) + break; + + case 16000000: + p1 = 2688; // 800MHz / 25 = 32 MHz (SGPIO), 16 MHz (codec) + break; + + case 20000000: + p1 = 2048; // 800MHz / 20 = 40 MHz (SGPIO), 20 MHz (codec) + break; + + default: + return false; + } + + /* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ + si5351c_configure_multisynth(0, p1, 0, 1, 1); + + /* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */ + si5351c_configure_multisynth(1, p1, 0, 1, 0); + + /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ + si5351c_configure_multisynth(2, p1, 0, 1, 0); + + /* MS0/CLK3 is the source for the external clock output. */ + si5351c_configure_multisynth(3, p1, 0, 1, 0); + + return true; +#endif +} + /* clock startup for Jellybean with Lemondrop attached */ void cpu_clock_init(void) { @@ -68,15 +158,6 @@ void cpu_clock_init(void) /* MS0/CLK0 is the source for the MAX2837 clock input. */ si5351c_configure_multisynth(0, 2048, 0, 1, 0); /* 40MHz */ - /* MS0/CLK1 is the source for the MAX5864 codec. */ - si5351c_configure_multisynth(1, 4608, 0, 1, 2); /* 10MHz */ - - /* MS0/CLK2 is the source for the CPLD codec clock (same as CLK1). */ - si5351c_configure_multisynth(2, 4608, 0, 1, 2); /* 10MHz */ - - /* MS0/CLK3 is the source for the SGPIO clock. */ - si5351c_configure_multisynth(3, 4608, 0, 1, 1); /* 20MHz */ - /* MS4/CLK4 is the source for the LPC43xx microcontroller. */ si5351c_configure_multisynth(4, 8021, 0, 3, 0); /* 12MHz */ @@ -97,18 +178,6 @@ void cpu_clock_init(void) * CLK7 -> LPC4330 (but LPC4330 starts up on its own crystal) */ - /* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ - si5351c_configure_multisynth(0, 4608, 0, 1, 1); /* 10MHz */ - - /* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */ - si5351c_configure_multisynth(1, 4608, 0, 1, 0); /* 20MHz */ - - /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ - si5351c_configure_multisynth(2, 4608, 0, 1, 0); /* 20MHz */ - - /* MS0/CLK3 is the source for the external clock output. */ - si5351c_configure_multisynth(3, 4608, 0, 1, 0); /* 20MHz */ - /* MS4/CLK4 is the source for the RFFC5071 mixer. */ si5351c_configure_multisynth(4, 1536, 0, 1, 0); /* 50MHz */ @@ -119,6 +188,9 @@ void cpu_clock_init(void) //si5351c_configure_multisynth(7, 8021, 0, 3, 0); /* 12MHz */ #endif + /* Set to 10 MHz, the common rate between Jellybean and Jawbreaker. */ + sample_rate_set(10000000); + si5351c_configure_clock_control(); si5351c_enable_clock_outputs(); diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index 7eb57698..35e7eb30 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -30,6 +30,7 @@ extern "C" #endif #include +#include /* hardware identification number */ #define BOARD_ID_JELLYBEAN 0 @@ -216,6 +217,8 @@ void pin_setup(void); void enable_1v8_power(void); +bool sample_rate_set(const uint32_t sampling_rate_hz); + #ifdef __cplusplus } #endif diff --git a/firmware/usb_performance/usb_performance.c b/firmware/usb_performance/usb_performance.c index efa25151..0e462ed7 100644 --- a/firmware/usb_performance/usb_performance.c +++ b/firmware/usb_performance/usb_performance.c @@ -293,6 +293,22 @@ bool usb_vendor_request_read_si5351c( } } +bool usb_vendor_request_set_sample_rate( + usb_endpoint_t* const endpoint, + const usb_transfer_stage_t stage +) { + if( stage == USB_TRANSFER_STAGE_SETUP ) { + const uint32_t sample_rate = (endpoint->setup.index << 16) | endpoint->setup.value; + if( sample_rate_set(sample_rate) ) { + usb_endpoint_schedule_ack(endpoint->in); + return true; + } + return false; + } else { + return true; + } +} + void usb_vendor_request( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage @@ -312,6 +328,18 @@ void usb_vendor_request( success = usb_vendor_request_read_max2837(endpoint, stage); break; + case 4: + success = usb_vendor_request_write_si5351c(endpoint, stage); + break; + + case 5: + success = usb_vendor_request_read_si5351c(endpoint, stage); + break; + + case 6: + success = usb_vendor_request_set_sample_rate(endpoint, stage); + break; + default: break; } diff --git a/host/libhackrf/examples/hackrf_transfer.c b/host/libhackrf/examples/hackrf_transfer.c index 7bee7b51..13defc3e 100644 --- a/host/libhackrf/examples/hackrf_transfer.c +++ b/host/libhackrf/examples/hackrf_transfer.c @@ -165,6 +165,12 @@ int main(int argc, char** argv) { signal(SIGINT, sigint_callback_handler); + result = hackrf_sample_rate_set(device, 10000000); + if( result != HACKRF_SUCCESS ) { + printf("hackrf_sample_rate_set() failed: %s (%d)\n", hackrf_error_name(result), result); + return -1; + } + if( transceiver_mode == TRANSCEIVER_MODE_RX ) { result = hackrf_start_rx(device, rx_callback); } else { diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index 61730c84..518a276c 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -34,6 +34,7 @@ typedef enum { 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; typedef enum { @@ -333,6 +334,25 @@ int hackrf_si5351c_write(hackrf_device* device, uint16_t register_number, uint16 } } +int hackrf_sample_rate_set(hackrf_device* device, const uint32_t sampling_rate_hz) { + int result = libusb_control_transfer( + device->usb_device, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + HACKRF_VENDOR_REQUEST_SAMPLE_RATE_SET, + sampling_rate_hz & 0xffff, + sampling_rate_hz >> 16, + 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; diff --git a/host/libhackrf/src/hackrf.h b/host/libhackrf/src/hackrf.h index 4bd37ac1..e8113471 100644 --- a/host/libhackrf/src/hackrf.h +++ b/host/libhackrf/src/hackrf.h @@ -53,8 +53,6 @@ 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); @@ -69,6 +67,8 @@ int hackrf_max2837_write(hackrf_device* device, uint8_t register_number, uint16_ int hackrf_si5351c_read(hackrf_device* device, uint16_t register_number, uint16_t* value); int hackrf_si5351c_write(hackrf_device* device, uint16_t register_number, uint16_t value); +int hackrf_sample_rate_set(hackrf_device* device, const uint32_t sampling_rate_hz); + const char* hackrf_error_name(enum hackrf_error errcode); #endif//__HACKRF_H__ From 549c943979dece29eea52786f0aac6f74d18fb68 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 17 Oct 2012 17:00:36 -0700 Subject: [PATCH 12/17] Add USB control of LPF baseband filter. Add max2837_set_lpf_bandwidth() function to choose available LPF filter bandwidth based on bandwidth in Hz. Change configuration of MAX2837 to set LPF_EN and FT at max2837_setup(), not in max2837_rx() or max2837_tx() (which was overriding prior filter configuration). --- firmware/common/hackrf_core.c | 5 ++ firmware/common/hackrf_core.h | 1 + firmware/common/max2837.c | 54 +++++++++++++++++++--- firmware/common/max2837.h | 4 ++ firmware/usb_performance/usb_performance.c | 20 ++++++++ host/libhackrf/examples/hackrf_transfer.c | 6 +++ host/libhackrf/src/hackrf.c | 20 ++++++++ host/libhackrf/src/hackrf.h | 1 + 8 files changed, 105 insertions(+), 6 deletions(-) diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index f32214b3..c6efb1dc 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -22,6 +22,7 @@ #include "hackrf_core.h" #include "si5351c.h" +#include "max2837.h" #include #include #include @@ -126,6 +127,10 @@ bool sample_rate_set(const uint32_t sample_rate_hz) { #endif } +bool baseband_filter_bandwidth_set(const uint32_t bandwidth_hz) { + return max2837_set_lpf_bandwidth(bandwidth_hz); +} + /* clock startup for Jellybean with Lemondrop attached */ void cpu_clock_init(void) { diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index 35e7eb30..b406ba90 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -218,6 +218,7 @@ void pin_setup(void); void enable_1v8_power(void); bool sample_rate_set(const uint32_t sampling_rate_hz); +bool baseband_filter_bandwidth_set(const uint32_t bandwidth_hz); #ifdef __cplusplus } diff --git a/firmware/common/max2837.c b/firmware/common/max2837.c index 464aa8b3..c525947d 100644 --- a/firmware/common/max2837.c +++ b/firmware/common/max2837.c @@ -115,6 +115,11 @@ void max2837_setup(void) /* maximum rx output common-mode voltage */ set_MAX2837_BUFF_VCM(MAX2837_BUFF_VCM_1_25); + /* configure baseband filter for 8 MHz TX */ + set_MAX2837_LPF_EN(1); + set_MAX2837_ModeCtrl(MAX2837_ModeCtrl_RxLPF); + set_MAX2837_FT(MAX2837_FT_5M); + max2837_regs_commit(); } @@ -192,10 +197,7 @@ void max2837_tx(void) LOG("# max2837_tx\n"); #if !defined TEST - /* configure baseband filter for 8 MHz TX */ - set_MAX2837_LPF_EN(1); set_MAX2837_ModeCtrl(MAX2837_ModeCtrl_TxLPF); - set_MAX2837_FT(MAX2837_FT_8M); max2837_regs_commit(); gpio_set(PORT_XCVR_ENABLE, PIN_XCVR_TXENABLE); @@ -206,10 +208,7 @@ void max2837_rx(void) { LOG("# max2837_rx\n"); - /* configure baseband filter for 8 MHz RX */ - set_MAX2837_LPF_EN(1); set_MAX2837_ModeCtrl(MAX2837_ModeCtrl_RxLPF); - set_MAX2837_FT(MAX2837_FT_8M); max2837_regs_commit(); #if !defined TEST @@ -290,6 +289,49 @@ void max2837_set_frequency(uint32_t freq) max2837_regs_commit(); } +typedef struct { + uint32_t bandwidth_hz; + uint32_t ft; +} max2837_ft_t; + +static const max2837_ft_t max2837_ft[] = { + { 1750000, MAX2837_FT_1_75M }, + { 2500000, MAX2837_FT_2_5M }, + { 3500000, MAX2837_FT_3_5M }, + { 5000000, MAX2837_FT_5M }, + { 5500000, MAX2837_FT_5_5M }, + { 6000000, MAX2837_FT_6M }, + { 7000000, MAX2837_FT_7M }, + { 8000000, MAX2837_FT_8M }, + { 9000000, MAX2837_FT_9M }, + { 10000000, MAX2837_FT_10M }, + { 12000000, MAX2837_FT_12M }, + { 14000000, MAX2837_FT_14M }, + { 15000000, MAX2837_FT_15M }, + { 20000000, MAX2837_FT_20M }, + { 24000000, MAX2837_FT_24M }, + { 28000000, MAX2837_FT_28M }, + { 0, 0 }, +}; + +bool max2837_set_lpf_bandwidth(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++; + } + + if( p->bandwidth_hz != 0 ) { + set_MAX2837_FT(p->ft); + max2837_regs_commit(); + return true; + } else { + return false; + } +} + #ifdef TEST int main(int ac, char **av) { diff --git a/firmware/common/max2837.h b/firmware/common/max2837.h index 50cf38d7..4983ca7e 100644 --- a/firmware/common/max2837.h +++ b/firmware/common/max2837.h @@ -1,6 +1,9 @@ #ifndef __MAX2837_H #define __MAX2837_H +#include +#include + /* TODO - make this a private header for max2837.c only, make new max2837.h */ /* 32 registers, each containing 10 bits of data. */ @@ -40,6 +43,7 @@ extern void max2837_stop(void); /* Set frequency in Hz. Frequency setting is a multi-step function * where order of register writes matters. */ extern void max2837_set_frequency(uint32_t freq); +bool max2837_set_lpf_bandwidth(const uint32_t bandwidth_hz); extern void max2837_tx(void); extern void max2837_rx(void); diff --git a/firmware/usb_performance/usb_performance.c b/firmware/usb_performance/usb_performance.c index 0e462ed7..a7ecac7f 100644 --- a/firmware/usb_performance/usb_performance.c +++ b/firmware/usb_performance/usb_performance.c @@ -309,6 +309,22 @@ bool usb_vendor_request_set_sample_rate( } } +bool usb_vendor_request_set_baseband_filter_bandwidth( + usb_endpoint_t* const endpoint, + const usb_transfer_stage_t stage +) { + if( stage == USB_TRANSFER_STAGE_SETUP ) { + const uint32_t bandwidth = (endpoint->setup.index << 16) | endpoint->setup.value; + if( baseband_filter_bandwidth_set(bandwidth) ) { + usb_endpoint_schedule_ack(endpoint->in); + return true; + } + return false; + } else { + return true; + } +} + void usb_vendor_request( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage @@ -340,6 +356,10 @@ void usb_vendor_request( success = usb_vendor_request_set_sample_rate(endpoint, stage); break; + case 7: + success = usb_vendor_request_set_baseband_filter_bandwidth(endpoint, stage); + break; + default: break; } diff --git a/host/libhackrf/examples/hackrf_transfer.c b/host/libhackrf/examples/hackrf_transfer.c index 13defc3e..b6e80b7c 100644 --- a/host/libhackrf/examples/hackrf_transfer.c +++ b/host/libhackrf/examples/hackrf_transfer.c @@ -171,6 +171,12 @@ int main(int argc, char** argv) { return -1; } + result = hackrf_baseband_filter_bandwidth_set(device, 5000000); + if( result != HACKRF_SUCCESS ) { + printf("hackrf_baseband_filter_bandwidth_set() failed: %s (%d)\n", hackrf_error_name(result), result); + return -1; + } + if( transceiver_mode == TRANSCEIVER_MODE_RX ) { result = hackrf_start_rx(device, rx_callback); } else { diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index 518a276c..a3efcf82 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -35,6 +35,7 @@ typedef enum { 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; typedef enum { @@ -353,6 +354,25 @@ int hackrf_sample_rate_set(hackrf_device* device, const uint32_t sampling_rate_h } } +int hackrf_baseband_filter_bandwidth_set(hackrf_device* device, const uint32_t bandwidth_hz) { + int 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 ) { + return HACKRF_ERROR_LIBUSB; + } else { + return HACKRF_SUCCESS; + } +} + static void* transfer_threadproc(void* arg) { hackrf_device* device = (hackrf_device*)arg; diff --git a/host/libhackrf/src/hackrf.h b/host/libhackrf/src/hackrf.h index e8113471..8c288ebd 100644 --- a/host/libhackrf/src/hackrf.h +++ b/host/libhackrf/src/hackrf.h @@ -68,6 +68,7 @@ int hackrf_si5351c_read(hackrf_device* device, uint16_t register_number, uint16_ int hackrf_si5351c_write(hackrf_device* device, uint16_t register_number, uint16_t value); int hackrf_sample_rate_set(hackrf_device* device, const uint32_t sampling_rate_hz); +int hackrf_baseband_filter_bandwidth_set(hackrf_device* device, const uint32_t bandwidth_hz); const char* hackrf_error_name(enum hackrf_error errcode); From 93c11753627c602f6e0289e5b836906bc24c7238 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 17 Oct 2012 17:01:56 -0700 Subject: [PATCH 13/17] Add a quick, dirty, and marginally-useful text configuration option to hackrf_si5351c example. --- host/libhackrf/examples/hackrf_si5351c.c | 58 +++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/host/libhackrf/examples/hackrf_si5351c.c b/host/libhackrf/examples/hackrf_si5351c.c index dc9214cf..3b723f4c 100644 --- a/host/libhackrf/examples/hackrf_si5351c.c +++ b/host/libhackrf/examples/hackrf_si5351c.c @@ -27,6 +27,7 @@ static void usage() { printf("\nUsage:\n"); + printf("\t-c, --config: print textual configuration information\n"); printf("\t-n, --register : 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 : write register specified by last -n argument with value \n"); @@ -37,6 +38,7 @@ static void usage() { } static struct option long_options[] = { + { "config", no_argument, 0, 'c' }, { "register", required_argument, 0, 'n' }, { "write", required_argument, 0, 'w' }, { "read", no_argument, 0, 'r' }, @@ -99,6 +101,56 @@ int write_register( #define REGISTER_INVALID 32767 +int dump_multisynth_config(hackrf_device* device, const uint_fast8_t ms_number) { + uint16_t parameters[8]; + uint_fast8_t reg_base = 42 + (ms_number * 8); + for(uint_fast8_t i=0; i<8; i++) { + uint_fast8_t reg_number = reg_base + i; + int result = hackrf_si5351c_read(device, reg_number, ¶meters[i]); + if( result != HACKRF_SUCCESS ) { + return result; + } + } + + const uint32_t p1 = + (parameters[2] & 0x03 << 16) + | (parameters[3] << 8) + | parameters[4] + ; + const uint32_t p2 = + (parameters[5] & 0x0F << 16) + | (parameters[6] << 8) + | parameters[7] + ; + const uint32_t p3 = + (parameters[5] & 0xF0 << 12) + | (parameters[0] << 8) + | parameters[1] + ; + const uint32_t r_div = + (parameters[2] >> 4) & 0x7 + ; + + printf("MS%d:", ms_number); + printf("\tp1 = %u\n", p1); + printf("\tp2 = %u\n", p2); + printf("\tp3 = %u\n", p3); + printf("\toutput divider = %u\n", 1 << r_div); + + return HACKRF_SUCCESS; +} + +int dump_configuration(hackrf_device* device) { + for(uint_fast8_t ms_number=0; ms_number<8; ms_number++) { + int result = dump_multisynth_config(device, ms_number); + if( result != HACKRF_SUCCESS ) { + return result; + } + } + + return HACKRF_SUCCESS; +} + int main(int argc, char** argv) { int opt; uint16_t register_number = REGISTER_INVALID; @@ -118,7 +170,7 @@ int main(int argc, char** argv) { } int option_index = 0; - while( (opt = getopt_long(argc, argv, "n:rw:", long_options, &option_index)) != EOF ) { + while( (opt = getopt_long(argc, argv, "cn:rw:", long_options, &option_index)) != EOF ) { switch( opt ) { case 'n': result = parse_int(optarg, ®ister_number); @@ -139,6 +191,10 @@ int main(int argc, char** argv) { } break; + case 'c': + dump_configuration(device); + break; + default: usage(); } From 2a5852878215be4608d7a097d885d7af0bbf64a0 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 17 Oct 2012 17:02:44 -0700 Subject: [PATCH 14/17] Made explicit a few libhackrf result tests -- comparing against HACKRF_SUCCESS instead of checking for non-zero. --- host/libhackrf/examples/hackrf_transfer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/host/libhackrf/examples/hackrf_transfer.c b/host/libhackrf/examples/hackrf_transfer.c index b6e80b7c..089fe823 100644 --- a/host/libhackrf/examples/hackrf_transfer.c +++ b/host/libhackrf/examples/hackrf_transfer.c @@ -140,13 +140,13 @@ int main(int argc, char** argv) { } int result = hackrf_init(); - if( result ) { + if( result != HACKRF_SUCCESS ) { printf("hackrf_init() failed: %s (%d)\n", hackrf_error_name(result), result); return -1; } result = hackrf_open(&device); - if( result ) { + if( result != HACKRF_SUCCESS ) { printf("hackrf_open() failed: %s (%d)\n", hackrf_error_name(result), result); return -1; } @@ -182,7 +182,7 @@ int main(int argc, char** argv) { } else { result = hackrf_start_tx(device, tx_callback); } - if( result ) { + if( result != HACKRF_SUCCESS ) { printf("hackrf_start_?x() failed: %s (%d)\n", hackrf_error_name(result), result); return -1; } @@ -211,7 +211,7 @@ int main(int argc, char** argv) { } result = hackrf_close(device); - if( result ) { + if( result != HACKRF_SUCCESS ) { printf("hackrf_close() failed: %s (%d)\n", hackrf_error_name(result), result); return -1; } From 2d79f6d69fa36adee768c246b1209bd3102e6896 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 17 Oct 2012 20:55:48 -0700 Subject: [PATCH 15/17] Added support for hackrf_max2837 utility to accept registers and values as "0x" (base-16) or "0b" (base-2). --- host/libhackrf/examples/hackrf_max2837.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/host/libhackrf/examples/hackrf_max2837.c b/host/libhackrf/examples/hackrf_max2837.c index f4fbdf2e..cac878ff 100644 --- a/host/libhackrf/examples/hackrf_max2837.c +++ b/host/libhackrf/examples/hackrf_max2837.c @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -43,9 +44,22 @@ static struct option long_options[] = { { 0, 0, 0, 0 }, }; -int parse_int(char* const s, uint16_t* const value) { +int parse_int(char* s, uint16_t* const value) { + uint_fast8_t base = 10; + if( strlen(s) > 2 ) { + if( s[0] == '0' ) { + if( (s[1] == 'x') || (s[1] == 'X') ) { + base = 16; + s += 2; + } else if( (s[1] == 'b') || (s[1] == 'B') ) { + base = 2; + s += 2; + } + } + } + char* s_end = s; - const long long_value = strtol(s, &s_end, 10); + const long long_value = strtol(s, &s_end, base); if( (s != s_end) && (*s_end == 0) ) { *value = long_value; return HACKRF_SUCCESS; From 143d845b0545cf2e37258999d263df05f68425d1 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 17 Oct 2012 21:48:41 -0700 Subject: [PATCH 16/17] Add code to control RXHP pin on MAX2837 (Jellybean only). I was hoping this would control the baseband DC offset problem, but no, it doesn't seem to help at all. --- firmware/common/hackrf_core.h | 7 +++++++ firmware/common/max2837.c | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index b406ba90..41a6ff71 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -97,6 +97,9 @@ extern "C" #define SCU_PINMUX_SGPIO15 (P4_10) /* MAX2837 GPIO (XCVR_CTL) PinMux */ +#ifdef JELLYBEAN +#define SCU_XCVR_RXHP (P4_0) /* GPIO2[0] on P4_0 */ +#endif #define SCU_XCVR_ENABLE (P4_6) /* GPIO2[6] on P4_6 */ #define SCU_XCVR_RXENABLE (P4_5) /* GPIO2[5] on P4_5 */ #define SCU_XCVR_TXENABLE (P4_4) /* GPIO2[4] on P4_4 */ @@ -145,6 +148,10 @@ extern "C" #define PIN_XCVR_RXENABLE (BIT5) /* GPIO2[5] on P4_5 */ #define PIN_XCVR_TXENABLE (BIT4) /* GPIO2[4] on P4_4 */ #define PORT_XCVR_ENABLE (GPIO2) /* PORT for ENABLE, TXENABLE, RXENABLE */ +#ifdef JELLYBEAN +#define PIN_XCVR_RXHP (BIT0) /* GPIO2[0] on P4_0 */ +#define PORT_XCVR_RXHP (GPIO2) +#endif #define PIN_AD_CS (BIT7) /* GPIO2[7] on P5_7 */ #define PORT_AD_CS (GPIO2) /* PORT for AD_CS */ diff --git a/firmware/common/max2837.c b/firmware/common/max2837.c index c525947d..ae4a313d 100644 --- a/firmware/common/max2837.c +++ b/firmware/common/max2837.c @@ -87,16 +87,25 @@ void max2837_setup(void) LOG("# max2837_setup\n"); #if !defined TEST /* Configure XCVR_CTL GPIO pins. */ +#ifdef JELLYBEAN + scu_pinmux(SCU_XCVR_RXHP, SCU_GPIO_FAST); +#endif scu_pinmux(SCU_XCVR_ENABLE, SCU_GPIO_FAST); scu_pinmux(SCU_XCVR_RXENABLE, SCU_GPIO_FAST); scu_pinmux(SCU_XCVR_TXENABLE, SCU_GPIO_FAST); /* Set GPIO pins as outputs. */ GPIO2_DIR |= (PIN_XCVR_ENABLE | PIN_XCVR_RXENABLE | PIN_XCVR_TXENABLE); +#ifdef JELLYBEAN + GPIO2_DIR |= PIN_XCVR_RXHP; +#endif /* disable everything */ gpio_clear(PORT_XCVR_ENABLE, (PIN_XCVR_ENABLE | PIN_XCVR_RXENABLE | PIN_XCVR_TXENABLE)); +#ifdef JELLYBEAN + gpio_set(PORT_XCVR_RXHP, PIN_XCVR_RXHP); +#endif #endif max2837_init(); From fc9632f19d67b1566d9b446a522ea8743fb30542 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 17 Oct 2012 22:28:10 -0700 Subject: [PATCH 17/17] Add code to control MAX2837 B1 through B7 from Jellybean. Another feeble attempt to control DC bias. --- firmware/common/hackrf_core.h | 15 +++++++++++++++ firmware/common/max2837.c | 27 ++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index 41a6ff71..ad84648e 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -99,6 +99,13 @@ extern "C" /* MAX2837 GPIO (XCVR_CTL) PinMux */ #ifdef JELLYBEAN #define SCU_XCVR_RXHP (P4_0) /* GPIO2[0] on P4_0 */ +#define SCU_XCVR_B1 (P5_0) /* GPIO2[9] on P5_0 */ +#define SCU_XCVR_B2 (P5_1) /* GPIO2[10] on P5_1 */ +#define SCU_XCVR_B3 (P5_2) /* GPIO2[11] on P5_2 */ +#define SCU_XCVR_B4 (P5_3) /* GPIO2[12] on P5_3 */ +#define SCU_XCVR_B5 (P5_4) /* GPIO2[13] on P5_4 */ +#define SCU_XCVR_B6 (P5_5) /* GPIO2[14] on P5_5 */ +#define SCU_XCVR_B7 (P5_6) /* GPIO2[15] on P5_6 */ #endif #define SCU_XCVR_ENABLE (P4_6) /* GPIO2[6] on P4_6 */ #define SCU_XCVR_RXENABLE (P4_5) /* GPIO2[5] on P4_5 */ @@ -151,6 +158,14 @@ extern "C" #ifdef JELLYBEAN #define PIN_XCVR_RXHP (BIT0) /* GPIO2[0] on P4_0 */ #define PORT_XCVR_RXHP (GPIO2) +#define PIN_XCVR_B1 (BIT9) /* GPIO2[9] on P5_0 */ +#define PIN_XCVR_B2 (BIT10) /* GPIO2[10] on P5_1 */ +#define PIN_XCVR_B3 (BIT11) /* GPIO2[11] on P5_2 */ +#define PIN_XCVR_B4 (BIT12) /* GPIO2[12] on P5_3 */ +#define PIN_XCVR_B5 (BIT13) /* GPIO2[13] on P5_4 */ +#define PIN_XCVR_B6 (BIT14) /* GPIO2[14] on P5_5 */ +#define PIN_XCVR_B7 (BIT15) /* GPIO2[15] on P5_6 */ +#define PORT_XCVR_B (GPIO2) #endif #define PIN_AD_CS (BIT7) /* GPIO2[7] on P5_7 */ diff --git a/firmware/common/max2837.c b/firmware/common/max2837.c index ae4a313d..725e04e6 100644 --- a/firmware/common/max2837.c +++ b/firmware/common/max2837.c @@ -89,6 +89,13 @@ void max2837_setup(void) /* Configure XCVR_CTL GPIO pins. */ #ifdef JELLYBEAN scu_pinmux(SCU_XCVR_RXHP, SCU_GPIO_FAST); + scu_pinmux(SCU_XCVR_B1, SCU_GPIO_FAST); + scu_pinmux(SCU_XCVR_B2, SCU_GPIO_FAST); + scu_pinmux(SCU_XCVR_B3, SCU_GPIO_FAST); + scu_pinmux(SCU_XCVR_B4, SCU_GPIO_FAST); + scu_pinmux(SCU_XCVR_B5, SCU_GPIO_FAST); + scu_pinmux(SCU_XCVR_B6, SCU_GPIO_FAST); + scu_pinmux(SCU_XCVR_B7, SCU_GPIO_FAST); #endif scu_pinmux(SCU_XCVR_ENABLE, SCU_GPIO_FAST); scu_pinmux(SCU_XCVR_RXENABLE, SCU_GPIO_FAST); @@ -97,7 +104,16 @@ void max2837_setup(void) /* Set GPIO pins as outputs. */ GPIO2_DIR |= (PIN_XCVR_ENABLE | PIN_XCVR_RXENABLE | PIN_XCVR_TXENABLE); #ifdef JELLYBEAN - GPIO2_DIR |= PIN_XCVR_RXHP; + GPIO_DIR(PORT_XCVR_RXHP) |= PIN_XCVR_RXHP; + GPIO_DIR(PORT_XCVR_B) |= + PIN_XCVR_B1 + | PIN_XCVR_B2 + | PIN_XCVR_B3 + | PIN_XCVR_B4 + | PIN_XCVR_B5 + | PIN_XCVR_B6 + | PIN_XCVR_B7 + ; #endif /* disable everything */ @@ -105,6 +121,15 @@ void max2837_setup(void) (PIN_XCVR_ENABLE | PIN_XCVR_RXENABLE | PIN_XCVR_TXENABLE)); #ifdef JELLYBEAN gpio_set(PORT_XCVR_RXHP, PIN_XCVR_RXHP); + gpio_set(PORT_XCVR_B, + PIN_XCVR_B1 + | PIN_XCVR_B2 + | PIN_XCVR_B3 + | PIN_XCVR_B4 + | PIN_XCVR_B5 + | PIN_XCVR_B6 + | PIN_XCVR_B7 + ); #endif #endif