Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
/*
* Copyright 2012-2026 Great Scott Gadgets <info@greatscottgadgets.com>
* Copyright 2012 Jared Boone
* Copyright 2013 Benjamin Vernoux
*
* 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 <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/lpc43xx/ipc.h>
#include <clock_gen.h>
#include <clock_io.h>
#include <cpld_jtag.h>
#include <cpu_clock.h>
#include <da7219.h>
#include <delay.h>
#include <fixed_point.h>
#include <hackrf_ui.h>
#include <i2c_bus.h>
#include <i2c_lpc.h>
#include <leds.h>
#include <operacake.h>
#include <mixer.h>
#include <pins.h>
#include <platform_detect.h>
#include <power.h>
#include <radio.h>
#include <rf_path.h>
#include <rom_iap.h>
#include <selftest.h>
#include <sgpio.h>
#include <transceiver_mode.h>
#include <tuning.h>
#include <usb.h>
#include <usb_queue.h>
#include <usb_request.h>
#include <usb_standard_request.h>
#include <usb_type.h>
#ifdef IS_EXPANSION_COMPATIBLE
#include <portapack.h>
#endif
#ifdef IS_NOT_RAD1O
#include <rffc5071.h>
#endif
#ifdef IS_PRALINE
#include <fpga.h>
#if !(defined(DFU_MODE) || defined(RAM_MODE))
#include <lz4_buf.h>
#include <spi_bus.h>
#include <w25q80bv.h>
#endif
#endif
#include "usb_api_adc.h"
#include "usb_api_board_info.h"
#include "usb_api_m0_state.h"
#include "usb_api_operacake.h"
#include "usb_api_register.h"
#include "usb_api_selftest.h"
#include "usb_api_spiflash.h"
#include "usb_api_sweep.h"
#include "usb_api_transceiver.h"
#include "usb_api_ui.h"
#include "usb_descriptor.h"
#include "usb_device.h"
#include "usb_endpoint.h"
#ifdef IS_PRALINE
#include "usb_api_praline.h"
#endif
#ifdef IS_NOT_PRALINE
#include "usb_api_cpld.h"
#endif
extern uint32_t __m0_start__;
extern uint32_t __m0_end__;
extern uint32_t __ram_m0_start__;
extern uint32_t _etext_ram, _text_ram, _etext_rom;
static usb_request_handler_fn vendor_request_handler[] = {
NULL,
usb_vendor_request_set_transceiver_mode,
usb_vendor_request_write_max283x,
usb_vendor_request_read_max283x,
usb_vendor_request_write_si5351c,
usb_vendor_request_read_si5351c,
usb_vendor_request_set_sample_rate_frac,
usb_vendor_request_set_baseband_filter_bandwidth,
#ifdef IS_NOT_RAD1O
usb_vendor_request_write_rffc5071,
usb_vendor_request_read_rffc5071,
#else
NULL, // write_rffc5071 not used
NULL, // read_rffc5071 not used
#endif
usb_vendor_request_erase_spiflash,
usb_vendor_request_write_spiflash,
usb_vendor_request_read_spiflash,
NULL, // used to be write_cpld
usb_vendor_request_read_board_id,
usb_vendor_request_read_version_string,
usb_vendor_request_set_freq,
usb_vendor_request_set_amp_enable,
usb_vendor_request_read_partid_serialno,
usb_vendor_request_set_lna_gain,
usb_vendor_request_set_vga_gain,
usb_vendor_request_set_txvga_gain,
NULL, // was set_if_freq
#if defined(IS_HACKRF_ONE) || defined(IS_PRALINE)
usb_vendor_request_set_antenna_enable,
#else
NULL,
#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,
usb_vendor_request_operacake_set_ranges,
usb_vendor_request_set_clkout_enable,
usb_vendor_request_spiflash_status,
usb_vendor_request_spiflash_clear_status,
usb_vendor_request_operacake_gpio_test,
#ifdef IS_HACKRF_ONE
usb_vendor_request_cpld_checksum,
#else
NULL,
#endif
usb_vendor_request_set_ui_enable,
usb_vendor_request_operacake_set_mode,
usb_vendor_request_operacake_get_mode,
usb_vendor_request_operacake_set_dwell_times,
usb_vendor_request_get_m0_state,
usb_vendor_request_set_tx_underrun_limit,
usb_vendor_request_set_rx_overrun_limit,
usb_vendor_request_get_clkin_status,
usb_vendor_request_read_board_rev,
usb_vendor_request_read_supported_platform,
usb_vendor_request_set_leds,
usb_vendor_request_user_config_set_bias_t_opts,
#ifdef IS_PRALINE
usb_vendor_request_write_fpga_reg,
usb_vendor_request_read_fpga_reg,
usb_vendor_request_p2_ctrl,
usb_vendor_request_p1_ctrl,
usb_vendor_request_set_narrowband_filter,
usb_vendor_request_set_fpga_bitstream,
usb_vendor_request_clkin_ctrl,
#else
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
#endif
usb_vendor_request_read_selftest,
usb_vendor_request_adc_read,
usb_vendor_request_test_rtc_osc,
usb_vendor_request_write_radio_reg,
usb_vendor_request_read_radio_reg,
usb_vendor_request_get_buffer_size,
usb_vendor_request_read_temperature,
};
static const uint32_t vendor_request_handler_count =
sizeof(vendor_request_handler) / sizeof(vendor_request_handler[0]);
usb_request_status_t usb_vendor_request(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage)
{
usb_request_status_t status = USB_REQUEST_STATUS_STALL;
if (endpoint->setup.request < vendor_request_handler_count) {
usb_request_handler_fn handler =
vendor_request_handler[endpoint->setup.request];
if (handler) {
status = handler(endpoint, stage);
}
}
return status;
}
const usb_request_handlers_t usb_request_handlers = {
.standard = usb_standard_request,
.class = 0,
.vendor = usb_vendor_request,
.reserved = 0,
};
void usb_configuration_changed(usb_device_t* const device)
{
/* Reset transceiver to idle state until other commands are received */
request_transceiver_mode(TRANSCEIVER_MODE_OFF);
if (device->configuration->number == 1) {
// transceiver configuration
led_on(LED1);
} else {
/* Configuration number equal 0 means usb bus reset. */
led_off(LED1);
}
usb_endpoint_init(&usb_endpoint_bulk_in, false);
usb_endpoint_init(&usb_endpoint_bulk_out, false);
}
void usb_set_descriptor_by_serial_number(void)
{
iap_cmd_res_t iap_cmd_res;
/* 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) {
usb_descriptor_string_serial_number[0] =
USB_DESCRIPTOR_STRING_SERIAL_BUF_LEN;
usb_descriptor_string_serial_number[1] = USB_DESCRIPTOR_TYPE_STRING;
/* 32 characters of serial number, convert to UTF-16LE */
for (size_t i = 0; i < USB_DESCRIPTOR_STRING_SERIAL_LEN; i++) {
const uint_fast8_t nibble =
(iap_cmd_res.status_res.iap_result[i >> 3] >>
(28 - (i & 7) * 4)) &
0xf;
const char c =
(nibble > 9) ? ('a' + nibble - 10) : ('0' + nibble);
usb_descriptor_string_serial_number[2 + i * 2] = c;
usb_descriptor_string_serial_number[3 + i * 2] = 0x00;
}
} else {
usb_descriptor_string_serial_number[0] = 2;
usb_descriptor_string_serial_number[1] = USB_DESCRIPTOR_TYPE_STRING;
}
}
static void m0_rom_to_ram(void)
{
uint32_t* dest = &__ram_m0_start__;
// Calculate the base address of ROM
uint32_t base = (uint32_t) (&_etext_rom - (&_etext_ram - &_text_ram));
// M0 image location, relative to the start of ROM
uint32_t src = (uint32_t) &__m0_start__;
uint32_t len = (uint32_t) &__m0_end__ - (uint32_t) src;
memcpy(dest, (uint32_t*) (base + src), len);
}
#if defined(IS_PRALINE) && !(defined(DFU_MODE) || defined(RAM_MODE))
extern uint32_t _binary_fpga_bin_start;
void fpga_loader_setup(void)
{
w25q80bv_setup(&spi_flash);
}
void fpga_loader_read(uint32_t addr, uint32_t size, uint8_t* buf)
{
w25q80bv_read(&spi_flash, addr, size, buf);
}
struct fpga_loader_t fpga_loader = {
.start_addr = (uint32_t) &_binary_fpga_bin_start,
.setup = fpga_loader_setup,
.read = fpga_loader_read,
.in_buffer = lz4_in_buf,
.out_buffer = lz4_out_buf,
};
#endif
void radio_changed(const uint32_t changed)
{
const uint64_t opmode = radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_OPMODE);
if (changed & (1 << RADIO_OPMODE)) {
switch (opmode) {
case TRANSCEIVER_MODE_TX:
case TRANSCEIVER_MODE_SS:
sgpio_configure(&sgpio_config, SGPIO_DIRECTION_TX);
hackrf_ui()->set_direction(RF_PATH_DIRECTION_TX);
break;
case TRANSCEIVER_MODE_RX:
case TRANSCEIVER_MODE_RX_SWEEP:
sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX);
hackrf_ui()->set_direction(RF_PATH_DIRECTION_RX);
break;
default:
sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX);
hackrf_ui()->set_direction(RF_PATH_DIRECTION_OFF);
break;
}
}
if (changed & (1 << RADIO_SAMPLE_RATE)) {
const uint64_t rate =
radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_SAMPLE_RATE);
hackrf_ui()->set_sample_rate(rate / SR_FP_ONE_HZ);
}
if (changed & (RADIO_REG_GROUP_FREQ)) {
const uint64_t img_reject =
radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_IMAGE_REJECT);
const uint64_t freq_lo =
radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_FREQUENCY_LO);
const uint64_t freq_if =
radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_FREQUENCY_IF);
const bool invert_spectrum =
((img_reject == RF_PATH_FILTER_LOW_PASS) && (freq_lo > freq_if));
sgpio_cpld_set_mixer_invert(&sgpio_config, invert_spectrum);
}
if (changed & (1 << RADIO_FREQUENCY_RF)) {
const uint64_t freq =
radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_FREQUENCY_RF);
if (opmode != TRANSCEIVER_MODE_RX_SWEEP) {
hackrf_ui()->set_frequency(freq / FP_ONE_HZ);
}
#ifdef IS_EXPANSION_COMPATIBLE
if (IS_EXPANSION_COMPATIBLE) {
operacake_set_range(freq / FP_ONE_MHZ);
}
#endif
}
if (changed & (1 << RADIO_IMAGE_REJECT)) {
if (opmode != TRANSCEIVER_MODE_RX_SWEEP) {
const uint64_t img_reject = radio_reg_read(
&radio,
RADIO_BANK_APPLIED,
RADIO_IMAGE_REJECT);
hackrf_ui()->set_filter(img_reject);
}
}
if (changed &
((1 << RADIO_BB_BANDWIDTH_TX) | (1 << RADIO_BB_BANDWIDTH_RX) |
(1 << RADIO_OPMODE))) {
uint64_t bw;
switch (opmode) {
case TRANSCEIVER_MODE_TX:
case TRANSCEIVER_MODE_SS:
bw = radio_reg_read(
&radio,
RADIO_BANK_APPLIED,
RADIO_BB_BANDWIDTH_TX);
break;
default:
bw = radio_reg_read(
&radio,
RADIO_BANK_APPLIED,
RADIO_BB_BANDWIDTH_RX);
}
hackrf_ui()->set_filter_bw(bw);
}
if (changed &
((1 << RADIO_GAIN_TX_RF) | (1 << RADIO_GAIN_RX_RF) | (1 << RADIO_OPMODE))) {
const uint64_t tx_rf =
radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_GAIN_TX_RF);
const uint64_t rx_rf =
radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_GAIN_RX_RF);
bool enable;
switch (opmode) {
case TRANSCEIVER_MODE_TX:
case TRANSCEIVER_MODE_SS:
enable = tx_rf;
break;
case TRANSCEIVER_MODE_RX:
case TRANSCEIVER_MODE_RX_SWEEP:
enable = rx_rf;
break;
default:
enable = false;
}
hackrf_ui()->set_lna_power(enable);
}
if (changed & (1 << RADIO_GAIN_TX_IF)) {
const uint64_t tx_if =
radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_GAIN_TX_IF);
hackrf_ui()->set_bb_tx_vga_gain(tx_if);
}
if (changed & (1 << RADIO_GAIN_RX_IF)) {
const uint64_t rx_if =
radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_GAIN_RX_IF);
hackrf_ui()->set_bb_lna_gain(rx_if);
}
if (changed & (1 << RADIO_GAIN_RX_BB)) {
const uint64_t rx_bb =
radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_GAIN_RX_BB);
hackrf_ui()->set_bb_vga_gain(rx_bb);
}
if (changed & (1 << RADIO_BIAS_TEE)) {
const uint64_t enable =
radio_reg_read(&radio, RADIO_BANK_APPLIED, RADIO_BIAS_TEE);
hackrf_ui()->set_antenna_bias(enable);
}
}
int main(void)
{
// Copy M0 image from ROM before SPIFI is disabled
m0_rom_to_ram();
// This will be cleared if any self-test check fails.
selftest.report.pass = true;
// Detect hardware platform before we do anything else.
detect_hardware_platform();
board_id_t board_id = detected_platform();
i2c_bus_start(&i2c0, &i2c_config_fast_clock);
pins_shutdown();
sgpio_pin_shutdown(&sgpio_config);
rf_path_pin_shutdown();
if (board_id != BOARD_ID_RAD1O) {
clock_gen_shutdown();
}
delay_ms(10);
pins_setup();
cpld_jtag_pin_setup();
mixer_bus_setup(&mixer);
sgpio_configure_pin_functions(&sgpio_config);
rf_path_pin_setup(&rf_path);
#ifdef IS_PRALINE
if (IS_PRALINE) {
enable_3v3aux_power();
#if !defined(DFU_MODE) && !defined(RAM_MODE)
enable_1v2_power();
enable_rf_power();
/*
* On Praline, the clock generator power supply comes from 3V3FPGA
* which is enabled when 1V2FPGA is turned on.
*/
clock_gen_init();
#endif
}
#endif
#ifdef IS_NOT_PRALINE
if (IS_NOT_PRALINE) {
enable_1v8_power();
#ifdef IS_NOT_RAD1O
if (IS_NOT_RAD1O) {
/*
* On rad1o, the clock generator power supply comes from the RF supply
* which is enabled later. On H1 and Jawbreaker, the clock generator is
* on the main 3V3 supply.
*/
clock_gen_init();
}
#endif
}
#endif
tuning_setup();
#ifdef IS_HACKRF_ONE
if (IS_HACKRF_ONE) {
// Set up mixer before enabling RF power, because its
// GPO is used to control the antenna bias tee.
mixer_setup(&mixer, RFFC5071_VARIANT);
}
#endif
#ifdef IS_H1_OR_RAD1O
if (IS_H1_OR_RAD1O) {
enable_rf_power();
}
#endif
#ifdef IS_RAD1O
if (IS_RAD1O) {
clock_gen_init();
}
#endif
cpu_clock_init();
/* Clock speed has changed, adjust I2C clock */
i2c_bus_start(&i2c0, &i2c_config_fast_clock);
/* Wake the M0 */
ipc_halt_m0();
ipc_start_m0((uint32_t) &__ram_m0_start__);
#ifdef IS_NOT_PRALINE
if (IS_NOT_PRALINE) {
if (!cpld_jtag_sram_load(&jtag_cpld)) {
halt_and_flash(1000);
}
}
#endif
#ifdef IS_PRALINE
if (IS_PRALINE) {
#if defined(DFU_MODE) || defined(RAM_MODE)
selftest.fpga_image_load = SKIPPED;
selftest.report.pass = false;
#else
fpga_image_load(&fpga_loader, 0);
#endif
delay_us(100);
fpga_spi_selftest();
fpga_sgpio_selftest();
}
#endif
radio.update_cb = radio_changed;
radio_init(&radio);
#ifdef IS_EXPANSION_COMPATIBLE
if (IS_EXPANSION_COMPATIBLE) {
portapack_init();
}
#endif
#ifndef DFU_MODE
usb_set_descriptor_by_serial_number();
#endif
usb_set_configuration_changed_cb(usb_configuration_changed);
usb_peripheral_reset();
#ifdef IS_HACKRF_ONE
if (IS_HACKRF_ONE) {
memcpy(&usb_device,
&usb_device_hackrf_one,
sizeof(usb_device_hackrf_one));
}
#endif
#ifdef IS_JAWBREAKER
if (IS_JAWBREAKER) {
memcpy(&usb_device,
&usb_device_jawbreaker,
sizeof(usb_device_jawbreaker));
}
#endif
#ifdef IS_RAD1O
if (IS_RAD1O) {
memcpy(&usb_device, &usb_device_rad1o, sizeof(usb_device_rad1o));
}
#endif
#ifdef IS_PRALINE
if (IS_PRALINE) {
memcpy(&usb_device, &usb_device_praline, sizeof(usb_device_praline));
}
#endif
usb_device_init(0, &usb_device);
usb_queue_init(&usb_endpoint_control_out_queue);
usb_queue_init(&usb_endpoint_control_in_queue);
usb_queue_init(&usb_endpoint_bulk_out_queue);
usb_queue_init(&usb_endpoint_bulk_in_queue);
usb_endpoint_init(&usb_endpoint_control_out, false);
usb_endpoint_init(&usb_endpoint_control_in, true);
nvic_set_priority(NVIC_USB0_IRQ, 255);
hackrf_ui()->init();
usb_run(&usb_device);
rf_path_init(&rf_path);
#ifdef IS_NOT_RAD1O
rffc5071_lock_test(&mixer.rffc5071);
#endif
#ifdef IS_PRALINE
if (IS_PRALINE) {
fpga_if_xcvr_selftest();
}
#endif
if (da7219_detect()) {
operacake_skip_i2c_address(DA7219_ADDRESS);
}
bool operacake_allow_gpio;
if (hackrf_ui()->operacake_gpio_compatible()) {
operacake_allow_gpio = true;
} else {
operacake_allow_gpio = false;
}
operacake_init(operacake_allow_gpio);
// FIXME: clock detection on r9 only works when calling init twice
if (detected_platform() == BOARD_ID_HACKRF1_R9) {
clkin_detect_init();
clkin_detect_init();
}
while (true) {
transceiver_request_t request;
// Briefly disable USB interrupt so that we can
// atomically retrieve both the transceiver mode
// and the mode change sequence number. They are
// changed together by request_transceiver_mode()
// called from the USB ISR.
nvic_disable_irq(NVIC_USB0_IRQ);
request = transceiver_request;
nvic_enable_irq(NVIC_USB0_IRQ);
radio_update(&radio);
switch (request.mode) {
case TRANSCEIVER_MODE_OFF:
off_mode(request.seq);
break;
case TRANSCEIVER_MODE_RX:
rx_mode(request.seq);
break;
case TRANSCEIVER_MODE_TX:
tx_mode(request.seq);
break;
case TRANSCEIVER_MODE_RX_SWEEP:
sweep_mode(request.seq);
break;
case TRANSCEIVER_MODE_CPLD_UPDATE:
#ifdef IS_NOT_PRALINE
if (IS_NOT_PRALINE) {
cpld_update();
}
#endif
break;
default:
break;
}
}
return 0;
}
7f96cc8e3This file is pinned to the selected release. Download the original to open it in your design tool.