From 7b86403ce83f96f2bb95ace5e8c0e747d596bc89 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Thu, 31 Jan 2019 09:24:59 +0000 Subject: [PATCH 1/3] PortaPack: If hardware not detected, try to init OperaCake. --- firmware/common/hackrf-ui.h | 34 ++++++++++++++++++++++++++++++++ firmware/common/ui_portapack.c | 4 ++++ firmware/common/ui_portapack.h | 28 -------------------------- firmware/hackrf_usb/hackrf_usb.c | 6 +++--- 4 files changed, 41 insertions(+), 31 deletions(-) diff --git a/firmware/common/hackrf-ui.h b/firmware/common/hackrf-ui.h index 2bff25e8..ad295d78 100644 --- a/firmware/common/hackrf-ui.h +++ b/firmware/common/hackrf-ui.h @@ -4,6 +4,40 @@ #include #include +typedef void (*hackrf_ui_init_fn)(void); +typedef void (*hackrf_ui_set_frequency_fn)(uint64_t frequency); +typedef void (*hackrf_ui_set_sample_rate_fn)(uint32_t sample_rate); +typedef void (*hackrf_ui_set_direction_fn)(const rf_path_direction_t direction); +typedef void (*hackrf_ui_set_filter_bw_fn)(uint32_t bandwidth); +typedef void (*hackrf_ui_set_lna_power_fn)(bool lna_on); +typedef void (*hackrf_ui_set_bb_lna_gain_fn)(const uint32_t gain_db); +typedef void (*hackrf_ui_set_bb_vga_gain_fn)(const uint32_t gain_db); +typedef void (*hackrf_ui_set_bb_tx_vga_gain_fn)(const uint32_t gain_db); +typedef void (*hackrf_ui_set_first_if_frequency_fn)(const uint64_t frequency); +typedef void (*hackrf_ui_set_filter_fn)(const rf_path_filter_t filter); +typedef void (*hackrf_ui_set_antenna_bias_fn)(bool antenna_bias); + +typedef struct { + hackrf_ui_init_fn init; + hackrf_ui_set_frequency_fn set_frequency; + hackrf_ui_set_sample_rate_fn set_sample_rate; + hackrf_ui_set_direction_fn set_direction; + hackrf_ui_set_filter_bw_fn set_filter_bw; + hackrf_ui_set_lna_power_fn set_lna_power; + hackrf_ui_set_bb_lna_gain_fn set_bb_lna_gain; + hackrf_ui_set_bb_vga_gain_fn set_bb_vga_gain; + hackrf_ui_set_bb_tx_vga_gain_fn set_bb_tx_vga_gain; + hackrf_ui_set_first_if_frequency_fn set_first_if_frequency; + hackrf_ui_set_filter_fn set_filter; + hackrf_ui_set_antenna_bias_fn set_antenna_bias; +} hackrf_ui_t; + +/* TODO: Lame hack to know that PortaPack was detected. + * In the future, whatever UI was detected will be returned here, + * or NULL if no UI was detected. + */ +const hackrf_ui_t* hackrf_ui(void) __attribute__((weak)); + void hackrf_ui_init(void) __attribute__((weak)); void hackrf_ui_setFrequency(uint64_t _freq) __attribute__((weak)); void hackrf_ui_setSampleRate(uint32_t _sample_rate) __attribute__((weak)); diff --git a/firmware/common/ui_portapack.c b/firmware/common/ui_portapack.c index b68a2e07..0539f80f 100644 --- a/firmware/common/ui_portapack.c +++ b/firmware/common/ui_portapack.c @@ -1046,6 +1046,10 @@ const hackrf_ui_t* portapack_detect(void) { static const hackrf_ui_t* ui = NULL; +const hackrf_ui_t* hackrf_ui(void) { + return ui; +} + void hackrf_ui_init(void) { ui = portapack_detect(); if( ui != NULL ) { diff --git a/firmware/common/ui_portapack.h b/firmware/common/ui_portapack.h index dffcdf47..d4ddda18 100644 --- a/firmware/common/ui_portapack.h +++ b/firmware/common/ui_portapack.h @@ -56,32 +56,4 @@ typedef struct ui_font_t { size_t data_stride; } ui_font_t; -typedef void (*hackrf_ui_init_fn)(void); -typedef void (*hackrf_ui_set_frequency_fn)(uint64_t frequency); -typedef void (*hackrf_ui_set_sample_rate_fn)(uint32_t sample_rate); -typedef void (*hackrf_ui_set_direction_fn)(const rf_path_direction_t direction); -typedef void (*hackrf_ui_set_filter_bw_fn)(uint32_t bandwidth); -typedef void (*hackrf_ui_set_lna_power_fn)(bool lna_on); -typedef void (*hackrf_ui_set_bb_lna_gain_fn)(const uint32_t gain_db); -typedef void (*hackrf_ui_set_bb_vga_gain_fn)(const uint32_t gain_db); -typedef void (*hackrf_ui_set_bb_tx_vga_gain_fn)(const uint32_t gain_db); -typedef void (*hackrf_ui_set_first_if_frequency_fn)(const uint64_t frequency); -typedef void (*hackrf_ui_set_filter_fn)(const rf_path_filter_t filter); -typedef void (*hackrf_ui_set_antenna_bias_fn)(bool antenna_bias); - -typedef struct { - hackrf_ui_init_fn init; - hackrf_ui_set_frequency_fn set_frequency; - hackrf_ui_set_sample_rate_fn set_sample_rate; - hackrf_ui_set_direction_fn set_direction; - hackrf_ui_set_filter_bw_fn set_filter_bw; - hackrf_ui_set_lna_power_fn set_lna_power; - hackrf_ui_set_bb_lna_gain_fn set_bb_lna_gain; - hackrf_ui_set_bb_vga_gain_fn set_bb_vga_gain; - hackrf_ui_set_bb_tx_vga_gain_fn set_bb_tx_vga_gain; - hackrf_ui_set_first_if_frequency_fn set_first_if_frequency; - hackrf_ui_set_filter_fn set_filter; - hackrf_ui_set_antenna_bias_fn set_antenna_bias; -} hackrf_ui_t; - #endif/*__UI_PORTAPACK_H__*/ diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index 75601f42..6c65da9f 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -243,9 +243,9 @@ int main(void) { rf_path_init(&rf_path); -#ifndef USER_INTERFACE_PORTAPACK - operacake_init(); -#endif + if( hackrf_ui() == NULL ) { + operacake_init(); + } unsigned int phase = 0; From 499ac3ad4aeabb01863880a64ff43e944857a45c Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Thu, 31 Jan 2019 09:37:48 +0000 Subject: [PATCH 2/3] PortaPack: Move UI code to hackrf_usb project. Was in common/ and in the common CMake file, which meant it was being included in the blinky project, which was unnecessary. --- firmware/hackrf-common.cmake | 7 ------- firmware/hackrf_usb/CMakeLists.txt | 7 +++++++ firmware/{common => hackrf_usb}/ui_portapack.c | 0 firmware/{common => hackrf_usb}/ui_portapack.h | 0 4 files changed, 7 insertions(+), 7 deletions(-) rename firmware/{common => hackrf_usb}/ui_portapack.c (100%) rename firmware/{common => hackrf_usb}/ui_portapack.h (100%) diff --git a/firmware/hackrf-common.cmake b/firmware/hackrf-common.cmake index ebd853a5..679d4fe7 100644 --- a/firmware/hackrf-common.cmake +++ b/firmware/hackrf-common.cmake @@ -139,13 +139,6 @@ macro(DeclareTargets) ) endif() - if(USER_INTERFACE STREQUAL "PORTAPACK") - SET(SRC_M4 - ${SRC_M4} - ${PATH_HACKRF_FIRMWARE_COMMON}/ui_portapack.c - ) - endif() - configure_file( ${PATH_HACKRF_FIRMWARE_COMMON}/m0_bin.s.cmake m0_bin.s diff --git a/firmware/hackrf_usb/CMakeLists.txt b/firmware/hackrf_usb/CMakeLists.txt index 9af27a13..d1bf109b 100644 --- a/firmware/hackrf_usb/CMakeLists.txt +++ b/firmware/hackrf_usb/CMakeLists.txt @@ -54,4 +54,11 @@ set(SRC_M4 "${PATH_HACKRF_FIRMWARE_COMMON}/operacake.c" ) +if(USER_INTERFACE STREQUAL "PORTAPACK") + SET(SRC_M4 + ${SRC_M4} + ui_portapack.c + ) +endif() + DeclareTargets() diff --git a/firmware/common/ui_portapack.c b/firmware/hackrf_usb/ui_portapack.c similarity index 100% rename from firmware/common/ui_portapack.c rename to firmware/hackrf_usb/ui_portapack.c diff --git a/firmware/common/ui_portapack.h b/firmware/hackrf_usb/ui_portapack.h similarity index 100% rename from firmware/common/ui_portapack.h rename to firmware/hackrf_usb/ui_portapack.h From fa2a9acd1aa09717ac9da3a0af510bfde8e0a099 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Thu, 31 Jan 2019 21:18:24 +0000 Subject: [PATCH 3/3] USB: initial CPLD checksum API support. --- firmware/common/cpld_xc2c.c | 320 ++++++++++++++++++++++++++++ firmware/common/cpld_xc2c.h | 32 +++ firmware/common/crc.c | 49 +++++ firmware/common/crc.h | 38 ++++ firmware/hackrf_usb/CMakeLists.txt | 2 + firmware/hackrf_usb/hackrf_usb.c | 4 +- firmware/hackrf_usb/usb_api_cpld.c | 25 +++ firmware/hackrf_usb/usb_api_cpld.h | 6 + host/hackrf-tools/src/hackrf_info.c | 11 + host/libhackrf/src/hackrf.c | 30 +++ host/libhackrf/src/hackrf.h | 3 + 11 files changed, 519 insertions(+), 1 deletion(-) create mode 100644 firmware/common/cpld_xc2c.c create mode 100644 firmware/common/cpld_xc2c.h create mode 100644 firmware/common/crc.c create mode 100644 firmware/common/crc.h diff --git a/firmware/common/cpld_xc2c.c b/firmware/common/cpld_xc2c.c new file mode 100644 index 00000000..4220abb5 --- /dev/null +++ b/firmware/common/cpld_xc2c.c @@ -0,0 +1,320 @@ +/* + * Copyright 2019 Jared Boone + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "cpld_xc2c.h" + +#include "crc.h" + +#include +#include + +#define CPLD_XC2C64A_ROWS (98) +#define CPLD_XC2C64A_BITS_IN_ROW (274) +#define CPLD_XC2C64A_BYTES_IN_ROW ((CPLD_XC2C64A_BITS_IN_ROW + 7) / 8) + +static const uint8_t cpld_xc2c64a_row_address[CPLD_XC2C64A_ROWS] = { + 0x00, 0x40, 0x60, 0x20, 0x30, 0x70, 0x50, 0x10, 0x18, 0x58, 0x78, 0x38, 0x28, 0x68, 0x48, 0x08, + 0x0c, 0x4c, 0x6c, 0x2c, 0x3c, 0x7c, 0x5c, 0x1c, 0x14, 0x54, 0x74, 0x34, 0x24, 0x64, 0x44, 0x04, + 0x06, 0x46, 0x66, 0x26, 0x36, 0x76, 0x56, 0x16, 0x1e, 0x5e, 0x7e, 0x3e, 0x2e, 0x6e, 0x4e, 0x0e, + 0x0a, 0x4a, 0x6a, 0x2a, 0x3a, 0x7a, 0x5a, 0x1a, 0x12, 0x52, 0x72, 0x32, 0x22, 0x62, 0x42, 0x02, + 0x03, 0x43, 0x63, 0x23, 0x33, 0x73, 0x53, 0x13, 0x1b, 0x5b, 0x7b, 0x3b, 0x2b, 0x6b, 0x4b, 0x0b, + 0x0f, 0x4f, 0x6f, 0x2f, 0x3f, 0x7f, 0x5f, 0x1f, 0x17, 0x57, 0x77, 0x37, 0x27, 0x67, 0x47, 0x07, + 0x05, 0x45, +}; + +static const uint8_t cpld_xc2c64a_mask[6][CPLD_XC2C64A_BYTES_IN_ROW] = { + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, }, + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, }, + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xf8, 0x1f, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, }, + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x80, 0x1f, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, }, + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x80, 0x07, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, }, +}; + +static const uint8_t cpld_xc2c64a_row_mask_index[CPLD_XC2C64A_ROWS] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2, 2, 2, 3, 4, 2, 2, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2, 2, 2, 2, 2, 5, 2, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, +}; + +typedef enum { + CPLD_XC2C_IR_INTEST = 0b00000010, + CPLD_XC2C_IR_BYPASS = 0b11111111, + CPLD_XC2C_IR_SAMPLE = 0b00000011, + CPLD_XC2C_IR_EXTEST = 0b00000000, + CPLD_XC2C_IR_IDCODE = 0b00000001, + CPLD_XC2C_IR_USERCODE = 0b11111101, + CPLD_XC2C_IR_HIGHZ = 0b11111100, + CPLD_XC2C_IR_ISC_ENABLE_CLAMP = 0b11101001, + CPLD_XC2C_IR_ISC_ENABLE_OTF = 0b11100100, + CPLD_XC2C_IR_ISC_ENABLE = 0b11101000, + CPLD_XC2C_IR_ISC_SRAM_READ = 0b11100111, + CPLD_XC2C_IR_ISC_WRITE = 0b11100110, + CPLD_XC2C_IR_ISC_ERASE = 0b11101101, + CPLD_XC2C_IR_ISC_PROGRAM = 0b11101010, + CPLD_XC2C_IR_ISC_READ = 0b11101110, + CPLD_XC2C_IR_ISC_INIT = 0b11110000, + CPLD_XC2C_IR_ISC_DISABLE = 0b11000000, + CPLD_XC2C_IR_TEST_ENABLE = 0b00010001, + CPLD_XC2C_IR_BULKPROG = 0b00010010, + CPLD_XC2C_IR_ERASE_ALL = 0b00010100, + CPLD_XC2C_IR_MVERIFY = 0b00010011, + CPLD_XC2C_IR_TEST_DISABLE = 0b00010101, + CPLD_XC2C_IR_STCTEST = 0b00010110, + CPLD_XC2C_IR_ISC_NOOP = 0b11100000, +} cpld_xc2c_ir_t; + +static bool cpld_xc2c_jtag_clock(const jtag_t* const jtag, const uint32_t tms, const uint32_t tdi) { + // 8 ns TMS/TDI to TCK setup + gpio_write(jtag->gpio->gpio_tdi, tdi); + gpio_write(jtag->gpio->gpio_tms, tms); + + // 20 ns TCK high time + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + + gpio_clear(jtag->gpio->gpio_tck); + + // 25 ns TCK falling edge to TDO valid + // 20 ns TCK low time + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + + gpio_set(jtag->gpio->gpio_tck); + + // 15 ns TCK to TMS/TDI hold time + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + + return gpio_read(jtag->gpio->gpio_tdo); +} + +static void cpld_xc2c_jtag_shift_ptr(const jtag_t* const jtag, uint8_t* const tdi_tdo, const size_t count) { + for(size_t i=0; i> 3; + const size_t bit_n = i & 7; + const uint32_t mask = (1U << bit_n); + const bool tms = (i == (count - 1)); + + const uint32_t tdo = cpld_xc2c_jtag_clock(jtag, tms, tdi_tdo[byte_n] & mask) ? 1 : 0; + + tdi_tdo[byte_n] &= ~mask; + tdi_tdo[byte_n] |= (tdo << bit_n); + } +} + +static uint32_t cpld_xc2c_jtag_shift_u32(const jtag_t* const jtag, const uint32_t tms, const uint32_t tdi, const size_t count) { + uint32_t tdo = 0; + + for(size_t i=0; i Shift-DR or Shift-IR */ + cpld_xc2c_jtag_shift_u32(jtag, 0b001, 0b000, 3); + /* Shift-[DI]R -> Exit1-[DI]R */ + cpld_xc2c_jtag_shift_ptr(jtag, tdi_tdo, bit_count); + if( pause_count ) { + /* Exit1-[DI]R -> Pause-[DI]R */ + cpld_xc2c_jtag_shift_u32(jtag, 0b0, 0, 1); + /* Pause-[DI]R -> Exit2-[DI]R */ + cpld_xc2c_jtag_pause(jtag, pause_count); + } + /* Exit1-[DI]R or Exit2-[DI]R -> Run-Test/Idle */ + cpld_xc2c_jtag_shift_u32(jtag, 0b01, 0, 2); +} + +static void cpld_xc2c_jtag_shift_dr(const jtag_t* const jtag, uint8_t* const tdi_tdo, const size_t bit_count, const size_t pause_count) { + cpld_xc2c_jtag_shift_dr_ir(jtag, tdi_tdo, bit_count, pause_count); +} + +static uint8_t cpld_xc2c_jtag_shift_ir_pause(const jtag_t* const jtag, const cpld_xc2c_ir_t ir, const size_t pause_count) { + /* Run-Test/Idle -> Select-DR-Scan */ + cpld_xc2c_jtag_shift_u32(jtag, 0b1, 0b0, 1); + uint8_t value = ir; + cpld_xc2c_jtag_shift_dr_ir(jtag, &value, 8, pause_count); + return value; +} + +static uint8_t cpld_xc2c_jtag_shift_ir(const jtag_t* const jtag, const cpld_xc2c_ir_t ir) { + return cpld_xc2c_jtag_shift_ir_pause(jtag, ir, 0); +} + +static void cpld_xc2c_jtag_reset_and_idle(const jtag_t* const jtag) { + /* Five TMS=1 to reach Test-Logic-Reset from any point in the TAP state diagram. + * One TMS=0 to move from Test-Logic-Reset to Run-Test-Idle. + */ + cpld_xc2c_jtag_shift_u32(jtag, 0b011111, 0, 6); +} + +static uint32_t cpld_xc2c_jtag_idcode(const jtag_t* const jtag) { + /* Enter and end at Run-Test-Idle state. */ + cpld_xc2c_jtag_shift_ir(jtag, CPLD_XC2C_IR_IDCODE); + uint32_t result = 0; + cpld_xc2c_jtag_shift_dr(jtag, (uint8_t*)&result, 32, 0); + return result; +} + +static bool cpld_xc2c64a_jtag_idcode_ok(const jtag_t* const jtag) { + return ((cpld_xc2c_jtag_idcode(jtag) ^ 0xf6e5f093) & 0x0fff8fff) == 0; +} + +static void cpld_xc2c_jtag_conld(const jtag_t* const jtag) { + cpld_xc2c_jtag_shift_ir(jtag, CPLD_XC2C_IR_ISC_DISABLE); + cpld_xc2c_jtag_clocks(jtag, 100); +} + +static void cpld_xc2c_jtag_enable(const jtag_t* const jtag) { + cpld_xc2c_jtag_shift_ir(jtag, CPLD_XC2C_IR_ISC_ENABLE); +} + +static uint32_t cpld_xc2c_jtag_bypass(const jtag_t* const jtag, const bool shift_dr) { + const uint8_t result = cpld_xc2c_jtag_shift_ir(jtag, CPLD_XC2C_IR_BYPASS); + if( shift_dr ) { + uint8_t dr = 0; + cpld_xc2c_jtag_shift_dr(jtag, &dr, 1, 0); + } + return result; +} + +static bool cpld_xc2c_jtag_read_write_protect(const jtag_t* const jtag) { + /* Enter and end at Run-Test-Idle state. */ + return ((cpld_xc2c_jtag_bypass(jtag, false) ^ 0x01) & 0x03) == 0; +} + +static bool cpld_xc2c_jtag_is_done(const jtag_t* const jtag) { + return ((cpld_xc2c_jtag_bypass(jtag, false) ^ 0x05) & 0x07) == 0; +} + +static void cpld_xc2c_jtag_init_special(const jtag_t* const jtag) { + cpld_xc2c_jtag_shift_ir(jtag, CPLD_XC2C_IR_ISC_INIT); + cpld_xc2c_jtag_clocks(jtag, 20); + /* Run-Test/Idle -> Shift-IR */ + cpld_xc2c_jtag_shift_u32(jtag, 0b0011, 0b0000, 4); + /* Shift-IR: 0xf0 -> Exit1-IR */ + cpld_xc2c_jtag_shift_u32(jtag, 0x80, CPLD_XC2C_IR_ISC_INIT, 8); + /* Exit1-IR -> Pause-IR */ + cpld_xc2c_jtag_shift_u32(jtag, 0b0, 0, 1); + /* Pause-IR -> Exit2-IR -> Update-IR -> Select-DR-Scan -> Capture-DR -> Exit1-DR -> Update-DR -> Run-Test/Idle */ + cpld_xc2c_jtag_shift_u32(jtag, 0b0110111, 0, 7); + cpld_xc2c_jtag_clocks(jtag, 800); +} + +static void cpld_xc2c_jtag_read(const jtag_t* const jtag) { + cpld_xc2c_jtag_shift_ir_pause(jtag, CPLD_XC2C_IR_ISC_READ, 1); +} + +static void cpld_xc2c64a_jtag_read_row(const jtag_t* const jtag, uint8_t address, uint8_t* const dr) { + cpld_xc2c_jtag_shift_dr(jtag, &address, 7, 20); + cpld_xc2c_jtag_clocks(jtag, 100); + + /* Set array to all ones so we don't transmit memory contents over TDI, and if we're not + * reading a full byte's worth of bits, the excess bits will be zero. + */ + memset(dr, 0xff, CPLD_XC2C64A_BYTES_IN_ROW); + cpld_xc2c_jtag_shift_dr(jtag, dr, CPLD_XC2C64A_BITS_IN_ROW, 0); + cpld_xc2c_jtag_clocks(jtag, 100); +} + +bool cpld_xc2c64a_jtag_checksum(const jtag_t* const jtag, uint32_t* const crc_value) { + cpld_xc2c_jtag_reset_and_idle(jtag); + + if( cpld_xc2c64a_jtag_idcode_ok(jtag) && cpld_xc2c_jtag_read_write_protect(jtag) && + cpld_xc2c64a_jtag_idcode_ok(jtag) && cpld_xc2c_jtag_read_write_protect(jtag) ) { + + cpld_xc2c_jtag_bypass(jtag, false); + + cpld_xc2c_jtag_enable(jtag); + cpld_xc2c_jtag_enable(jtag); + cpld_xc2c_jtag_enable(jtag); + + cpld_xc2c_jtag_read(jtag); + + crc32_t crc; + crc32_init(&crc); + + uint8_t dr[CPLD_XC2C64A_BYTES_IN_ROW]; + for(size_t row=0; row + * + * 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 __CPLD_XC2C_H__ +#define __CPLD_XC2C_H__ + +#include +#include + +#include "cpld_jtag.h" + +bool cpld_xc2c64a_jtag_checksum(const jtag_t* const jtag, uint32_t* const crc_value); + +#endif/*__CPLD_XC2C_H__*/ diff --git a/firmware/common/crc.c b/firmware/common/crc.c new file mode 100644 index 00000000..4a687e70 --- /dev/null +++ b/firmware/common/crc.c @@ -0,0 +1,49 @@ +/* + * Copyright 2019 Jared Boone + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "crc.h" + +#include + +void crc32_init(crc32_t* const crc) { + crc->remainder = 0xffffffff; + crc->reversed_polynomial = 0xedb88320; + crc->final_xor = 0xffffffff; +} + +void crc32_update(crc32_t* const crc, const uint8_t* const data, const size_t byte_count) { + uint32_t remainder = crc->remainder; + const size_t bit_count = byte_count * 8; + for(size_t bit_n=0; bit_n> 3] & (1 << (bit_n & 7)); + remainder ^= (bit_in ? 1 : 0); + const bool bit_out = (remainder & 1); + remainder >>= 1; + if( bit_out ) { + remainder ^= crc->reversed_polynomial; + } + } + crc->remainder = remainder; +} + +uint32_t crc32_digest(const crc32_t* const crc) { + return crc->remainder ^ crc->final_xor; +} diff --git a/firmware/common/crc.h b/firmware/common/crc.h new file mode 100644 index 00000000..9ee1a2ad --- /dev/null +++ b/firmware/common/crc.h @@ -0,0 +1,38 @@ +/* + * Copyright 2019 Jared Boone + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __CRC_H__ +#define __CRC_H__ + +#include +#include + +typedef struct { + uint32_t remainder; + uint32_t reversed_polynomial; + uint32_t final_xor; +} crc32_t; + +void crc32_init(crc32_t* const crc); +void crc32_update(crc32_t* const crc, const uint8_t* const data, const size_t byte_count); +uint32_t crc32_digest(const crc32_t* const crc); + +#endif//__CRC_H__ diff --git a/firmware/hackrf_usb/CMakeLists.txt b/firmware/hackrf_usb/CMakeLists.txt index d1bf109b..e6c827c1 100644 --- a/firmware/hackrf_usb/CMakeLists.txt +++ b/firmware/hackrf_usb/CMakeLists.txt @@ -47,6 +47,8 @@ set(SRC_M4 "${PATH_HACKRF_FIRMWARE_COMMON}/usb_queue.c" "${PATH_HACKRF_FIRMWARE_COMMON}/fault_handler.c" "${PATH_HACKRF_FIRMWARE_COMMON}/cpld_jtag.c" + "${PATH_HACKRF_FIRMWARE_COMMON}/cpld_xc2c.c" + "${PATH_HACKRF_FIRMWARE_COMMON}/crc.c" "${PATH_HACKRF_FIRMWARE_COMMON}/xapp058/lenval.c" "${PATH_HACKRF_FIRMWARE_COMMON}/xapp058/micro.c" "${PATH_HACKRF_FIRMWARE_COMMON}/xapp058/ports.c" diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index 6c65da9f..8bb8b417 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -87,6 +87,7 @@ typedef enum { HACKRF_VENDOR_REQUEST_SPIFLASH_STATUS = 33, HACKRF_VENDOR_REQUEST_SPIFLASH_CLEAR_STATUS = 34, HACKRF_VENDOR_REQUEST_OPERACAKE_GPIO_TEST = 35, + HACKRF_VENDOR_REQUEST_CPLD_CHECKSUM = 36, /* Update to be the next integer after the highest-numbered request. */ _HACKRF_VENDOR_REQUEST_ARRAY_SIZE @@ -137,7 +138,8 @@ static usb_request_handler_fn vendor_request_handler[] = { usb_vendor_request_set_clkout_enable, usb_vendor_request_spiflash_status, usb_vendor_request_spiflash_clear_status, - usb_vendor_request_operacake_gpio_test + usb_vendor_request_operacake_gpio_test, + usb_vendor_request_cpld_checksum, }; static const uint32_t vendor_request_handler_count = diff --git a/firmware/hackrf_usb/usb_api_cpld.c b/firmware/hackrf_usb/usb_api_cpld.c index 3b5b8c91..f1cf1ec4 100644 --- a/firmware/hackrf_usb/usb_api_cpld.c +++ b/firmware/hackrf_usb/usb_api_cpld.c @@ -24,6 +24,7 @@ #include #include +#include #include #include "usb_endpoint.h" @@ -95,3 +96,27 @@ void cpld_update(void) while (1); } } + +usb_request_status_t usb_vendor_request_cpld_checksum( + usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) +{ + static uint32_t cpld_crc; + uint8_t length; + + if (stage == USB_TRANSFER_STAGE_SETUP) + { + cpld_jtag_take(&jtag_cpld); + const bool checksum_success = cpld_xc2c64a_jtag_checksum(&jtag_cpld, &cpld_crc); + cpld_jtag_release(&jtag_cpld); + + if(!checksum_success) { + return USB_REQUEST_STATUS_STALL; + } + + length = (uint8_t)sizeof(cpld_crc); + usb_transfer_schedule_block(endpoint->in, &cpld_crc, length, + NULL, NULL); + usb_transfer_schedule_ack(endpoint->out); + } + return USB_REQUEST_STATUS_OK; +} diff --git a/firmware/hackrf_usb/usb_api_cpld.h b/firmware/hackrf_usb/usb_api_cpld.h index 5bafdfef..a097c6a8 100644 --- a/firmware/hackrf_usb/usb_api_cpld.h +++ b/firmware/hackrf_usb/usb_api_cpld.h @@ -25,8 +25,14 @@ #include +#include +#include + extern volatile bool start_cpld_update; void cpld_update(void); +usb_request_status_t usb_vendor_request_cpld_checksum( + usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); + #endif /* end of include guard: __USB_API_CPLD_H__ */ diff --git a/host/hackrf-tools/src/hackrf_info.c b/host/hackrf-tools/src/hackrf_info.c index 1eb2273b..9c10ad5f 100644 --- a/host/hackrf-tools/src/hackrf_info.c +++ b/host/hackrf-tools/src/hackrf_info.c @@ -126,6 +126,17 @@ int main(void) } } + uint32_t cpld_crc = 0; + result = hackrf_cpld_checksum(device, &cpld_crc); + if ((result != HACKRF_SUCCESS) && (result != HACKRF_ERROR_USB_API_VERSION)) { + fprintf(stderr, "hackrf_cpld_checksum() failed: %s (%d)\n", + hackrf_error_name(result), result); + return EXIT_FAILURE; + } + if(result == HACKRF_SUCCESS) { + printf("CPLD checksum: 0x%08x\n", cpld_crc); + } + result = hackrf_close(device); if (result != HACKRF_SUCCESS) { fprintf(stderr, "hackrf_close() failed: %s (%d)\n", diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index 56e9318d..db1cf862 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -84,6 +84,7 @@ typedef enum { HACKRF_VENDOR_REQUEST_SPIFLASH_STATUS = 33, HACKRF_VENDOR_REQUEST_SPIFLASH_CLEAR_STATUS = 34, HACKRF_VENDOR_REQUEST_OPERACAKE_GPIO_TEST = 35, + HACKRF_VENDOR_REQUEST_CPLD_CHECKSUM = 36, } hackrf_vendor_request; #define USB_CONFIG_STANDARD 0x1 @@ -2104,6 +2105,35 @@ int ADDCALL hackrf_operacake_gpio_test(hackrf_device* device, const uint8_t addr } } +int ADDCALL hackrf_cpld_checksum(hackrf_device* device, + uint32_t* crc) +{ + USB_API_REQUIRED(device, 0x0103) + uint8_t length; + int result; + + length = sizeof(*crc); + result = libusb_control_transfer( + device->usb_device, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + HACKRF_VENDOR_REQUEST_CPLD_CHECKSUM, + 0, + 0, + (unsigned char*)crc, + length, + 0 + ); + + if (result < length) + { + last_libusb_error = result; + return HACKRF_ERROR_LIBUSB; + } else { + *crc = TO_LE(*crc); + return HACKRF_SUCCESS; + } +} + #ifdef __cplusplus } // __cplusplus defined. #endif diff --git a/host/libhackrf/src/hackrf.h b/host/libhackrf/src/hackrf.h index abd7debd..2dfdb8d4 100644 --- a/host/libhackrf/src/hackrf.h +++ b/host/libhackrf/src/hackrf.h @@ -255,6 +255,9 @@ extern ADDAPI int ADDCALL hackrf_operacake_gpio_test(hackrf_device* device, uint8_t address, uint16_t* test_result); +extern ADDAPI int ADDCALL hackrf_cpld_checksum(hackrf_device* device, + uint32_t* crc); + #ifdef __cplusplus } // __cplusplus defined. #endif