2015-07-08 11:39:24 -04:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
|
|
|
*
|
|
|
|
* This file is part of PortaPack.
|
|
|
|
*
|
|
|
|
* 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 "radio.hpp"
|
|
|
|
|
|
|
|
#include "rf_path.hpp"
|
2016-02-16 13:28:13 -05:00
|
|
|
|
|
|
|
#include "rffc507x.hpp"
|
|
|
|
#include "max2837.hpp"
|
2015-07-08 11:39:24 -04:00
|
|
|
#include "max5864.hpp"
|
|
|
|
#include "baseband_cpld.hpp"
|
|
|
|
|
|
|
|
#include "tuning.hpp"
|
|
|
|
|
|
|
|
#include "spi_arbiter.hpp"
|
|
|
|
|
|
|
|
#include "hackrf_hal.hpp"
|
|
|
|
#include "hackrf_gpio.hpp"
|
|
|
|
using namespace hackrf::one;
|
|
|
|
|
2015-08-01 16:42:27 -04:00
|
|
|
#include "portapack.hpp"
|
2015-07-08 11:39:24 -04:00
|
|
|
|
|
|
|
namespace radio {
|
|
|
|
|
|
|
|
static constexpr uint32_t ssp1_cpsr = 2;
|
|
|
|
|
|
|
|
static constexpr uint32_t ssp_scr(
|
|
|
|
const float pclk_f,
|
|
|
|
const uint32_t cpsr,
|
|
|
|
const float spi_f
|
|
|
|
) {
|
|
|
|
return static_cast<uint8_t>(pclk_f / cpsr / spi_f - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static constexpr SPIConfig ssp_config_max2837 = {
|
|
|
|
.end_cb = NULL,
|
|
|
|
.ssport = gpio_max2837_select.port(),
|
|
|
|
.sspad = gpio_max2837_select.pad(),
|
|
|
|
.cr0 =
|
|
|
|
CR0_CLOCKRATE(ssp_scr(ssp1_pclk_f, ssp1_cpsr, max2837_spi_f))
|
|
|
|
| CR0_FRFSPI
|
|
|
|
| CR0_DSS16BIT
|
|
|
|
,
|
|
|
|
.cpsr = ssp1_cpsr,
|
|
|
|
};
|
|
|
|
|
|
|
|
static constexpr SPIConfig ssp_config_max5864 = {
|
|
|
|
.end_cb = NULL,
|
|
|
|
.ssport = gpio_max5864_select.port(),
|
|
|
|
.sspad = gpio_max5864_select.pad(),
|
|
|
|
.cr0 =
|
|
|
|
CR0_CLOCKRATE(ssp_scr(ssp1_pclk_f, ssp1_cpsr, max5864_spi_f))
|
|
|
|
| CR0_FRFSPI
|
|
|
|
| CR0_DSS8BIT
|
|
|
|
,
|
|
|
|
.cpsr = ssp1_cpsr,
|
|
|
|
};
|
|
|
|
|
2015-08-01 16:42:27 -04:00
|
|
|
static spi::arbiter::Arbiter ssp1_arbiter(portapack::ssp1);
|
2015-07-08 11:39:24 -04:00
|
|
|
|
|
|
|
static spi::arbiter::Target ssp1_target_max2837 {
|
|
|
|
ssp1_arbiter,
|
|
|
|
ssp_config_max2837
|
|
|
|
};
|
|
|
|
|
|
|
|
static spi::arbiter::Target ssp1_target_max5864 {
|
|
|
|
ssp1_arbiter,
|
|
|
|
ssp_config_max5864
|
|
|
|
};
|
|
|
|
|
|
|
|
static rf::path::Path rf_path;
|
|
|
|
rffc507x::RFFC507x first_if;
|
2015-12-13 14:50:06 -05:00
|
|
|
max2837::MAX2837 second_if { ssp1_target_max2837 };
|
2015-07-08 11:39:24 -04:00
|
|
|
static max5864::MAX5864 baseband_codec { ssp1_target_max5864 };
|
|
|
|
static baseband::CPLD baseband_cpld;
|
|
|
|
|
|
|
|
static rf::Direction direction { rf::Direction::Receive };
|
|
|
|
|
|
|
|
void init() {
|
|
|
|
rf_path.init();
|
|
|
|
first_if.init();
|
|
|
|
second_if.init();
|
|
|
|
baseband_codec.init();
|
|
|
|
baseband_cpld.init();
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_direction(const rf::Direction new_direction) {
|
|
|
|
/* TODO: Refactor all the various "Direction" enumerations into one. */
|
|
|
|
/* TODO: Only make changes if direction changes, but beware of clock enabling. */
|
|
|
|
direction = new_direction;
|
|
|
|
|
|
|
|
second_if.set_mode((direction == rf::Direction::Transmit) ? max2837::Mode::Transmit : max2837::Mode::Receive);
|
|
|
|
rf_path.set_direction(direction);
|
|
|
|
|
|
|
|
baseband_codec.set_mode((direction == rf::Direction::Transmit) ? max5864::Mode::Transmit : max5864::Mode::Receive);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool set_tuning_frequency(const rf::Frequency frequency) {
|
2015-08-24 15:10:39 -04:00
|
|
|
const auto tuning_config = tuning::config::create(frequency);
|
2015-07-08 11:39:24 -04:00
|
|
|
if( tuning_config.is_valid() ) {
|
|
|
|
first_if.disable();
|
|
|
|
|
|
|
|
if( tuning_config.first_lo_frequency ) {
|
|
|
|
first_if.set_frequency(tuning_config.first_lo_frequency);
|
|
|
|
first_if.enable();
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto result_second_if = second_if.set_frequency(tuning_config.second_lo_frequency);
|
|
|
|
|
|
|
|
rf_path.set_band(tuning_config.rf_path_band);
|
2016-08-21 14:34:46 -04:00
|
|
|
baseband_cpld.set_invert(tuning_config.baseband_invert);
|
2015-07-08 11:39:24 -04:00
|
|
|
|
|
|
|
return result_second_if;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_rf_amp(const bool rf_amp) {
|
|
|
|
rf_path.set_rf_amp(rf_amp);
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_lna_gain(const int_fast8_t db) {
|
|
|
|
second_if.set_lna_gain(db);
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_vga_gain(const int_fast8_t db) {
|
|
|
|
second_if.set_vga_gain(db);
|
|
|
|
}
|
|
|
|
|
2016-08-03 19:12:22 -04:00
|
|
|
void set_tx_gain(const int_fast8_t db) {
|
|
|
|
second_if.set_tx_vga_gain(db);
|
|
|
|
}
|
|
|
|
|
2015-07-08 11:39:24 -04:00
|
|
|
void set_baseband_filter_bandwidth(const uint32_t bandwidth_minimum) {
|
|
|
|
second_if.set_lpf_rf_bandwidth(bandwidth_minimum);
|
|
|
|
}
|
|
|
|
|
2016-02-05 19:36:36 -05:00
|
|
|
void set_baseband_rate(const uint32_t rate) {
|
|
|
|
portapack::clock_manager.set_sampling_frequency(rate);
|
|
|
|
}
|
|
|
|
|
2016-01-23 02:24:20 -05:00
|
|
|
void set_antenna_bias(const bool on) {
|
|
|
|
/* Pull MOSFET gate low to turn on antenna bias. */
|
|
|
|
first_if.set_gpo1(on ? 0 : 1);
|
|
|
|
}
|
|
|
|
|
2015-07-08 11:39:24 -04:00
|
|
|
void disable() {
|
2016-01-23 02:24:20 -05:00
|
|
|
set_antenna_bias(false);
|
2015-07-08 11:39:24 -04:00
|
|
|
baseband_codec.set_mode(max5864::Mode::Shutdown);
|
2015-12-17 23:59:21 -05:00
|
|
|
second_if.set_mode(max2837::Mode::Standby);
|
2015-07-08 11:39:24 -04:00
|
|
|
first_if.disable();
|
|
|
|
set_rf_amp(false);
|
|
|
|
}
|
|
|
|
|
2016-02-10 19:58:25 -05:00
|
|
|
void enable(Configuration configuration) {
|
|
|
|
configure(configuration);
|
|
|
|
}
|
|
|
|
|
|
|
|
void configure(Configuration configuration) {
|
|
|
|
set_tuning_frequency(configuration.tuning_frequency);
|
|
|
|
set_rf_amp(configuration.rf_amp);
|
|
|
|
set_lna_gain(configuration.lna_gain);
|
|
|
|
set_vga_gain(configuration.vga_gain);
|
|
|
|
set_baseband_rate(configuration.baseband_rate);
|
|
|
|
set_baseband_filter_bandwidth(configuration.baseband_filter_bandwidth);
|
|
|
|
set_direction(configuration.direction);
|
|
|
|
}
|
|
|
|
|
2016-02-16 13:28:13 -05:00
|
|
|
namespace debug {
|
|
|
|
|
|
|
|
namespace first_if {
|
|
|
|
|
|
|
|
uint32_t register_read(const size_t register_number) {
|
|
|
|
return radio::first_if.read(register_number);
|
|
|
|
}
|
|
|
|
|
|
|
|
} /* namespace first_if */
|
|
|
|
|
|
|
|
namespace second_if {
|
|
|
|
|
|
|
|
uint32_t register_read(const size_t register_number) {
|
|
|
|
return radio::second_if.read(register_number);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t temp_sense() {
|
|
|
|
return radio::second_if.temp_sense() & 0x1f;
|
|
|
|
}
|
|
|
|
|
|
|
|
} /* namespace second_if */
|
|
|
|
|
|
|
|
} /* namespace debug */
|
|
|
|
|
2015-07-08 11:39:24 -04:00
|
|
|
} /* namespace radio */
|