This commit is contained in:
Jared Boone
2013-03-22 16:59:27 -07:00
15 changed files with 720 additions and 37 deletions

1
firmware/.gitignore vendored
View File

@ -6,3 +6,4 @@
*.map
*.o
*.srec
*.dfu

View File

@ -1,6 +1,7 @@
/*
* Copyright 2012 Michael Ossmann <mike@ossmann.com>
* Copyright 2012 Jared Boone <jared@sharebrained.com>
* Copyright 2013 Benjamin Vernoux <titanmkd@gmail.com>
*
* This file is part of HackRF.
*
@ -23,6 +24,7 @@
#include "hackrf_core.h"
#include "si5351c.h"
#include "max2837.h"
#include "rffc5071.h"
#include <libopencm3/lpc43xx/i2c.h>
#include <libopencm3/lpc43xx/cgu.h>
#include <libopencm3/lpc43xx/gpio.h>

View File

@ -535,7 +535,7 @@ void rffc5071_set_gpo(uint8_t gpo)
int main(int ac, char **av)
{
rffc5071_setup();
rffc5071_tx();
rffc5071_tx(0);
rffc5071_set_frequency(500, 0);
rffc5071_set_frequency(525, 0);
rffc5071_set_frequency(550, 0);
@ -543,7 +543,7 @@ int main(int ac, char **av)
rffc5071_set_frequency(1525, 0);
rffc5071_set_frequency(1550, 0);
rffc5071_disable();
rffc5071_rx();
rffc5071_rx(0);
rffc5071_disable();
rffc5071_rxtx();
rffc5071_disable();

View File

@ -36,12 +36,12 @@ extern uint32_t rffc5071_regs_dirty;
* RF switches on Jawbreaker are controlled by General Purpose Outputs (GPO) on
* the RFFC5072.
*/
#define SWITCHCTRL_NO_TX_AMP_PWR (1 << 0) /* turn off TX amp power */
#define SWITCHCTRL_AMP_BYPASS (1 << 1) /* bypass amp section */
#define SWITCHCTRL_TX (1 << 2) /* 1 for TX mode, 0 for RX mode */
#define SWITCHCTRL_MIX_BYPASS (1 << 3) /* bypass RFFC5072 mixer section */
#define SWITCHCTRL_HP (1 << 4) /* 1 for high-pass, 0 for low-pass */
#define SWITCHCTRL_NO_RX_AMP_PWR (1 << 5) /* turn off RX amp power */
#define SWITCHCTRL_NO_TX_AMP_PWR (1 << 0) /* GPO1 turn off TX amp power */
#define SWITCHCTRL_AMP_BYPASS (1 << 1) /* GPO2 bypass amp section */
#define SWITCHCTRL_TX (1 << 2) /* GPO3 1 for TX mode, 0 for RX mode */
#define SWITCHCTRL_MIX_BYPASS (1 << 3) /* GPO4 bypass RFFC5072 mixer section */
#define SWITCHCTRL_HP (1 << 4) /* GPO5 1 for high-pass, 0 for low-pass */
#define SWITCHCTRL_NO_RX_AMP_PWR (1 << 5) /* GPO6 turn off RX amp power */
/*
* Safe (initial) switch settings turn off both amplifiers and enable both amp

101
firmware/common/rom_iap.c Normal file
View File

@ -0,0 +1,101 @@
/*
* Copyright 2013 Benjamin Vernoux <titanmkd@gmail.com>
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "hackrf_core.h"
#include <stdint.h>
#include "rom_iap.h"
#define ROM_IAP_ADDR (0x10400100)
#define ROM_IAP_UNDEF_ADDR (0x12345678)
#define ROM_OTP_PART_ID_ADDR (0x40045000)
#define ROM_OTP_SERIAL_NO_ADDR (0x40045050) /* To be confirmed */
typedef void (* IAP_t)(uint32_t [],uint32_t[]);
typedef struct {
const IAP_t IAP; /* If equal to 0x12345678 IAP not implemented */
/* Other TBD */
} *pENTRY_ROM_API_t;
#define pROM_API ((pENTRY_ROM_API_t)ROM_IAP_ADDR)
/*
See Errata sheet ES_LPC43X0_A.pdf (LPC4350/30/20/10 Rev A)
3.5 IAP.1: In-Application Programming API not present on flashless parts
Introduction:
The LPC43x0 microcontrollers contain an APIfor In-Application Programming of flash
memory. This API also allows identification of the part.
Problem:
On the LPC43x0 microcontrollers, the IAP API is not present. The ISP interface is present
which allows the part to be identified externally (via the UART) but part identification is not
possible internally using the IAP call because it is not implemented.
The first word of the Part ID can be read directly from OTP at 0x40045000. The second word of the Part ID is always
'0' on flashless parts. */
bool iap_is_implemented(void)
{
bool res;
if( *((uint32_t*)ROM_IAP_ADDR) != ROM_IAP_UNDEF_ADDR )
{
res = true;
}else
{
res = false;
}
return res;
}
isp_iap_ret_code_t iap_cmd_call(iap_cmd_res_t* iap_cmd_res)
{
uint32_t* p_u32_data;
if( iap_is_implemented() )
{
pROM_API->IAP( (uint32_t*)&iap_cmd_res->cmd_param, (uint32_t*)&iap_cmd_res->status_res);
}else
{
/* Alternative way to retrieve Part Id & Serial No on MCU with no IAP */
switch(iap_cmd_res->cmd_param.command_code)
{
case IAP_CMD_READ_PART_ID_NO:
p_u32_data = (uint32_t*)ROM_OTP_PART_ID_ADDR;
iap_cmd_res->status_res.iap_result[0] = p_u32_data[0];
iap_cmd_res->status_res.iap_result[1] = p_u32_data[1];
iap_cmd_res->status_res.status_ret = CMD_SUCCESS;
break;
case IAP_CMD_READ_SERIAL_NO:
p_u32_data = (uint32_t*)ROM_OTP_SERIAL_NO_ADDR;
iap_cmd_res->status_res.iap_result[0] = p_u32_data[0];
iap_cmd_res->status_res.iap_result[1] = p_u32_data[1];
iap_cmd_res->status_res.iap_result[2] = p_u32_data[2];
iap_cmd_res->status_res.iap_result[3] = p_u32_data[3];
iap_cmd_res->status_res.status_ret = CMD_SUCCESS;
break;
default:
iap_cmd_res->status_res.status_ret = ERROR_IAP_NOT_IMPLEMENTED;
break;
}
}
return iap_cmd_res->status_res.status_ret;
}

121
firmware/common/rom_iap.h Normal file
View File

@ -0,0 +1,121 @@
/*
* Copyright 2013 Benjamin Vernoux <titanmkd@gmail.com>
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __ROM_IAP__
#define __ROM_IAP__
#include <stdint.h>
typedef enum
{
/* TODO define other commands */
IAP_CMD_INIT_IAP = 49,
/* Command Init IAP
Input Command code: 49 (decimal)
Return Code CMD_SUCCESS
Result None
Description Initializes and prepares the flash for erase and write operations.
Stack usage 88 B */
IAP_CMD_READ_PART_ID_NO = 54,
/* Read part identification number
Command Read part identification number
Input Command code: 54 (decimal)
Parameters:None
Return Code CMD_SUCCESS |
Result Result0:Part Identification Number.
Result1:Part Identification Number.
Description This command is used to read the part identification number. See Table 1082
LPC43xx part identification numbers.
The command returns two words: word0 followed by word1. Word 0 corresponds
to the part id and word1 indicates the flash configuration or contains 0x0 for
flashless parts.
Stack usage 8 B */
IAP_CMD_READ_SERIAL_NO = 58
/* Read device serial number
Input Command code: 58 (decimal)
Parameters: None
Return Code CMD_SUCCESS
Result Result0:First 32-bit word of Device Identification Number (at the lowest address)
Result1:Second 32-bit word of Device Identification Number
Result2:Third 32-bit word of Device Identification Number
Result3:Fourth 32-bit word of Device Identification Number
Description This command is used to read the device identification number. The serial number
may be used to uniquely identify a single unit among all LPC43xx devices.
Stack usage 8 B */
} iap_cmd_code_t;
/* ISP/IAP Return Code */
typedef enum
{
CMD_SUCCESS = 0x00000000, /* CMD_SUCCESS Command is executed successfully. Sent by ISP handler only when command given by the host has been completely and successfully executed. */
INVALID_COMMAND = 0x00000001, /* Invalid command. */
SRC_ADDR_ERROR = 0x00000002, /* Source address is not on word boundary. */
DST_ADDR_ERROR = 0x00000003, /* Destination address not on word or 256 byte boundary. */
SRC_ADDR_NOT_MAPPED = 0x00000004, /* Source address is not mapped in the memory map. Count value is taken into consideration where applicable. */
DST_ADDR_NOT_MAPPED = 0x00000005, /* Destination address is not mapped in the memory map. Count value is taken into consideration where applicable.*/
COUNT_ERROR = 0x00000006, /* Byte count is not multiple of 4 or is not a permitted value. */
INVALID_SECTOR = 0x00000007, /* Sector number is invalid or end sector number is greater than start sector number. */
SECTOR_NOT_BLANK = 0x00000008, /* Sector is not blank. */
SECTOR_NOT_PREP_WRITE_OP = 0x00000009, /* Command to prepare sector for write operation was not executed. */
COMPARE_ERROR = 0x0000000A, /* Source and destination data not equal. */
BUSY = 0x0000000B, /* Flash programming hardware interface is busy. */
PARAM_ERROR = 0x0000000C, /* Insufficient number of parameters or invalid parameter. */
ADDR_ERROR = 0x0000000D, /* Address is not on word boundary. */
ADDR_NOT_MAPPED = 0x0000000E, /* Address is not mapped in the memory map. Count value is taken in to consideration where applicable. */
CMD_LOCKED = 0x0000000F, /* Command is locked. */
INVALID_CODE = 0x00000010, /* Unlock code is invalid. */
INVALID_BAUD_RATE = 0x00000011, /* Invalid baud rate setting. */
INVALID_STOP_BIT = 0x00000012, /* Invalid stop bit setting. */
CODE_READ_PROTECTION_ENABLED = 0x00000013, /* Code read protection enabled. */
INVALID_FLASH_UNIT = 0x00000014, /* Invalid flash unit. */
USER_CODE_CHECKSUM = 0x00000015,
ERROR_SETTING_ACTIVE_PARTITION = 0x00000016,
/* Special Error */
ERROR_IAP_NOT_IMPLEMENTED = 0x00000100 /* IAP is not implemented in this part */
} isp_iap_ret_code_t;
typedef struct
{
/* Input Command/Param */
struct
{
iap_cmd_code_t command_code;
uint32_t iap_param[5];
} cmd_param;
/* Output Status/Result */
struct
{
isp_iap_ret_code_t status_ret;
uint32_t iap_result[4];
} status_res;
} iap_cmd_res_t;
/* Check if IAP is implemented */
bool iap_is_implemented(void);
isp_iap_ret_code_t iap_cmd_call(iap_cmd_res_t* iap_cmd_res);
#endif//__ROM_IAP__

View File

@ -38,6 +38,7 @@ SRC = $(BINARY).c \
../common/cpld_jtag.c \
../common/xapp058/lenval.c \
../common/xapp058/micro.c \
../common/xapp058/ports.c
../common/xapp058/ports.c \
../common/rom_iap.c
include ../common/Makefile_inc.mk

View File

@ -38,7 +38,8 @@ SRC = usb_performance.c \
../common/cpld_jtag.c \
../common/xapp058/lenval.c \
../common/xapp058/micro.c \
../common/xapp058/ports.c
../common/xapp058/ports.c \
../common/rom_iap.c
LDSCRIPT = ../common/LPC4330_M4_rom_to_ram.ld
include ../common/Makefile_inc.mk

View File

@ -34,6 +34,7 @@
#include <w25q80bv.h>
#include <cpld_jtag.h>
#include <sgpio.h>
#include <rom_iap.h>
#include "usb.h"
#include "usb_type.h"
@ -53,8 +54,113 @@ const uint_fast8_t usb_td_bulk_count = sizeof(usb_td_bulk) / sizeof(usb_td_bulk[
uint8_t spiflash_buffer[W25Q80BV_PAGE_LEN];
char version_string[] = VERSION_STRING;
typedef struct {
uint32_t freq_mhz;
uint32_t freq_hz;
} set_freq_params_t;
set_freq_params_t set_freq_params;
uint8_t spiflash_buffer[W25Q80BV_PAGE_LEN];
uint8_t switchctrl = 0;
void update_switches(void)
{
if (transceiver_mode == TRANSCEIVER_MODE_RX) {
rffc5071_rx(switchctrl);
} else if (transceiver_mode == TRANSCEIVER_MODE_TX) {
rffc5071_tx(switchctrl);
}
}
#define FREQ_ONE_MHZ (1000*1000)
#define MIN_LP_FREQ_MHZ (30)
#define MAX_LP_FREQ_MHZ (2300)
#define MIN_BYPASS_FREQ_MHZ (2300)
#define MAX_BYPASS_FREQ_MHZ (2700)
#define MIN_HP_FREQ_MHZ (2700)
#define MAX_HP_FREQ_MHZ (6000)
#define MAX2837_FREQ_NOMINAL_HZ (2600000000)
#define MAX2837_FREQ_NOMINAL_MHZ (MAX2837_FREQ_NOMINAL_HZ / FREQ_ONE_MHZ)
/*
* Set freq/tuning between 30MHz to 6000 MHz (less than 16bits really used)
* hz between 0 to 999999 Hz (not checked)
* return false on error or true if success.
*/
bool set_freq(uint32_t freq_mhz, uint32_t freq_hz)
{
bool success;
uint32_t RFFC5071_freq_mhz;
uint32_t MAX2837_freq_hz;
uint32_t real_RFFC5071_freq_mhz;
uint32_t tmp_hz;
success = true;
if(freq_mhz >= MIN_LP_FREQ_MHZ)
{
if(freq_mhz < MAX_LP_FREQ_MHZ)
{
switchctrl &= ~(SWITCHCTRL_HP | SWITCHCTRL_MIX_BYPASS);
RFFC5071_freq_mhz = MAX2837_FREQ_NOMINAL_MHZ - freq_mhz;
/* Set Freq and read real freq */
real_RFFC5071_freq_mhz = rffc5071_set_frequency(RFFC5071_freq_mhz, 0);
if(real_RFFC5071_freq_mhz < RFFC5071_freq_mhz)
{
tmp_hz = -((RFFC5071_freq_mhz - real_RFFC5071_freq_mhz) * FREQ_ONE_MHZ);
}else
{
tmp_hz = ((real_RFFC5071_freq_mhz - RFFC5071_freq_mhz) * FREQ_ONE_MHZ);
}
MAX2837_freq_hz = MAX2837_FREQ_NOMINAL_HZ + tmp_hz + freq_hz;
max2837_set_frequency(MAX2837_freq_hz);
update_switches();
}else if( (freq_mhz >= MIN_BYPASS_FREQ_MHZ) && (freq_mhz < MAX_BYPASS_FREQ_MHZ) )
{
switchctrl |= SWITCHCTRL_MIX_BYPASS;
MAX2837_freq_hz = (freq_mhz * FREQ_ONE_MHZ) + freq_hz;
/* RFFC5071_freq_mhz <= not used in Bypass mode */
max2837_set_frequency(MAX2837_freq_hz);
update_switches();
}else if( (freq_mhz >= MIN_HP_FREQ_MHZ) && (freq_mhz < MAX_HP_FREQ_MHZ) )
{
switchctrl &= ~SWITCHCTRL_MIX_BYPASS;
switchctrl |= SWITCHCTRL_HP;
RFFC5071_freq_mhz = freq_mhz - MAX2837_FREQ_NOMINAL_MHZ;
/* Set Freq and read real freq */
real_RFFC5071_freq_mhz = rffc5071_set_frequency(RFFC5071_freq_mhz, 0);
if(real_RFFC5071_freq_mhz < RFFC5071_freq_mhz)
{
tmp_hz = ((RFFC5071_freq_mhz - real_RFFC5071_freq_mhz) * FREQ_ONE_MHZ);
}else
{
tmp_hz = -((real_RFFC5071_freq_mhz - RFFC5071_freq_mhz) * FREQ_ONE_MHZ);
}
MAX2837_freq_hz = MAX2837_FREQ_NOMINAL_HZ + tmp_hz + freq_hz;
max2837_set_frequency(MAX2837_freq_hz);
update_switches();
}else
{
/* Error freq_mhz too high */
success = false;
}
}else
{
/* Error freq_mhz too low */
success = false;
}
return success;
}
static void usb_init_buffers_bulk() {
usb_td_bulk[0].next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE;
usb_td_bulk[0].total_bytes
@ -187,6 +293,8 @@ void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) {
gpio_set(PORT_LED1_3, PIN_LED2);
usb_endpoint_init(&usb_endpoint_bulk_in);
rffc5071_rx(switchctrl);
//rffc5071_set_frequency(1700, 0); // 2600 MHz IF - 1700 MHz LO = 900 MHz RF
max2837_start();
max2837_rx();
} else if (transceiver_mode == TRANSCEIVER_MODE_TX) {
@ -194,6 +302,8 @@ void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) {
gpio_set(PORT_LED1_3, PIN_LED3);
usb_endpoint_init(&usb_endpoint_bulk_out);
rffc5071_tx(switchctrl);
//rffc5071_set_frequency(1700, 0); // 2600 MHz IF - 1700 MHz LO = 900 MHz RF
max2837_start();
max2837_tx();
} else {
@ -432,22 +542,44 @@ usb_request_status_t usb_vendor_request_write_spiflash(
usb_request_status_t usb_vendor_request_read_spiflash(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage)
{
uint32_t i;
uint32_t addr;
uint16_t len;
uint8_t* u8_addr_pt;
if (stage == USB_TRANSFER_STAGE_SETUP) {
if (stage == USB_TRANSFER_STAGE_SETUP)
{
addr = (endpoint->setup.value << 16) | endpoint->setup.index;
len = endpoint->setup.length;
if ((len > W25Q80BV_PAGE_LEN) || (addr > W25Q80BV_NUM_BYTES)
|| ((addr + len) > W25Q80BV_NUM_BYTES)) {
return USB_REQUEST_STATUS_STALL;
} else {
//FIXME need implementation
//usb_endpoint_schedule(endpoint->in, &endpoint->buffer, len);
usb_endpoint_schedule_ack(endpoint->out);
/* TODO flush SPIFI "cache" before to read the SPIFI memory */
u8_addr_pt = (uint8_t*)addr;
for(i=0; i<len; i++)
{
spiflash_buffer[i] = u8_addr_pt[i];
}
usb_endpoint_schedule(endpoint->in, &spiflash_buffer[0], len);
return USB_REQUEST_STATUS_OK;
}
} else {
} else if (stage == USB_TRANSFER_STAGE_DATA)
{
addr = (endpoint->setup.value << 16) | endpoint->setup.index;
len = endpoint->setup.length;
/* This check is redundant but makes me feel better. */
if ((len > W25Q80BV_PAGE_LEN) || (addr > W25Q80BV_NUM_BYTES)
|| ((addr + len) > W25Q80BV_NUM_BYTES))
{
return USB_REQUEST_STATUS_STALL;
} else
{
usb_endpoint_schedule_ack(endpoint->out);
return USB_REQUEST_STATUS_OK;
}
} else
{
return USB_REQUEST_STATUS_OK;
}
}
@ -491,6 +623,92 @@ usb_request_status_t usb_vendor_request_read_version_string(
return USB_REQUEST_STATUS_OK;
}
usb_request_status_t usb_vendor_request_set_freq(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage)
{
if (stage == USB_TRANSFER_STAGE_SETUP)
{
usb_endpoint_schedule(endpoint->out, &set_freq_params, sizeof(set_freq_params_t));
return USB_REQUEST_STATUS_OK;
} else if (stage == USB_TRANSFER_STAGE_DATA)
{
if( set_freq(set_freq_params.freq_mhz, set_freq_params.freq_hz) )
{
usb_endpoint_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK;
}
return USB_REQUEST_STATUS_STALL;
} else
{
return USB_REQUEST_STATUS_OK;
}
}
usb_request_status_t usb_vendor_request_set_amp_enable(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage)
{
if (stage == USB_TRANSFER_STAGE_SETUP) {
switch (endpoint->setup.value) {
case 0:
switchctrl |= SWITCHCTRL_AMP_BYPASS;
update_switches();
usb_endpoint_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK;
case 1:
switchctrl &= ~SWITCHCTRL_AMP_BYPASS;
update_switches();
usb_endpoint_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK;
default:
return USB_REQUEST_STATUS_STALL;
}
} else {
return USB_REQUEST_STATUS_OK;
}
}
typedef struct {
uint32_t part_id[2];
uint32_t serial_no[4];
} read_partid_serialno_t;
usb_request_status_t usb_vendor_request_read_partid_serialno(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage)
{
uint8_t length;
read_partid_serialno_t read_partid_serialno;
iap_cmd_res_t iap_cmd_res;
if (stage == USB_TRANSFER_STAGE_SETUP)
{
/* Read IAP Part Number Identification */
iap_cmd_res.cmd_param.command_code = IAP_CMD_READ_PART_ID_NO;
iap_cmd_call(&iap_cmd_res);
if(iap_cmd_res.status_res.status_ret != CMD_SUCCESS)
return USB_REQUEST_STATUS_STALL;
read_partid_serialno.part_id[0] = iap_cmd_res.status_res.iap_result[0];
read_partid_serialno.part_id[1] = iap_cmd_res.status_res.iap_result[1];
/* Read IAP Serial Number Identification */
iap_cmd_res.cmd_param.command_code = IAP_CMD_READ_SERIAL_NO;
iap_cmd_call(&iap_cmd_res);
if(iap_cmd_res.status_res.status_ret != CMD_SUCCESS)
return USB_REQUEST_STATUS_STALL;
read_partid_serialno.serial_no[0] = iap_cmd_res.status_res.iap_result[0];
read_partid_serialno.serial_no[1] = iap_cmd_res.status_res.iap_result[1];
read_partid_serialno.serial_no[2] = iap_cmd_res.status_res.iap_result[2];
read_partid_serialno.serial_no[3] = iap_cmd_res.status_res.iap_result[3];
length = (uint8_t)sizeof(read_partid_serialno_t);
usb_endpoint_schedule(endpoint->in, &read_partid_serialno, length);
usb_endpoint_schedule_ack(endpoint->out);
}
return USB_REQUEST_STATUS_OK;
}
static const usb_request_handler_fn vendor_request_handler[] = {
NULL,
usb_vendor_request_set_transceiver_mode,
@ -507,7 +725,10 @@ static const usb_request_handler_fn vendor_request_handler[] = {
usb_vendor_request_read_spiflash,
usb_vendor_request_write_cpld,
usb_vendor_request_read_board_id,
usb_vendor_request_read_version_string
usb_vendor_request_read_version_string,
usb_vendor_request_set_freq,
usb_vendor_request_set_amp_enable,
usb_vendor_request_read_partid_serialno
};
static const uint32_t vendor_request_handler_count =
@ -666,8 +887,6 @@ int main(void) {
#ifdef JAWBREAKER
switchctrl = SWITCHCTRL_AMP_BYPASS;
#endif
rffc5071_rx(switchctrl);
rffc5071_set_frequency(1700, 0); // 2600 MHz IF - 1700 MHz LO = 900 MHz RF
while(true) {
// Wait until buffer 0 is transmitted/received.

2
hardware/.gitignore vendored
View File

@ -19,3 +19,5 @@ $savepcb.*
# other kicad generated files
*.csv
*.svg
*.pdf

View File

@ -32,6 +32,7 @@ int main(int argc, char** argv)
int result = HACKRF_SUCCESS;
uint8_t board_id = BOARD_ID_INVALID;
char version[255 + 1];
read_partid_serialno_t read_partid_serialno;
result = hackrf_init();
if (result != HACKRF_SUCCESS) {
@ -55,7 +56,6 @@ int main(int argc, char** argv)
hackrf_error_name(result), result);
return EXIT_FAILURE;
}
printf("Board ID Number: %d (%s)\n", board_id,
hackrf_board_id_name(board_id));
@ -65,9 +65,23 @@ int main(int argc, char** argv)
hackrf_error_name(result), result);
return EXIT_FAILURE;
}
printf("Firmware Version: %s\n", version);
result = hackrf_board_partid_serialno_read(device, &read_partid_serialno);
if (result != HACKRF_SUCCESS) {
fprintf(stderr, "hackrf_board_partid_serialno_read() failed: %s (%d)\n",
hackrf_error_name(result), result);
return EXIT_FAILURE;
}
printf("Part ID Number: 0x%08x 0x%08x\n",
read_partid_serialno.part_id[0],
read_partid_serialno.part_id[1]);
printf("Serial Number: 0x%08x 0x%08x 0x%08x 0x%08x\n",
read_partid_serialno.serial_no[0],
read_partid_serialno.serial_no[1],
read_partid_serialno.serial_no[2],
read_partid_serialno.serial_no[3]);
result = hackrf_close(device);
if (result != HACKRF_SUCCESS) {
fprintf(stderr, "hackrf_close() failed: %s (%d)\n",

View File

@ -41,7 +41,7 @@ static struct option long_options[] = {
{ 0, 0, 0, 0 },
};
int parse_int(char* s, uint32_t* const value)
int parse_u32(char* s, uint32_t* const value)
{
uint_fast8_t base = 10;
if (strlen(s) > 2) {
@ -57,9 +57,9 @@ int parse_int(char* s, uint32_t* const value)
}
char* s_end = s;
const long long_value = strtol(s, &s_end, base);
const uint32_t u32_value = strtoul(s, &s_end, base);
if ((s != s_end) && (*s_end == 0)) {
*value = long_value;
*value = u32_value;
return HACKRF_SUCCESS;
} else {
return HACKRF_ERROR_INVALID_PARAM;
@ -80,12 +80,13 @@ int main(int argc, char** argv)
int opt;
uint32_t address = 0;
uint32_t length = 0;
uint32_t tmp_length;
uint16_t xfer_len = 0;
const char* path = NULL;
hackrf_device* device = NULL;
int result = HACKRF_SUCCESS;
int option_index = 0;
uint8_t data[MAX_LENGTH];
static uint8_t data[MAX_LENGTH];
uint8_t* pdata = &data[0];
FILE* fd = NULL;
bool read = false;
@ -95,11 +96,11 @@ int main(int argc, char** argv)
&option_index)) != EOF) {
switch (opt) {
case 'a':
result = parse_int(optarg, &address);
result = parse_u32(optarg, &address);
break;
case 'l':
result = parse_int(optarg, &length);
result = parse_u32(optarg, &length);
break;
case 'r':
@ -113,6 +114,7 @@ int main(int argc, char** argv)
break;
default:
fprintf(stderr, "opt error: %d\n", opt);
usage();
return EXIT_FAILURE;
}
@ -179,14 +181,24 @@ int main(int argc, char** argv)
return EXIT_FAILURE;
}
if (read) {
result = hackrf_spiflash_read(device, address, length, data);
if (result != HACKRF_SUCCESS) {
fprintf(stderr, "hackrf_spiflash_read() failed: %s (%d)\n",
hackrf_error_name(result), result);
fclose(fd);
fd = NULL;
return EXIT_FAILURE;
if (read)
{
tmp_length = length;
while (tmp_length)
{
xfer_len = (tmp_length > 256) ? 256 : tmp_length;
printf("Reading %d bytes from 0x%06x.\n", xfer_len, address);
result = hackrf_spiflash_read(device, address, xfer_len, pdata);
if (result != HACKRF_SUCCESS) {
fprintf(stderr, "hackrf_spiflash_read() failed: %s (%d)\n",
hackrf_error_name(result), result);
fclose(fd);
fd = NULL;
return EXIT_FAILURE;
}
address += xfer_len;
pdata += xfer_len;
tmp_length -= xfer_len;
}
const ssize_t bytes_written = fwrite(data, 1, length, fd);
if (bytes_written != length) {

View File

@ -42,6 +42,9 @@
#include <sys/time.h>
#include <signal.h>
#define FREQ_MIN_HZ (30000000ull) /* 30MHz */
#define FREQ_MAX_HZ (6000000000ull) /* 6000MHz */
#if defined _WIN32
#define sleep(a) Sleep( (a*1000) )
#endif
@ -59,6 +62,54 @@ 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_u64(char* s, uint64_t* const value) {
uint_fast8_t base = 10;
if( strlen(s) > 2 ) {
if( s[0] == '0' ) {
if( (s[1] == 'x') || (s[1] == 'X') ) {
base = 16;
s += 2;
} else if( (s[1] == 'b') || (s[1] == 'B') ) {
base = 2;
s += 2;
}
}
}
char* s_end = s;
const unsigned long long u64_value = strtoull(s, &s_end, base);
if( (s != s_end) && (*s_end == 0) ) {
*value = u64_value;
return HACKRF_SUCCESS;
} else {
return HACKRF_ERROR_INVALID_PARAM;
}
}
int parse_int(char* s, uint32_t* const value) {
uint_fast8_t base = 10;
if( strlen(s) > 2 ) {
if( s[0] == '0' ) {
if( (s[1] == 'x') || (s[1] == 'X') ) {
base = 16;
s += 2;
} else if( (s[1] == 'b') || (s[1] == 'B') ) {
base = 2;
s += 2;
}
}
}
char* s_end = s;
const unsigned long ulong_value = strtoul(s, &s_end, base);
if( (s != s_end) && (*s_end == 0) ) {
*value = ulong_value;
return HACKRF_SUCCESS;
} else {
return HACKRF_ERROR_INVALID_PARAM;
}
}
FILE* fd = NULL;
volatile uint32_t byte_count = 0;
@ -67,6 +118,12 @@ bool transmit = false;
struct timeval time_start;
struct timeval t_start;
bool freq = false;
uint64_t freq_hz;
bool amp = false;
uint32_t amp_enable;
int rx_callback(hackrf_transfer* transfer) {
if( fd != NULL )
{
@ -105,6 +162,8 @@ static void usage() {
printf("Usage:\n");
printf("\t-r <filename> # Receive data into file.\n");
printf("\t-t <filename> # Transmit data from file.\n");
printf("\t[-f set_freq_hz] # Set Freq in Hz (between [%lld, %lld[).\n", FREQ_MIN_HZ, FREQ_MAX_HZ);
printf("\t[-a set_amp] # Set Amp 1=Enable, 0=Disable.\n");
}
static hackrf_device* device = NULL;
@ -168,8 +227,10 @@ void sigint_callback_handler(int signum)
int main(int argc, char** argv) {
int opt;
const char* path = NULL;
int result;
while( (opt = getopt(argc, argv, "r:t:")) != EOF ) {
while( (opt = getopt(argc, argv, "r:t:f:a:")) != EOF ) {
result = HACKRF_SUCCESS;
switch( opt ) {
case 'r':
receive = true;
@ -181,11 +242,45 @@ int main(int argc, char** argv) {
path = optarg;
break;
case 'f':
freq = true;
result = parse_u64(optarg, &freq_hz);
break;
case 'a':
amp = true;
result = parse_int(optarg, &amp_enable);
break;
default:
usage();
return EXIT_FAILURE;
}
if( result != HACKRF_SUCCESS ) {
printf("argument error: %s (%d)\n", hackrf_error_name(result), result);
usage();
break;
}
}
if( freq ) {
if( (freq_hz >= FREQ_MAX_HZ) || (freq_hz < FREQ_MIN_HZ) )
{
printf("argument error: set_freq_hz shall be between [%lld, %lld[.\n", FREQ_MIN_HZ, FREQ_MAX_HZ);
usage();
return EXIT_FAILURE;
}
}
if( amp ) {
if( amp_enable > 1 )
{
printf("argument error: set_amp shall be 0 or 1.\n");
usage();
return EXIT_FAILURE;
}
}
if( transmit == receive )
{
@ -213,7 +308,7 @@ int main(int argc, char** argv) {
return EXIT_FAILURE;
}
int result = hackrf_init();
result = hackrf_init();
if( result != HACKRF_SUCCESS ) {
printf("hackrf_init() failed: %s (%d)\n", hackrf_error_name(result), result);
usage();
@ -262,6 +357,24 @@ int main(int argc, char** argv) {
return EXIT_FAILURE;
}
if( freq ) {
printf("call hackrf_set_freq(%lld Hz)\n", freq_hz);
result = hackrf_set_freq(device, freq_hz);
if( result != HACKRF_SUCCESS ) {
printf("hackrf_set_freq() failed: %s (%d)\n", hackrf_error_name(result), result);
return EXIT_FAILURE;
}
}
if( amp ) {
printf("call hackrf_set_amp_enable(%ld)\n", amp_enable);
result = hackrf_set_amp_enable(device, (uint8_t)amp_enable);
if( result != HACKRF_SUCCESS ) {
printf("hackrf_set_amp_enable() failed: %s (%d)\n", hackrf_error_name(result), result);
return EXIT_FAILURE;
}
}
gettimeofday(&t_start, NULL);
gettimeofday(&time_start, NULL);

View File

@ -44,7 +44,10 @@ typedef enum {
HACKRF_VENDOR_REQUEST_SPIFLASH_READ = 12,
HACKRF_VENDOR_REQUEST_CPLD_WRITE = 13,
HACKRF_VENDOR_REQUEST_BOARD_ID_READ = 14,
HACKRF_VENDOR_REQUEST_VERSION_STRING_READ = 15
HACKRF_VENDOR_REQUEST_VERSION_STRING_READ = 15,
HACKRF_VENDOR_REQUEST_SET_FREQ = 16,
HACKRF_VENDOR_REQUEST_AMP_ENABLE = 17,
HACKRF_VENDOR_REQUEST_BOARD_PARTID_SERIALNO_READ = 18
} hackrf_vendor_request;
typedef enum {
@ -569,6 +572,88 @@ int hackrf_version_string_read(hackrf_device* device, char* version,
}
}
typedef struct {
uint32_t freq_mhz; /* From 30 to 6000MHz */
uint32_t freq_hz; /* From 0 to 999999Hz */
/* Final Freq = freq_mhz+freq_hz */
} set_freq_params_t;
#define FREQ_ONE_MHZ (1000*1000ull)
int hackrf_set_freq(hackrf_device* device, const uint64_t freq_hz)
{
uint32_t l_freq_mhz;
uint32_t l_freq_hz;
set_freq_params_t set_freq_params;
uint8_t length;
/* Convert Freq Hz 64bits to Freq MHz (32bits) & Freq Hz (32bits) */
l_freq_mhz = (uint32_t)(freq_hz / FREQ_ONE_MHZ);
l_freq_hz = (uint32_t)(freq_hz - (((uint64_t)l_freq_mhz) * FREQ_ONE_MHZ));
set_freq_params.freq_mhz = l_freq_mhz;
set_freq_params.freq_hz = l_freq_hz;
length = sizeof(set_freq_params_t);
int result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_SET_FREQ,
0,
0,
(unsigned char*)&set_freq_params,
length,
0
);
if (result < length) {
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int hackrf_set_amp_enable(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_AMP_ENABLE,
value,
0,
NULL,
0,
0
);
if (result != 0) {
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
int hackrf_board_partid_serialno_read(hackrf_device* device, read_partid_serialno_t* read_partid_serialno)
{
uint8_t length;
length = sizeof(read_partid_serialno_t);
int result = libusb_control_transfer(
device->usb_device,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_BOARD_PARTID_SERIALNO_READ,
0,
0,
(unsigned char*)read_partid_serialno,
length,
0
);
if (result < length) {
return HACKRF_ERROR_LIBUSB;
} else {
return HACKRF_SUCCESS;
}
}
static void* transfer_threadproc(void* arg) {
hackrf_device* device = (hackrf_device*)arg;

View File

@ -52,6 +52,11 @@ typedef struct {
int valid_length;
} hackrf_transfer;
typedef struct {
uint32_t part_id[2];
uint32_t serial_no[4];
} read_partid_serialno_t;
typedef int (*hackrf_sample_block_cb_fn)(hackrf_transfer* transfer);
int hackrf_init();
@ -93,6 +98,12 @@ int hackrf_board_id_read(hackrf_device* device, uint8_t* value);
int hackrf_version_string_read(hackrf_device* device, char* version,
uint8_t length);
int hackrf_set_freq(hackrf_device* device, const uint64_t freq_hz);
int hackrf_set_amp_enable(hackrf_device* device, const uint8_t value);
int hackrf_board_partid_serialno_read(hackrf_device* device, read_partid_serialno_t* read_partid_serialno);
const char* hackrf_error_name(enum hackrf_error errcode);
const char* hackrf_board_id_name(enum hackrf_board_id board_id);