diff --git a/.gitignore b/.gitignore index 320f0b71..0c016b75 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ *.hex *.srec host/build/ +host/**/build # Operating system spew .DS_Store diff --git a/.travis.yml b/.travis.yml index ccdbafd6..8476bf27 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ language: c cache: apt sudo: false +dist: trusty os: - linux @@ -10,32 +11,48 @@ os: compiler: - gcc -# - clang + - clang + +matrix: + exclude: + - os: osx + compiler: gcc + - os: linux + compiler: clang before_script: -# - wget https://launchpad.net/gcc-arm-embedded/5.0/5-2016-q1-update/+download/gcc-arm-none-eabi-5_3-2016q1-20160330-linux.tar.bz2 -O /tmp/gcc-arm.tar.bz2 -# - tar -xvf /tmp/gcc-arm.tar.bz2 -# - export PATH=$PWD/gcc-arm-none-eabi-5_3-2016q1/bin:$PATH - export CFLAGS="-Wall -Wextra -Werror" before_install: - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install libusb; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew tap PX4/homebrew-px4; brew update; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install libusb fftw gcc-arm-none-eabi dfu-util; fi + # For virtualenv(?) reasons we can't apt-get install python-yaml + - pip install PyYAML script: - mkdir host/build - cd host/build - cmake .. - make -# - cd ../../firmware/hackrf_usb -# - mkdir build -# - cd build -# - export CC="arm-none-eabi-gcc" -# - export CXX="arm-none-eabi-g++" -# - cmake .. -# - make + - cd ../.. + - mkdir firmware/build-hackrf-one + - mkdir firmware/build-jawbreaker + - cd firmware/libopencm3 + - make + - cd ../build-hackrf-one + - cmake .. + - make + - cd ../build-jawbreaker + - cmake -DBOARD=JAWBREAKER .. + - make addons: apt: + sources: + - debian-sid packages: - libusb-1.0-0-dev + - libfftw3-dev + - gcc-arm-none-eabi + - libnewlib-arm-none-eabi + - dfu-util diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..4869b2a0 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,27 @@ +os: Visual Studio 2015 +clone_depth: 1 + +configuration: + - Release + - Debug + +install: + - appveyor DownloadFile "https://downloads.sourceforge.net/project/libusb/libusb-1.0/libusb-1.0.21/libusb-1.0.21.7z?r=https%3A%2F%2Fsourceforge.net%2Fprojects%2Flibusb%2Ffiles%2Flibusb-1.0%2Flibusb-1.0.21%2F&ts=1485478643&use_mirror=cytranet" -FileName "C:\libusb.7z" + - 7z x -y "C:\libusb.7z" -o"C:\libusb" + - appveyor DownloadFile "http://mirrors.kernel.org/sourceware/pthreads-win32/pthreads-w32-2-9-1-release.zip" -FileName "C:\pthreads-w32-release.zip" + - 7z x -y "C:\pthreads-w32-release.zip" -o"C:\pthreads" + - appveyor DownloadFile "http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/pkg-config_0.26-1_win32.zip" -FileName "C:\pkg-config_win32.zip" + - 7z x -y "C:\pkg-config_win32.zip" -o"C:\pkg-config" + + +build_script: + - mkdir c:\projects\hackrf\host\build + - cd c:\projects\hackrf\host\build + - cmake -G "Visual Studio 14 2015 Win64" \ + -DLIBUSB_LIBRARIES="C:\libusb\MS64\dll\libusb-1.0.lib" \ + -DLIBUSB_INCLUDE_DIR="C:\libusb\include\libusb-1.0" \ + -DTHREADS_PTHREADS_INCLUDE_DIR=c:\pthreads\Pre-built.2\include \ + -DTHREADS_PTHREADS_WIN32_LIBRARY=c:\pthreads\Pre-built.2\lib\x64\pthreadVC2.lib \ + -DPKG_CONFIG_EXECUTABLE="C:\pkg-config\bin\pkg-config.exe" \ + .. + - msbuild .\ALL_BUILD.vcxproj /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" diff --git a/firmware/README b/firmware/README index 293e162b..45b5aae5 100644 --- a/firmware/README +++ b/firmware/README @@ -6,7 +6,7 @@ projects. The cpld directory contains HDL source for the CPLD. The firmware is set up for compilation with the GCC toolchain available here: -https://launchpad.net/gcc-arm-embedded +https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads Required dependency: diff --git a/firmware/blinky/blinky.c b/firmware/blinky/blinky.c index 143c9940..631ce907 100644 --- a/firmware/blinky/blinky.c +++ b/firmware/blinky/blinky.c @@ -23,7 +23,6 @@ int main(void) { - int i; pin_setup(); /* enable all power supplies */ @@ -36,15 +35,13 @@ int main(void) led_on(LED2); led_on(LED3); - for (i = 0; i < 2000000; i++) /* Wait a bit. */ - __asm__("nop"); + delay(2000000); led_off(LED1); led_off(LED2); led_off(LED3); - for (i = 0; i < 2000000; i++) /* Wait a bit. */ - __asm__("nop"); + delay(2000000); } return 0; diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index ed398314..a6b8432a 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -75,11 +75,24 @@ static struct gpio_t gpio_max2837_b7 = GPIO(2, 15); /* MAX5864 SPI chip select (AD_CS) GPIO PinMux */ static struct gpio_t gpio_max5864_select = GPIO(2, 7); -/* RF LDO control */ -#ifdef JAWBREAKER -static struct gpio_t gpio_rf_ldo_enable = GPIO(2, 9); +#if (defined JAWBREAKER || defined HACKRF_ONE || defined RAD1O) +/* +static struct gpio_t gpio_sync_in_a = GPIO(3, 8); +static struct gpio_t gpio_sync_in_b = GPIO(3, 9); +static struct gpio_t gpio_sync_out_a = GPIO(3, 10); +static struct gpio_t gpio_sync_out_b = GPIO(3, 11); +*/ +static struct gpio_t gpio_sync_in_a = GPIO(3, 10); +static struct gpio_t gpio_sync_in_b = GPIO(3, 11); +static struct gpio_t gpio_sync_out_a = GPIO(3, 8); +static struct gpio_t gpio_sync_out_b = GPIO(3, 9); #endif +/* RF LDO control */ +// #ifdef JAWBREAKER +// static struct gpio_t gpio_rf_ldo_enable = GPIO(2, 9); +// #endif + /* RF supply (VAA) control */ #ifdef HACKRF_ONE static struct gpio_t gpio_vaa_disable = GPIO(2, 9); @@ -886,6 +899,15 @@ void pin_setup(void) { /* Safe state: start with VAA turned off: */ disable_rf_power(); + + scu_pinmux(SCU_PINMUX_GPIO3_10, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_GPIO3_11, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); + + gpio_input(&gpio_sync_in_a); + gpio_input(&gpio_sync_in_b); + + gpio_output(&gpio_sync_out_a); + gpio_output(&gpio_sync_out_b); #endif #ifdef RAD1O @@ -894,6 +916,15 @@ void pin_setup(void) { /* Safe state: start with VAA turned off: */ disable_rf_power(); + + scu_pinmux(SCU_PINMUX_GPIO3_10, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); + scu_pinmux(SCU_PINMUX_GPIO3_11, SCU_GPIO_PDN | SCU_CONF_FUNCTION0); + + gpio_input(&gpio_sync_in_a); + gpio_input(&gpio_sync_in_b); + + gpio_output(&gpio_sync_out_a); + gpio_output(&gpio_sync_out_b); #endif /* enable input on SCL and SDA pins */ @@ -950,3 +981,33 @@ void led_off(const led_t led) { void led_toggle(const led_t led) { gpio_toggle(&gpio_led[led]); } + +void hw_sync_syn() { + gpio_set(&gpio_sync_out_a); +} + +void hw_sync_stop() { + gpio_clear(&gpio_sync_out_a); + gpio_clear(&gpio_sync_out_b); +} + +void hw_sync_ack() { + gpio_set(&gpio_sync_out_b); +} + +void hw_sync_copy_state() { + if(gpio_read(&gpio_sync_in_a)) { + gpio_set(&gpio_sync_out_a); + } else { + gpio_clear(&gpio_sync_out_a); + } + if(gpio_read(&gpio_sync_in_b)) { + gpio_set(&gpio_sync_out_b); + } else { + gpio_clear(&gpio_sync_out_b); + } +} + +bool hw_sync_ready() { + return (gpio_read(&gpio_sync_in_a) && gpio_read(&gpio_sync_in_b)); +} diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index f0cb92c0..9f4e748a 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -264,6 +264,11 @@ typedef enum { TRANSCEIVER_MODE_CPLD_UPDATE = 4 } transceiver_mode_t; +typedef enum { + HW_SYNC_MODE_OFF = 0, + HW_SYNC_MODE_ON = 1, +} hw_sync_mode_t; + void delay(uint32_t duration); /* TODO: Hide these configurations */ @@ -279,6 +284,7 @@ extern w25q80bv_driver_t spi_flash; extern sgpio_config_t sgpio_config; extern rf_path_t rf_path; extern jtag_t jtag_cpld; +extern i2c_bus_t i2c0; void cpu_clock_init(void); void cpu_clock_pll1_low_speed(void); @@ -311,6 +317,13 @@ void led_on(const led_t led); void led_off(const led_t led); void led_toggle(const led_t led); +void hw_sync_syn(); +void hw_sync_stop(); +void hw_sync_ack(); +bool hw_sync_ready(); +void hw_sync_copy_state(); + + #ifdef __cplusplus } #endif diff --git a/firmware/common/i2c_lpc.c b/firmware/common/i2c_lpc.c index f7bf4393..607a1a0a 100644 --- a/firmware/common/i2c_lpc.c +++ b/firmware/common/i2c_lpc.c @@ -44,17 +44,23 @@ void i2c_lpc_transfer(i2c_bus_t* const bus, uint8_t* const data_rx, const size_t count_rx ) { const uint32_t port = (uint32_t)bus->obj; - i2c_tx_start(port); - i2c_tx_byte(port, (slave_address << 1) | I2C_WRITE); - for(size_t i=0; i 0)) { + i2c_tx_start(port); + i2c_tx_byte(port, (slave_address << 1) | I2C_WRITE); + for(i=0; i 0)) { i2c_tx_start(port); i2c_tx_byte(port, (slave_address << 1) | I2C_READ); - for(size_t i=0; i + * + * 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 "operacake.h" +#include "hackrf_core.h" + +#define OPERACAKE_PIN_OE(x) (x<<7) +#define OPERACAKE_PIN_U2CTRL1(x) (x<<6) +#define OPERACAKE_PIN_U2CTRL0(x) (x<<5) +#define OPERACAKE_PIN_U3CTRL1(x) (x<<4) +#define OPERACAKE_PIN_U3CTRL0(x) (x<<3) +#define OPERACAKE_PIN_U1CTRL(x) (x<<2) +#define OPERACAKE_PIN_LEDEN2(x) (x<<1) +#define OPERACAKE_PIN_LEDEN(x) (x<<0) + +#define OPERACAKE_PORT_A1 (OPERACAKE_PIN_U2CTRL0(0) | OPERACAKE_PIN_U2CTRL1(0)) +#define OPERACAKE_PORT_A2 (OPERACAKE_PIN_U2CTRL0(1) | OPERACAKE_PIN_U2CTRL1(0)) +#define OPERACAKE_PORT_A3 (OPERACAKE_PIN_U2CTRL0(0) | OPERACAKE_PIN_U2CTRL1(1)) +#define OPERACAKE_PORT_A4 (OPERACAKE_PIN_U2CTRL0(1) | OPERACAKE_PIN_U2CTRL1(1)) + +#define OPERACAKE_PORT_B1 (OPERACAKE_PIN_U3CTRL0(0) | OPERACAKE_PIN_U3CTRL1(0)) +#define OPERACAKE_PORT_B2 (OPERACAKE_PIN_U3CTRL0(1) | OPERACAKE_PIN_U3CTRL1(0)) +#define OPERACAKE_PORT_B3 (OPERACAKE_PIN_U3CTRL0(0) | OPERACAKE_PIN_U3CTRL1(1)) +#define OPERACAKE_PORT_B4 (OPERACAKE_PIN_U3CTRL0(1) | OPERACAKE_PIN_U3CTRL1(1)) + +#define OPERACAKE_SAMESIDE OPERACAKE_PIN_U1CTRL(1) +#define OPERACAKE_CROSSOVER OPERACAKE_PIN_U1CTRL(0) +#define OPERACAKE_EN_LEDS (OPERACAKE_PIN_LEDEN2(1) | OPERACAKE_PIN_LEDEN2(0)) +#define OPERACAKE_GPIO_EN OPERACAKE_PIN_OE(0) +#define OPERACAKE_GPIO_DISABLE OPERACAKE_PIN_OE(1) + +#define OPERACAKE_REG_INPUT 0x00 +#define OPERACAKE_REG_OUTPUT 0x01 +#define OPERACAKE_REG_POLARITY 0x02 +#define OPERACAKE_REG_CONFIG 0x03 + +#define OPERACAKE_DEFAULT_OUTPUT (OPERACAKE_GPIO_DISABLE | OPERACAKE_SAMESIDE \ + | OPERACAKE_PORT_A1 | OPERACAKE_PORT_B1 \ + | OPERACAKE_EN_LEDS) +#define OPERACAKE_CONFIG_ALL_OUTPUT (0x00) + +#define OPERACAKE_DEFAULT_ADDRESS 0x18 + +i2c_bus_t* const oc_bus = &i2c0; +uint8_t operacake_boards[8] = {0,0,0,0,0,0,0,0}; + +/* read single register */ +uint8_t operacake_read_reg(i2c_bus_t* const bus, uint8_t address, uint8_t reg) { + const uint8_t data_tx[] = { reg }; + uint8_t data_rx[] = { 0x00 }; + i2c_bus_transfer(bus, address, data_tx, 1, data_rx, 1); + return data_rx[0]; +} + +/* Write to one of the PCA9557 registers */ +void operacake_write_reg(i2c_bus_t* const bus, uint8_t address, uint8_t reg, uint8_t value) { + const uint8_t data[] = {reg, value}; + i2c_bus_transfer(bus, address, data, 2, NULL, 0); +} + +uint8_t operacake_init(void) { + uint8_t reg, addr, i, j = 0; + /* Find connected operacakes */ + for(i=0; i<8; i++) { + addr = OPERACAKE_DEFAULT_ADDRESS | i; + operacake_write_reg(oc_bus, addr, OPERACAKE_REG_OUTPUT, + OPERACAKE_DEFAULT_OUTPUT); + operacake_write_reg(oc_bus, addr, OPERACAKE_REG_CONFIG, + OPERACAKE_CONFIG_ALL_OUTPUT); + reg = operacake_read_reg(oc_bus, addr, OPERACAKE_REG_CONFIG); + if(reg==OPERACAKE_CONFIG_ALL_OUTPUT) + operacake_boards[j++] = addr; + } + return 0; +} + +uint8_t port_to_pins(uint8_t port) { + switch(port) { + case OPERACAKE_PA1: + return OPERACAKE_PORT_A1; + case OPERACAKE_PA2: + return OPERACAKE_PORT_A2; + case OPERACAKE_PA3: + return OPERACAKE_PORT_A3; + case OPERACAKE_PA4: + return OPERACAKE_PORT_A4; + + case OPERACAKE_PB1: + return OPERACAKE_PORT_B1; + case OPERACAKE_PB2: + return OPERACAKE_PORT_B2; + case OPERACAKE_PB3: + return OPERACAKE_PORT_B3; + case OPERACAKE_PB4: + return OPERACAKE_PORT_B4; + } + return 0xFF; +} + +uint8_t operacake_set_ports(uint8_t address, uint8_t PA, uint8_t PB) { + uint8_t side, pa, pb, reg; + /* Start with some error checking, + * which should have been done either + * on the host or elsewhere in firmware + */ + if((PA > OPERACAKE_PB4) || (PB > OPERACAKE_PB4)) { + return 1; + } + /* Check which side PA and PB are on */ + if(((PA <= OPERACAKE_PA4) && (PB <= OPERACAKE_PA4)) + || ((PA > OPERACAKE_PA4) && (PB > OPERACAKE_PA4))) { + return 1; + } + + if(PA > OPERACAKE_PA4) { + side = OPERACAKE_CROSSOVER; + } else { + side = OPERACAKE_SAMESIDE; + } + + pa = port_to_pins(PA); + pb = port_to_pins(PB); + + reg = (OPERACAKE_GPIO_DISABLE | side + | pa | pb | OPERACAKE_EN_LEDS); + operacake_write_reg(oc_bus, address, OPERACAKE_REG_OUTPUT, reg); + return 0; +} + diff --git a/firmware/common/operacake.h b/firmware/common/operacake.h new file mode 100644 index 00000000..0fda1f2b --- /dev/null +++ b/firmware/common/operacake.h @@ -0,0 +1,53 @@ +/* + * Copyright 2016 Dominic Spill + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __OPERACAKE_H +#define __OPERACAKE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include "i2c_bus.h" + +#define OPERACAKE_PA1 0 +#define OPERACAKE_PA2 1 +#define OPERACAKE_PA3 2 +#define OPERACAKE_PA4 3 + +#define OPERACAKE_PB1 4 +#define OPERACAKE_PB2 5 +#define OPERACAKE_PB3 6 +#define OPERACAKE_PB4 7 + +/* Up to 8 Operacake boards can be used with one HackRF */ +extern uint8_t operacake_boards[8]; + +uint8_t operacake_init(void); +uint8_t operacake_set_ports(uint8_t address, uint8_t PA, uint8_t PB); + +#ifdef __cplusplus +} +#endif + +#endif /* __OPERACAKE_H */ diff --git a/firmware/common/rf_path.c b/firmware/common/rf_path.c index f4aa3ff4..5f653e38 100644 --- a/firmware/common/rf_path.c +++ b/firmware/common/rf_path.c @@ -230,6 +230,7 @@ static void switchctrl_set_rad1o(rf_path_t* const rf_path, uint8_t ctrl) { static void switchctrl_set(rf_path_t* const rf_path, const uint8_t gpo) { #ifdef JAWBREAKER + (void) rf_path; /* silence unused param warning */ mixer_set_gpo(&mixer, gpo); #elif HACKRF_ONE switchctrl_set_hackrf_one(rf_path, gpo); @@ -274,9 +275,13 @@ void rf_path_pin_setup(rf_path_t* const rf_path) { gpio_output(rf_path->gpio_tx); gpio_output(rf_path->gpio_mix_bypass); gpio_output(rf_path->gpio_rx); -#endif -#ifdef RAD1O + /* + * Safe (initial) switch settings turn off both amplifiers and antenna port + * power and enable both amp bypass and mixer bypass. + */ + switchctrl_set(rf_path, SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_MIX_BYPASS); +#elif RAD1O /* Configure RF switch control signals */ scu_pinmux(SCU_BY_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); scu_pinmux(SCU_BY_AMP_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); @@ -305,13 +310,15 @@ void rf_path_pin_setup(rf_path_t* const rf_path) { gpio_output(rf_path->gpio_low_high_filt_n); gpio_output(rf_path->gpio_tx_amp); gpio_output(rf_path->gpio_rx_lna); -#endif /* * Safe (initial) switch settings turn off both amplifiers and antenna port * power and enable both amp bypass and mixer bypass. */ switchctrl_set(rf_path, SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_MIX_BYPASS); +#else + (void) rf_path; /* silence unused param warning */ +#endif } void rf_path_init(rf_path_t* const rf_path) { diff --git a/firmware/common/rffc5071.c b/firmware/common/rffc5071.c index 71ba9f5c..10542b6c 100644 --- a/firmware/common/rffc5071.c +++ b/firmware/common/rffc5071.c @@ -117,6 +117,10 @@ void rffc5071_setup(rffc5071_driver_t* const drv) /* GPOs are active at all times */ set_RFFC5071_GATE(drv, 1); + /* Output LOCK status on GPO4 and enable lock detect */ + set_RFFC5071_LOCK(drv, 1); + set_RFFC5071_LDEN(drv, 1); + rffc5071_regs_commit(drv); } @@ -254,13 +258,6 @@ uint64_t rffc5071_config_synth_int(rffc5071_driver_t* const drv, uint16_t lo) { tune_freq_hz = (REF_FREQ * (tmp_n >> 5ULL) * fbkdiv * FREQ_ONE_MHZ) / (lodiv * (1 << 24ULL)); - /* Path 1 */ - set_RFFC5071_P1LODIV(drv, n_lo); - set_RFFC5071_P1N(drv, n); - set_RFFC5071_P1PRESC(drv, fbkdiv >> 1); - set_RFFC5071_P1NMSB(drv, p1nmsb); - set_RFFC5071_P1NLSB(drv, p1nlsb); - /* Path 2 */ set_RFFC5071_P2LODIV(drv, n_lo); set_RFFC5071_P2N(drv, n); diff --git a/firmware/common/rffc5071_spi.c b/firmware/common/rffc5071_spi.c index 7c3d9da2..5699f93c 100644 --- a/firmware/common/rffc5071_spi.c +++ b/firmware/common/rffc5071_spi.c @@ -94,10 +94,7 @@ void rffc5071_spi_stop(spi_bus_t* const bus) { static void rffc5071_spi_serial_delay(spi_bus_t* const bus) { (void)bus; - volatile uint32_t i; - - for (i = 0; i < 2; i++) - __asm__("nop"); + __asm__("nop"); } static void rffc5071_spi_sck(spi_bus_t* const bus) { diff --git a/firmware/common/streaming.c b/firmware/common/streaming.c index 07db7b64..61105f76 100644 --- a/firmware/common/streaming.c +++ b/firmware/common/streaming.c @@ -37,4 +37,4 @@ void baseband_streaming_disable(sgpio_config_t* const sgpio_config) { sgpio_cpld_stream_disable(sgpio_config); nvic_disable_irq(NVIC_SGPIO_IRQ); -} \ No newline at end of file +} diff --git a/firmware/dfu.py b/firmware/dfu.py new file mode 100644 index 00000000..d8057505 --- /dev/null +++ b/firmware/dfu.py @@ -0,0 +1,8 @@ +import os.path +import struct +import sys + +with open("_header.bin", "wb") as f: + x = struct.pack(' -#include - #include #include +#include "tuning.h" + #include "usb.h" #include "usb_standard_request.h" @@ -40,77 +40,14 @@ #include "usb_api_cpld.h" #include "usb_api_register.h" #include "usb_api_spiflash.h" - +#include "usb_api_operacake.h" +#include "operacake.h" +#include "usb_api_sweep.h" #include "usb_api_transceiver.h" -#include "sgpio_isr.h" #include "usb_bulk_buffer.h" #include "hackrf-ui.h" -static volatile transceiver_mode_t _transceiver_mode = TRANSCEIVER_MODE_OFF; - -void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) { - baseband_streaming_disable(&sgpio_config); - - usb_endpoint_disable(&usb_endpoint_bulk_in); - usb_endpoint_disable(&usb_endpoint_bulk_out); - - _transceiver_mode = new_transceiver_mode; - - if( _transceiver_mode == TRANSCEIVER_MODE_RX ) { - led_off(LED3); - led_on(LED2); - usb_endpoint_init(&usb_endpoint_bulk_in); - rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_RX); - vector_table.irq[NVIC_SGPIO_IRQ] = sgpio_isr_rx; - } else if (_transceiver_mode == TRANSCEIVER_MODE_TX) { - led_off(LED2); - led_on(LED3); - usb_endpoint_init(&usb_endpoint_bulk_out); - rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_TX); - vector_table.irq[NVIC_SGPIO_IRQ] = sgpio_isr_tx; - } else { - led_off(LED2); - led_off(LED3); - rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_OFF); - vector_table.irq[NVIC_SGPIO_IRQ] = sgpio_isr_rx; - } - - if( _transceiver_mode != TRANSCEIVER_MODE_OFF ) { - si5351c_activate_best_clock_source(&clock_gen); - baseband_streaming_enable(&sgpio_config); - } -} - -transceiver_mode_t transceiver_mode(void) { - return _transceiver_mode; -} - -usb_request_status_t usb_vendor_request_set_transceiver_mode( - usb_endpoint_t* const endpoint, - const usb_transfer_stage_t stage -) { - if( stage == USB_TRANSFER_STAGE_SETUP ) { - switch( endpoint->setup.value ) { - case TRANSCEIVER_MODE_OFF: - case TRANSCEIVER_MODE_RX: - case TRANSCEIVER_MODE_TX: - set_transceiver_mode(endpoint->setup.value); - usb_transfer_schedule_ack(endpoint->in); - return USB_REQUEST_STATUS_OK; - case TRANSCEIVER_MODE_CPLD_UPDATE: - usb_endpoint_init(&usb_endpoint_bulk_out); - start_cpld_update = true; - usb_transfer_schedule_ack(endpoint->in); - return USB_REQUEST_STATUS_OK; - default: - 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, @@ -147,6 +84,11 @@ static const usb_request_handler_fn vendor_request_handler[] = { #endif usb_vendor_request_set_freq_explicit, usb_vendor_request_read_wcid, // USB_WCID_VENDOR_REQ + usb_vendor_request_init_sweep, + usb_vendor_request_operacake_get_boards, + usb_vendor_request_operacake_set_ports, + usb_vendor_request_set_hw_sync_mode, + usb_vendor_request_reset }; static const uint32_t vendor_request_handler_count = @@ -247,13 +189,23 @@ int main(void) { usb_run(&usb_device); rf_path_init(&rf_path); + operacake_init(); unsigned int phase = 0; + while(true) { // Check whether we need to initiate a CPLD update if (start_cpld_update) cpld_update(); + // Check whether we need to initiate sweep mode + if (start_sweep_mode) { + start_sweep_mode = false; + sweep_mode(); + } + + start_streaming_on_hw_sync(); + // Set up IN transfer of buffer 0. if ( usb_bulk_buffer_offset >= 16384 && phase == 1 @@ -267,7 +219,7 @@ int main(void) { ); phase = 0; } - + // Set up IN transfer of buffer 1. if ( usb_bulk_buffer_offset < 16384 && phase == 0 @@ -282,6 +234,6 @@ int main(void) { phase = 1; } } - + return 0; } diff --git a/firmware/hackrf_usb/usb_api_board_info.c b/firmware/hackrf_usb/usb_api_board_info.c index 7cad222f..ba2a6ddd 100644 --- a/firmware/hackrf_usb/usb_api_board_info.c +++ b/firmware/hackrf_usb/usb_api_board_info.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -91,3 +92,13 @@ usb_request_status_t usb_vendor_request_read_partid_serialno( } return USB_REQUEST_STATUS_OK; } + +usb_request_status_t usb_vendor_request_reset( + usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) +{ + if (stage == USB_TRANSFER_STAGE_SETUP) { + wwdt_reset(100000); + usb_transfer_schedule_ack(endpoint->in); + } + return USB_REQUEST_STATUS_OK; +} \ No newline at end of file diff --git a/firmware/hackrf_usb/usb_api_board_info.h b/firmware/hackrf_usb/usb_api_board_info.h index 90a76cb9..39824b8d 100644 --- a/firmware/hackrf_usb/usb_api_board_info.h +++ b/firmware/hackrf_usb/usb_api_board_info.h @@ -39,5 +39,7 @@ usb_request_status_t usb_vendor_request_read_version_string( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); usb_request_status_t usb_vendor_request_read_partid_serialno( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); +usb_request_status_t usb_vendor_request_reset( + usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); #endif /* end of include guard: __USB_API_BOARD_INFO_H__ */ diff --git a/firmware/hackrf_usb/usb_api_operacake.c b/firmware/hackrf_usb/usb_api_operacake.c new file mode 100644 index 00000000..d9e5affa --- /dev/null +++ b/firmware/hackrf_usb/usb_api_operacake.c @@ -0,0 +1,49 @@ +/* + * Copyright 2016 Dominic Spill + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "usb_api_operacake.h" +#include "usb_queue.h" + +#include + +usb_request_status_t usb_vendor_request_operacake_get_boards( + usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) +{ + if (stage == USB_TRANSFER_STAGE_SETUP) { + usb_transfer_schedule_block(endpoint->in, operacake_boards, 8, NULL, NULL); + usb_transfer_schedule_ack(endpoint->out); + } + return USB_REQUEST_STATUS_OK; +} + +usb_request_status_t usb_vendor_request_operacake_set_ports( + usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) +{ + uint8_t address, port_a, port_b; + address = endpoint->setup.value & 0xFF; + port_a = endpoint->setup.index & 0xFF; + port_b = (endpoint->setup.index >> 8) & 0xFF; + if (stage == USB_TRANSFER_STAGE_SETUP) { + operacake_set_ports(address, port_a, port_b); + usb_transfer_schedule_ack(endpoint->in); + } + return USB_REQUEST_STATUS_OK; +} diff --git a/firmware/hackrf_usb/usb_api_operacake.h b/firmware/hackrf_usb/usb_api_operacake.h new file mode 100644 index 00000000..4339488d --- /dev/null +++ b/firmware/hackrf_usb/usb_api_operacake.h @@ -0,0 +1,34 @@ +/* + * Copyright 2016 Dominic Spill + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __USB_API_OPERACAKE_H__ +#define __USB_API_OPERACAKE_H__ + +#include +#include + +usb_request_status_t usb_vendor_request_operacake_get_boards( + usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); + +usb_request_status_t usb_vendor_request_operacake_set_ports( + usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); + +#endif /* end of include guard: __USB_API_OPERACAKE_H__ */ diff --git a/firmware/hackrf_usb/usb_api_sweep.c b/firmware/hackrf_usb/usb_api_sweep.c new file mode 100644 index 00000000..581faacc --- /dev/null +++ b/firmware/hackrf_usb/usb_api_sweep.c @@ -0,0 +1,109 @@ +/* + * Copyright 2016 Mike Walters, Dominic Spill + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "usb_api_sweep.h" +#include "usb_queue.h" +#include +#include +#include "usb_api_transceiver.h" +#include "usb_bulk_buffer.h" +#include "tuning.h" +#include "usb_endpoint.h" + +#define MIN(x,y) ((x)<(y)?(x):(y)) +#define MAX(x,y) ((x)>(y)?(x):(y)) +#define FREQ_GRANULARITY 1000000 +#define MIN_FREQ 1 +#define MAX_FREQ 6000 +#define MAX_FREQ_COUNT 1000 + +volatile bool start_sweep_mode = false; +static uint64_t sweep_freq; +bool odd = true; +static uint16_t frequencies[MAX_FREQ_COUNT]; +static uint16_t frequency_count = 0; +static uint32_t dwell_blocks = 0; + +usb_request_status_t usb_vendor_request_init_sweep( + usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) +{ + uint32_t dwell_time; + if (stage == USB_TRANSFER_STAGE_SETUP) { + dwell_time = (endpoint->setup.index << 16) | endpoint->setup.value; + dwell_blocks = dwell_time / 0x4000; + frequency_count = endpoint->setup.length / sizeof(uint16_t); + usb_transfer_schedule_block(endpoint->out, &frequencies, + endpoint->setup.length, NULL, NULL); + } else if (stage == USB_TRANSFER_STAGE_DATA) { + sweep_freq = frequencies[0]; + set_freq(sweep_freq*FREQ_GRANULARITY); + start_sweep_mode = true; + usb_transfer_schedule_ack(endpoint->in); + } + return USB_REQUEST_STATUS_OK; +} + +void sweep_mode(void) { + unsigned int blocks_queued = 0; + unsigned int phase = 0; + unsigned int ifreq = 0; + + uint8_t *buffer; + bool transfer = false; + + while(transceiver_mode() != TRANSCEIVER_MODE_OFF) { + // Set up IN transfer of buffer 0. + if ( usb_bulk_buffer_offset >= 16384 && phase == 1) { + transfer = true; + buffer = &usb_bulk_buffer[0x0000]; + phase = 0; + blocks_queued++; + } + + // Set up IN transfer of buffer 1. + if ( usb_bulk_buffer_offset < 16384 && phase == 0) { + transfer = true; + buffer = &usb_bulk_buffer[0x4000]; + phase = 1; + blocks_queued++; + } + + if (transfer) { + *(uint16_t*)buffer = 0x7F7F; + *(uint16_t*)(buffer+2) = sweep_freq; + usb_transfer_schedule_block( + &usb_endpoint_bulk_in, + buffer, + 0x4000, + NULL, NULL + ); + transfer = false; + } + + if (blocks_queued >= dwell_blocks) { + if(++ifreq >= frequency_count) + ifreq = 0; + sweep_freq = frequencies[ifreq]; + set_freq(sweep_freq*FREQ_GRANULARITY); + blocks_queued = 0; + } + } +} diff --git a/firmware/hackrf_usb/usb_api_sweep.h b/firmware/hackrf_usb/usb_api_sweep.h new file mode 100644 index 00000000..828647cd --- /dev/null +++ b/firmware/hackrf_usb/usb_api_sweep.h @@ -0,0 +1,36 @@ +/* + * Copyright 2016 Mike Walters, Dominic Spill + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __USB_API_SCAN_H__ +#define __USB_API_SCAN_H__ + +#include +#include +#include + +extern volatile bool start_sweep_mode; + +usb_request_status_t usb_vendor_request_init_sweep( + usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); + +void sweep_mode(void); + +#endif /* __USB_API_SPCAN_H__ */ diff --git a/firmware/hackrf_usb/usb_api_transceiver.c b/firmware/hackrf_usb/usb_api_transceiver.c index 5d6ae4e8..4532d28a 100644 --- a/firmware/hackrf_usb/usb_api_transceiver.c +++ b/firmware/hackrf_usb/usb_api_transceiver.c @@ -23,10 +23,16 @@ #include "usb_api_transceiver.h" #include "hackrf-ui.h" +#include +#include +#include "sgpio_isr.h" + +#include "usb_api_cpld.h" // Remove when CPLD update is handled elsewhere #include #include #include +#include #include #include @@ -226,3 +232,105 @@ usb_request_status_t usb_vendor_request_set_freq_explicit( return USB_REQUEST_STATUS_OK; } } + +static volatile transceiver_mode_t _transceiver_mode = TRANSCEIVER_MODE_OFF; +static volatile hw_sync_mode_t _hw_sync_mode = HW_SYNC_MODE_OFF; + +void set_hw_sync_mode(const hw_sync_mode_t new_hw_sync_mode) { + _hw_sync_mode = new_hw_sync_mode; +} + +transceiver_mode_t transceiver_mode(void) { + return _transceiver_mode; +} + +void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) { + baseband_streaming_disable(&sgpio_config); + + usb_endpoint_disable(&usb_endpoint_bulk_in); + usb_endpoint_disable(&usb_endpoint_bulk_out); + + _transceiver_mode = new_transceiver_mode; + + if( _transceiver_mode == TRANSCEIVER_MODE_RX ) { + led_off(LED3); + led_on(LED2); + usb_endpoint_init(&usb_endpoint_bulk_in); + rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_RX); + vector_table.irq[NVIC_SGPIO_IRQ] = sgpio_isr_rx; + } else if (_transceiver_mode == TRANSCEIVER_MODE_TX) { + led_off(LED2); + led_on(LED3); + usb_endpoint_init(&usb_endpoint_bulk_out); + rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_TX); + vector_table.irq[NVIC_SGPIO_IRQ] = sgpio_isr_tx; + } else { + led_off(LED2); + led_off(LED3); + rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_OFF); + vector_table.irq[NVIC_SGPIO_IRQ] = sgpio_isr_rx; + + hw_sync_stop(); + } + + hw_sync_stop(); + + if( _transceiver_mode != TRANSCEIVER_MODE_OFF ) { + si5351c_activate_best_clock_source(&clock_gen); + + if( _hw_sync_mode != HW_SYNC_MODE_OFF) { + hw_sync_syn(); + } else { + baseband_streaming_enable(&sgpio_config); + } + } +} + +usb_request_status_t usb_vendor_request_set_transceiver_mode( + usb_endpoint_t* const endpoint, + const usb_transfer_stage_t stage) +{ + if( stage == USB_TRANSFER_STAGE_SETUP ) { + switch( endpoint->setup.value ) { + case TRANSCEIVER_MODE_OFF: + case TRANSCEIVER_MODE_RX: + case TRANSCEIVER_MODE_TX: + set_transceiver_mode(endpoint->setup.value); + usb_transfer_schedule_ack(endpoint->in); + return USB_REQUEST_STATUS_OK; + case TRANSCEIVER_MODE_CPLD_UPDATE: + usb_endpoint_init(&usb_endpoint_bulk_out); + start_cpld_update = true; + usb_transfer_schedule_ack(endpoint->in); + return USB_REQUEST_STATUS_OK; + default: + return USB_REQUEST_STATUS_STALL; + } + } else { + return USB_REQUEST_STATUS_OK; + } +} + +usb_request_status_t usb_vendor_request_set_hw_sync_mode( + usb_endpoint_t* const endpoint, + const usb_transfer_stage_t stage) +{ + if( stage == USB_TRANSFER_STAGE_SETUP ) { + set_hw_sync_mode(endpoint->setup.value); + usb_transfer_schedule_ack(endpoint->in); + return USB_REQUEST_STATUS_OK; + } else { + return USB_REQUEST_STATUS_OK; + } +} + +void start_streaming_on_hw_sync() +{ + if( _hw_sync_mode != HW_SYNC_MODE_OFF) { + while(!hw_sync_ready()) { } + hw_sync_ack(); + led_on(LED3); + + baseband_streaming_enable(&sgpio_config); + } +} diff --git a/firmware/hackrf_usb/usb_api_transceiver.h b/firmware/hackrf_usb/usb_api_transceiver.h index 24244025..eb4a5c35 100644 --- a/firmware/hackrf_usb/usb_api_transceiver.h +++ b/firmware/hackrf_usb/usb_api_transceiver.h @@ -27,6 +27,7 @@ #include #include +void set_hw_sync_mode(const hw_sync_mode_t new_hw_sync_mode); usb_request_status_t usb_vendor_request_set_transceiver_mode( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); @@ -52,5 +53,11 @@ usb_request_status_t usb_vendor_request_set_antenna_enable( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); usb_request_status_t usb_vendor_request_set_freq_explicit( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); +usb_request_status_t usb_vendor_request_set_hw_sync_mode( + usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); + +transceiver_mode_t transceiver_mode(void); +void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode); +void start_streaming_on_hw_sync(); #endif/*__USB_API_TRANSCEIVER_H__*/ diff --git a/firmware/libopencm3 b/firmware/libopencm3 index 50c51c7b..d3d6f3e7 160000 --- a/firmware/libopencm3 +++ b/firmware/libopencm3 @@ -1 +1 @@ -Subproject commit 50c51c7b5fd2f113440241bb13be3a0e64724b8d +Subproject commit d3d6f3e74b34593d1b56175abe5b4cb72da4ec9d diff --git a/firmware/sgpio-rx/sgpio-rx.c b/firmware/sgpio-rx/sgpio-rx.c index 4922541e..4eec4133 100644 --- a/firmware/sgpio-rx/sgpio-rx.c +++ b/firmware/sgpio-rx/sgpio-rx.c @@ -46,20 +46,20 @@ void tx_test() { } void rx_test() { - volatile uint32_t buffer[4096]; - uint32_t i = 0; + volatile uint32_t buffer[4096]; + uint32_t i = 0; uint32_t magsq; int8_t sigi, sigq; - rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_RX); - sgpio_cpld_stream_enable(&sgpio_config); + rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_RX); + sgpio_cpld_stream_enable(&sgpio_config); led_on(LED2); - while(true) { - while(SGPIO_STATUS_1 == 0); + while(true) { + while(SGPIO_STATUS_1 == 0); led_on(LED1); - SGPIO_CLR_STATUS_1 = 1; - buffer[i & 4095] = SGPIO_REG_SS(SGPIO_SLICE_A); + SGPIO_CLR_STATUS_1 = 1; + buffer[i & 4095] = SGPIO_REG_SS(SGPIO_SLICE_A); /* find the magnitude squared */ sigi = buffer[i & 4095] & 0xff; @@ -72,7 +72,7 @@ void rx_test() { else led_off(LED3); i++; - } + } } int main(void) { @@ -86,7 +86,7 @@ int main(void) { enable_rf_power(); #endif cpu_clock_init(); - rf_path_init(&rf_path); + rf_path_init(&rf_path); set_freq(freq); diff --git a/host/README.md b/host/README.md index 6b7f8bb4..5efd28f6 100644 --- a/host/README.md +++ b/host/README.md @@ -4,34 +4,34 @@ produce a low cost, open source software radio platform. ##How to build the host software on Linux: ###Prerequisites for Linux (Debian/Ubuntu): - -`sudo apt-get install build-essential cmake libusb-1.0-0-dev pkg-config` +`sudo apt-get install build-essential cmake libusb-1.0-0-dev pkg-config libfftw3-dev` ###Build host software on Linux: +``` +mkdir host/build +cd host/build +cmake .. +make +sudo make install +sudo ldconfig +``` -`cd host` +By defualt this will attempt to install a udev rule to '/etc/udev/rules.d` to +provide the `usb` or `plugdev` group access to HackRF. If your setup requires +the udev rule to be installed elsewhere you can modify the path with +`-DUDEV_RULES_PATH=/path/to/udev`. -`mkdir build` - -`cd build` - -`cmake ../ -DINSTALL_UDEV_RULES=ON` - -`make` - -`sudo make install` - -`sudo ldconfig` +Note: The udev rule is not installed for by default for PyBOMBS installs as +they do not ususally get installed with root privileges. ##Clean CMake temporary files/dirs: - -`cd host/build` - -`rm -rf *` +``` +cd host/build +rm -rf * +``` ##How to build host software on Windows: - -###Prerequisites for cygwin or mingw: +###Prerequisites for cygwin, mingw, or Visual Studio: * cmake-2.8.12.1 or more see http://www.cmake.org/cmake/resources/software.html * libusbx-1.0.18 or more see http://sourceforge.net/projects/libusbx/files/latest/download?source=files @@ -43,56 +43,45 @@ produce a low cost, open source software radio platform. Ctrl C is not managed correctly and especially for hackrf_transfer the Ctrl C(abort) will not stop correctly and will corrupt the file. ###For Cygwin: - -`cd host` - -`mkdir build` - -`cd build` - -`cmake ../ -G "Unix Makefiles" -DCMAKE_LEGACY_CYGWIN_WIN32=1 -DLIBUSB_INCLUDE_DIR=/usr/local/include/libusb-1.0/` - -`make` - -`make install` - +``` +mkdir host/build +cd host/build +cmake ../ -G "Unix Makefiles" -DCMAKE_LEGACY_CYGWIN_WIN32=1 -DLIBUSB_INCLUDE_DIR=/usr/local/include/libusb-1.0/ +make +make install +``` ###For MinGW: +``` +mkdir host/build +cd host/build +cmake ../ -G "MSYS Makefiles" -DLIBUSB_INCLUDE_DIR=/usr/local/include/libusb-1.0/ +make +make install +``` -`cd host` +###For Visual Studio 2015 x64 +``` +c:\hackrf\host\build> cmake ../ -G "Visual Studio 14 2015 Win64" \ +-DLIBUSB_INCLUDE_DIR=c:\libusb-1.0.18-win\include\libusb-1.0 \ +-DLIBUSB_LIBRARIES=c:\libusb-1.0.18-win\MS64\static\libusb-1.0.lib \ +-DTHREADS_PTHREADS_INCLUDE_DIR=c:\pthreads-w32-2-9-1-release\Pre-built.2\include \ +-DTHREADS_PTHREADS_WIN32_LIBRARY=c:\pthreads-w32-2-9-1-release\Pre-built.2\lib\x64\pthreadVC2.lib +``` -`mkdir build` - -`cd build` - -Normal version: - -* -`cmake ../ -G "MSYS Makefiles" -DLIBUSB_INCLUDE_DIR=/usr/local/include/libusb-1.0/` - -Debug version: - -* -`cmake ../ -G "MSYS Makefiles" -DCMAKE_BUILD_TYPE=Debug -DLIBUSB_INCLUDE_DIR=/usr/local/include/libusb-1.0/` - -`make` - -`make install` - -###For Visual Studio 2012 x64 -`c:\hackrf\host\cmake>cmake ../ -G "Visual Studio 11 2012 Win64" -DLIBUSB_INCLUDE_DIR=c:\libusb-1.0.18-win\include\libusb-1.0 -DLIBUSB_LIBRARIES=c:\libusb-1.0.18-win\MS64\static\libusb-1.0.lib -DTHREADS_PTHREADS_INCLUDE_DIR=c:\pthreads-w32-2-9-1-release\Pre-built.2\include -DTHREADS_PTHREADS_WIN32_LIBRARY=c:\pthreads-w32-2-9-1-release\Pre-built.2\lib\x64\pthreadVC2.lib` - -Solution file: `c:\hackrf\host\cmake\hackrf_all.sln` +Cmake will produce a solution file named `hackrf_all.sln` and a series of +project files which can be used with msbuild as follows: +`c:\hackrf\host\build> msbuild ALL_BUILD.vcxproj` ##How to build host the software on FreeBSD - You can use the binary package: `# pkg install hackrf` You can build and install from ports: -`# cd /usr/ports/comms/hackrf` -`# make install` - +``` +# cd /usr/ports/comms/hackrf +# make install +``` principal author: Michael Ossmann diff --git a/host/cmake/modules/FindFFTW.cmake b/host/cmake/modules/FindFFTW.cmake new file mode 100644 index 00000000..00c3401c --- /dev/null +++ b/host/cmake/modules/FindFFTW.cmake @@ -0,0 +1,22 @@ +# - Find FFTW +# Find the native FFTW includes and library +# +# FFTW_INCLUDES - where to find fftw3.h +# FFTW_LIBRARIES - List of libraries when using FFTW. +# FFTW_FOUND - True if FFTW found. + +if (FFTW_INCLUDES) + # Already in cache, be silent + set (FFTW_FIND_QUIETLY TRUE) +endif (FFTW_INCLUDES) + +find_path (FFTW_INCLUDES fftw3.h) + +find_library (FFTW_LIBRARIES NAMES fftw3) + +# handle the QUIETLY and REQUIRED arguments and set FFTW_FOUND to TRUE if +# all listed variables are TRUE +include (FindPackageHandleStandardArgs) +find_package_handle_standard_args (FFTW DEFAULT_MSG FFTW_LIBRARIES FFTW_INCLUDES) + +mark_as_advanced (FFTW_LIBRARIES FFTW_INCLUDES) diff --git a/host/hackrf-tools/CMakeLists.txt b/host/hackrf-tools/CMakeLists.txt index cc7ff9be..82ea47d8 100644 --- a/host/hackrf-tools/CMakeLists.txt +++ b/host/hackrf-tools/CMakeLists.txt @@ -24,7 +24,7 @@ cmake_minimum_required(VERSION 2.8) project(hackrf-tools C) set(MAJOR_VERSION 0) -set(MINOR_VERSION 4) +set(MINOR_VERSION 5) set(PACKAGE hackrf-tools) set(VERSION_STRING ${MAJOR_VERSION}.${MINOR_VERSION}) set(VERSION ${VERSION_STRING}) diff --git a/host/hackrf-tools/Readme.md b/host/hackrf-tools/Readme.md deleted file mode 100644 index beb0c947..00000000 --- a/host/hackrf-tools/Readme.md +++ /dev/null @@ -1,34 +0,0 @@ -This repository contains hardware designs and software for HackRF, a project to -produce a low cost, open source software radio platform. - -![Jawbreaker](https://raw.github.com/mossmann/hackrf/master/doc/jawbreaker.jpeg) - -How to build host software on Windows: -prerequisite for cygwin or mingw: -* cmake-2.8.10.2 or more see http://www.cmake.org/cmake/resources/software.html -* libusbx-1.0.14 or more see http://sourceforge.net/projects/libusbx/files/latest/download?source=files -* Install Windows driver for HackRF hardware or use Zadig see http://sourceforge.net/projects/libwdi/files/zadig - - If you want to use Zadig select HackRF USB device and just install/replace it with WinUSB driver. -* Build libhackrf before to build this library, see host/libhackrf/Readme.md. - -For Cygwin: -cmake -G "Unix Makefiles" -DCMAKE_LEGACY_CYGWIN_WIN32=1 -DLIBUSB_INCLUDE_DIR=/usr/local/include/libusb-1.0/ -make -make install - -For Mingw: -#normal version -cmake -G "MSYS Makefiles" -DLIBUSB_INCLUDE_DIR=/usr/local/include/libusb-1.0/ -#debug version -cmake -G "MSYS Makefiles" -DCMAKE_BUILD_TYPE=Debug -DLIBUSB_INCLUDE_DIR=/usr/local/include/libusb-1.0/ -make -make install - -How to build host software on Linux: -cmake ./ -make -make install - -principal author: Michael Ossmann - -http://greatscottgadgets.com/hackrf/ diff --git a/host/hackrf-tools/src/CMakeLists.txt b/host/hackrf-tools/src/CMakeLists.txt index db3576c1..d8f602c1 100644 --- a/host/hackrf-tools/src/CMakeLists.txt +++ b/host/hackrf-tools/src/CMakeLists.txt @@ -23,10 +23,16 @@ set(INSTALL_DEFAULT_BINDIR "bin" CACHE STRING "Appended to CMAKE_INSTALL_PREFIX") +INCLUDE(FindPkgConfig) + if(MSVC) -add_library(libgetopt_static STATIC - ../getopt/getopt.c -) + add_library(libgetopt_static STATIC + ../getopt/getopt.c + ) +else() + pkg_check_modules(FFTW REQUIRED fftw3f) + LIST(APPEND TOOLS hackrf_sweep) + LIST(APPEND TOOLS_LINK_LIBS m fftw3f) endif() SET(TOOLS @@ -37,6 +43,7 @@ SET(TOOLS hackrf_spiflash hackrf_cpldjtag hackrf_info + hackrf_operacake ) if(NOT libhackrf_SOURCE_DIR) @@ -55,4 +62,3 @@ foreach(tool ${TOOLS}) target_link_libraries(${tool} ${TOOLS_LINK_LIBS}) install(TARGETS ${tool} RUNTIME DESTINATION ${INSTALL_DEFAULT_BINDIR}) endforeach(tool) - diff --git a/host/hackrf-tools/src/hackrf_info.c b/host/hackrf-tools/src/hackrf_info.c index eed24c37..def5371d 100644 --- a/host/hackrf-tools/src/hackrf_info.c +++ b/host/hackrf-tools/src/hackrf_info.c @@ -32,9 +32,10 @@ int main(void) uint8_t board_id = BOARD_ID_INVALID; char version[255 + 1]; read_partid_serialno_t read_partid_serialno; + uint8_t operacakes[8]; hackrf_device_list_t *list; hackrf_device* device; - int i; + int i, j; result = hackrf_init(); if (result != HACKRF_SUCCESS) { @@ -98,7 +99,20 @@ int main(void) read_partid_serialno.serial_no[1], read_partid_serialno.serial_no[2], read_partid_serialno.serial_no[3]); - + + result = hackrf_get_operacake_boards(device, &operacakes[0]); + if (result != HACKRF_SUCCESS) { + fprintf(stderr, "hackrf_get_operacake_boards() failed: %s (%d)\n", + hackrf_error_name(result), result); + return EXIT_FAILURE; + } + for(j=0; j<8; j++) { + if(operacakes[j] == 0) + break; + printf("Operacake found, address: 0x%02x\n", operacakes[j]); + + } + result = hackrf_close(device); if (result != HACKRF_SUCCESS) { fprintf(stderr, "hackrf_close() failed: %s (%d)\n", diff --git a/host/hackrf-tools/src/hackrf_operacake.c b/host/hackrf-tools/src/hackrf_operacake.c new file mode 100644 index 00000000..086af5cb --- /dev/null +++ b/host/hackrf-tools/src/hackrf_operacake.c @@ -0,0 +1,158 @@ +/* + * Copyright 2016 Dominic Spill + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include +#include + +#ifndef bool +typedef int bool; +#define true 1 +#define false 0 +#endif + +static void usage() { + printf("\nUsage:\n"); + printf("\t-s, --serial : specify a particular device by serial number\n"); + printf("\t-d, --device : specify a particular device by number\n"); + printf("\t-o, --address : specify a particular operacake by address [default: 0x00]\n"); + printf("\t-a : set port A connection\n"); + printf("\t-b : set port B connection\n"); + printf("\t-v: verbose, list available operacake boards\n"); +} + +static struct option long_options[] = { + { "device", no_argument, 0, 'd' }, + { "serial", no_argument, 0, 's' }, + { "address", no_argument, 0, 'o' }, + { 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 = (uint16_t)long_value; + return HACKRF_SUCCESS; + } else { + return HACKRF_ERROR_INVALID_PARAM; + } +} + +int main(int argc, char** argv) { + int opt; + const char* serial_number = NULL; + int device_index = 0; + int operacake_address = 0; + int port_a = 0; + int port_b = 0; + int verbose = 0; + uint8_t operacakes[8]; + int i = 0; + hackrf_device* device = NULL; + int option_index = 0; + + int result = hackrf_init(); + if( result ) { + printf("hackrf_init() failed: %s (%d)\n", hackrf_error_name(result), result); + return -1; + } + + while( (opt = getopt_long(argc, argv, "d:s:o:a:b:v", long_options, &option_index)) != EOF ) { + switch( opt ) { + case 'd': + device_index = atoi(optarg); + break; + + case 's': + serial_number = optarg; + break; + + case 'o': + operacake_address = atoi(optarg); + break; + + case 'a': + port_a = atoi(optarg); + break; + + case 'b': + port_b = atoi(optarg); + break; + + case 'v': + verbose = 1; + break; + + default: + usage(); + } + + if( result != HACKRF_SUCCESS ) { + printf("argument error: %s (%d)\n", hackrf_error_name(result), result); + break; + } + } + + if(serial_number != NULL) { + result = hackrf_open_by_serial(serial_number, &device); + } else { + hackrf_device_list_t* device_list = hackrf_device_list(); + if(device_list->devicecount <= 0) { + result = HACKRF_ERROR_NOT_FOUND; + } else { + result = hackrf_device_list_open(device_list, device_index, &device); + } + } + + if( result ) { + printf("hackrf_open() failed: %s (%d)\n", hackrf_error_name(result), result); + return -1; + } + + if(verbose) { + hackrf_get_operacake_boards(device, operacakes); + printf("Operacakes found:\n"); + for(i=0; i<8; i++) { + if(operacakes[i] !=0) + printf("%d\n", operacakes[i]); + } + printf("\n"); + } + + result = hackrf_set_operacake_ports(device, operacake_address, port_a, port_b); + if( result ) { + printf("hackrf_set_operacake_ports() failed: %s (%d)\n", hackrf_error_name(result), result); + return -1; + } + + result = hackrf_close(device); + if( result ) { + printf("hackrf_close() failed: %s (%d)\n", hackrf_error_name(result), result); + return -1; + } + + hackrf_exit(); + + return 0; +} diff --git a/host/hackrf-tools/src/hackrf_spiflash.c b/host/hackrf-tools/src/hackrf_spiflash.c index 20a50d3f..49cc2bf9 100644 --- a/host/hackrf-tools/src/hackrf_spiflash.c +++ b/host/hackrf-tools/src/hackrf_spiflash.c @@ -91,6 +91,7 @@ static void usage() printf("\t-r : Read data into file.\n"); printf("\t-w : Write data from file.\n"); printf("\t-d : Serial number of device, if multiple devices\n"); + printf("\t-R: Reset HackRF after other operations.\n"); printf("\t-v: Verbose output.\n"); } @@ -112,8 +113,9 @@ int main(int argc, char** argv) bool read = false; bool write = false; bool verbose = false; + bool reset = false; - while ((opt = getopt_long(argc, argv, "a:l:r:w:d:v", long_options, + while ((opt = getopt_long(argc, argv, "a:l:r:w:d:vR", long_options, &option_index)) != EOF) { switch (opt) { case 'a': @@ -142,8 +144,16 @@ int main(int argc, char** argv) verbose = true; break; + case 'R': + reset = true; + break; + + case '?': + usage(); + return EXIT_FAILURE; + default: - fprintf(stderr, "opt error: %d\n", opt); + fprintf(stderr, "unknown argument '-%c %s'\n", opt, optarg); usage(); return EXIT_FAILURE; } @@ -156,28 +166,24 @@ int main(int argc, char** argv) } } - if (write == read) { - if (write == true) { - fprintf(stderr, "Read and write options are mutually exclusive.\n"); - } else { - fprintf(stderr, "Specify either read or write option.\n"); - } + if(write && read) { + fprintf(stderr, "Read and write options are mutually exclusive.\n"); usage(); return EXIT_FAILURE; } - - if (path == NULL) { - fprintf(stderr, "Specify a path to a file.\n"); + + if(!(write || read || reset)) { + fprintf(stderr, "Specify either read, write, or reset option.\n"); usage(); return EXIT_FAILURE; - } + } if( write ) { fd = fopen(path, "rb"); if(fd == NULL) { - printf("Error to open file %s\n", path); + printf("Error opening file %s\n", path); return EXIT_FAILURE; } /* Get size of the file */ @@ -214,7 +220,7 @@ int main(int argc, char** argv) } } - if (fd == NULL) { + if((read || write) && (fd == NULL)) { fprintf(stderr, "Failed to open file: %s\n", path); return EXIT_FAILURE; } @@ -233,8 +239,7 @@ int main(int argc, char** argv) return EXIT_FAILURE; } - if (read) - { + if(read) { ssize_t bytes_written; tmp_length = length; while (tmp_length) @@ -261,7 +266,9 @@ int main(int argc, char** argv) fd = NULL; return EXIT_FAILURE; } - } else { + } + + if(write) { ssize_t bytes_read = fread(data, 1, length, fd); if (bytes_read != length) { fprintf(stderr, "Failed read file (read %d bytes).\n", @@ -297,6 +304,17 @@ int main(int argc, char** argv) } } + if(reset) { + result = hackrf_reset(device); + if (result != HACKRF_SUCCESS) { + fprintf(stderr, "hackrf_reset() failed: %s (%d)\n", + hackrf_error_name(result), result); + fclose(fd); + fd = NULL; + return EXIT_FAILURE; + } + } + result = hackrf_close(device); if (result != HACKRF_SUCCESS) { fprintf(stderr, "hackrf_close() failed: %s (%d)\n", diff --git a/host/hackrf-tools/src/hackrf_sweep.c b/host/hackrf-tools/src/hackrf_sweep.c new file mode 100644 index 00000000..da700fa2 --- /dev/null +++ b/host/hackrf-tools/src/hackrf_sweep.c @@ -0,0 +1,549 @@ +/* + * Copyright 2016 Dominic Spill + * Copyright 2016 Mike Walters + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define _FILE_OFFSET_BITS 64 + +#ifndef bool +typedef int bool; +#define true 1 +#define false 0 +#endif + +#ifdef _WIN32 +#include + +#ifdef _MSC_VER + +#ifdef _WIN64 +typedef int64_t ssize_t; +#else +typedef int32_t ssize_t; +#endif + +#define strtoull _strtoui64 +#define snprintf _snprintf + +int gettimeofday(struct timeval *tv, void* ignored) { + FILETIME ft; + unsigned __int64 tmp = 0; + if (NULL != tv) { + GetSystemTimeAsFileTime(&ft); + tmp |= ft.dwHighDateTime; + tmp <<= 32; + tmp |= ft.dwLowDateTime; + tmp /= 10; + tmp -= 11644473600000000Ui64; + tv->tv_sec = (long)(tmp / 1000000UL); + tv->tv_usec = (long)(tmp % 1000000UL); + } + return 0; +} + +#endif +#endif + +#if defined(__GNUC__) +#include +#include +#endif + +#include + +#define FD_BUFFER_SIZE (8*1024) + +#define FREQ_ONE_MHZ (1000000ull) + +#define FREQ_MIN_HZ (0ull) /* 0 Hz */ +#define FREQ_MAX_HZ (7250000000ull) /* 7250MHz */ + +#define DEFAULT_SAMPLE_RATE_HZ (20000000) /* 20MHz default sample rate */ +#define DEFAULT_BASEBAND_FILTER_BANDWIDTH (15000000) /* 5MHz default */ + +#define FREQ_STEP (DEFAULT_SAMPLE_RATE_HZ / FREQ_ONE_MHZ) +#define MAX_FREQ_COUNT 1000 + +#define DEFAULT_SAMPLE_COUNT 0x4000 + +#if defined _WIN32 + #define sleep(a) Sleep( (a*1000) ) +#endif + +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 parse_u32(char* s, uint32_t* const value) { + uint_fast8_t base = 10; + char* s_end; + uint64_t ulong_value; + + if( strlen(s) > 2 ) { + if( s[0] == '0' ) { + if( (s[1] == 'x') || (s[1] == 'X') ) { + base = 16; + s += 2; + } else if( (s[1] == 'b') || (s[1] == 'B') ) { + base = 2; + s += 2; + } + } + } + + s_end = s; + ulong_value = strtoul(s, &s_end, base); + if( (s != s_end) && (*s_end == 0) ) { + *value = (uint32_t)ulong_value; + return HACKRF_SUCCESS; + } else { + return HACKRF_ERROR_INVALID_PARAM; + } +} + +int parse_u32_range(char* s, uint32_t* const value_min, uint32_t* const value_max) { + int result; + + char *sep = strchr(s, ':'); + if (!sep) + return HACKRF_ERROR_INVALID_PARAM; + + *sep = 0; + + result = parse_u32(s, value_min); + if (result != HACKRF_SUCCESS) + return result; + result = parse_u32(sep + 1, value_max); + if (result != HACKRF_SUCCESS) + return result; + + return HACKRF_SUCCESS; +} + +volatile bool do_exit = false; + +FILE* fd = NULL; +volatile uint32_t byte_count = 0; + +struct timeval time_start; +struct timeval t_start; + +bool amp = false; +uint32_t amp_enable; + +bool antenna = false; +uint32_t antenna_enable; + +uint32_t freq_min; +uint32_t freq_max; + +int fftSize; +fftwf_complex *fftwIn = NULL; +fftwf_complex *fftwOut = NULL; +fftwf_plan fftwPlan = NULL; +float* pwr; +float* window; + +float logPower(fftwf_complex in, float scale) +{ + float re = in[0] * scale; + float im = in[1] * scale; + float magsq = re * re + im * im; + return log2f(magsq) * 10.0f / log2(10.0f); +} + +int rx_callback(hackrf_transfer* transfer) { + /* This is where we need to do interesting things with the samples + * FFT + * Throw away unused bins + * write output to pipe + */ + ssize_t bytes_to_write; + ssize_t bytes_written; + int8_t* buf; + float frequency; + int i, j; + + if( fd != NULL ) { + byte_count += transfer->valid_length; + bytes_to_write = transfer->valid_length; + buf = (int8_t*) transfer->buffer; + for(j=0; j<16; j++) { + if(buf[0] == 0x7F && buf[1] == 0x7F) { + frequency = *(uint16_t*)&buf[2]; + } + /* copy to fftwIn as floats */ + buf += 16384 - (fftSize * 2); + for(i=0; i < fftSize; i++) { + fftwIn[i][0] = buf[i*2] * window[i] * 1.0f / 128.0f; + fftwIn[i][1] = buf[i*2+1] * window[i] * 1.0f / 128.0f; + } + buf += fftSize * 2; + fftwf_execute(fftwPlan); + for (i=0; i < fftSize; i++) { + // Start from the middle of the FFTW array and wrap + // to rearrange the data + int k = i ^ (fftSize >> 1); + pwr[i] = logPower(fftwOut[k], 1.0f / fftSize); + } + fwrite(&frequency, sizeof(float), 1, stdout); + fwrite(pwr, sizeof(float), fftSize, stdout); + } + + bytes_written = fwrite(transfer->buffer, 1, bytes_to_write, fd); + if (bytes_written != bytes_to_write) { + return -1; + } else { + return 0; + } + } else { + return -1; + } +} + +static void usage() { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\t[-d serial_number] # Serial number of desired HackRF.\n"); + fprintf(stderr, "\t[-a amp_enable] # RX/TX RF amplifier 1=Enable, 0=Disable.\n"); + fprintf(stderr, "\t[-f freq_min:freq_max # Specify minimum & maximum sweep frequencies (MHz).\n"); + fprintf(stderr, "\t[-p antenna_enable] # Antenna port power, 1=Enable, 0=Disable.\n"); + fprintf(stderr, "\t[-l gain_db] # RX LNA (IF) gain, 0-40dB, 8dB steps\n"); + fprintf(stderr, "\t[-g gain_db] # RX VGA (baseband) gain, 0-62dB, 2dB steps\n"); + fprintf(stderr, "\t[-x gain_db] # TX VGA (IF) gain, 0-47dB, 1dB steps\n"); + fprintf(stderr, "\t[-n num_samples] # Number of samples per frequency, 0-4294967296\n"); +} + +static hackrf_device* device = NULL; + +#ifdef _MSC_VER +BOOL WINAPI +sighandler(int signum) { + if (CTRL_C_EVENT == signum) { + fprintf(stderr, "Caught signal %d\n", signum); + do_exit = true; + return TRUE; + } + return FALSE; +} +#else +void sigint_callback_handler(int signum) { + fprintf(stderr, "Caught signal %d\n", signum); + do_exit = true; +} +#endif + +int main(int argc, char** argv) { + int opt, i, result, ifreq = 0; + bool odd; + const char* path = "/dev/null"; + const char* serial_number = NULL; + int exit_code = EXIT_SUCCESS; + struct timeval t_end; + float time_diff; + unsigned int lna_gain=16, vga_gain=20, txvga_gain=0; + uint16_t frequencies[MAX_FREQ_COUNT]; + uint32_t num_samples = DEFAULT_SAMPLE_COUNT; + + while( (opt = getopt(argc, argv, "a:f:p:l:g:x:d:n:")) != EOF ) { + result = HACKRF_SUCCESS; + switch( opt ) + { + case 'd': + serial_number = optarg; + break; + + case 'a': + amp = true; + result = parse_u32(optarg, &_enable); + break; + + case 'f': + result = parse_u32_range(optarg, &freq_min, &freq_max); + fprintf(stderr, "Scanning %uMHz to %uMHz\n", freq_min, freq_max); + frequencies[ifreq++] = freq_min; + odd = true; + while(frequencies[ifreq-1] <= freq_max) { + if (odd) + frequencies[ifreq] = frequencies[ifreq-1] + FREQ_STEP / 4; + else + frequencies[ifreq] = frequencies[ifreq-1] + 3*(FREQ_STEP/4); + ifreq++; + odd = !odd; + } + break; + + case 'p': + antenna = true; + result = parse_u32(optarg, &antenna_enable); + break; + + case 'l': + result = parse_u32(optarg, &lna_gain); + break; + + case 'g': + result = parse_u32(optarg, &vga_gain); + break; + + case 'x': + result = parse_u32(optarg, &txvga_gain); + break; + + case 'n': + result = parse_u32(optarg, &num_samples); + break; + + default: + fprintf(stderr, "unknown argument '-%c %s'\n", opt, optarg); + usage(); + return EXIT_FAILURE; + } + + if( result != HACKRF_SUCCESS ) { + fprintf(stderr, "argument error: '-%c %s' %s (%d)\n", opt, optarg, hackrf_error_name(result), result); + usage(); + return EXIT_FAILURE; + } + } + + if (lna_gain % 8) + fprintf(stderr, "warning: lna_gain (-l) must be a multiple of 8\n"); + + if (vga_gain % 2) + fprintf(stderr, "warning: vga_gain (-g) must be a multiple of 2\n"); + + if (num_samples % 0x4000) { + fprintf(stderr, "warning: num_samples (-n) must be a multiple of 16384\n"); + return EXIT_FAILURE; + } + + if( amp ) { + if( amp_enable > 1 ) { + fprintf(stderr, "argument error: amp_enable shall be 0 or 1.\n"); + usage(); + return EXIT_FAILURE; + } + } + + if (antenna) { + if (antenna_enable > 1) { + fprintf(stderr, "argument error: antenna_enable shall be 0 or 1.\n"); + usage(); + return EXIT_FAILURE; + } + } + + if (ifreq == 0) { + fprintf(stderr, "argument error: must specify sweep frequency range (-f).\n"); + usage(); + return EXIT_FAILURE; + } + + fftSize = 64; + fftwIn = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fftSize); + fftwOut = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fftSize); + fftwPlan = fftwf_plan_dft_1d(fftSize, fftwIn, fftwOut, FFTW_FORWARD, FFTW_MEASURE); + pwr = (float*)fftwf_malloc(sizeof(float) * fftSize); + window = (float*)fftwf_malloc(sizeof(float) * fftSize); + for (i = 0; i < fftSize; i++) { + window[i] = 0.5f * (1.0f - cos(2 * M_PI * i / (fftSize - 1))); + } + + result = hackrf_init(); + if( result != HACKRF_SUCCESS ) { + fprintf(stderr, "hackrf_init() failed: %s (%d)\n", hackrf_error_name(result), result); + usage(); + return EXIT_FAILURE; + } + + result = hackrf_open_by_serial(serial_number, &device); + if( result != HACKRF_SUCCESS ) { + fprintf(stderr, "hackrf_open() failed: %s (%d)\n", hackrf_error_name(result), result); + usage(); + return EXIT_FAILURE; + } + + fd = fopen(path, "wb"); + if( fd == NULL ) { + fprintf(stderr, "Failed to open file: %s\n", path); + return EXIT_FAILURE; + } + /* Change fd buffer to have bigger one to store or read data on/to HDD */ + result = setvbuf(fd , NULL , _IOFBF , FD_BUFFER_SIZE); + if( result != 0 ) { + fprintf(stderr, "setvbuf() failed: %d\n", result); + usage(); + return EXIT_FAILURE; + } + +#ifdef _MSC_VER + SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE ); +#else + signal(SIGINT, &sigint_callback_handler); + signal(SIGILL, &sigint_callback_handler); + signal(SIGFPE, &sigint_callback_handler); + signal(SIGSEGV, &sigint_callback_handler); + signal(SIGTERM, &sigint_callback_handler); + signal(SIGABRT, &sigint_callback_handler); +#endif + fprintf(stderr, "call hackrf_sample_rate_set(%.03f MHz)\n", + ((float)DEFAULT_SAMPLE_RATE_HZ/(float)FREQ_ONE_MHZ)); + result = hackrf_set_sample_rate_manual(device, DEFAULT_SAMPLE_RATE_HZ, 1); + if( result != HACKRF_SUCCESS ) { + fprintf(stderr, "hackrf_sample_rate_set() failed: %s (%d)\n", + hackrf_error_name(result), result); + usage(); + return EXIT_FAILURE; + } + + fprintf(stderr, "call hackrf_baseband_filter_bandwidth_set(%.03f MHz)\n", + ((float)DEFAULT_BASEBAND_FILTER_BANDWIDTH/(float)FREQ_ONE_MHZ)); + result = hackrf_set_baseband_filter_bandwidth(device, DEFAULT_BASEBAND_FILTER_BANDWIDTH); + if( result != HACKRF_SUCCESS ) { + fprintf(stderr, "hackrf_baseband_filter_bandwidth_set() failed: %s (%d)\n", + hackrf_error_name(result), result); + usage(); + return EXIT_FAILURE; + } + + result = hackrf_set_vga_gain(device, vga_gain); + result |= hackrf_set_lna_gain(device, lna_gain); + result |= hackrf_start_rx(device, rx_callback, NULL); + if (result != HACKRF_SUCCESS) { + fprintf(stderr, "hackrf_start_?x() failed: %s (%d)\n", hackrf_error_name(result), result); + usage(); + return EXIT_FAILURE; + } + + result = hackrf_init_sweep(device, frequencies, ifreq, num_samples); + if( result != HACKRF_SUCCESS ) { + fprintf(stderr, "hackrf_init_sweep() failed: %s (%d)\n", + hackrf_error_name(result), result); + usage(); + return EXIT_FAILURE; + } + + if (amp) { + fprintf(stderr, "call hackrf_set_amp_enable(%u)\n", amp_enable); + result = hackrf_set_amp_enable(device, (uint8_t)amp_enable); + if (result != HACKRF_SUCCESS) { + fprintf(stderr, "hackrf_set_amp_enable() failed: %s (%d)\n", + hackrf_error_name(result), result); + usage(); + return EXIT_FAILURE; + } + } + + if (antenna) { + fprintf(stderr, "call hackrf_set_antenna_enable(%u)\n", antenna_enable); + result = hackrf_set_antenna_enable(device, (uint8_t)antenna_enable); + if (result != HACKRF_SUCCESS) { + fprintf(stderr, "hackrf_set_antenna_enable() failed: %s (%d)\n", + hackrf_error_name(result), result); + usage(); + return EXIT_FAILURE; + } + } + + gettimeofday(&t_start, NULL); + gettimeofday(&time_start, NULL); + + fprintf(stderr, "Stop with Ctrl-C\n"); + while((hackrf_is_streaming(device) == HACKRF_TRUE) && (do_exit == false)) { + uint32_t byte_count_now; + struct timeval time_now; + float time_difference, rate; + sleep(1); + + gettimeofday(&time_now, NULL); + + byte_count_now = byte_count; + byte_count = 0; + + time_difference = TimevalDiff(&time_now, &time_start); + rate = (float)byte_count_now / time_difference; + fprintf(stderr, "%4.1f MiB / %5.3f sec = %4.1f MiB/second\n", + (byte_count_now / 1e6f), time_difference, (rate / 1e6f) ); + + time_start = time_now; + + if (byte_count_now == 0) { + exit_code = EXIT_FAILURE; + fprintf(stderr, "\nCouldn't transfer any bytes for one second.\n"); + break; + } + } + + result = hackrf_is_streaming(device); + if (do_exit) { + fprintf(stderr, "\nUser cancel, exiting...\n"); + } else { + fprintf(stderr, "\nExiting... hackrf_is_streaming() result: %s (%d)\n", + hackrf_error_name(result), result); + } + + gettimeofday(&t_end, NULL); + time_diff = TimevalDiff(&t_end, &t_start); + fprintf(stderr, "Total time: %5.5f s\n", time_diff); + + if(device != NULL) { + result = hackrf_stop_rx(device); + if(result != HACKRF_SUCCESS) { + fprintf(stderr, "hackrf_stop_rx() failed: %s (%d)\n", + hackrf_error_name(result), result); + } else { + fprintf(stderr, "hackrf_stop_rx() done\n"); + } + + result = hackrf_close(device); + if(result != HACKRF_SUCCESS) { + fprintf(stderr, "hackrf_close() failed: %s (%d)\n", + hackrf_error_name(result), result); + } else { + fprintf(stderr, "hackrf_close() done\n"); + } + + hackrf_exit(); + fprintf(stderr, "hackrf_exit() done\n"); + } + + if(fd != NULL) { + fclose(fd); + fd = NULL; + fprintf(stderr, "fclose(fd) done\n"); + } + fprintf(stderr, "exit\n"); + return exit_code; +} diff --git a/host/hackrf-tools/src/hackrf_transfer.c b/host/hackrf-tools/src/hackrf_transfer.c index 8fca3b3b..9b668293 100644 --- a/host/hackrf-tools/src/hackrf_transfer.c +++ b/host/hackrf-tools/src/hackrf_transfer.c @@ -34,6 +34,8 @@ #include #include +#define _FILE_OFFSET_BITS 64 + #ifndef bool typedef int bool; #define true 1 @@ -114,6 +116,11 @@ typedef enum { TRANSCEIVER_MODE_SS = 3, } transceiver_mode_t; +typedef enum { + HW_SYNC_MODE_OFF = 0, + HW_SYNC_MODE_ON = 1, +} hw_sync_mode_t; + /* WAVE or RIFF WAVE file format containing IQ 2x8bits data for HackRF compatible with SDR# Wav IQ file */ typedef struct { @@ -303,6 +310,8 @@ volatile uint32_t byte_count = 0; bool signalsource = false; uint32_t amplitude = 0; +bool hw_sync = false; + bool receive = false; bool receive_wav = false; uint64_t stream_size = 0; @@ -338,7 +347,7 @@ uint32_t sample_rate_hz; bool limit_num_samples = false; uint64_t samples_to_xfer = 0; -ssize_t bytes_to_xfer = 0; +size_t bytes_to_xfer = 0; bool baseband_filter_bw = false; uint32_t baseband_filter_bw_hz = 0; @@ -349,9 +358,9 @@ bool crystal_correct = false; uint32_t crystal_correct_ppm ; int rx_callback(hackrf_transfer* transfer) { - ssize_t bytes_to_write; - ssize_t bytes_written; - int i; + size_t bytes_to_write; + size_t bytes_written; + unsigned int i; if( fd != NULL ) { @@ -370,25 +379,28 @@ int rx_callback(hackrf_transfer* transfer) { } } if (stream_size>0){ - if ((stream_size-1+stream_head-stream_tail)%stream_size buffer,bytes_to_write); - }else{ - memcpy(stream_buf+stream_tail,transfer->buffer,(stream_size-stream_tail)); - memcpy(stream_buf,transfer->buffer+(stream_size-stream_tail),bytes_to_write-(stream_size-stream_tail)); - }; - __atomic_store_n(&stream_tail,(stream_tail+bytes_to_write)%stream_size,__ATOMIC_RELEASE); +#ifndef _WIN32 + if ((stream_size-1+stream_head-stream_tail)%stream_size buffer,bytes_to_write); + } else { + memcpy(stream_buf+stream_tail,transfer->buffer,(stream_size-stream_tail)); + memcpy(stream_buf,transfer->buffer+(stream_size-stream_tail),bytes_to_write-(stream_size-stream_tail)); + }; + __atomic_store_n(&stream_tail,(stream_tail+bytes_to_write)%stream_size,__ATOMIC_RELEASE); } +#endif return 0; - }else{ - bytes_written = fwrite(transfer->buffer, 1, bytes_to_write, fd); - if ((bytes_written != bytes_to_write) - || (limit_num_samples && (bytes_to_xfer == 0))) { - return -1; } else { - return 0; + bytes_written = fwrite(transfer->buffer, 1, bytes_to_write, fd); + if ((bytes_written != bytes_to_write) + || (limit_num_samples && (bytes_to_xfer == 0))) { + return -1; + } else { + return 0; + } } } } else { @@ -397,9 +409,9 @@ int rx_callback(hackrf_transfer* transfer) { } int tx_callback(hackrf_transfer* transfer) { - ssize_t bytes_to_read; - ssize_t bytes_read; - int i; + size_t bytes_to_read; + size_t bytes_read; + unsigned int i; if( fd != NULL ) { @@ -416,15 +428,17 @@ int tx_callback(hackrf_transfer* transfer) { bytes_to_xfer -= bytes_to_read; } bytes_read = fread(transfer->buffer, 1, bytes_to_read, fd); - if ((bytes_read != bytes_to_read) - || (limit_num_samples && (bytes_to_xfer == 0))) { + if (limit_num_samples && (bytes_to_xfer == 0)) { + return -1; + } + if (bytes_read != bytes_to_read) { if (repeat) { printf("Input file end reached. Rewind to beginning.\n"); rewind(fd); fread(transfer->buffer + bytes_read, 1, bytes_to_read - bytes_read, fd); return 0; } else { - return -1; // not loopback mode, EOF + return -1; /* not repeat mode, end of file */ } } else { @@ -479,11 +493,15 @@ static void usage() { printf("\t[-s sample_rate_hz] # Sample rate in Hz (4/8/10/12.5/16/20MHz, default %sMHz).\n", u64toa((DEFAULT_SAMPLE_RATE_HZ/FREQ_ONE_MHZ),&ascii_u64_data1)); printf("\t[-n num_samples] # Number of samples to transfer (default is unlimited).\n"); +#ifndef _WIN32 +/* The required atomic load/store functions aren't available when using C with MSVC */ printf("\t[-S buf_size] # Enable receive streaming with buffer size buf_size.\n"); +#endif printf("\t[-c amplitude] # CW signal source mode, amplitude 0-127 (DC value to DAC).\n"); printf("\t[-R] # Repeat TX mode (default is off) \n"); - printf("\t[-b baseband_filter_bw_hz] # Set baseband filter bandwidth in Hz.\n\tPossible values: 1.75/2.5/3.5/5/5.5/6/7/8/9/10/12/14/15/20/24/28MHz, default < sample_rate_hz.\n" ); + printf("\t[-b baseband_filter_bw_hz] # Set baseband filter bandwidth in Hz.\n\tPossible values: 1.75/2.5/3.5/5/5.5/6/7/8/9/10/12/14/15/20/24/28MHz, default <= 0.75 * sample_rate_hz.\n" ); printf("\t[-C ppm] # Set Internal crystal clock error in ppm.\n"); + printf("\t[-H] # Synchronise USB transfer using GPIO pins.\n"); } static hackrf_device* device = NULL; @@ -527,11 +545,14 @@ int main(int argc, char** argv) { float time_diff; unsigned int lna_gain=8, vga_gain=20, txvga_gain=0; - while( (opt = getopt(argc, argv, "wr:t:f:i:o:m:a:p:s:n:b:l:g:x:c:d:C:RS:")) != EOF ) + while( (opt = getopt(argc, argv, "Hwr:t:f:i:o:m:a:p:s:n:b:l:g:x:c:d:C:RS:")) != EOF ) { result = HACKRF_SUCCESS; switch( opt ) { + case 'H': + hw_sync = true; + break; case 'w': receive_wav = true; break; @@ -653,6 +674,10 @@ int main(int argc, char** argv) { result = parse_u32(optarg, &crystal_correct_ppm); break; + case '?': + usage(); + return EXIT_FAILURE; + default: fprintf(stderr, "unknown argument '-%c %s'\n", opt, optarg); usage(); @@ -778,24 +803,20 @@ int main(int argc, char** argv) { { /* Compute nearest freq for bw filter */ baseband_filter_bw_hz = hackrf_compute_baseband_filter_bw(baseband_filter_bw_hz); - }else - { - /* Compute default value depending on sample rate */ - baseband_filter_bw_hz = hackrf_compute_baseband_filter_bw_round_down_lt(sample_rate_hz); - } - if (baseband_filter_bw_hz > BASEBAND_FILTER_BW_MAX) { - fprintf(stderr, "argument error: baseband_filter_bw_hz must be less or equal to %u Hz/%.03f MHz\n", - BASEBAND_FILTER_BW_MAX, (float)(BASEBAND_FILTER_BW_MAX/FREQ_ONE_MHZ)); - usage(); - return EXIT_FAILURE; - } + if (baseband_filter_bw_hz > BASEBAND_FILTER_BW_MAX) { + fprintf(stderr, "argument error: baseband_filter_bw_hz must be less or equal to %u Hz/%.03f MHz\n", + BASEBAND_FILTER_BW_MAX, (float)(BASEBAND_FILTER_BW_MAX/FREQ_ONE_MHZ)); + usage(); + return EXIT_FAILURE; + } - if (baseband_filter_bw_hz < BASEBAND_FILTER_BW_MIN) { - fprintf(stderr, "argument error: baseband_filter_bw_hz must be greater or equal to %u Hz/%.03f MHz\n", - BASEBAND_FILTER_BW_MIN, (float)(BASEBAND_FILTER_BW_MIN/FREQ_ONE_MHZ)); - usage(); - return EXIT_FAILURE; + if (baseband_filter_bw_hz < BASEBAND_FILTER_BW_MIN) { + fprintf(stderr, "argument error: baseband_filter_bw_hz must be greater or equal to %u Hz/%.03f MHz\n", + BASEBAND_FILTER_BW_MIN, (float)(BASEBAND_FILTER_BW_MIN/FREQ_ONE_MHZ)); + usage(); + return EXIT_FAILURE; + } } if( (transmit == false) && (receive == receive_wav) ) @@ -926,19 +947,30 @@ int main(int argc, char** argv) { signal(SIGTERM, &sigint_callback_handler); signal(SIGABRT, &sigint_callback_handler); #endif - fprintf(stderr, "call hackrf_sample_rate_set(%u Hz/%.03f MHz)\n", sample_rate_hz,((float)sample_rate_hz/(float)FREQ_ONE_MHZ)); - result = hackrf_set_sample_rate_manual(device, sample_rate_hz, 1); + fprintf(stderr, "call hackrf_set_sample_rate(%u Hz/%.03f MHz)\n", sample_rate_hz,((float)sample_rate_hz/(float)FREQ_ONE_MHZ)); + result = hackrf_set_sample_rate(device, sample_rate_hz); if( result != HACKRF_SUCCESS ) { - fprintf(stderr, "hackrf_sample_rate_set() failed: %s (%d)\n", hackrf_error_name(result), result); + fprintf(stderr, "hackrf_set_sample_rate() failed: %s (%d)\n", hackrf_error_name(result), result); usage(); return EXIT_FAILURE; } - fprintf(stderr, "call hackrf_baseband_filter_bandwidth_set(%d Hz/%.03f MHz)\n", - baseband_filter_bw_hz, ((float)baseband_filter_bw_hz/(float)FREQ_ONE_MHZ)); - result = hackrf_set_baseband_filter_bandwidth(device, baseband_filter_bw_hz); + if( baseband_filter_bw ) { + fprintf(stderr, "call hackrf_baseband_filter_bandwidth_set(%d Hz/%.03f MHz)\n", + baseband_filter_bw_hz, ((float)baseband_filter_bw_hz/(float)FREQ_ONE_MHZ)); + result = hackrf_set_baseband_filter_bandwidth(device, baseband_filter_bw_hz); + if( result != HACKRF_SUCCESS ) { + fprintf(stderr, "hackrf_baseband_filter_bandwidth_set() failed: %s (%d)\n", hackrf_error_name(result), result); + usage(); + return EXIT_FAILURE; + } + } + + fprintf(stderr, "call hackrf_set_hw_sync_mode(%d)\n", + hw_sync); + result = hackrf_set_hw_sync_mode(device, hw_sync ? HW_SYNC_MODE_ON : HW_SYNC_MODE_OFF); if( result != HACKRF_SUCCESS ) { - fprintf(stderr, "hackrf_baseband_filter_bandwidth_set() failed: %s (%d)\n", hackrf_error_name(result), result); + fprintf(stderr, "hackrf_set_hw_sync_mode() failed: %s (%d)\n", hackrf_error_name(result), result); usage(); return EXIT_FAILURE; } @@ -1017,47 +1049,49 @@ int main(int argc, char** argv) { uint32_t byte_count_now; struct timeval time_now; float time_difference, rate; - if (stream_size>0){ - if(stream_head==stream_tail){ - usleep(10000); // queue empty - }else{ - ssize_t len; - ssize_t bytes_written; - uint32_t _st= __atomic_load_n(&stream_tail,__ATOMIC_ACQUIRE); - if(stream_head<_st) - len=_st-stream_head; - else - len=stream_size-stream_head; - bytes_written = fwrite(stream_buf+stream_head, 1, len, fd); - if (len != bytes_written){ - printf("write failed"); - do_exit=true; - }; - stream_head=(stream_head+len)%stream_size; + if (stream_size>0) { +#ifndef _WIN32 + if(stream_head==stream_tail) { + usleep(10000); // queue empty + } else { + ssize_t len; + ssize_t bytes_written; + uint32_t _st= __atomic_load_n(&stream_tail,__ATOMIC_ACQUIRE); + if(stream_head<_st) + len=_st-stream_head; + else + len=stream_size-stream_head; + bytes_written = fwrite(stream_buf+stream_head, 1, len, fd); + if (len != bytes_written) { + printf("write failed"); + do_exit=true; + }; + stream_head=(stream_head+len)%stream_size; } - if(stream_drop>0){ - uint32_t drops= __atomic_exchange_n (&stream_drop,0,__ATOMIC_SEQ_CST); - printf("dropped frames: [%d]\n",drops); + if(stream_drop>0) { + uint32_t drops= __atomic_exchange_n (&stream_drop,0,__ATOMIC_SEQ_CST); + printf("dropped frames: [%d]\n",drops); } - }else{ - sleep(1); - - gettimeofday(&time_now, NULL); - - byte_count_now = byte_count; - byte_count = 0; - - time_difference = TimevalDiff(&time_now, &time_start); - rate = (float)byte_count_now / time_difference; - fprintf(stderr, "%4.1f MiB / %5.3f sec = %4.1f MiB/second\n", - (byte_count_now / 1e6f), time_difference, (rate / 1e6f) ); +#endif + } else { + sleep(1); + gettimeofday(&time_now, NULL); + + byte_count_now = byte_count; + byte_count = 0; + + time_difference = TimevalDiff(&time_now, &time_start); + rate = (float)byte_count_now / time_difference; + fprintf(stderr, "%4.1f MiB / %5.3f sec = %4.1f MiB/second\n", + (byte_count_now / 1e6f), time_difference, (rate / 1e6f) ); - time_start = time_now; + time_start = time_now; - if (byte_count_now == 0) { - exit_code = EXIT_FAILURE; - fprintf(stderr, "\nCouldn't transfer any bytes for one second.\n"); - break; + if (byte_count_now == 0) { + exit_code = EXIT_FAILURE; + fprintf(stderr, "\nCouldn't transfer any bytes for one second.\n"); + break; + } } } } diff --git a/host/libhackrf/Readme.md b/host/libhackrf/Readme.md deleted file mode 100644 index 40321c82..00000000 --- a/host/libhackrf/Readme.md +++ /dev/null @@ -1,33 +0,0 @@ -This repository contains hardware designs and software for HackRF, a project to -produce a low cost, open source software radio platform. - -![Jawbreaker](https://raw.github.com/mossmann/hackrf/master/doc/jawbreaker.jpeg) - -How to build host software on Windows: -prerequisite for cygwin or mingw: -* cmake-2.8.10.2 or more see http://www.cmake.org/cmake/resources/software.html -* libusbx-1.0.14 or more see http://sourceforge.net/projects/libusbx/files/latest/download?source=files -* Install Windows driver for HackRF hardware or use Zadig see http://sourceforge.net/projects/libwdi/files/zadig - - If you want to use Zadig select HackRF USB device and just install/replace it with WinUSB driver. - -For Cygwin: -cmake -G "Unix Makefiles" -DCMAKE_LEGACY_CYGWIN_WIN32=1 -DLIBUSB_INCLUDE_DIR=/usr/local/include/libusb-1.0/ -make -make install - -For Mingw: -#normal version -cmake -G "MSYS Makefiles" -DLIBUSB_INCLUDE_DIR=/usr/local/include/libusb-1.0/ -#debug version -cmake -G "MSYS Makefiles" -DCMAKE_BUILD_TYPE=Debug -DLIBUSB_INCLUDE_DIR=/usr/local/include/libusb-1.0/ -make -make install - -How to build host software on Linux: -cmake ./ -make -make install - -principal author: Michael Ossmann - -http://greatscottgadgets.com/hackrf/ diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index a759fb3a..30c604f2 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -26,6 +26,11 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSI #include #include + +#ifdef _WIN32 +/* Avoid redefinition of timespec from time.h (included by libusb.h) */ +#define HAVE_STRUCT_TIMESPEC 1 +#endif #include #ifndef bool @@ -67,6 +72,12 @@ typedef enum { HACKRF_VENDOR_REQUEST_SET_TXVGA_GAIN = 21, HACKRF_VENDOR_REQUEST_ANTENNA_ENABLE = 23, HACKRF_VENDOR_REQUEST_SET_FREQ_EXPLICIT = 24, + // USB_WCID_VENDOR_REQ = 25 + HACKRF_VENDOR_REQUEST_INIT_SWEEP = 26, + HACKRF_VENDOR_REQUEST_OPERACAKE_GET_BOARDS = 27, + HACKRF_VENDOR_REQUEST_OPERACAKE_SET_PORTS = 28, + HACKRF_VENDOR_REQUEST_SET_HW_SYNC_MODE = 29, + HACKRF_VENDOR_REQUEST_RESET = 30, } hackrf_vendor_request; typedef enum { @@ -82,6 +93,11 @@ typedef enum { TRANSCEIVER_MODE_CPLD_UPDATE = 4, } hackrf_transceiver_mode; +typedef enum { + HACKRF_HW_SYNC_MODE_OFF = 0, + HACKRF_HW_SYNC_MODE_ON = 1, +} hackrf_hw_sync_mode; + struct hackrf_device { libusb_device_handle* usb_device; struct libusb_transfer** transfers; @@ -1094,6 +1110,11 @@ typedef struct { } set_fracrate_params_t; +/* + * You should probably use hackrf_set_sample_rate() below instead of this + * function. They both result in automatic baseband filter selection as + * described below. + */ int ADDCALL hackrf_set_sample_rate_manual(hackrf_device* device, const uint32_t freq_hz, uint32_t divider) { @@ -1120,10 +1141,17 @@ int ADDCALL hackrf_set_sample_rate_manual(hackrf_device* device, { return HACKRF_ERROR_LIBUSB; } else { - return HACKRF_SUCCESS; + return hackrf_set_baseband_filter_bandwidth(device, + hackrf_compute_baseband_filter_bw((uint32_t)(0.75*freq_hz/divider))); } } +/* + * For anti-aliasing, the baseband filter bandwidth is automatically set to the + * widest available setting that is no more than 75% of the sample rate. This + * happens every time the sample rate is set. If you want to override the + * baseband filter selection, you must do so after setting the sample rate. + */ int ADDCALL hackrf_set_sample_rate(hackrf_device* device, const double freq) { const int MAX_N = 32; @@ -1417,6 +1445,7 @@ static int create_transfer_thread(hackrf_device* device, if( device->transfer_thread_started == false ) { device->streaming = false; + do_exit = false; result = prepare_transfers( device, endpoint_address, @@ -1548,6 +1577,26 @@ int ADDCALL hackrf_close(hackrf_device* device) return result1; } +int ADDCALL hackrf_set_hw_sync_mode(hackrf_device* device, const uint8_t value) { + int result = libusb_control_transfer( + device->usb_device, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + HACKRF_VENDOR_REQUEST_SET_HW_SYNC_MODE, + value, + 0, + NULL, + 0, + 0 + ); + + if( result != 0 ) + { + return HACKRF_ERROR_LIBUSB; + } else { + return HACKRF_SUCCESS; + } +} + const char* ADDCALL hackrf_error_name(enum hackrf_error errcode) { switch(errcode) @@ -1695,6 +1744,111 @@ uint32_t ADDCALL hackrf_compute_baseband_filter_bw(const uint32_t bandwidth_hz) return p->bandwidth_hz; } +/* Initialise sweep mode with alist of frequencies and dwell time in samples */ +int ADDCALL hackrf_init_sweep(hackrf_device* device, uint16_t* frequency_list, int length, uint32_t dwell_time) +{ + int result, i; + int size = length * sizeof(frequency_list[0]); + + for(i=0; iusb_device, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + HACKRF_VENDOR_REQUEST_INIT_SWEEP, + dwell_time & 0xffff, + (dwell_time >> 16) & 0xffff, + (unsigned char*)frequency_list, + size, + 0 + ); + + if (result < size) { + return HACKRF_ERROR_LIBUSB; + } else { + return HACKRF_SUCCESS; + } +} + +/* Retrieve list of Operacake board addresses + * boards must be *uint8_t[8] + */ +int ADDCALL hackrf_get_operacake_boards(hackrf_device* device, uint8_t* boards) +{ + int result; + result = libusb_control_transfer( + device->usb_device, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + HACKRF_VENDOR_REQUEST_OPERACAKE_GET_BOARDS, + 0, + 0, + boards, + 8, + 0 + ); + + if (result < 8) + { + return HACKRF_ERROR_LIBUSB; + } else { + return HACKRF_SUCCESS; + } +} + +/* Set Operacake ports */ +int ADDCALL hackrf_set_operacake_ports(hackrf_device* device, + uint8_t address, + uint8_t port_a, + uint8_t port_b) +{ + int result; + /* Error checking */ + if((port_a > OPERACAKE_PB4) || (port_b > OPERACAKE_PB4)) { + return HACKRF_ERROR_INVALID_PARAM; + } + /* Check which side PA and PB are on */ + if(((port_a <= OPERACAKE_PA4) && (port_b <= OPERACAKE_PA4)) + || ((port_a > OPERACAKE_PA4) && (port_b > OPERACAKE_PA4))) { + return HACKRF_ERROR_INVALID_PARAM; + } + result = libusb_control_transfer( + device->usb_device, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + HACKRF_VENDOR_REQUEST_OPERACAKE_SET_PORTS, + address, + port_a | (port_b<<8), + NULL, + 0, + 0 + ); + + if (result != 0) { + return HACKRF_ERROR_LIBUSB; + } else { + return HACKRF_SUCCESS; + } +} + +int ADDCALL hackrf_reset(hackrf_device* device) { + int result = libusb_control_transfer( + device->usb_device, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + HACKRF_VENDOR_REQUEST_RESET, + 0, + 0, + NULL, + 0, + 0 + ); + + if( result != 0 ) { + return HACKRF_ERROR_LIBUSB; + } else { + return HACKRF_SUCCESS; + } +} + #ifdef __cplusplus } // __cplusplus defined. #endif diff --git a/host/libhackrf/src/hackrf.h b/host/libhackrf/src/hackrf.h index 7ac0530f..06826aad 100644 --- a/host/libhackrf/src/hackrf.h +++ b/host/libhackrf/src/hackrf.h @@ -83,6 +83,17 @@ enum rf_path_filter { RF_PATH_FILTER_HIGH_PASS = 2, }; +enum operacake_ports { + OPERACAKE_PA1 = 0, + OPERACAKE_PA2 = 1, + OPERACAKE_PA3 = 2, + OPERACAKE_PA4 = 3, + OPERACAKE_PB1 = 4, + OPERACAKE_PB2 = 5, + OPERACAKE_PB3 = 6, + OPERACAKE_PB4 = 7, +}; + typedef struct hackrf_device hackrf_device; typedef struct { @@ -187,6 +198,9 @@ extern ADDAPI int ADDCALL hackrf_set_txvga_gain(hackrf_device* device, uint32_t /* antenna port power control */ extern ADDAPI int ADDCALL hackrf_set_antenna_enable(hackrf_device* device, const uint8_t value); +/* set hardware sync mode */ +extern ADDAPI int ADDCALL hackrf_set_hw_sync_mode(hackrf_device* device, const uint8_t value); + extern ADDAPI const char* ADDCALL hackrf_error_name(enum hackrf_error errcode); extern ADDAPI const char* ADDCALL hackrf_board_id_name(enum hackrf_board_id board_id); extern ADDAPI const char* ADDCALL hackrf_usb_board_id_name(enum hackrf_usb_board_id usb_board_id); @@ -196,6 +210,19 @@ extern ADDAPI const char* ADDCALL hackrf_filter_path_name(const enum rf_path_fil extern ADDAPI uint32_t ADDCALL hackrf_compute_baseband_filter_bw_round_down_lt(const uint32_t bandwidth_hz); /* Compute best default value depending on sample rate (auto filter) */ extern ADDAPI uint32_t ADDCALL hackrf_compute_baseband_filter_bw(const uint32_t bandwidth_hz); +/* Start scan mode */ +extern ADDAPI int ADDCALL hackrf_init_sweep(hackrf_device* device, + uint16_t* frequency_list, + int length, uint32_t dwell_time); + +/* Operacake functions */ +extern ADDAPI int ADDCALL hackrf_get_operacake_boards(hackrf_device* device, uint8_t* boards); +extern ADDAPI int ADDCALL hackrf_set_operacake_ports(hackrf_device* device, + uint8_t address, + uint8_t port_a, + uint8_t port_b); + +extern ADDAPI int ADDCALL hackrf_reset(hackrf_device* device); #ifdef __cplusplus } // __cplusplus defined. diff --git a/host/python/max2837_dump.py b/host/python/max2837_dump.py deleted file mode 100755 index 6624737b..00000000 --- a/host/python/max2837_dump.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python -# -# 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. -# - -import usb -import struct -import sys - -device = usb.core.find(idVendor=0x1d50, idProduct=0x604b) -if device: - print 'Find: HackRF Jawbreaker' -else: - device = usb.core.find(idVendor=0x1d50, idProduct=0x6089) - if device: - print 'Find: HackRF One' - else: - device = usb.core.find(idVendor=0x1d50, idProduct=0xcc15) - if device: - print 'Find: rad1o' - else: - print 'Not find any HackRF device.' - sys.exit() -device.set_configuration() - -def read_max2837_register(register_number): - return struct.unpack('