From 6babcbe579d1151cdca545c4a59d1fb46ac77d1d Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 17 Oct 2012 11:57:44 -0700 Subject: [PATCH] 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__