diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index 3bca88df..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 @@ -36,10 +37,107 @@ 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 +} + +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) { - 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(); @@ -65,15 +163,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 */ @@ -94,18 +183,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 */ @@ -116,10 +193,15 @@ 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(); //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 @@ -194,6 +276,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/common/hackrf_core.h b/firmware/common/hackrf_core.h index 7eb57698..ad84648e 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 @@ -96,6 +97,16 @@ 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 */ +#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 */ #define SCU_XCVR_TXENABLE (P4_4) /* GPIO2[4] on P4_4 */ @@ -144,6 +155,18 @@ 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) +#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 */ #define PORT_AD_CS (GPIO2) /* PORT for AD_CS */ @@ -216,6 +239,9 @@ 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 } #endif diff --git a/firmware/common/max2837.c b/firmware/common/max2837.c index 464aa8b3..725e04e6 100644 --- a/firmware/common/max2837.c +++ b/firmware/common/max2837.c @@ -87,16 +87,50 @@ 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); + 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); 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 + 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 */ gpio_clear(PORT_XCVR_ENABLE, (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 max2837_init(); @@ -115,6 +149,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 +231,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 +242,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 +323,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/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/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.c b/firmware/usb_performance/usb.c index 535cb52d..2737201e 100644 --- a/firmware/usb_performance/usb.c +++ b/firmware/usb_performance/usb.c @@ -557,6 +557,9 @@ static void usb_check_for_setup_events() { ); if( endpoint && endpoint->setup_complete ) { copy_setup(&endpoint->setup, usb_queue_head(endpoint->address)->setup); + // TODO: Clean up this duplicated effort by providing + // a cleaner way to get the SETUP data. + copy_setup(&endpoint->in->setup, usb_queue_head(endpoint->address)->setup); usb_clear_endpoint_setup_status(endptsetupstat_bit); endpoint->setup_complete(endpoint); } else { diff --git a/firmware/usb_performance/usb_performance.c b/firmware/usb_performance/usb_performance.c index 6d9e7145..4c74acf7 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 @@ -177,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); @@ -191,7 +196,7 @@ void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) { sgpio_cpld_stream_enable(); } -bool usb_vendor_request_set_transceiver_mode( +usb_request_status_t usb_vendor_request_set_transceiver_mode( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage ) { @@ -200,22 +205,22 @@ bool usb_vendor_request_set_transceiver_mode( case 1: set_transceiver_mode(TRANSCEIVER_MODE_RX); usb_endpoint_schedule_ack(endpoint->in); - return true; + return USB_REQUEST_STATUS_OK; case 2: set_transceiver_mode(TRANSCEIVER_MODE_TX); usb_endpoint_schedule_ack(endpoint->in); - return true; + return USB_REQUEST_STATUS_OK; default: - return false; + return USB_REQUEST_STATUS_STALL; } } else { - return true; + return USB_REQUEST_STATUS_OK; } } -bool usb_vendor_request_write_max2837( +usb_request_status_t usb_vendor_request_write_max2837( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage ) { @@ -224,60 +229,130 @@ bool usb_vendor_request_write_max2837( if( endpoint->setup.value < 0x3ff ) { max2837_reg_write(endpoint->setup.index, endpoint->setup.value); usb_endpoint_schedule_ack(endpoint->in); - return true; + return USB_REQUEST_STATUS_OK; } } - return false; + return USB_REQUEST_STATUS_STALL; } else { - return true; + return USB_REQUEST_STATUS_OK; } } -bool usb_vendor_request_read_max2837( +usb_request_status_t usb_vendor_request_read_max2837( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage ) { 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; + return USB_REQUEST_STATUS_OK; } - return false; + return USB_REQUEST_STATUS_STALL; } else { - return true; + return USB_REQUEST_STATUS_OK; } } -void usb_vendor_request( +usb_request_status_t usb_vendor_request_write_si5351c( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage ) { - bool success = false; + 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 USB_REQUEST_STATUS_OK; + } + } + return USB_REQUEST_STATUS_STALL; + } else { + return USB_REQUEST_STATUS_OK; + } +} + +usb_request_status_t 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 USB_REQUEST_STATUS_OK; + } + return USB_REQUEST_STATUS_STALL; + } else { + return USB_REQUEST_STATUS_OK; + } +} + +usb_request_status_t 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 USB_REQUEST_STATUS_OK; + } + return USB_REQUEST_STATUS_STALL; + } else { + return USB_REQUEST_STATUS_OK; + } +} + +usb_request_status_t 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 USB_REQUEST_STATUS_OK; + } + return USB_REQUEST_STATUS_STALL; + } else { + return USB_REQUEST_STATUS_OK; + } +} + +static const usb_request_handler_fn vendor_request_handler[] = { + NULL, + usb_vendor_request_set_transceiver_mode, + usb_vendor_request_write_max2837, + usb_vendor_request_read_max2837, + usb_vendor_request_write_si5351c, + usb_vendor_request_read_si5351c, + usb_vendor_request_set_sample_rate, + usb_vendor_request_set_baseband_filter_bandwidth, +}; + +static const uint32_t vendor_request_handler_count = + sizeof(vendor_request_handler) / sizeof(vendor_request_handler[0]); + +usb_request_status_t usb_vendor_request( + usb_endpoint_t* const endpoint, + const usb_transfer_stage_t stage +) { + usb_request_status_t status = USB_REQUEST_STATUS_STALL; - switch(endpoint->setup.request) { - case 1: - success = usb_vendor_request_set_transceiver_mode(endpoint, stage); - break; - - case 2: - success = usb_vendor_request_write_max2837(endpoint, stage); - break; - - case 3: - success = usb_vendor_request_read_max2837(endpoint, stage); - break; - - default: - break; + if( endpoint->setup.request < vendor_request_handler_count ) { + usb_request_handler_fn handler = vendor_request_handler[endpoint->setup.request]; + if( handler ) { + status = handler(endpoint, stage); + } } - if( success != true ) { - usb_endpoint_stall(endpoint); - } + return status; } const usb_request_handlers_t usb_request_handlers = { @@ -332,27 +407,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; @@ -366,12 +469,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); @@ -384,6 +481,9 @@ int main(void) { usb_run(&usb_device); ssp1_init(); + ssp1_set_mode_max5864(); + max5864_xcvr(); + ssp1_set_mode_max2837(); max2837_setup(); @@ -397,8 +497,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. diff --git a/firmware/usb_performance/usb_request.c b/firmware/usb_performance/usb_request.c index bfa4ea75..25132fd4 100644 --- a/firmware/usb_performance/usb_request.c +++ b/firmware/usb_performance/usb_request.c @@ -28,6 +28,7 @@ static void usb_request( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage ) { + usb_request_status_t status = USB_REQUEST_STATUS_STALL; usb_request_handler_fn handler = 0; switch( endpoint->setup.request_type & USB_SETUP_REQUEST_TYPE_mask ) { @@ -49,8 +50,10 @@ static void usb_request( } if( handler ) { - handler(endpoint, stage); - } else { + status = handler(endpoint, stage); + } + + if( status != USB_REQUEST_STATUS_OK ) { // USB 2.0 section 9.2.7 "Request Error" usb_endpoint_stall(endpoint); } diff --git a/firmware/usb_performance/usb_request.h b/firmware/usb_performance/usb_request.h index 2d32bcea..9c1ef84f 100644 --- a/firmware/usb_performance/usb_request.h +++ b/firmware/usb_performance/usb_request.h @@ -37,7 +37,12 @@ typedef enum { USB_TRANSFER_STAGE_STATUS, } usb_transfer_stage_t; -typedef void (*usb_request_handler_fn)( +typedef enum { + USB_REQUEST_STATUS_OK = 0, + USB_REQUEST_STATUS_STALL = 1, +} usb_request_status_t; + +typedef usb_request_status_t (*usb_request_handler_fn)( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage ); diff --git a/firmware/usb_performance/usb_standard_request.c b/firmware/usb_performance/usb_standard_request.c index 286d783b..71a38232 100644 --- a/firmware/usb_performance/usb_standard_request.c +++ b/firmware/usb_performance/usb_standard_request.c @@ -63,7 +63,7 @@ extern bool usb_set_configuration( const uint_fast8_t configuration_number ); -static void usb_send_descriptor( +static usb_request_status_t usb_send_descriptor( usb_endpoint_t* const endpoint, uint8_t* const descriptor_data ) { @@ -77,113 +77,110 @@ static void usb_send_descriptor( descriptor_data, (setup_length > descriptor_length) ? descriptor_length : setup_length ); + usb_endpoint_schedule_ack(endpoint->out); + return USB_REQUEST_STATUS_OK; } -static void usb_send_descriptor_string( +static usb_request_status_t usb_send_descriptor_string( usb_endpoint_t* const endpoint ) { uint_fast8_t index = endpoint->setup.value_l; for( uint_fast8_t i=0; usb_descriptor_strings[i] != 0; i++ ) { if( i == index ) { - usb_send_descriptor(endpoint, usb_descriptor_strings[i]); - return; + return usb_send_descriptor(endpoint, usb_descriptor_strings[i]); } } - usb_endpoint_stall(endpoint); + return USB_REQUEST_STATUS_STALL; } -static void usb_standard_request_get_descriptor_setup( +static usb_request_status_t usb_standard_request_get_descriptor_setup( usb_endpoint_t* const endpoint ) { switch( endpoint->setup.value_h ) { case USB_DESCRIPTOR_TYPE_DEVICE: - usb_send_descriptor(endpoint, usb_descriptor_device); - break; + return usb_send_descriptor(endpoint, usb_descriptor_device); case USB_DESCRIPTOR_TYPE_CONFIGURATION: // TODO: Duplicated code. Refactor. if( usb_speed(endpoint->device) == USB_SPEED_HIGH ) { - usb_send_descriptor(endpoint, usb_descriptor_configuration_high_speed); + return usb_send_descriptor(endpoint, usb_descriptor_configuration_high_speed); } else { - usb_send_descriptor(endpoint, usb_descriptor_configuration_full_speed); + return usb_send_descriptor(endpoint, usb_descriptor_configuration_full_speed); } - break; case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER: - usb_send_descriptor(endpoint, usb_descriptor_device_qualifier); - break; + return usb_send_descriptor(endpoint, usb_descriptor_device_qualifier); case USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION: // TODO: Duplicated code. Refactor. if( usb_speed(endpoint->device) == USB_SPEED_HIGH ) { - usb_send_descriptor(endpoint, usb_descriptor_configuration_full_speed); + return usb_send_descriptor(endpoint, usb_descriptor_configuration_full_speed); } else { - usb_send_descriptor(endpoint, usb_descriptor_configuration_high_speed); + return usb_send_descriptor(endpoint, usb_descriptor_configuration_high_speed); } - break; case USB_DESCRIPTOR_TYPE_STRING: - usb_send_descriptor_string(endpoint); - break; + return usb_send_descriptor_string(endpoint); case USB_DESCRIPTOR_TYPE_INTERFACE: case USB_DESCRIPTOR_TYPE_ENDPOINT: default: - usb_endpoint_stall(endpoint); - break; + return USB_REQUEST_STATUS_STALL; } } -static void usb_standard_request_get_descriptor( +static usb_request_status_t usb_standard_request_get_descriptor( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage ) { switch( stage ) { case USB_TRANSFER_STAGE_SETUP: - usb_standard_request_get_descriptor_setup(endpoint); - usb_endpoint_schedule_ack(endpoint->out); - break; + return usb_standard_request_get_descriptor_setup(endpoint); case USB_TRANSFER_STAGE_DATA: - break; - case USB_TRANSFER_STAGE_STATUS: - break; + return USB_REQUEST_STATUS_OK; + default: + return USB_REQUEST_STATUS_STALL; } } /*********************************************************************/ -static void usb_standard_request_set_address( +static usb_request_status_t usb_standard_request_set_address_setup( + usb_endpoint_t* const endpoint +) { + usb_set_address_deferred(endpoint->device, endpoint->setup.value_l); + usb_endpoint_schedule_ack(endpoint->in); + return USB_REQUEST_STATUS_OK; +} + +static usb_request_status_t usb_standard_request_set_address( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage ) { switch( stage ) { case USB_TRANSFER_STAGE_SETUP: - usb_set_address_deferred(endpoint->device, endpoint->setup.value_l); - usb_endpoint_schedule_ack(endpoint->in); - break; + return usb_standard_request_set_address_setup(endpoint); case USB_TRANSFER_STAGE_DATA: - break; - case USB_TRANSFER_STAGE_STATUS: /* NOTE: Not necessary to set address here, as DEVICEADR.USBADRA bit * will cause controller to automatically perform set address * operation on IN ACK. */ - break; + return USB_REQUEST_STATUS_OK; default: - break; + return USB_REQUEST_STATUS_STALL; } } /*********************************************************************/ -static void usb_standard_request_set_configuration_setup( +static usb_request_status_t usb_standard_request_set_configuration_setup( usb_endpoint_t* const endpoint ) { const uint8_t usb_configuration = endpoint->setup.value_l; @@ -193,32 +190,32 @@ static void usb_standard_request_set_configuration_setup( usb_set_address_immediate(endpoint->device, 0); } usb_endpoint_schedule_ack(endpoint->in); + return USB_REQUEST_STATUS_OK; } else { - usb_endpoint_stall(endpoint); + return USB_REQUEST_STATUS_STALL; } } -static void usb_standard_request_set_configuration( +static usb_request_status_t usb_standard_request_set_configuration( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage ) { switch( stage ) { case USB_TRANSFER_STAGE_SETUP: - usb_standard_request_set_configuration_setup(endpoint); - break; + return usb_standard_request_set_configuration_setup(endpoint); case USB_TRANSFER_STAGE_DATA: - break; - case USB_TRANSFER_STAGE_STATUS: - break; + return USB_REQUEST_STATUS_OK; + default: + return USB_REQUEST_STATUS_STALL; } } /*********************************************************************/ -static void usb_standard_request_get_configuration_setup( +static usb_request_status_t usb_standard_request_get_configuration_setup( usb_endpoint_t* const endpoint ) { if( endpoint->setup.length == 1 ) { @@ -227,52 +224,50 @@ static void usb_standard_request_get_configuration_setup( endpoint->buffer[0] = endpoint->device->configuration->number; } usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 1); + usb_endpoint_schedule_ack(endpoint->out); + return USB_REQUEST_STATUS_OK; } else { - usb_endpoint_stall(endpoint); + return USB_REQUEST_STATUS_STALL; } } -static void usb_standard_request_get_configuration( +static usb_request_status_t usb_standard_request_get_configuration( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage ) { switch( stage ) { case USB_TRANSFER_STAGE_SETUP: - usb_standard_request_get_configuration_setup(endpoint); - usb_endpoint_schedule_ack(endpoint->out); - break; + return usb_standard_request_get_configuration_setup(endpoint); case USB_TRANSFER_STAGE_DATA: - break; - case USB_TRANSFER_STAGE_STATUS: - break; - + return USB_REQUEST_STATUS_OK; + + default: + return USB_REQUEST_STATUS_STALL; } } /*********************************************************************/ -void usb_standard_request( +usb_request_status_t usb_standard_request( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage ) { switch( endpoint->setup.request ) { case USB_STANDARD_REQUEST_GET_DESCRIPTOR: - usb_standard_request_get_descriptor(endpoint, stage); - break; + return usb_standard_request_get_descriptor(endpoint, stage); case USB_STANDARD_REQUEST_SET_ADDRESS: - usb_standard_request_set_address(endpoint, stage); - break; + return usb_standard_request_set_address(endpoint, stage); case USB_STANDARD_REQUEST_SET_CONFIGURATION: - usb_standard_request_set_configuration(endpoint, stage); - break; + return usb_standard_request_set_configuration(endpoint, stage); case USB_STANDARD_REQUEST_GET_CONFIGURATION: - usb_standard_request_get_configuration(endpoint, stage); - break; - + return usb_standard_request_get_configuration(endpoint, stage); + + default: + return USB_REQUEST_STATUS_STALL; } } diff --git a/firmware/usb_performance/usb_standard_request.h b/firmware/usb_performance/usb_standard_request.h index e96dba21..5a0bdac6 100644 --- a/firmware/usb_performance/usb_standard_request.h +++ b/firmware/usb_performance/usb_standard_request.h @@ -25,7 +25,7 @@ #include "usb_type.h" #include "usb_request.h" -void usb_standard_request( +usb_request_status_t usb_standard_request( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage ); 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..3ab34119 --- /dev/null +++ b/host/libhackrf/examples/CMakeLists.txt @@ -0,0 +1,35 @@ +# 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_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) +endif(EXAMPLES) diff --git a/host/libhackrf/examples/hackrf_max2837.c b/host/libhackrf/examples/hackrf_max2837.c new file mode 100644 index 00000000..cac878ff --- /dev/null +++ b/host/libhackrf/examples/hackrf_max2837.c @@ -0,0 +1,175 @@ +/* + * 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 + +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* 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, base); + 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_si5351c.c b/host/libhackrf/examples/hackrf_si5351c.c new file mode 100644 index 00000000..3b723f4c --- /dev/null +++ b/host/libhackrf/examples/hackrf_si5351c.c @@ -0,0 +1,217 @@ +/* + * 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-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"); + 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[] = { + { "config", no_argument, 0, 'c' }, + { "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 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; + 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, "cn: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; + + case 'c': + dump_configuration(device); + 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..089fe823 --- /dev/null +++ b/host/libhackrf/examples/hackrf_transfer.c @@ -0,0 +1,222 @@ +/* + * 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 != HACKRF_SUCCESS ) { + printf("hackrf_init() failed: %s (%d)\n", hackrf_error_name(result), result); + return -1; + } + + result = hackrf_open(&device); + if( result != HACKRF_SUCCESS ) { + 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); + + 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; + } + + 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 { + result = hackrf_start_tx(device, tx_callback); + } + if( result != HACKRF_SUCCESS ) { + 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 != HACKRF_SUCCESS ) { + 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..a3efcf82 --- /dev/null +++ b/host/libhackrf/src/hackrf.c @@ -0,0 +1,544 @@ +/* + * 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_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 { + 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; + } +} + +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; + } +} + +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; + } +} + +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; + + 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..8c288ebd --- /dev/null +++ b/host/libhackrf/src/hackrf.h @@ -0,0 +1,75 @@ +/* + * 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_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); + +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); +int hackrf_baseband_filter_bandwidth_set(hackrf_device* device, const uint32_t bandwidth_hz); + +const char* hackrf_error_name(enum hackrf_error errcode); + +#endif//__HACKRF_H__ diff --git a/host/usb_test/max2837_dump.py b/host/python/max2837_dump.py similarity index 94% rename from host/usb_test/max2837_dump.py rename to host/python/max2837_dump.py index 1bda15fc..3e85d6a7 100755 --- a/host/usb_test/max2837_dump.py +++ b/host/python/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(' -# 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 c984898c..00000000 --- a/host/usb_test/usb_test.c +++ /dev/null @@ -1,292 +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_pid = 0x1d50; -const uint16_t hackrf_usb_vid = 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; - write(fd, transfer->buffer, transfer->actual_length); - libusb_submit_transfer(transfer); - } 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; - read(fd, transfer->buffer, transfer->actual_length); - libusb_submit_transfer(transfer); - } 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_pid, hackrf_usb_vid); - 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; -}