2015-07-08 08:39:24 -07: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 "rf_path.hpp"
|
2023-02-16 12:09:23 +00:00
|
|
|
#include "platform.hpp"
|
2015-07-08 08:39:24 -07:00
|
|
|
|
|
|
|
#include <array>
|
|
|
|
#include <initializer_list>
|
|
|
|
|
|
|
|
#include "hackrf_gpio.hpp"
|
|
|
|
using namespace hackrf::one;
|
|
|
|
|
|
|
|
#include "utility.hpp"
|
|
|
|
|
|
|
|
namespace rf {
|
|
|
|
namespace path {
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2023-02-16 12:09:23 +00:00
|
|
|
using GPIOs = std::array<GPIO, 11>;
|
2015-07-08 08:39:24 -07:00
|
|
|
|
|
|
|
/* TODO: ARM GCC 4.8 2014q3 doesn't like this array inside struct Config.
|
|
|
|
* No idea why.
|
|
|
|
*/
|
2023-05-19 08:16:05 +12:00
|
|
|
constexpr GPIOs gpios{
|
|
|
|
gpio_mix_bypass,
|
|
|
|
gpio_not_mix_bypass,
|
|
|
|
gpio_tx_mix_bp,
|
|
|
|
gpio_rx_mix_bp,
|
|
|
|
gpio_hp,
|
|
|
|
gpio_lp,
|
|
|
|
gpio_amp_bypass,
|
|
|
|
gpio_tx_amp,
|
|
|
|
gpio_not_tx_amp_pwr,
|
|
|
|
gpio_rx_amp,
|
|
|
|
gpio_not_rx_amp_pwr,
|
2015-07-08 08:39:24 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
struct Config {
|
2023-05-19 08:16:05 +12:00
|
|
|
using base_type = uint16_t;
|
|
|
|
|
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
bool tx : 1;
|
|
|
|
bool rx : 1;
|
|
|
|
bool mix_bypass : 1;
|
|
|
|
bool not_mix_bypass : 1;
|
|
|
|
bool tx_mix_bp : 1;
|
|
|
|
bool rx_mix_bp : 1;
|
|
|
|
bool hp : 1;
|
|
|
|
bool lp : 1;
|
|
|
|
bool amp_bypass : 1;
|
|
|
|
bool tx_amp : 1;
|
|
|
|
bool not_tx_amp : 1;
|
|
|
|
bool rx_amp : 1;
|
|
|
|
bool not_rx_amp : 1;
|
|
|
|
};
|
|
|
|
base_type w;
|
|
|
|
};
|
|
|
|
|
|
|
|
constexpr Config(
|
|
|
|
const Direction direction,
|
|
|
|
const Band band,
|
|
|
|
const bool amplify)
|
|
|
|
: tx(direction == Direction::Transmit),
|
|
|
|
rx(direction == Direction::Receive),
|
|
|
|
mix_bypass(band == Band::Mid),
|
|
|
|
not_mix_bypass(band != Band::Mid),
|
|
|
|
tx_mix_bp((direction == Direction::Transmit) && (band == Band::Mid)),
|
|
|
|
rx_mix_bp((direction == Direction::Receive) && (band == Band::Mid)),
|
|
|
|
hp(band == Band::High),
|
|
|
|
lp(band == Band::Low),
|
|
|
|
amp_bypass(!amplify),
|
|
|
|
tx_amp((direction == Direction::Transmit) && amplify),
|
|
|
|
not_tx_amp(!tx_amp),
|
|
|
|
rx_amp((direction == Direction::Receive) && amplify),
|
|
|
|
not_rx_amp(!rx_amp) {
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr Config()
|
|
|
|
: Config(Direction::Receive, Band::Mid, false) {
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr Config(
|
|
|
|
const base_type w)
|
|
|
|
: w(w) {
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr Config operator^(const Config& r) const {
|
|
|
|
return w ^ r.w;
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr Config operator&(const Config& r) const {
|
|
|
|
return w & r.w;
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr bool operator[](const size_t n) const {
|
|
|
|
return (w >> n) & 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gpio_init() {
|
|
|
|
if (hackrf_r9) {
|
|
|
|
gpio_r9_rx.output();
|
|
|
|
} else {
|
|
|
|
gpio_og_tx.output();
|
|
|
|
gpio_og_rx.output();
|
|
|
|
}
|
|
|
|
for (auto gpio : gpios) {
|
|
|
|
gpio.output();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void apply() const {
|
|
|
|
/* NOTE: Assumes order in gpios[] and Config bitfield match,
|
|
|
|
* after the 'tx' and 'rx' fields which are handled specially. */
|
|
|
|
for (size_t n = 0; n < gpios.size() + 2; n++) {
|
|
|
|
bool value = (*this)[n];
|
|
|
|
switch (n) {
|
|
|
|
case 0:
|
|
|
|
if (!hackrf_r9) {
|
|
|
|
gpio_og_tx.write(value);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
if (hackrf_r9) {
|
|
|
|
gpio_r9_rx.write(value);
|
|
|
|
} else {
|
|
|
|
gpio_og_rx.write(value);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
gpios[n - 2].write(value);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-07-08 08:39:24 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
using ConfigAmp = std::array<Config, 2>;
|
|
|
|
using ConfigDirection = std::array<ConfigAmp, 2>;
|
|
|
|
using ConfigBand = std::array<ConfigDirection, 3>;
|
|
|
|
|
|
|
|
constexpr ConfigAmp config_amp(
|
2023-05-19 08:16:05 +12:00
|
|
|
const Direction direction,
|
|
|
|
const Band band) {
|
|
|
|
return {{
|
|
|
|
{.direction = direction, .band = band, .amplify = false},
|
|
|
|
{.direction = direction, .band = band, .amplify = true},
|
|
|
|
}};
|
2015-07-08 08:39:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
constexpr ConfigDirection config_rx_tx(
|
2023-05-19 08:16:05 +12:00
|
|
|
const Band band) {
|
|
|
|
return {
|
|
|
|
config_amp(Direction::Receive, band),
|
|
|
|
config_amp(Direction::Transmit, band),
|
|
|
|
};
|
2015-07-08 08:39:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
constexpr ConfigBand config_band() {
|
2023-05-19 08:16:05 +12:00
|
|
|
return {
|
|
|
|
config_rx_tx(Band::Low),
|
|
|
|
config_rx_tx(Band::Mid),
|
|
|
|
config_rx_tx(Band::High),
|
|
|
|
};
|
2015-07-08 08:39:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
constexpr ConfigBand config_table = config_band();
|
|
|
|
|
|
|
|
static_assert(sizeof(config_table) == sizeof(Config::base_type) * 3 * 2 * 2, "rf path config table unexpected size");
|
|
|
|
|
|
|
|
constexpr Config get_config(
|
2023-05-19 08:16:05 +12:00
|
|
|
const Direction direction,
|
|
|
|
const Band band,
|
|
|
|
const bool amplify) {
|
|
|
|
return config_table[toUType(band)][toUType(direction)][amplify ? 1 : 0];
|
2015-07-08 08:39:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
} /* namespace */
|
|
|
|
|
|
|
|
void Path::init() {
|
2023-05-19 08:16:05 +12:00
|
|
|
update();
|
|
|
|
Config::gpio_init();
|
2015-07-08 08:39:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void Path::set_direction(const Direction new_direction) {
|
2023-05-19 08:16:05 +12:00
|
|
|
direction = new_direction;
|
|
|
|
update();
|
2015-07-08 08:39:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void Path::set_band(const Band new_band) {
|
2023-05-19 08:16:05 +12:00
|
|
|
band = new_band;
|
|
|
|
update();
|
2015-07-08 08:39:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void Path::set_rf_amp(const bool new_rf_amp) {
|
2023-05-19 08:16:05 +12:00
|
|
|
rf_amp = new_rf_amp;
|
|
|
|
update();
|
2015-07-08 08:39:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void Path::update() {
|
2023-05-19 08:16:05 +12:00
|
|
|
/* 0 ^ 0 => 0 & 0 = 0 ^ 0 = 0 (no change)
|
|
|
|
* 0 ^ 1 => 1 & 0 = 0 ^ 0 = 0 (ignore change to 1)
|
|
|
|
* 1 ^ 0 => 1 & 1 = 1 ^ 1 = 0 (allow change to 0)
|
|
|
|
* 1 ^ 1 => 0 & 1 = 0 ^ 1 = 1 (no change)
|
|
|
|
*/
|
|
|
|
// const Config changed = _config ^ config_next;
|
|
|
|
// const Config turned_off = _config & changed;
|
|
|
|
|
|
|
|
/* In transition, ignore the bits that are turning on. So this transition phase
|
|
|
|
* only turns off signals. It doesn't turn on signals.
|
|
|
|
*/
|
|
|
|
// const Config transition_config = _config ^ turned_off;
|
|
|
|
// update_signals(transition_config);
|
|
|
|
|
|
|
|
/* Move to the final state by turning on required signals. */
|
|
|
|
const auto config = get_config(direction, band, rf_amp);
|
|
|
|
config.apply();
|
2015-07-08 08:39:24 -07:00
|
|
|
}
|
|
|
|
|
2023-05-19 08:16:05 +12:00
|
|
|
} // namespace path
|
|
|
|
} // namespace rf
|