@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include "hackrf_core.h"
|
#include "hackrf_core.h"
|
||||||
#include "si5351c.h"
|
#include "si5351c.h"
|
||||||
|
#include "max2837.h"
|
||||||
#include <libopencm3/lpc43xx/i2c.h>
|
#include <libopencm3/lpc43xx/i2c.h>
|
||||||
#include <libopencm3/lpc43xx/cgu.h>
|
#include <libopencm3/lpc43xx/cgu.h>
|
||||||
#include <libopencm3/lpc43xx/gpio.h>
|
#include <libopencm3/lpc43xx/gpio.h>
|
||||||
@ -36,10 +37,107 @@ void delay(uint32_t duration)
|
|||||||
__asm__("nop");
|
__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 */
|
/* clock startup for Jellybean with Lemondrop attached */
|
||||||
void cpu_clock_init(void)
|
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_all_outputs();
|
||||||
si5351c_disable_oeb_pin_control();
|
si5351c_disable_oeb_pin_control();
|
||||||
@ -65,15 +163,6 @@ void cpu_clock_init(void)
|
|||||||
/* MS0/CLK0 is the source for the MAX2837 clock input. */
|
/* MS0/CLK0 is the source for the MAX2837 clock input. */
|
||||||
si5351c_configure_multisynth(0, 2048, 0, 1, 0); /* 40MHz */
|
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. */
|
/* MS4/CLK4 is the source for the LPC43xx microcontroller. */
|
||||||
si5351c_configure_multisynth(4, 8021, 0, 3, 0); /* 12MHz */
|
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)
|
* 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. */
|
/* MS4/CLK4 is the source for the RFFC5071 mixer. */
|
||||||
si5351c_configure_multisynth(4, 1536, 0, 1, 0); /* 50MHz */
|
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 */
|
//si5351c_configure_multisynth(7, 8021, 0, 3, 0); /* 12MHz */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Set to 10 MHz, the common rate between Jellybean and Jawbreaker. */
|
||||||
|
sample_rate_set(10000000);
|
||||||
|
|
||||||
si5351c_configure_clock_control();
|
si5351c_configure_clock_control();
|
||||||
si5351c_enable_clock_outputs();
|
si5351c_enable_clock_outputs();
|
||||||
|
|
||||||
//FIXME disable I2C
|
//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
|
* 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 */
|
/* use PLL0USB as clock source for USB0 */
|
||||||
CGU_BASE_USB0_CLK = CGU_BASE_USB0_CLK_AUTOBLOCK
|
CGU_BASE_USB0_CLK = CGU_BASE_USB0_CLK_AUTOBLOCK
|
||||||
| CGU_BASE_USB0_CLK_CLK_SEL(CGU_SRC_PLL0USB);
|
| 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)
|
void ssp1_init(void)
|
||||||
|
@ -30,6 +30,7 @@ extern "C"
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
/* hardware identification number */
|
/* hardware identification number */
|
||||||
#define BOARD_ID_JELLYBEAN 0
|
#define BOARD_ID_JELLYBEAN 0
|
||||||
@ -96,6 +97,16 @@ extern "C"
|
|||||||
#define SCU_PINMUX_SGPIO15 (P4_10)
|
#define SCU_PINMUX_SGPIO15 (P4_10)
|
||||||
|
|
||||||
/* MAX2837 GPIO (XCVR_CTL) PinMux */
|
/* 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_ENABLE (P4_6) /* GPIO2[6] on P4_6 */
|
||||||
#define SCU_XCVR_RXENABLE (P4_5) /* GPIO2[5] on P4_5 */
|
#define SCU_XCVR_RXENABLE (P4_5) /* GPIO2[5] on P4_5 */
|
||||||
#define SCU_XCVR_TXENABLE (P4_4) /* GPIO2[4] on P4_4 */
|
#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_RXENABLE (BIT5) /* GPIO2[5] on P4_5 */
|
||||||
#define PIN_XCVR_TXENABLE (BIT4) /* GPIO2[4] on P4_4 */
|
#define PIN_XCVR_TXENABLE (BIT4) /* GPIO2[4] on P4_4 */
|
||||||
#define PORT_XCVR_ENABLE (GPIO2) /* PORT for ENABLE, TXENABLE, RXENABLE */
|
#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 PIN_AD_CS (BIT7) /* GPIO2[7] on P5_7 */
|
||||||
#define PORT_AD_CS (GPIO2) /* PORT for AD_CS */
|
#define PORT_AD_CS (GPIO2) /* PORT for AD_CS */
|
||||||
@ -216,6 +239,9 @@ void pin_setup(void);
|
|||||||
|
|
||||||
void enable_1v8_power(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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -87,16 +87,50 @@ void max2837_setup(void)
|
|||||||
LOG("# max2837_setup\n");
|
LOG("# max2837_setup\n");
|
||||||
#if !defined TEST
|
#if !defined TEST
|
||||||
/* Configure XCVR_CTL GPIO pins. */
|
/* 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_ENABLE, SCU_GPIO_FAST);
|
||||||
scu_pinmux(SCU_XCVR_RXENABLE, SCU_GPIO_FAST);
|
scu_pinmux(SCU_XCVR_RXENABLE, SCU_GPIO_FAST);
|
||||||
scu_pinmux(SCU_XCVR_TXENABLE, SCU_GPIO_FAST);
|
scu_pinmux(SCU_XCVR_TXENABLE, SCU_GPIO_FAST);
|
||||||
|
|
||||||
/* Set GPIO pins as outputs. */
|
/* Set GPIO pins as outputs. */
|
||||||
GPIO2_DIR |= (PIN_XCVR_ENABLE | PIN_XCVR_RXENABLE | PIN_XCVR_TXENABLE);
|
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 */
|
/* disable everything */
|
||||||
gpio_clear(PORT_XCVR_ENABLE,
|
gpio_clear(PORT_XCVR_ENABLE,
|
||||||
(PIN_XCVR_ENABLE | PIN_XCVR_RXENABLE | PIN_XCVR_TXENABLE));
|
(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
|
#endif
|
||||||
|
|
||||||
max2837_init();
|
max2837_init();
|
||||||
@ -115,6 +149,11 @@ void max2837_setup(void)
|
|||||||
/* maximum rx output common-mode voltage */
|
/* maximum rx output common-mode voltage */
|
||||||
set_MAX2837_BUFF_VCM(MAX2837_BUFF_VCM_1_25);
|
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();
|
max2837_regs_commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,10 +231,7 @@ void max2837_tx(void)
|
|||||||
LOG("# max2837_tx\n");
|
LOG("# max2837_tx\n");
|
||||||
#if !defined TEST
|
#if !defined TEST
|
||||||
|
|
||||||
/* configure baseband filter for 8 MHz TX */
|
|
||||||
set_MAX2837_LPF_EN(1);
|
|
||||||
set_MAX2837_ModeCtrl(MAX2837_ModeCtrl_TxLPF);
|
set_MAX2837_ModeCtrl(MAX2837_ModeCtrl_TxLPF);
|
||||||
set_MAX2837_FT(MAX2837_FT_8M);
|
|
||||||
max2837_regs_commit();
|
max2837_regs_commit();
|
||||||
|
|
||||||
gpio_set(PORT_XCVR_ENABLE, PIN_XCVR_TXENABLE);
|
gpio_set(PORT_XCVR_ENABLE, PIN_XCVR_TXENABLE);
|
||||||
@ -206,10 +242,7 @@ void max2837_rx(void)
|
|||||||
{
|
{
|
||||||
LOG("# max2837_rx\n");
|
LOG("# max2837_rx\n");
|
||||||
|
|
||||||
/* configure baseband filter for 8 MHz RX */
|
|
||||||
set_MAX2837_LPF_EN(1);
|
|
||||||
set_MAX2837_ModeCtrl(MAX2837_ModeCtrl_RxLPF);
|
set_MAX2837_ModeCtrl(MAX2837_ModeCtrl_RxLPF);
|
||||||
set_MAX2837_FT(MAX2837_FT_8M);
|
|
||||||
max2837_regs_commit();
|
max2837_regs_commit();
|
||||||
|
|
||||||
#if !defined TEST
|
#if !defined TEST
|
||||||
@ -290,6 +323,49 @@ void max2837_set_frequency(uint32_t freq)
|
|||||||
max2837_regs_commit();
|
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
|
#ifdef TEST
|
||||||
int main(int ac, char **av)
|
int main(int ac, char **av)
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
#ifndef __MAX2837_H
|
#ifndef __MAX2837_H
|
||||||
#define __MAX2837_H
|
#define __MAX2837_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
/* TODO - make this a private header for max2837.c only, make new max2837.h */
|
/* TODO - make this a private header for max2837.c only, make new max2837.h */
|
||||||
|
|
||||||
/* 32 registers, each containing 10 bits of data. */
|
/* 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
|
/* Set frequency in Hz. Frequency setting is a multi-step function
|
||||||
* where order of register writes matters. */
|
* where order of register writes matters. */
|
||||||
extern void max2837_set_frequency(uint32_t freq);
|
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_tx(void);
|
||||||
extern void max2837_rx(void);
|
extern void max2837_rx(void);
|
||||||
|
@ -45,6 +45,9 @@ void si5351c_configure_multisynth(const uint_fast8_t ms_number,
|
|||||||
void si5351c_configure_clock_control();
|
void si5351c_configure_clock_control();
|
||||||
void si5351c_enable_clock_outputs();
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -96,13 +96,6 @@ int main(void) {
|
|||||||
pin_setup();
|
pin_setup();
|
||||||
enable_1v8_power();
|
enable_1v8_power();
|
||||||
cpu_clock_init();
|
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_init();
|
||||||
ssp1_set_mode_max2837();
|
ssp1_set_mode_max2837();
|
||||||
max2837_setup();
|
max2837_setup();
|
||||||
|
@ -72,12 +72,6 @@ int main(void) {
|
|||||||
cpu_clock_init();
|
cpu_clock_init();
|
||||||
ssp1_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);
|
gpio_set(PORT_LED1_3, PIN_LED1);
|
||||||
|
|
||||||
ssp1_set_mode_max5864();
|
ssp1_set_mode_max5864();
|
||||||
|
@ -354,13 +354,6 @@ int main(void)
|
|||||||
enable_1v8_power();
|
enable_1v8_power();
|
||||||
cpu_clock_init();
|
cpu_clock_init();
|
||||||
ssp1_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);
|
gpio_set(PORT_LED1_3, PIN_LED1);
|
||||||
|
|
||||||
//test_sgpio_sliceA_D();
|
//test_sgpio_sliceA_D();
|
||||||
|
@ -557,6 +557,9 @@ static void usb_check_for_setup_events() {
|
|||||||
);
|
);
|
||||||
if( endpoint && endpoint->setup_complete ) {
|
if( endpoint && endpoint->setup_complete ) {
|
||||||
copy_setup(&endpoint->setup, usb_queue_head(endpoint->address)->setup);
|
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);
|
usb_clear_endpoint_setup_status(endptsetupstat_bit);
|
||||||
endpoint->setup_complete(endpoint);
|
endpoint->setup_complete(endpoint);
|
||||||
} else {
|
} else {
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include <libopencm3/lpc43xx/sgpio.h>
|
#include <libopencm3/lpc43xx/sgpio.h>
|
||||||
|
|
||||||
#include <hackrf_core.h>
|
#include <hackrf_core.h>
|
||||||
|
#include <si5351c.h>
|
||||||
#include <max5864.h>
|
#include <max5864.h>
|
||||||
#include <max2837.h>
|
#include <max2837.h>
|
||||||
#include <rffc5071.h>
|
#include <rffc5071.h>
|
||||||
@ -177,9 +178,13 @@ void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) {
|
|||||||
if( transceiver_mode == TRANSCEIVER_MODE_RX ) {
|
if( transceiver_mode == TRANSCEIVER_MODE_RX ) {
|
||||||
gpio_clear(PORT_LED1_3, PIN_LED3);
|
gpio_clear(PORT_LED1_3, PIN_LED3);
|
||||||
usb_endpoint_init(&usb_endpoint_bulk_in);
|
usb_endpoint_init(&usb_endpoint_bulk_in);
|
||||||
|
|
||||||
|
max2837_rx();
|
||||||
} else {
|
} else {
|
||||||
gpio_set(PORT_LED1_3, PIN_LED3);
|
gpio_set(PORT_LED1_3, PIN_LED3);
|
||||||
usb_endpoint_init(&usb_endpoint_bulk_out);
|
usb_endpoint_init(&usb_endpoint_bulk_out);
|
||||||
|
|
||||||
|
max2837_tx();
|
||||||
}
|
}
|
||||||
|
|
||||||
sgpio_configure(transceiver_mode, true);
|
sgpio_configure(transceiver_mode, true);
|
||||||
@ -191,7 +196,7 @@ void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) {
|
|||||||
sgpio_cpld_stream_enable();
|
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,
|
usb_endpoint_t* const endpoint,
|
||||||
const usb_transfer_stage_t stage
|
const usb_transfer_stage_t stage
|
||||||
) {
|
) {
|
||||||
@ -200,22 +205,22 @@ bool usb_vendor_request_set_transceiver_mode(
|
|||||||
case 1:
|
case 1:
|
||||||
set_transceiver_mode(TRANSCEIVER_MODE_RX);
|
set_transceiver_mode(TRANSCEIVER_MODE_RX);
|
||||||
usb_endpoint_schedule_ack(endpoint->in);
|
usb_endpoint_schedule_ack(endpoint->in);
|
||||||
return true;
|
return USB_REQUEST_STATUS_OK;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
set_transceiver_mode(TRANSCEIVER_MODE_TX);
|
set_transceiver_mode(TRANSCEIVER_MODE_TX);
|
||||||
usb_endpoint_schedule_ack(endpoint->in);
|
usb_endpoint_schedule_ack(endpoint->in);
|
||||||
return true;
|
return USB_REQUEST_STATUS_OK;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return USB_REQUEST_STATUS_STALL;
|
||||||
}
|
}
|
||||||
} else {
|
} 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,
|
usb_endpoint_t* const endpoint,
|
||||||
const usb_transfer_stage_t stage
|
const usb_transfer_stage_t stage
|
||||||
) {
|
) {
|
||||||
@ -224,60 +229,130 @@ bool usb_vendor_request_write_max2837(
|
|||||||
if( endpoint->setup.value < 0x3ff ) {
|
if( endpoint->setup.value < 0x3ff ) {
|
||||||
max2837_reg_write(endpoint->setup.index, endpoint->setup.value);
|
max2837_reg_write(endpoint->setup.index, endpoint->setup.value);
|
||||||
usb_endpoint_schedule_ack(endpoint->in);
|
usb_endpoint_schedule_ack(endpoint->in);
|
||||||
return true;
|
return USB_REQUEST_STATUS_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return USB_REQUEST_STATUS_STALL;
|
||||||
} else {
|
} 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,
|
usb_endpoint_t* const endpoint,
|
||||||
const usb_transfer_stage_t stage
|
const usb_transfer_stage_t stage
|
||||||
) {
|
) {
|
||||||
if( stage == USB_TRANSFER_STAGE_SETUP ) {
|
if( stage == USB_TRANSFER_STAGE_SETUP ) {
|
||||||
if( endpoint->setup.index < 32 ) {
|
if( endpoint->setup.index < 32 ) {
|
||||||
const uint16_t value = max2837_reg_read(endpoint->setup.index);
|
const uint16_t value = max2837_reg_read(endpoint->setup.index);
|
||||||
endpoint->buffer[0] = value >> 8;
|
endpoint->buffer[0] = value & 0xff;
|
||||||
endpoint->buffer[1] = value & 0xff;
|
endpoint->buffer[1] = value >> 8;
|
||||||
usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 2);
|
usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 2);
|
||||||
usb_endpoint_schedule_ack(endpoint->out);
|
usb_endpoint_schedule_ack(endpoint->out);
|
||||||
return true;
|
return USB_REQUEST_STATUS_OK;
|
||||||
}
|
}
|
||||||
return false;
|
return USB_REQUEST_STATUS_STALL;
|
||||||
} else {
|
} 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,
|
usb_endpoint_t* const endpoint,
|
||||||
const usb_transfer_stage_t stage
|
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) {
|
if( endpoint->setup.request < vendor_request_handler_count ) {
|
||||||
case 1:
|
usb_request_handler_fn handler = vendor_request_handler[endpoint->setup.request];
|
||||||
success = usb_vendor_request_set_transceiver_mode(endpoint, stage);
|
if( handler ) {
|
||||||
break;
|
status = handler(endpoint, stage);
|
||||||
|
}
|
||||||
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( success != true ) {
|
return status;
|
||||||
usb_endpoint_stall(endpoint);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const usb_request_handlers_t usb_request_handlers = {
|
const usb_request_handlers_t usb_request_handlers = {
|
||||||
@ -332,27 +407,55 @@ bool usb_set_configuration(
|
|||||||
};
|
};
|
||||||
|
|
||||||
void sgpio_irqhandler() {
|
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];
|
uint32_t* const p = (uint32_t*)&usb_bulk_buffer[usb_bulk_buffer_offset];
|
||||||
if( transceiver_mode == TRANSCEIVER_MODE_RX ) {
|
if( transceiver_mode == TRANSCEIVER_MODE_RX ) {
|
||||||
p[7] = SGPIO_REG_SS(SGPIO_SLICE_A);
|
__asm__(
|
||||||
p[6] = SGPIO_REG_SS(SGPIO_SLICE_I);
|
"ldr r0, [%[SGPIO_REG_SS], #44]\n\t"
|
||||||
p[5] = SGPIO_REG_SS(SGPIO_SLICE_E);
|
"str r0, [%[p], #0]\n\t"
|
||||||
p[4] = SGPIO_REG_SS(SGPIO_SLICE_J);
|
"ldr r0, [%[SGPIO_REG_SS], #20]\n\t"
|
||||||
p[3] = SGPIO_REG_SS(SGPIO_SLICE_C);
|
"str r0, [%[p], #4]\n\t"
|
||||||
p[2] = SGPIO_REG_SS(SGPIO_SLICE_K);
|
"ldr r0, [%[SGPIO_REG_SS], #40]\n\t"
|
||||||
p[1] = SGPIO_REG_SS(SGPIO_SLICE_F);
|
"str r0, [%[p], #8]\n\t"
|
||||||
p[0] = SGPIO_REG_SS(SGPIO_SLICE_L);
|
"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 {
|
} else {
|
||||||
SGPIO_REG_SS(SGPIO_SLICE_A) = p[7];
|
__asm__(
|
||||||
SGPIO_REG_SS(SGPIO_SLICE_I) = p[6];
|
"ldr r0, [%[p], #0]\n\t"
|
||||||
SGPIO_REG_SS(SGPIO_SLICE_E) = p[5];
|
"str r0, [%[SGPIO_REG_SS], #44]\n\t"
|
||||||
SGPIO_REG_SS(SGPIO_SLICE_J) = p[4];
|
"ldr r0, [%[p], #4]\n\t"
|
||||||
SGPIO_REG_SS(SGPIO_SLICE_C) = p[3];
|
"str r0, [%[SGPIO_REG_SS], #20]\n\t"
|
||||||
SGPIO_REG_SS(SGPIO_SLICE_K) = p[2];
|
"ldr r0, [%[p], #8]\n\t"
|
||||||
SGPIO_REG_SS(SGPIO_SLICE_F) = p[1];
|
"str r0, [%[SGPIO_REG_SS], #40]\n\t"
|
||||||
SGPIO_REG_SS(SGPIO_SLICE_L) = p[0];
|
"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;
|
usb_bulk_buffer_offset = (usb_bulk_buffer_offset + 32) & usb_bulk_buffer_mask;
|
||||||
@ -366,12 +469,6 @@ int main(void) {
|
|||||||
enable_1v8_power();
|
enable_1v8_power();
|
||||||
cpu_clock_init();
|
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_peripheral_reset();
|
||||||
|
|
||||||
usb_device_init(0, &usb_device);
|
usb_device_init(0, &usb_device);
|
||||||
@ -384,6 +481,9 @@ int main(void) {
|
|||||||
usb_run(&usb_device);
|
usb_run(&usb_device);
|
||||||
|
|
||||||
ssp1_init();
|
ssp1_init();
|
||||||
|
ssp1_set_mode_max5864();
|
||||||
|
max5864_xcvr();
|
||||||
|
|
||||||
ssp1_set_mode_max2837();
|
ssp1_set_mode_max2837();
|
||||||
max2837_setup();
|
max2837_setup();
|
||||||
|
|
||||||
@ -397,8 +497,6 @@ int main(void) {
|
|||||||
max2837_set_frequency(freq);
|
max2837_set_frequency(freq);
|
||||||
max2837_start();
|
max2837_start();
|
||||||
max2837_rx();
|
max2837_rx();
|
||||||
ssp1_set_mode_max5864();
|
|
||||||
max5864_xcvr();
|
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
// Wait until buffer 0 is transmitted/received.
|
// Wait until buffer 0 is transmitted/received.
|
||||||
|
@ -28,6 +28,7 @@ static void usb_request(
|
|||||||
usb_endpoint_t* const endpoint,
|
usb_endpoint_t* const endpoint,
|
||||||
const usb_transfer_stage_t stage
|
const usb_transfer_stage_t stage
|
||||||
) {
|
) {
|
||||||
|
usb_request_status_t status = USB_REQUEST_STATUS_STALL;
|
||||||
usb_request_handler_fn handler = 0;
|
usb_request_handler_fn handler = 0;
|
||||||
|
|
||||||
switch( endpoint->setup.request_type & USB_SETUP_REQUEST_TYPE_mask ) {
|
switch( endpoint->setup.request_type & USB_SETUP_REQUEST_TYPE_mask ) {
|
||||||
@ -49,8 +50,10 @@ static void usb_request(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( handler ) {
|
if( handler ) {
|
||||||
handler(endpoint, stage);
|
status = handler(endpoint, stage);
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
if( status != USB_REQUEST_STATUS_OK ) {
|
||||||
// USB 2.0 section 9.2.7 "Request Error"
|
// USB 2.0 section 9.2.7 "Request Error"
|
||||||
usb_endpoint_stall(endpoint);
|
usb_endpoint_stall(endpoint);
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,12 @@ typedef enum {
|
|||||||
USB_TRANSFER_STAGE_STATUS,
|
USB_TRANSFER_STAGE_STATUS,
|
||||||
} usb_transfer_stage_t;
|
} 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,
|
usb_endpoint_t* const endpoint,
|
||||||
const usb_transfer_stage_t stage
|
const usb_transfer_stage_t stage
|
||||||
);
|
);
|
||||||
|
@ -63,7 +63,7 @@ extern bool usb_set_configuration(
|
|||||||
const uint_fast8_t configuration_number
|
const uint_fast8_t configuration_number
|
||||||
);
|
);
|
||||||
|
|
||||||
static void usb_send_descriptor(
|
static usb_request_status_t usb_send_descriptor(
|
||||||
usb_endpoint_t* const endpoint,
|
usb_endpoint_t* const endpoint,
|
||||||
uint8_t* const descriptor_data
|
uint8_t* const descriptor_data
|
||||||
) {
|
) {
|
||||||
@ -77,113 +77,110 @@ static void usb_send_descriptor(
|
|||||||
descriptor_data,
|
descriptor_data,
|
||||||
(setup_length > descriptor_length) ? descriptor_length : setup_length
|
(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
|
usb_endpoint_t* const endpoint
|
||||||
) {
|
) {
|
||||||
uint_fast8_t index = endpoint->setup.value_l;
|
uint_fast8_t index = endpoint->setup.value_l;
|
||||||
for( uint_fast8_t i=0; usb_descriptor_strings[i] != 0; i++ ) {
|
for( uint_fast8_t i=0; usb_descriptor_strings[i] != 0; i++ ) {
|
||||||
if( i == index ) {
|
if( i == index ) {
|
||||||
usb_send_descriptor(endpoint, usb_descriptor_strings[i]);
|
return usb_send_descriptor(endpoint, usb_descriptor_strings[i]);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
usb_endpoint_t* const endpoint
|
||||||
) {
|
) {
|
||||||
switch( endpoint->setup.value_h ) {
|
switch( endpoint->setup.value_h ) {
|
||||||
case USB_DESCRIPTOR_TYPE_DEVICE:
|
case USB_DESCRIPTOR_TYPE_DEVICE:
|
||||||
usb_send_descriptor(endpoint, usb_descriptor_device);
|
return usb_send_descriptor(endpoint, usb_descriptor_device);
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_DESCRIPTOR_TYPE_CONFIGURATION:
|
case USB_DESCRIPTOR_TYPE_CONFIGURATION:
|
||||||
// TODO: Duplicated code. Refactor.
|
// TODO: Duplicated code. Refactor.
|
||||||
if( usb_speed(endpoint->device) == USB_SPEED_HIGH ) {
|
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 {
|
} 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:
|
case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER:
|
||||||
usb_send_descriptor(endpoint, usb_descriptor_device_qualifier);
|
return usb_send_descriptor(endpoint, usb_descriptor_device_qualifier);
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION:
|
case USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION:
|
||||||
// TODO: Duplicated code. Refactor.
|
// TODO: Duplicated code. Refactor.
|
||||||
if( usb_speed(endpoint->device) == USB_SPEED_HIGH ) {
|
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 {
|
} 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:
|
case USB_DESCRIPTOR_TYPE_STRING:
|
||||||
usb_send_descriptor_string(endpoint);
|
return usb_send_descriptor_string(endpoint);
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_DESCRIPTOR_TYPE_INTERFACE:
|
case USB_DESCRIPTOR_TYPE_INTERFACE:
|
||||||
case USB_DESCRIPTOR_TYPE_ENDPOINT:
|
case USB_DESCRIPTOR_TYPE_ENDPOINT:
|
||||||
default:
|
default:
|
||||||
usb_endpoint_stall(endpoint);
|
return USB_REQUEST_STATUS_STALL;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void usb_standard_request_get_descriptor(
|
static usb_request_status_t usb_standard_request_get_descriptor(
|
||||||
usb_endpoint_t* const endpoint,
|
usb_endpoint_t* const endpoint,
|
||||||
const usb_transfer_stage_t stage
|
const usb_transfer_stage_t stage
|
||||||
) {
|
) {
|
||||||
switch( stage ) {
|
switch( stage ) {
|
||||||
case USB_TRANSFER_STAGE_SETUP:
|
case USB_TRANSFER_STAGE_SETUP:
|
||||||
usb_standard_request_get_descriptor_setup(endpoint);
|
return usb_standard_request_get_descriptor_setup(endpoint);
|
||||||
usb_endpoint_schedule_ack(endpoint->out);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_TRANSFER_STAGE_DATA:
|
case USB_TRANSFER_STAGE_DATA:
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_TRANSFER_STAGE_STATUS:
|
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,
|
usb_endpoint_t* const endpoint,
|
||||||
const usb_transfer_stage_t stage
|
const usb_transfer_stage_t stage
|
||||||
) {
|
) {
|
||||||
switch( stage ) {
|
switch( stage ) {
|
||||||
case USB_TRANSFER_STAGE_SETUP:
|
case USB_TRANSFER_STAGE_SETUP:
|
||||||
usb_set_address_deferred(endpoint->device, endpoint->setup.value_l);
|
return usb_standard_request_set_address_setup(endpoint);
|
||||||
usb_endpoint_schedule_ack(endpoint->in);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_TRANSFER_STAGE_DATA:
|
case USB_TRANSFER_STAGE_DATA:
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_TRANSFER_STAGE_STATUS:
|
case USB_TRANSFER_STAGE_STATUS:
|
||||||
/* NOTE: Not necessary to set address here, as DEVICEADR.USBADRA bit
|
/* NOTE: Not necessary to set address here, as DEVICEADR.USBADRA bit
|
||||||
* will cause controller to automatically perform set address
|
* will cause controller to automatically perform set address
|
||||||
* operation on IN ACK.
|
* operation on IN ACK.
|
||||||
*/
|
*/
|
||||||
break;
|
return USB_REQUEST_STATUS_OK;
|
||||||
|
|
||||||
default:
|
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
|
usb_endpoint_t* const endpoint
|
||||||
) {
|
) {
|
||||||
const uint8_t usb_configuration = endpoint->setup.value_l;
|
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_set_address_immediate(endpoint->device, 0);
|
||||||
}
|
}
|
||||||
usb_endpoint_schedule_ack(endpoint->in);
|
usb_endpoint_schedule_ack(endpoint->in);
|
||||||
|
return USB_REQUEST_STATUS_OK;
|
||||||
} else {
|
} 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,
|
usb_endpoint_t* const endpoint,
|
||||||
const usb_transfer_stage_t stage
|
const usb_transfer_stage_t stage
|
||||||
) {
|
) {
|
||||||
switch( stage ) {
|
switch( stage ) {
|
||||||
case USB_TRANSFER_STAGE_SETUP:
|
case USB_TRANSFER_STAGE_SETUP:
|
||||||
usb_standard_request_set_configuration_setup(endpoint);
|
return usb_standard_request_set_configuration_setup(endpoint);
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_TRANSFER_STAGE_DATA:
|
case USB_TRANSFER_STAGE_DATA:
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_TRANSFER_STAGE_STATUS:
|
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
|
usb_endpoint_t* const endpoint
|
||||||
) {
|
) {
|
||||||
if( endpoint->setup.length == 1 ) {
|
if( endpoint->setup.length == 1 ) {
|
||||||
@ -227,52 +224,50 @@ static void usb_standard_request_get_configuration_setup(
|
|||||||
endpoint->buffer[0] = endpoint->device->configuration->number;
|
endpoint->buffer[0] = endpoint->device->configuration->number;
|
||||||
}
|
}
|
||||||
usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 1);
|
usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 1);
|
||||||
|
usb_endpoint_schedule_ack(endpoint->out);
|
||||||
|
return USB_REQUEST_STATUS_OK;
|
||||||
} else {
|
} 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,
|
usb_endpoint_t* const endpoint,
|
||||||
const usb_transfer_stage_t stage
|
const usb_transfer_stage_t stage
|
||||||
) {
|
) {
|
||||||
switch( stage ) {
|
switch( stage ) {
|
||||||
case USB_TRANSFER_STAGE_SETUP:
|
case USB_TRANSFER_STAGE_SETUP:
|
||||||
usb_standard_request_get_configuration_setup(endpoint);
|
return usb_standard_request_get_configuration_setup(endpoint);
|
||||||
usb_endpoint_schedule_ack(endpoint->out);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_TRANSFER_STAGE_DATA:
|
case USB_TRANSFER_STAGE_DATA:
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_TRANSFER_STAGE_STATUS:
|
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,
|
usb_endpoint_t* const endpoint,
|
||||||
const usb_transfer_stage_t stage
|
const usb_transfer_stage_t stage
|
||||||
) {
|
) {
|
||||||
switch( endpoint->setup.request ) {
|
switch( endpoint->setup.request ) {
|
||||||
case USB_STANDARD_REQUEST_GET_DESCRIPTOR:
|
case USB_STANDARD_REQUEST_GET_DESCRIPTOR:
|
||||||
usb_standard_request_get_descriptor(endpoint, stage);
|
return usb_standard_request_get_descriptor(endpoint, stage);
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_STANDARD_REQUEST_SET_ADDRESS:
|
case USB_STANDARD_REQUEST_SET_ADDRESS:
|
||||||
usb_standard_request_set_address(endpoint, stage);
|
return usb_standard_request_set_address(endpoint, stage);
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_STANDARD_REQUEST_SET_CONFIGURATION:
|
case USB_STANDARD_REQUEST_SET_CONFIGURATION:
|
||||||
usb_standard_request_set_configuration(endpoint, stage);
|
return usb_standard_request_set_configuration(endpoint, stage);
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_STANDARD_REQUEST_GET_CONFIGURATION:
|
case USB_STANDARD_REQUEST_GET_CONFIGURATION:
|
||||||
usb_standard_request_get_configuration(endpoint, stage);
|
return usb_standard_request_get_configuration(endpoint, stage);
|
||||||
break;
|
|
||||||
|
default:
|
||||||
|
return USB_REQUEST_STATUS_STALL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
#include "usb_type.h"
|
#include "usb_type.h"
|
||||||
#include "usb_request.h"
|
#include "usb_request.h"
|
||||||
|
|
||||||
void usb_standard_request(
|
usb_request_status_t usb_standard_request(
|
||||||
usb_endpoint_t* const endpoint,
|
usb_endpoint_t* const endpoint,
|
||||||
const usb_transfer_stage_t stage
|
const usb_transfer_stage_t stage
|
||||||
);
|
);
|
||||||
|
41
host/libhackrf/CMakeLists.txt
Normal file
41
host/libhackrf/CMakeLists.txt
Normal file
@ -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)
|
||||||
|
|
38
host/libhackrf/FindUSB1.cmake
Normal file
38
host/libhackrf/FindUSB1.cmake
Normal file
@ -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, <montel@kde.org>
|
||||||
|
#
|
||||||
|
# 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)
|
35
host/libhackrf/examples/CMakeLists.txt
Normal file
35
host/libhackrf/examples/CMakeLists.txt
Normal file
@ -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)
|
175
host/libhackrf/examples/hackrf_max2837.c
Normal file
175
host/libhackrf/examples/hackrf_max2837.c
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
|
*
|
||||||
|
* 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 <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
|
static void usage() {
|
||||||
|
printf("\nUsage:\n");
|
||||||
|
printf("\t-n, --register <n>: 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 <v>: write register specified by last -n argument with value <v>\n");
|
||||||
|
printf("\nExamples:\n");
|
||||||
|
printf("\t<command> -n 12 -r # reads from register 12\n");
|
||||||
|
printf("\t<command> -r # reads all registers\n");
|
||||||
|
printf("\t<command> -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;
|
||||||
|
}
|
217
host/libhackrf/examples/hackrf_si5351c.c
Normal file
217
host/libhackrf/examples/hackrf_si5351c.c
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
|
*
|
||||||
|
* 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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
|
static void usage() {
|
||||||
|
printf("\nUsage:\n");
|
||||||
|
printf("\t-c, --config: print textual configuration information\n");
|
||||||
|
printf("\t-n, --register <n>: 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 <v>: write register specified by last -n argument with value <v>\n");
|
||||||
|
printf("\nExamples:\n");
|
||||||
|
printf("\t<command> -n 12 -r # reads from register 12\n");
|
||||||
|
printf("\t<command> -r # reads all registers\n");
|
||||||
|
printf("\t<command> -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;
|
||||||
|
}
|
222
host/libhackrf/examples/hackrf_transfer.c
Normal file
222
host/libhackrf/examples/hackrf_transfer.c
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
|
*
|
||||||
|
* 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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
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 <filename> # Receive data into file.\n");
|
||||||
|
printf("\t-t <filename> # 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;
|
||||||
|
}
|
69
host/libhackrf/src/CMakeLists.txt
Normal file
69
host/libhackrf/src/CMakeLists.txt
Normal file
@ -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} )
|
544
host/libhackrf/src/hackrf.c
Normal file
544
host/libhackrf/src/hackrf.c
Normal file
@ -0,0 +1,544 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
|
*
|
||||||
|
* 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 <stdlib.h>
|
||||||
|
|
||||||
|
#include <libusb.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
// 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_index<device->transfer_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_index<device->transfer_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_index<device->transfer_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_index<device->transfer_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";
|
||||||
|
}
|
||||||
|
}
|
75
host/libhackrf/src/hackrf.h
Normal file
75
host/libhackrf/src/hackrf.h
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
|
*
|
||||||
|
* 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 <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
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__
|
@ -27,7 +27,7 @@ device = usb.core.find(idVendor=0x1d50, idProduct=0x604b)
|
|||||||
device.set_configuration()
|
device.set_configuration()
|
||||||
|
|
||||||
def read_max2837_register(register_number):
|
def read_max2837_register(register_number):
|
||||||
return struct.unpack('>H', device.ctrl_transfer(0xC0, 3, 0, register_number, 2))[0]
|
return struct.unpack('<H', device.ctrl_transfer(0xC0, 3, 0, register_number, 2))[0]
|
||||||
|
|
||||||
def write_max2837_register(register_number, value):
|
def write_max2837_register(register_number, value):
|
||||||
device.ctrl_transfer(0x40, 2, value, register_number)
|
device.ctrl_transfer(0x40, 2, value, register_number)
|
@ -1,77 +0,0 @@
|
|||||||
# Hey Emacs, this is a -*- makefile -*-
|
|
||||||
#
|
|
||||||
# Copyright 2010 Michael Ossmann <mike@ossmann.com>
|
|
||||||
# Copyright 2012 Jared Boone <jared@sharebrained.com>
|
|
||||||
#
|
|
||||||
# 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
|
|
@ -1,292 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
|
||||||
*
|
|
||||||
* 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 <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <libusb-1.0/libusb.h>
|
|
||||||
|
|
||||||
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_index<transfer_count; transfer_index++) {
|
|
||||||
libusb_free_transfer(transfers[transfer_index]);
|
|
||||||
}
|
|
||||||
free(transfers);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct libusb_transfer** prepare_transfers(
|
|
||||||
libusb_device_handle* const device,
|
|
||||||
const uint_fast8_t endpoint_address,
|
|
||||||
const uint32_t transfer_count,
|
|
||||||
const uint32_t buffer_size,
|
|
||||||
libusb_transfer_cb_fn callback
|
|
||||||
) {
|
|
||||||
struct libusb_transfer** const transfers = calloc(transfer_count, sizeof(struct libusb_transfer));
|
|
||||||
if( transfers == NULL ) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(uint32_t transfer_index=0; transfer_index<transfer_count; transfer_index++) {
|
|
||||||
transfers[transfer_index] = libusb_alloc_transfer(0);
|
|
||||||
if( transfers[transfer_index] == NULL ) {
|
|
||||||
free_transfers(transfers, transfer_count);
|
|
||||||
printf("libusb_alloc_transfer() failed\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
libusb_fill_bulk_transfer(
|
|
||||||
transfers[transfer_index],
|
|
||||||
device,
|
|
||||||
endpoint_address,
|
|
||||||
(unsigned char*)malloc(buffer_size),
|
|
||||||
buffer_size,
|
|
||||||
callback,
|
|
||||||
NULL,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
if( transfers[transfer_index]->buffer == 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;
|
|
||||||
}
|
|
Reference in New Issue
Block a user