diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index 700e19f5..d1be02e7 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -39,6 +39,69 @@ void delay(uint32_t duration) __asm__("nop"); } +bool set_fracrate(const float freq) { + + uint32_t MSx_P1,MSx_P2,MSx_P3; + uint32_t b,c; + float div = (800/freq); + uint32_t a = (uint32_t)div; + float x = div-a; + + if(a != div){ + uint32_t j=0,k=1,l=1,m=1; + while (k <= 0xFFFF && m <= 0xFFFF){ + float n = (float)(j+l)/(k+m); + if( x == n){ + if(k + m <= 0xFFFF){ + b=j+l; c=k+m; + break; + } else if(m > k){ + b=l; c=m; + break; + } else { + b=j; c=k; + break; + } + } + else if(x > n){ + j+=l; k+=m; + } + else{ + l+=j; m+=k; + } + } + if (k > 0xFFFF){ + b=l; c=m; + } + else{ + b=j; c=k; + } + } else { + b=0; c=1; + } + + MSx_P1 = 128*a + (128 * b/c) - 512; + MSx_P2 = (128*b)%c; + MSx_P3 = c; + + + /* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ + si5351c_configure_multisynth(0, MSx_P1, MSx_P2, MSx_P3, 1); + + /* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */ + si5351c_configure_multisynth(1, 0, 0, 0, 0);//p1 doesn't matter + + /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ + si5351c_configure_multisynth(2, 0, 0, 0, 0);//p1 doesn't matter + + /* MS0/CLK3 is the source for the external clock output. */ + //si5351c_configure_multisynth(3, p1, 0, 1, 0); // no clk out + + return true; + +} + + bool sample_rate_set(const uint32_t sample_rate_hz) { #ifdef JELLYBEAN /* Due to design issues, Jellybean/Lemondrop frequency plan is limited. diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index 462f8b1d..d32f27e4 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -259,6 +259,7 @@ void pin_setup(void); void enable_1v8_power(void); +bool set_fracrate(const float sampling_rate_mhz); bool sample_rate_set(const uint32_t sampling_rate_hz); bool baseband_filter_bandwidth_set(const uint32_t bandwidth_hz); diff --git a/firmware/common/si5351c.c b/firmware/common/si5351c.c index 59b478b3..6cc0d253 100644 --- a/firmware/common/si5351c.c +++ b/firmware/common/si5351c.c @@ -230,20 +230,20 @@ void si5351c_configure_clock_control() void si5351c_configure_clock_control() { uint8_t data[] = {16 - ,SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(SI5351C_CLK_PLL_SRC_A) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_8MA) + ,SI5351C_CLK_FRAC_MODE | SI5351C_CLK_PLL_SRC(SI5351C_CLK_PLL_SRC_A) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_8MA) ,SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(SI5351C_CLK_PLL_SRC_A) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_0_4) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_8MA) ,SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(SI5351C_CLK_PLL_SRC_A) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_0_4) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_8MA) ,SI5351C_CLK_POWERDOWN /*not connected, clock out*/ ,SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(SI5351C_CLK_PLL_SRC_A) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_8MA) ,SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(SI5351C_CLK_PLL_SRC_A) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_8MA) ,SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE /*not connected, but: plla int mode*/ - ,SI5351C_CLK_POWERDOWN/* pllb int mode*/| SI5351C_CLK_PLL_SRC(SI5351C_CLK_PLL_SRC_A) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_8MA) + ,SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE /* pllb int mode*/| SI5351C_CLK_PLL_SRC(SI5351C_CLK_PLL_SRC_B) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_8MA) }; si5351c_write(data, sizeof(data)); } #endif -/* Enable CLK outputs 0, 1, 2, 4, 5, 7 only. */ +/* Enable CLK outputs 0, 1, 2, 4, 5, ~7 only. */ void si5351c_enable_clock_outputs() { uint8_t data[] = { 3, 0xC8 }; diff --git a/firmware/common/si5351c.h b/firmware/common/si5351c.h index ac57a8f9..12f1dc3a 100644 --- a/firmware/common/si5351c.h +++ b/firmware/common/si5351c.h @@ -35,6 +35,7 @@ extern "C" #define SI5351C_CLK_POWERDOWN (1<<7) #define SI5351C_CLK_INT_MODE (1<<6) +#define SI5351C_CLK_FRAC_MODE (0<<6) #define SI5351C_CLK_PLL_SRC(x) (x<<5) #define SI5351C_CLK_PLL_SRC_A 0 diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index 83059efa..e42fbb9e 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -67,6 +67,12 @@ typedef struct { set_freq_params_t set_freq_params; +typedef struct { + float freq_mhz; +} set_sample_r_params_t; + +set_sample_r_params_t set_sample_r_params; + uint8_t switchctrl = 0; void update_switches(void) @@ -696,6 +702,28 @@ usb_request_status_t usb_vendor_request_set_freq( } } +usb_request_status_t usb_vendor_request_set_fracrate( + usb_endpoint_t* const endpoint, + const usb_transfer_stage_t stage) +{ + if (stage == USB_TRANSFER_STAGE_SETUP) + { + usb_endpoint_schedule(endpoint->out, &set_sample_r_params, sizeof(set_sample_r_params_t)); + return USB_REQUEST_STATUS_OK; + } else if (stage == USB_TRANSFER_STAGE_DATA) + { + if( set_fracrate(set_sample_r_params.freq_mhz*2) ) + { + usb_endpoint_schedule_ack(endpoint->in); + return USB_REQUEST_STATUS_OK; + } + return USB_REQUEST_STATUS_STALL; + } else + { + return USB_REQUEST_STATUS_OK; + } +} + usb_request_status_t usb_vendor_request_set_amp_enable( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) { @@ -821,7 +849,8 @@ static const usb_request_handler_fn vendor_request_handler[] = { usb_vendor_request_read_partid_serialno, usb_vendor_request_set_lna_gain, usb_vendor_request_set_vga_gain, - usb_vendor_request_set_txvga_gain + usb_vendor_request_set_txvga_gain, + usb_vendor_request_set_fracrate }; static const uint32_t vendor_request_handler_count = diff --git a/host/libhackrf/CMakeLists.txt b/host/libhackrf/CMakeLists.txt index 649d861c..9e376720 100644 --- a/host/libhackrf/CMakeLists.txt +++ b/host/libhackrf/CMakeLists.txt @@ -31,10 +31,16 @@ set(VERSION ${VERSION_STRING}) set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../cmake/modules) if(MSVC) -set(THREADS_USE_PTHREADS_WIN32 true) + set(THREADS_USE_PTHREADS_WIN32 true) else() -add_definitions(-Wall) -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu90") + add_definitions(-Wall) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu90") + + INCLUDE(TestBigEndian) + TEST_BIG_ENDIAN(BIGENDIAN) + if(${BIGENDIAN}) + add_definitions(-DBIG_ENDIAN) + endif(${BIGENDIAN}) endif() find_package(USB1 REQUIRED) find_package(Threads REQUIRED) diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index 67c2d97b..e31fb714 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -33,6 +33,13 @@ typedef int bool; #define true 1 #define false 0 #endif + +#ifdef BIG_ENDIAN +#define TO_LE(x) __builtin_bswap32(x) +#else +#define TO_LE(x) x +#endif + // TODO: Factor this into a shared #include so that firmware can use // the same values. typedef enum { @@ -57,6 +64,7 @@ typedef enum { HACKRF_VENDOR_REQUEST_SET_LNA_GAIN = 19, HACKRF_VENDOR_REQUEST_SET_VGA_GAIN = 20, HACKRF_VENDOR_REQUEST_SET_TXVGA_GAIN = 21, + HACKRF_VENDOR_REQUEST_SET_FRACRATE = 22, } hackrf_vendor_request; typedef enum { @@ -731,8 +739,8 @@ int ADDCALL hackrf_set_freq(hackrf_device* device, const uint64_t freq_hz) /* Convert Freq Hz 64bits to Freq MHz (32bits) & Freq Hz (32bits) */ l_freq_mhz = (uint32_t)(freq_hz / FREQ_ONE_MHZ); l_freq_hz = (uint32_t)(freq_hz - (((uint64_t)l_freq_mhz) * FREQ_ONE_MHZ)); - set_freq_params.freq_mhz = l_freq_mhz; - set_freq_params.freq_hz = l_freq_hz; + set_freq_params.freq_mhz = TO_LE(l_freq_mhz); + set_freq_params.freq_hz = TO_LE(l_freq_hz); length = sizeof(set_freq_params_t); result = libusb_control_transfer( @@ -754,6 +762,42 @@ int ADDCALL hackrf_set_freq(hackrf_device* device, const uint64_t freq_hz) } } + +typedef struct { + float freq_mhz; +} set_fracrate_params_t; + + +int ADDCALL hackrf_set_fracrate(hackrf_device* device, const float freq_mhz) +{ + uint32_t l_freq_mhz; + uint32_t l_freq_hz; + set_fracrate_params_t set_fracrate_params; + uint8_t length; + int result; + + set_fracrate_params.freq_mhz = TO_LE(freq_mhz); + length = sizeof(set_fracrate_params_t); + + result = libusb_control_transfer( + device->usb_device, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + HACKRF_VENDOR_REQUEST_SET_FRACRATE, + 0, + 0, + (unsigned char*)&set_fracrate_params, + length, + 0 + ); + + if (result < length) + { + return HACKRF_ERROR_LIBUSB; + } else { + return HACKRF_SUCCESS; + } +} + int ADDCALL hackrf_set_amp_enable(hackrf_device* device, const uint8_t value) { int result; @@ -797,6 +841,14 @@ int ADDCALL hackrf_board_partid_serialno_read(hackrf_device* device, read_partid { return HACKRF_ERROR_LIBUSB; } else { + + read_partid_serialno->part_id[0] = TO_LE(read_partid_serialno->part_id[0]); + read_partid_serialno->part_id[0] = TO_LE(read_partid_serialno->part_id[1]); + read_partid_serialno->serial_no[0] = TO_LE(read_partid_serialno->serial_no[0]); + read_partid_serialno->serial_no[1] = TO_LE(read_partid_serialno->serial_no[1]); + read_partid_serialno->serial_no[2] = TO_LE(read_partid_serialno->serial_no[2]); + read_partid_serialno->serial_no[3] = TO_LE(read_partid_serialno->serial_no[3]); + return HACKRF_SUCCESS; } } @@ -804,6 +856,7 @@ int ADDCALL hackrf_board_partid_serialno_read(hackrf_device* device, read_partid int ADDCALL hackrf_set_lna_gain(hackrf_device* device, uint32_t value) { int result; + uint8_t retval; if( value > 40 ) { @@ -812,16 +865,16 @@ int ADDCALL hackrf_set_lna_gain(hackrf_device* device, uint32_t value) result = libusb_control_transfer( device->usb_device, - LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, HACKRF_VENDOR_REQUEST_SET_LNA_GAIN, 0, value, - NULL, - 0, + &retval, + 1, 0 ); - if( result != 0 ) + if( result != 1 || !retval ) { return HACKRF_ERROR_INVALID_PARAM; } else { @@ -832,6 +885,7 @@ int ADDCALL hackrf_set_lna_gain(hackrf_device* device, uint32_t value) int ADDCALL hackrf_set_vga_gain(hackrf_device* device, uint32_t value) { int result; + uint8_t retval; if( value > 62 ) { @@ -840,16 +894,16 @@ int ADDCALL hackrf_set_vga_gain(hackrf_device* device, uint32_t value) result = libusb_control_transfer( device->usb_device, - LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, HACKRF_VENDOR_REQUEST_SET_VGA_GAIN, 0, value, - NULL, - 0, + &retval, + 1, 0 ); - if( result != 0 ) + if( result != 1 || !retval ) { return HACKRF_ERROR_INVALID_PARAM; } else { @@ -860,6 +914,7 @@ int ADDCALL hackrf_set_vga_gain(hackrf_device* device, uint32_t value) int ADDCALL hackrf_set_txvga_gain(hackrf_device* device, uint32_t value) { int result; + uint8_t retval; if( value > 47 ) { @@ -868,16 +923,16 @@ int ADDCALL hackrf_set_txvga_gain(hackrf_device* device, uint32_t value) result = libusb_control_transfer( device->usb_device, - LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, HACKRF_VENDOR_REQUEST_SET_TXVGA_GAIN, 0, value, - NULL, - 0, + &retval, + 1, 0 ); - if( result != 0 ) + if( result != 1 || !retval ) { return HACKRF_ERROR_INVALID_PARAM; } else { diff --git a/host/libhackrf/src/hackrf.h b/host/libhackrf/src/hackrf.h index 14968319..96d2dcf6 100644 --- a/host/libhackrf/src/hackrf.h +++ b/host/libhackrf/src/hackrf.h @@ -129,6 +129,7 @@ extern ADDAPI int ADDCALL hackrf_board_id_read(hackrf_device* device, uint8_t* v extern ADDAPI int ADDCALL hackrf_version_string_read(hackrf_device* device, char* version, uint8_t length); extern ADDAPI int ADDCALL hackrf_set_freq(hackrf_device* device, const uint64_t freq_hz); +extern ADDAPI int ADDCALL hackrf_set_fracrate(hackrf_device* device, const float freq_mhz); /* external amp, bool on/off */ extern ADDAPI int ADDCALL hackrf_set_amp_enable(hackrf_device* device, const uint8_t value);