diff --git a/Readme.md b/Readme.md index ea9e9afe..ab366c05 100644 --- a/Readme.md +++ b/Readme.md @@ -1,7 +1,8 @@ This repository contains hardware designs and software for HackRF, a project to produce a low cost, open source software radio platform. -![Lemondrop and Jellybean](https://github.com/wishi/hackrf/raw/master/doc/lemonAndjelly.jpeg) +![Jawbreaker](https://raw.github.com/mossmann/hackrf/master/doc/jawbreaker.jpeg) principal author: Michael Ossmann -source repository: https://github.com/mossmann/hackrf + +http://greatscottgadgets.com/hackrf/ diff --git a/doc/jawbreaker.jpeg b/doc/jawbreaker.jpeg new file mode 100644 index 00000000..6d3a8e78 Binary files /dev/null and b/doc/jawbreaker.jpeg differ diff --git a/firmware/common/LPC4330_M4_ram_only.ld b/firmware/common/LPC4330_M4_ram_only.ld deleted file mode 100644 index 4149fbd7..00000000 --- a/firmware/common/LPC4330_M4_ram_only.ld +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2012 Michael Ossmann - * 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. - */ - -/* Linker script for HackRF Jellybean (LPC4330, 1M SPI flash, 264K SRAM). */ - -MEMORY -{ - ram_local1 (rwx) : ORIGIN = 0x10000000, LENGTH = 128K - ram_local2 (rwx) : ORIGIN = 0x10080000, LENGTH = 72K - ram_ahb1 (rwx) : ORIGIN = 0x20000000, LENGTH = 16K - /* Removed 32K of AHB SRAM for USB buffer. Straddles two blocks of RAM - * to get performance benefit of having two USB buffers addressable - * simultaneously (on two different buses of the AHB multilayer matrix) - */ - ram_ahb2 (rwx) : ORIGIN = 0x2000C000, LENGTH = 16K -} - -/* Include the common ld script. */ -INCLUDE libopencm3_lpc43xx_ram_only.ld diff --git a/firmware/common/Makefile_inc.mk b/firmware/common/Makefile_inc.mk index 8ea2f6be..891495c0 100644 --- a/firmware/common/Makefile_inc.mk +++ b/firmware/common/Makefile_inc.mk @@ -75,12 +75,23 @@ all: images images: $(BINARY).images flash: $(BINARY).flash +program: $(BINARY).dfu + $(Q)dfu-util --device 1fc9:000c --alt 0 --download $(BINARY).dfu + %.images: %.bin %.hex %.srec %.list @#echo "*** $* images generated ***" +%.dfu: %.bin + $(Q)rm -f _tmp.dfu _header.bin + $(Q)cp $(*).bin _tmp.dfu + $(Q)dfu-suffix --vid=0x1fc9 --pid=0x000c --did=0x0 -s 0 -a _tmp.dfu + $(Q)python -c "import os.path; import struct; print('0000000: da ff ' + ' '.join(map(lambda s: '%02x' % ord(s), struct.pack(' _header.bin + $(Q)cat _header.bin _tmp.dfu >$(*).dfu + $(Q)rm -f _tmp.dfu _header.bin + %.bin: %.elf @#printf " OBJCOPY $(*).bin\n" - $(Q)$(OBJCOPY) -Obinary $(*).elf $(*).bin + $(Q)$(OBJCOPY) -Obinary -j .text -j .ARM.exidx $(*).elf $(*).bin %.hex: %.elf @#printf " OBJCOPY $(*).hex\n" @@ -107,6 +118,8 @@ clean: $(Q)rm -f *.d $(Q)rm -f *.elf $(Q)rm -f *.bin + $(Q)rm -f *.dfu + $(Q)rm -f _tmp.dfu _header.bin $(Q)rm -f *.hex $(Q)rm -f *.srec $(Q)rm -f *.list diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index 37722b1c..7eb57698 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -200,6 +200,11 @@ extern "C" /* TODO add other Pins */ +typedef enum { + TRANSCEIVER_MODE_RX, + TRANSCEIVER_MODE_TX, +} transceiver_mode_t; + void delay(uint32_t duration); void cpu_clock_init(void); diff --git a/firmware/common/max2837.c b/firmware/common/max2837.c index 633fbca1..464aa8b3 100644 --- a/firmware/common/max2837.c +++ b/firmware/common/max2837.c @@ -110,7 +110,7 @@ void max2837_setup(void) set_MAX2837_LNAgain_SPI_EN(1); set_MAX2837_LNAgain(MAX2837_LNAgain_MAX); /* maximum gain */ set_MAX2837_VGAgain_SPI_EN(1); - set_MAX2837_VGA(0x00); /* minimum attenuation */ + set_MAX2837_VGA(0x18); /* reasonable gain for noisy 2.4GHz environment */ /* maximum rx output common-mode voltage */ set_MAX2837_BUFF_VCM(MAX2837_BUFF_VCM_1_25); @@ -121,10 +121,9 @@ void max2837_setup(void) /* SPI register read. */ uint16_t max2837_spi_read(uint8_t r) { gpio_clear(PORT_XCVR_CS, PIN_XCVR_CS); - // FIXME: Unimplemented. - r=r; + const uint16_t value = ssp_transfer(SSP1_NUM, (uint16_t)((1 << 15) | (r << 10))); gpio_set(PORT_XCVR_CS, PIN_XCVR_CS); - return 0; + return value & 0x3ff; } /* SPI register write */ @@ -137,7 +136,7 @@ void max2837_spi_write(uint8_t r, uint16_t v) { LOG("0x%03x -> reg%d\n", v, r); #else gpio_clear(PORT_XCVR_CS, PIN_XCVR_CS); - ssp_write(SSP1_NUM, (uint16_t)((r << 10) | (v & 0x3ff))); + ssp_transfer(SSP1_NUM, (uint16_t)((r << 10) | (v & 0x3ff))); gpio_set(PORT_XCVR_CS, PIN_XCVR_CS); #endif } diff --git a/firmware/common/max5864.c b/firmware/common/max5864.c index a0f5dcff..094ed700 100644 --- a/firmware/common/max5864.c +++ b/firmware/common/max5864.c @@ -29,7 +29,7 @@ void max5864_spi_write(uint_fast8_t value) { gpio_clear(PORT_AD_CS, PIN_AD_CS); - ssp_write(SSP1_NUM, value); + ssp_transfer(SSP1_NUM, value); gpio_set(PORT_AD_CS, PIN_AD_CS); } diff --git a/firmware/common/sgpio.c b/firmware/common/sgpio.c index 2db69608..d53c3f87 100644 --- a/firmware/common/sgpio.c +++ b/firmware/common/sgpio.c @@ -59,17 +59,23 @@ void sgpio_test_interface() { // Make all SGPIO controlled by SGPIO's "GPIO" registers for (uint_fast8_t i = 0; i < 16; i++) { - SGPIO_OUT_MUX_CFG(i) = (0L << 4) | (4L << 0); + SGPIO_OUT_MUX_CFG(i) = + SGPIO_OUT_MUX_CFG_P_OE_CFG(0) + | SGPIO_OUT_MUX_CFG_P_OUT_CFG(4); } // Set SGPIO output values. - SGPIO_GPIO_OUTREG = (1L << host_direction_sgpio_pin) - | (1L << host_disable_sgpio_pin); + SGPIO_GPIO_OUTREG = + (1L << host_direction_sgpio_pin) + | (1L << host_disable_sgpio_pin); // Enable SGPIO pin outputs. - SGPIO_GPIO_OENREG = (1L << host_direction_sgpio_pin) - | (1L << host_disable_sgpio_pin) | (0L << host_capture_sgpio_pin) - | (0L << host_clock_sgpio_pin) | (0xFF << 0); + SGPIO_GPIO_OENREG = + (1L << host_direction_sgpio_pin) + | (1L << host_disable_sgpio_pin) + | (0L << host_capture_sgpio_pin) + | (0L << host_clock_sgpio_pin) + | (0xFF << 0); // Configure SGPIO slices. @@ -83,159 +89,61 @@ void sgpio_test_interface() { } } -void sgpio_configure_for_tx() { +void sgpio_configure( + const transceiver_mode_t transceiver_mode, + const bool multi_slice +) { // Disable all counters during configuration SGPIO_CTRL_ENABLE = 0; sgpio_configure_pin_functions(); // Set SGPIO output values. + const uint_fast8_t cpld_direction = + (transceiver_mode == TRANSCEIVER_MODE_TX) ? 1 : 0; SGPIO_GPIO_OUTREG = - (1L << 11) | // direction - (1L << 10); // disable + (cpld_direction << 11) + | (1L << 10) // disable + ; // Enable SGPIO pin outputs. + const uint_fast16_t sgpio_gpio_data_direction = + (transceiver_mode == TRANSCEIVER_MODE_TX) + ? (0xFF << 0) + : (0x00 << 0); SGPIO_GPIO_OENREG = - (1L << 11) | // direction: TX: data to CPLD - (1L << 10) | // disable - (0L << 9) | // capture - (0L << 8) | // clock - 0xFF; // data: output + (1L << 11) // direction + | (1L << 10) // disable + | (0L << 9) // capture + | (0L << 8) // clock + | sgpio_gpio_data_direction + ; - SGPIO_OUT_MUX_CFG( 8) = 0; // SGPIO: Input: clock - SGPIO_OUT_MUX_CFG( 9) = 0; // SGPIO: Input: qualifier - SGPIO_OUT_MUX_CFG(10) = (0L << 4) | (4L << 0); // GPIO: Output: disable - SGPIO_OUT_MUX_CFG(11) = (0L << 4) | (4L << 0); // GPIO: Output: direction + SGPIO_OUT_MUX_CFG( 8) = // SGPIO: Input: clock + SGPIO_OUT_MUX_CFG_P_OE_CFG(0) + | SGPIO_OUT_MUX_CFG_P_OUT_CFG(0) + ; + SGPIO_OUT_MUX_CFG( 9) = // SGPIO: Input: qualifier + SGPIO_OUT_MUX_CFG_P_OE_CFG(0) + | SGPIO_OUT_MUX_CFG_P_OUT_CFG(0) + ; + SGPIO_OUT_MUX_CFG(10) = // GPIO: Output: disable + SGPIO_OUT_MUX_CFG_P_OE_CFG(0) + | SGPIO_OUT_MUX_CFG_P_OUT_CFG(4) + ; + SGPIO_OUT_MUX_CFG(11) = // GPIO: Output: direction + SGPIO_OUT_MUX_CFG_P_OE_CFG(0) + | SGPIO_OUT_MUX_CFG_P_OUT_CFG(4) + ; + const uint_fast8_t output_multiplexing_mode = + multi_slice ? 11 : 9; for(uint_fast8_t i=0; i<8; i++) { // SGPIO pin 0 outputs slice A bit "i". SGPIO_OUT_MUX_CFG(i) = - (0L << 4) | // P_OE_CFG = 0 - (9L << 0); // P_OUT_CFG = 9, dout_doutm8a (8-bit mode 8a) - } - - // Slice A - SGPIO_MUX_CFG(SGPIO_SLICE_A) = - (0L << 12) | // CONCAT_ORDER = 0 (self-loop) - (1L << 11) | // CONCAT_ENABLE = 1 (concatenate data) - (0L << 9) | // QUALIFIER_SLICE_MODE = X - (1L << 7) | // QUALIFIER_PIN_MODE = 1 (SGPIO9) - (3L << 5) | // QUALIFIER_MODE = 3 (external SGPIO pin) - (0L << 3) | // CLK_SOURCE_SLICE_MODE = X - (0L << 1) | // CLK_SOURCE_PIN_MODE = 0 (SGPIO8) - (1L << 0); // EXT_CLK_ENABLE = 1, external clock signal (slice) - - SGPIO_SLICE_MUX_CFG(SGPIO_SLICE_A) = - (0L << 8) | // INV_QUALIFIER = 0 (use normal qualifier) - (3L << 6) | // PARALLEL_MODE = 3 (shift 8 bits per clock) - (0L << 4) | // DATA_CAPTURE_MODE = 0 (detect rising edge) - (0L << 3) | // INV_OUT_CLK = 0 (normal clock) - (1L << 2) | // CLKGEN_MODE = 1 (use external pin clock) - (0L << 1) | // CLK_CAPTURE_MODE = 0 (use rising clock edge) - (0L << 0); // MATCH_MODE = 0 (do not match data) - - SGPIO_PRESET(SGPIO_SLICE_A) = 0; - SGPIO_COUNT(SGPIO_SLICE_A) = 0; - SGPIO_POS(SGPIO_SLICE_A) = (0x3L << 8) | (0x3L << 0); - SGPIO_REG(SGPIO_SLICE_A) = 0x80808080; // Primary output data register - SGPIO_REG_SS(SGPIO_SLICE_A) = 0x80808080; // Shadow output data register - - // Start SGPIO operation by enabling slice clocks. - SGPIO_CTRL_ENABLE = - (1L << SGPIO_SLICE_A) - ; -} - -void sgpio_configure_for_rx() { - // Disable all counters during configuration - SGPIO_CTRL_ENABLE = 0; - - sgpio_configure_pin_functions(); - - // Set SGPIO output values. - SGPIO_GPIO_OUTREG = - (0L << 11) | // direction - (1L << 10); // disable - - // Enable SGPIO pin outputs. - SGPIO_GPIO_OENREG = - (1L << 11) | // direction: RX: data from CPLD - (1L << 10) | // disable - (0L << 9) | // capture - (0L << 8) | // clock - 0x00; // data: input - - SGPIO_OUT_MUX_CFG( 8) = 0; // SGPIO: Input: clock - SGPIO_OUT_MUX_CFG( 9) = 0; // SGPIO: Input: qualifier - SGPIO_OUT_MUX_CFG(10) = (0L << 4) | (4L << 0); // GPIO: Output: disable - SGPIO_OUT_MUX_CFG(11) = (0L << 4) | (4L << 0); // GPIO: Output: direction - - for(uint_fast8_t i=0; i<8; i++) { - SGPIO_OUT_MUX_CFG(i) = - (0L << 4) | // P_OE_CFG = 0 - (9L << 0); // P_OUT_CFG = 9, dout_doutm8a (8-bit mode 8a) - } - - // Slice A - SGPIO_MUX_CFG(SGPIO_SLICE_A) = - (0L << 12) | // CONCAT_ORDER = X - (0L << 11) | // CONCAT_ENABLE = 0 (concatenate data) - (0L << 9) | // QUALIFIER_SLICE_MODE = X - (1L << 7) | // QUALIFIER_PIN_MODE = 1 (SGPIO9) - (3L << 5) | // QUALIFIER_MODE = 3 (external SGPIO pin) - (0L << 3) | // CLK_SOURCE_SLICE_MODE = X - (0L << 1) | // CLK_SOURCE_PIN_MODE = 0 (SGPIO8) - (1L << 0); // EXT_CLK_ENABLE = 1, external clock signal (slice) - - SGPIO_SLICE_MUX_CFG(SGPIO_SLICE_A) = - (0L << 8) | // INV_QUALIFIER = 0 (use normal qualifier) - (3L << 6) | // PARALLEL_MODE = 3 (shift 8 bits per clock) - (0L << 4) | // DATA_CAPTURE_MODE = 0 (detect rising edge) - (0L << 3) | // INV_OUT_CLK = X - (1L << 2) | // CLKGEN_MODE = 1 (use external pin clock) - (1L << 1) | // CLK_CAPTURE_MODE = 1 (use falling clock edge) - (0L << 0); // MATCH_MODE = 0 (do not match data) - - SGPIO_PRESET(SGPIO_SLICE_A) = 0; - SGPIO_COUNT(SGPIO_SLICE_A) = 0; - SGPIO_POS(SGPIO_SLICE_A) = (0 << 8) | (0 << 0); - SGPIO_REG(SGPIO_SLICE_A) = 0xCAFEBABE; // Primary output data register - SGPIO_REG_SS(SGPIO_SLICE_A) = 0xDEADBEEF; // Shadow output data register - - // Start SGPIO operation by enabling slice clocks. - SGPIO_CTRL_ENABLE = - (1L << SGPIO_SLICE_A) - ; -} - -void sgpio_configure_for_rx_deep() { - // Disable all counters during configuration - SGPIO_CTRL_ENABLE = 0; - - sgpio_configure_pin_functions(); - - // Set SGPIO output values. - SGPIO_GPIO_OUTREG = - (0L << 11) | // direction - (1L << 10); // disable - - // Enable SGPIO pin outputs. - SGPIO_GPIO_OENREG = - (1L << 11) | // direction: RX: data from CPLD - (1L << 10) | // disable - (0L << 9) | // capture - (0L << 8) | // clock - 0x00; // data: input - - SGPIO_OUT_MUX_CFG( 8) = 0; // SGPIO: Input: clock - SGPIO_OUT_MUX_CFG( 9) = 0; // SGPIO: Input: qualifier - SGPIO_OUT_MUX_CFG(10) = (0L << 4) | (4L << 0); // GPIO: Output: disable - SGPIO_OUT_MUX_CFG(11) = (0L << 4) | (4L << 0); // GPIO: Output: direction - - for(uint_fast8_t i=0; i<8; i++) { - SGPIO_OUT_MUX_CFG(i) = - (0L << 4) | // P_OE_CFG = 0 - (9L << 0); // P_OUT_CFG = 9, dout_doutm8a (8-bit mode 8a) + SGPIO_OUT_MUX_CFG_P_OE_CFG(0) + | SGPIO_OUT_MUX_CFG_P_OUT_CFG(output_multiplexing_mode) + ; } const uint_fast8_t slice_indices[] = { @@ -249,35 +157,46 @@ void sgpio_configure_for_rx_deep() { SGPIO_SLICE_L, }; + const uint_fast8_t pos = multi_slice ? 0x1f : 0x03; + const bool single_slice = !multi_slice; + const uint_fast8_t slice_count = multi_slice ? 8 : 1; + uint32_t slice_enable_mask = 0; - for(uint_fast8_t i=0; i<8; i++) { - uint_fast8_t slice_index = slice_indices[i]; - const uint_fast8_t concat_order = (slice_index == SGPIO_SLICE_A) ? 0 : 3; - const uint_fast8_t concat_enable = (slice_index == SGPIO_SLICE_A) ? 0 : 1; + for(uint_fast8_t i=0; i + void sgpio_configure_pin_functions(); void sgpio_test_interface(); -void sgpio_configure_for_tx(); -void sgpio_configure_for_rx(); -void sgpio_configure_for_rx_deep(); +void sgpio_configure( + const transceiver_mode_t transceiver_mode, + const bool multi_slice +); void sgpio_cpld_stream_enable(); void sgpio_cpld_stream_disable(); bool sgpio_cpld_stream_is_enabled(); diff --git a/firmware/sgpio-rx/sgpio-rx.c b/firmware/sgpio-rx/sgpio-rx.c index ff87195b..62f29988 100644 --- a/firmware/sgpio-rx/sgpio-rx.c +++ b/firmware/sgpio-rx/sgpio-rx.c @@ -33,7 +33,7 @@ #include void tx_test() { - sgpio_configure_for_tx(); + sgpio_configure(TRANSCEIVER_MODE_TX, false); // LSB goes out first, samples are 0x volatile uint32_t buffer[] = { @@ -54,7 +54,7 @@ void tx_test() { } void rx_test() { - sgpio_configure_for_rx(); + sgpio_configure(TRANSCEIVER_MODE_RX, false); volatile uint32_t buffer[4096]; uint32_t i = 0; diff --git a/firmware/sgpio/sgpio.c b/firmware/sgpio/sgpio.c index 88008313..fbf40ffd 100644 --- a/firmware/sgpio/sgpio.c +++ b/firmware/sgpio/sgpio.c @@ -31,7 +31,7 @@ #include void tx_test() { - sgpio_configure_for_tx(); + sgpio_configure(TRANSCEIVER_MODE_TX, false); // LSB goes out first, samples are 0x volatile uint32_t buffer[] = { @@ -52,7 +52,7 @@ void tx_test() { } void rx_test() { - sgpio_configure_for_rx(); + sgpio_configure(TRANSCEIVER_MODE_RX, false); volatile uint32_t buffer[4096]; uint32_t i = 0; diff --git a/firmware/usb_performance/Makefile b/firmware/usb_performance/Makefile index 7222a2f4..cdde8dd1 100644 --- a/firmware/usb_performance/Makefile +++ b/firmware/usb_performance/Makefile @@ -35,5 +35,4 @@ SRC = $(BINARY).c \ ../common/max5864.c \ ../common/rffc5071.c -LDSCRIPT = ../common/LPC4330_M4_ram_only.ld include ../common/Makefile_inc.mk diff --git a/firmware/usb_performance/usb.h b/firmware/usb_performance/usb.h index 7b9c9390..ccaa9184 100644 --- a/firmware/usb_performance/usb.h +++ b/firmware/usb_performance/usb.h @@ -28,9 +28,8 @@ #include "usb_type.h" -#define ATTR_ALIGNED(x) __attribute__ ((aligned(x))) -#define ATTR_SECTION(x) __attribute__ ((section(x))) - +// TODO: This is a lame move, requiring an extern to be defined to complete +// the interface between this API and the application. extern bool usb_set_configuration( usb_device_t* const device, const uint_fast8_t configuration_number diff --git a/firmware/usb_performance/usb_performance.c b/firmware/usb_performance/usb_performance.c index 5a6989e3..376863b8 100644 --- a/firmware/usb_performance/usb_performance.c +++ b/firmware/usb_performance/usb_performance.c @@ -38,6 +38,8 @@ #include "usb_descriptor.h" #include "usb_standard_request.h" +static volatile transceiver_mode_t transceiver_mode = TRANSCEIVER_MODE_TX; + uint8_t* const usb_bulk_buffer = (uint8_t*)0x20004000; static volatile uint32_t usb_bulk_buffer_offset = 0; static const uint32_t usb_bulk_buffer_mask = 32768 - 1; @@ -202,12 +204,15 @@ bool usb_set_configuration( // hard-coding, this whole function can move into a shared/reusable // library. if( device->configuration && (device->configuration->number == 1) ) { - usb_endpoint_init(&usb_endpoint_bulk_in); - usb_endpoint_init(&usb_endpoint_bulk_out); + if( transceiver_mode == TRANSCEIVER_MODE_RX ) { + sgpio_configure(transceiver_mode, true); + usb_endpoint_init(&usb_endpoint_bulk_in); + } else { + sgpio_configure(transceiver_mode, true); + usb_endpoint_init(&usb_endpoint_bulk_out); + } usb_init_buffers_bulk(); - - sgpio_configure_for_rx_deep(); nvic_set_priority(NVIC_M4_SGPIO_IRQ, 0); nvic_enable_irq(NVIC_M4_SGPIO_IRQ); @@ -237,15 +242,26 @@ void sgpio_irqhandler() { SGPIO_CLR_STATUS_1 = 0xFFFFFFFF; uint32_t* const p = (uint32_t*)&usb_bulk_buffer[usb_bulk_buffer_offset]; - p[7] = SGPIO_REG_SS(SGPIO_SLICE_A); - p[6] = SGPIO_REG_SS(SGPIO_SLICE_I); - p[5] = SGPIO_REG_SS(SGPIO_SLICE_E); - p[4] = SGPIO_REG_SS(SGPIO_SLICE_J); - p[3] = SGPIO_REG_SS(SGPIO_SLICE_C); - p[2] = SGPIO_REG_SS(SGPIO_SLICE_K); - p[1] = SGPIO_REG_SS(SGPIO_SLICE_F); - p[0] = SGPIO_REG_SS(SGPIO_SLICE_L); - + if( transceiver_mode == TRANSCEIVER_MODE_RX ) { + p[7] = SGPIO_REG_SS(SGPIO_SLICE_A); + p[6] = SGPIO_REG_SS(SGPIO_SLICE_I); + p[5] = SGPIO_REG_SS(SGPIO_SLICE_E); + p[4] = SGPIO_REG_SS(SGPIO_SLICE_J); + p[3] = SGPIO_REG_SS(SGPIO_SLICE_C); + p[2] = SGPIO_REG_SS(SGPIO_SLICE_K); + p[1] = SGPIO_REG_SS(SGPIO_SLICE_F); + p[0] = SGPIO_REG_SS(SGPIO_SLICE_L); + } else { + SGPIO_REG_SS(SGPIO_SLICE_A) = p[7]; + SGPIO_REG_SS(SGPIO_SLICE_I) = p[6]; + SGPIO_REG_SS(SGPIO_SLICE_E) = p[5]; + SGPIO_REG_SS(SGPIO_SLICE_J) = p[4]; + SGPIO_REG_SS(SGPIO_SLICE_C) = p[3]; + SGPIO_REG_SS(SGPIO_SLICE_K) = p[2]; + SGPIO_REG_SS(SGPIO_SLICE_F) = p[1]; + SGPIO_REG_SS(SGPIO_SLICE_L) = p[0]; + } + usb_bulk_buffer_offset = (usb_bulk_buffer_offset + 32) & usb_bulk_buffer_mask; } @@ -290,14 +306,28 @@ int main(void) { max2837_rx(); ssp1_set_mode_max5864(); max5864_xcvr(); - - while(true) { - while( usb_bulk_buffer_offset < 16384 ); - usb_endpoint_schedule_no_int(&usb_endpoint_bulk_in, &usb_td_bulk[0]); - - while( usb_bulk_buffer_offset >= 16384 ); - usb_endpoint_schedule_no_int(&usb_endpoint_bulk_in, &usb_td_bulk[1]); - } + while(true) { + // Wait until buffer 0 is transmitted/received. + while( usb_bulk_buffer_offset < 16384 ); + + // Set up IN transfer of buffer 0. + usb_endpoint_schedule_no_int( + (transceiver_mode == TRANSCEIVER_MODE_RX) + ? &usb_endpoint_bulk_in : &usb_endpoint_bulk_out, + &usb_td_bulk[0] + ); + + // Wait until buffer 1 is transmitted/received. + while( usb_bulk_buffer_offset >= 16384 ); + + // Set up IN transfer of buffer 1. + usb_endpoint_schedule_no_int( + (transceiver_mode == TRANSCEIVER_MODE_RX) + ? &usb_endpoint_bulk_in : &usb_endpoint_bulk_out, + &usb_td_bulk[1] + ); + } + return 0; } diff --git a/firmware/usb_performance/usb_request.c b/firmware/usb_performance/usb_request.c index df6ae427..bfa4ea75 100644 --- a/firmware/usb_performance/usb_request.c +++ b/firmware/usb_performance/usb_request.c @@ -19,6 +19,7 @@ * Boston, MA 02110-1301, USA. */ +#include "usb.h" #include "usb_request.h" #include @@ -49,6 +50,9 @@ static void usb_request( if( handler ) { handler(endpoint, stage); + } else { + // USB 2.0 section 9.2.7 "Request Error" + usb_endpoint_stall(endpoint); } } diff --git a/firmware/usb_performance/usb_request.h b/firmware/usb_performance/usb_request.h index a637924f..2d32bcea 100644 --- a/firmware/usb_performance/usb_request.h +++ b/firmware/usb_performance/usb_request.h @@ -38,7 +38,7 @@ typedef enum { } usb_transfer_stage_t; typedef void (*usb_request_handler_fn)( - usb_endpoint_t* const response, + usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage ); diff --git a/firmware/usb_performance/usb_standard_request.c b/firmware/usb_performance/usb_standard_request.c index 1b42bd5e..286d783b 100644 --- a/firmware/usb_performance/usb_standard_request.c +++ b/firmware/usb_performance/usb_standard_request.c @@ -67,7 +67,7 @@ static void usb_send_descriptor( usb_endpoint_t* const endpoint, uint8_t* const descriptor_data ) { - const uint32_t setup_length = (endpoint->setup.length_h << 8) | endpoint->setup.length_l; + const uint32_t setup_length = endpoint->setup.length; uint32_t descriptor_length = descriptor_data[0]; if( descriptor_data[1] == USB_DESCRIPTOR_TYPE_CONFIGURATION ) { descriptor_length = (descriptor_data[3] << 8) | descriptor_data[2]; @@ -221,7 +221,7 @@ static void usb_standard_request_set_configuration( static void usb_standard_request_get_configuration_setup( usb_endpoint_t* const endpoint ) { - if( (endpoint->setup.length_h == 0) && (endpoint->setup.length_l == 1) ) { + if( endpoint->setup.length == 1 ) { endpoint->buffer[0] = 0; if( endpoint->device->configuration ) { endpoint->buffer[0] = endpoint->device->configuration->number; diff --git a/firmware/usb_performance/usb_type.h b/firmware/usb_performance/usb_type.h index 54287fd5..fed3172b 100644 --- a/firmware/usb_performance/usb_type.h +++ b/firmware/usb_performance/usb_type.h @@ -25,15 +25,35 @@ #include #include -typedef struct { +// TODO: Move this to some common compiler-tricks location. +#define ATTR_PACKED __attribute__((packed)) +#define ATTR_ALIGNED(x) __attribute__ ((aligned(x))) +#define ATTR_SECTION(x) __attribute__ ((section(x))) + +typedef struct ATTR_PACKED { uint8_t request_type; uint8_t request; - uint8_t value_l; - uint8_t value_h; - uint8_t index_l; - uint8_t index_h; - uint8_t length_l; - uint8_t length_h; + union { + struct { + uint8_t value_l; + uint8_t value_h; + }; + uint16_t value; + }; + union { + struct { + uint8_t index_l; + uint8_t index_h; + }; + uint16_t index; + }; + union { + struct { + uint8_t length_l; + uint8_t length_h; + }; + uint16_t length; + }; } usb_setup_t; typedef enum { diff --git a/host/usb_test/usb_test.c b/host/usb_test/usb_test.c index 29f08a86..c984898c 100644 --- a/host/usb_test/usb_test.c +++ b/host/usb_test/usb_test.c @@ -21,13 +21,25 @@ #include #include +#include #include +#include #include +#include #include #include +const uint16_t hackrf_usb_pid = 0x1d50; +const uint16_t hackrf_usb_vid = 0x604b; + +typedef enum { + TRANSCEIVER_MODE_RX, + TRANSCEIVER_MODE_TX, +} transceiver_mode_t; +static transceiver_mode_t transceiver_mode = TRANSCEIVER_MODE_RX; + static float TimevalDiff(const struct timeval *a, const struct timeval *b) { @@ -48,31 +60,27 @@ void write_callback(struct libusb_transfer* transfer) { } } -int main(int argc, char** argv) { - if( argc != 2 ) { - printf("Usage: usb_test \n"); - return -1; - } - - const uint32_t buffer_size = 16384; - - fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO); - if( fd == -1 ) { - printf("Failed to open file for write\n"); - return -2; +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_context* context = NULL; +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 -4; + return NULL; } - libusb_device_handle* device = libusb_open_device_with_vid_pid(context, 0x1d50, 0x604b); + 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 -5; + return NULL; } //int speed = libusb_get_device_speed(device); @@ -80,26 +88,46 @@ int main(int argc, char** argv) { result = libusb_set_configuration(device, 1); if( result != 0 ) { + libusb_close(device); printf("libusb_set_configuration() failed: %d\n", result); - return -6; + return NULL; } result = libusb_claim_interface(device, 0); if( result != 0 ) { + libusb_close(device); printf("libusb_claim_interface() failed: %d\n", result); - return -7; + return NULL; } - - unsigned char endpoint_address = 0x81; - //unsigned char endpoint_address = 0x02; - const uint32_t transfer_count = 1024; - struct libusb_transfer* transfers[transfer_count]; + return device; +} + +void free_transfers(struct libusb_transfer** const transfers, const uint32_t transfer_count) { + for(uint32_t transfer_index=0; transfer_indexbuffer == 0 ) { + if( transfers[transfer_index]->buffer == NULL ) { + free_transfers(transfers, transfer_count); printf("malloc() failed\n"); - return -7; + 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 -8; + 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 }; @@ -158,7 +276,9 @@ int main(int argc, char** argv) { call_count += 1; } while(1); - result = libusb_release_interface(device, 0); + 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;