diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index 1c05e221..d1e4d71d 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -498,8 +498,6 @@ void cpu_clock_init(void) si5351c_set_clock_source(&clock_gen, PLL_SOURCE_XTAL); // soft reset - // uint8_t resetdata[] = { 177, 0xac }; - // si5351c_write(&clock_gen, resetdata, sizeof(resetdata)); si5351c_reset_pll(&clock_gen); si5351c_enable_clock_outputs(&clock_gen); diff --git a/firmware/common/si5351c.c b/firmware/common/si5351c.c index 3bdefcda..a217d6d5 100644 --- a/firmware/common/si5351c.c +++ b/firmware/common/si5351c.c @@ -197,12 +197,27 @@ void si5351c_configure_clock_control(si5351c_driver_t* const drv, const enum pll si5351c_write(drv, data, sizeof(data)); } +#define SI5351C_CLK_ENABLE(x) (0<setup.value); + usb_transfer_schedule_ack(endpoint->in); + } + return USB_REQUEST_STATUS_OK; +} diff --git a/firmware/hackrf_usb/usb_api_register.h b/firmware/hackrf_usb/usb_api_register.h index 06eb8df7..9fef6eed 100644 --- a/firmware/hackrf_usb/usb_api_register.h +++ b/firmware/hackrf_usb/usb_api_register.h @@ -50,5 +50,9 @@ usb_request_status_t usb_vendor_request_read_rffc5071( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage ); +usb_request_status_t usb_vendor_request_set_clkout_enable( + usb_endpoint_t* const endpoint, + const usb_transfer_stage_t stage +); #endif /* end of include guard: __USB_API_REGISTER_H__ */ diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 34136f09..03e31ee7 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -3,6 +3,8 @@ cmake_minimum_required(VERSION 2.8) project (HackRF) +set(CMAKE_C_FLAGS "$ENV{CFLAGS}" CACHE STRING "C Flags") + add_subdirectory(libhackrf) add_subdirectory(hackrf-tools) diff --git a/host/hackrf-tools/src/CMakeLists.txt b/host/hackrf-tools/src/CMakeLists.txt index ea396455..40f11dc0 100644 --- a/host/hackrf-tools/src/CMakeLists.txt +++ b/host/hackrf-tools/src/CMakeLists.txt @@ -31,6 +31,7 @@ SET(TOOLS hackrf_cpldjtag hackrf_info hackrf_debug + hackrf_clock hackrf_sweep hackrf_operacake ) diff --git a/host/hackrf-tools/src/hackrf_clock.c b/host/hackrf-tools/src/hackrf_clock.c new file mode 100644 index 00000000..bd3344dd --- /dev/null +++ b/host/hackrf-tools/src/hackrf_clock.c @@ -0,0 +1,337 @@ +/* + * Copyright 2017 Dominic Spill + * + * 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 + +#ifndef bool +typedef int bool; +#define true 1 +#define false 0 +#endif + +#define CLOCK_UNDEFINED 0xFF +#define REGISTER_INVALID 32767 + +int parse_int(char* s, uint16_t* const value) { + uint_fast8_t base = 10; + char* s_end; + long long_value; + + 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; + } + } + } + + s_end = s; + long_value = strtol(s, &s_end, base); + if( (s != s_end) && (*s_end == 0) ) { + *value = (uint16_t)long_value; + return HACKRF_SUCCESS; + } else { + return HACKRF_ERROR_INVALID_PARAM; + } +} + +int si5351c_read_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_si5351c_read() failed: %s (%d)\n", hackrf_error_name(result), result); + } + + return result; +} + +int si5351c_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 SI5351C_CLK_POWERDOWN (1<<7) +#define SI5351C_CLK_INT_MODE (1<<6) +#define SI5351C_CLK_PLL_SRC (1<<5) +#define SI5351C_CLK_INV (1<<4) +#define SI5351C_CLK_SRC_XTAL 0 +#define SI5351C_CLK_SRC_CLKIN 1 +#define SI5351C_CLK_SRC_MULTISYNTH_0_4 2 +#define SI5351C_CLK_SRC_MULTISYNTH_SELF 3 + +void print_clk_control(uint8_t clk_ctrl) { + uint8_t clk_src, clk_pwr; + printf("\tclock control = "); + if(clk_ctrl & SI5351C_CLK_POWERDOWN) + printf("Down, "); + else + printf("Up, "); + if(clk_ctrl & SI5351C_CLK_INT_MODE) + printf("Int Mode, "); + else + printf("Frac Mode, "); + if(clk_ctrl & SI5351C_CLK_PLL_SRC) + printf("PLL src B, "); + else + printf("PLL src A, "); + if(clk_ctrl & SI5351C_CLK_INV) + printf("Inverted, "); + clk_src = (clk_ctrl >> 2) & 0x3; + switch (clk_src) { + case 0: + printf("XTAL, "); + break; + case 1: + printf("CLKIN, "); + break; + case 2: + printf("MULTISYNTH 0 4, "); + break; + case 3: + printf("MULTISYNTH SELF, "); + break; + } + clk_pwr = clk_ctrl & 0x3; + switch (clk_pwr) { + case 0: + printf("2 mA\n"); + break; + case 1: + printf("4 mA\n"); + break; + case 2: + printf("6 mA\n"); + break; + case 3: + printf("8 mA\n"); + break; + } +} + +int si5351c_read_multisynth_config(hackrf_device* device, const uint_fast8_t ms_number) { + uint_fast8_t i, reg_base, reg_number; + uint16_t parameters[8], clk_control; + uint32_t p1,p2,p3,r_div; + uint_fast8_t div_lut[] = {1,2,4,8,16,32,64,128}; + int result; + + printf("MS%d:\n", ms_number); + result = hackrf_si5351c_read(device, 16+ms_number, &clk_control); + if( result != HACKRF_SUCCESS ) { + return result; + } + print_clk_control(clk_control); + if(ms_number <6){ + reg_base = 42 + (ms_number * 8); + for(i=0; i<8; i++) { + reg_number = reg_base + i; + result = hackrf_si5351c_read(device, reg_number, ¶meters[i]); + if( result != HACKRF_SUCCESS ) { + return result; + } + } + + p1 = ((parameters[2] & 0x03) << 16) + | (parameters[3] << 8) + | parameters[4]; + p2 = ((parameters[5] & 0x0F) << 16) + | (parameters[6] << 8) + | parameters[7]; + p3 = ((parameters[5] & 0xF0) << 12) + | (parameters[0] << 8) + | parameters[1]; + r_div = (parameters[2] >> 4) & 0x7; + + printf("\tp1 = %u\n", p1); + printf("\tp2 = %u\n", p2); + printf("\tp3 = %u\n", p3); + if(p3) + printf("\tOutput (800Mhz PLL): %#.10f Mhz\n", ((double)800 / (double)(((double)p1*p3 + p2 + 512*p3)/(double)(128*p3))) / div_lut[r_div] ); + } else { + // MS6 and 7 are integer only + unsigned int parms; + reg_base = 90; + + for(i=0; i<3; 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; + } + } + r_div = (ms_number == 6) ? parameters[2] & 0x7 : (parameters[2] & 0x70) >> 4 ; + parms = (ms_number == 6) ? parameters[0] : parameters[1]; + printf("\tp1_int = %u\n", parms); + if(parms) + printf("\tOutput (800Mhz PLL): %#.10f Mhz\n", (800.0f / parms) / div_lut[r_div] ); + } + printf("\toutput divider = %u\n", div_lut[r_div]); + return HACKRF_SUCCESS; +} + +int si5351c_read_configuration(hackrf_device* device) { + uint_fast8_t ms_number; + int result; + + for(ms_number=0; ms_number<8; ms_number++) { + result = si5351c_read_multisynth_config(device, ms_number); + if( result != HACKRF_SUCCESS ) { + return result; + } + } + return HACKRF_SUCCESS; +} + +static void usage() { + printf("hackrf_clock - HackRF clock configuration utility\n"); + printf("Usage:\n"); + printf("\t-h, --help: this help\n"); + printf("\t-r, --read : read settings for clock_num\n"); + printf("\t-a, --all: read settings for all clocks\n"); + printf("\t-o, --clkout : enable/disable CLKOUT\n"); + printf("\t-d, --device : Serial number of desired HackRF.\n"); + printf("\nExamples:\n"); + printf("\thackrf_clock -r 3 : prints settings for CLKOUT\n"); +} + +static struct option long_options[] = { + { "help", no_argument, 0, 'h' }, + { "read", required_argument, 0, 'r' }, + { "all", no_argument, 0, 'a' }, + { "clkout", required_argument, 0, 'o' }, + { "device", required_argument, 0, 'd' }, + { 0, 0, 0, 0 }, +}; + +int main(int argc, char** argv) { + hackrf_device* device = NULL; + int opt, option_index = 0; + bool read = false; + uint16_t clock = CLOCK_UNDEFINED; + bool clkout = false; + uint16_t clkout_enable; + const char* serial_number = NULL; + + int result = hackrf_init(); + if(result) { + printf("hackrf_init() failed: %s (%d)\n", hackrf_error_name(result), result); + return EXIT_FAILURE; + } + + while( (opt = getopt_long(argc, argv, "r:ao:d:h?", long_options, &option_index)) != EOF ) { + switch( opt ) { + case 'r': + read = true; + result = parse_int(optarg, &clock); + break; + + case 'a': + read = true; + break; + + case 'o': + clkout = true; + result = parse_int(optarg, &clkout_enable); + break; + + case 'd': + serial_number = optarg; + break; + + case 'h': + case '?': + usage(); + return EXIT_SUCCESS; + default: + fprintf(stderr, "unknown argument '-%c %s'\n", opt, optarg); + usage(); + return EXIT_FAILURE; + } + + if(result != HACKRF_SUCCESS) { + printf("argument error: %s (%d)\n", hackrf_error_name(result), result); + usage(); + return EXIT_FAILURE; + } + } + + if(!clkout && !read) { + fprintf(stderr, "Either read or enable CLKOUT option must be specified.\n"); + usage(); + return EXIT_FAILURE; + } + + result = hackrf_open_by_serial(serial_number, &device); + if(result) { + printf("hackrf_open() failed: %s (%d)\n", hackrf_error_name(result), result); + return EXIT_FAILURE; + } + + if(clkout) { + result = hackrf_set_clkout_enable(device, clkout_enable); + if(result) { + printf("hackrf_set_clkout_enable() failed: %s (%d)\n", hackrf_error_name(result), result); + return EXIT_FAILURE; + } + } + + if(read) { + if(clock == CLOCK_UNDEFINED) + si5351c_read_configuration(device); + else { + printf("%d\n", clock); + si5351c_read_multisynth_config(device, clock); + } + } + + result = hackrf_close(device); + if(result) { + printf("hackrf_close() failed: %s (%d)\n", hackrf_error_name(result), result); + return EXIT_FAILURE; + } + + hackrf_exit(); + return EXIT_SUCCESS; +} diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index 4fb28406..e0a9f527 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -79,6 +79,7 @@ typedef enum { HACKRF_VENDOR_REQUEST_SET_HW_SYNC_MODE = 29, HACKRF_VENDOR_REQUEST_RESET = 30, HACKRF_VENDOR_REQUEST_OPERACAKE_SET_RANGES = 31, + HACKRF_VENDOR_REQUEST_CLKOUT_ENABLE = 32, } hackrf_vendor_request; #define USB_CONFIG_STANDARD 0x1 @@ -1991,6 +1992,31 @@ int ADDCALL hackrf_set_operacake_ranges(hackrf_device* device, uint8_t* ranges, return HACKRF_SUCCESS; } } + +int ADDCALL hackrf_set_clkout_enable(hackrf_device* device, const uint8_t value) +{ + USB_API_REQUIRED(device, 0x0103) + int result; + result = libusb_control_transfer( + device->usb_device, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + HACKRF_VENDOR_REQUEST_CLKOUT_ENABLE, + value, + 0, + NULL, + 0, + 0 + ); + + if (result != 0) + { + last_libusb_error = result; + return HACKRF_ERROR_LIBUSB; + } else { + return HACKRF_SUCCESS; + } +} + #ifdef __cplusplus } // __cplusplus defined. #endif diff --git a/host/libhackrf/src/hackrf.h b/host/libhackrf/src/hackrf.h index c2b28206..2e335c01 100644 --- a/host/libhackrf/src/hackrf.h +++ b/host/libhackrf/src/hackrf.h @@ -246,6 +246,8 @@ extern ADDAPI int ADDCALL hackrf_set_operacake_ranges(hackrf_device* device, uint8_t* ranges, uint8_t num_ranges); +extern ADDAPI int ADDCALL hackrf_set_clkout_enable(hackrf_device* device, const uint8_t value); + #ifdef __cplusplus } // __cplusplus defined. #endif