mirror of
https://github.com/saymrwulf/uhd.git
synced 2026-05-16 21:10:10 +00:00
So, both the set_tx_antenna_switches and set_rx_antenna_switches functions configure the TX0_ANT_11 register (which controls the final switch before the TX/RX port, switching it between the three TX paths and the RX path). The RX antenna configuration code will, if the RX antenna is set to TX/RX, configure that switch to the TX/RX->RX path when the ATR is set to RX. However, the TX antenna config code will always configure that switch to the "bypass" path, for both the 0X and RX ATR modes, regardless of whether the RX side actually needs that path. Ergo, this change makes set_tx_antenna_switches only configure that switch when it is configuring the XX or TX modes.
155 lines
5.7 KiB
C++
155 lines
5.7 KiB
C++
//
|
|
// Copyright 2020 Ettus Research, a National Instruments Brand
|
|
//
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
//
|
|
|
|
#include <uhd/types/time_spec.hpp>
|
|
#include <uhdlib/usrp/dboard/zbx/zbx_cpld_ctrl.hpp>
|
|
#include <boost/test/unit_test.hpp>
|
|
#include <iostream>
|
|
|
|
using namespace uhd::usrp::zbx;
|
|
|
|
struct mock_reg_iface_type
|
|
{
|
|
uint32_t last_addr = 0;
|
|
zbx_cpld_ctrl::chan_t last_chan;
|
|
std::map<uint32_t, uint32_t> memory;
|
|
uhd::time_spec_t sleep_counter = uhd::time_spec_t(0.0);
|
|
};
|
|
|
|
|
|
struct zbx_cpld_fixture
|
|
{
|
|
zbx_cpld_fixture()
|
|
: cpld(
|
|
[&](const uint32_t addr,
|
|
const uint32_t data,
|
|
const zbx_cpld_ctrl::chan_t chan) {
|
|
std::cout << "[MOCKREGS] poke32(" << addr << ", " << data << ")"
|
|
<< std::endl;
|
|
mock_reg_iface.last_addr = addr;
|
|
mock_reg_iface.last_chan = chan;
|
|
mock_reg_iface.memory[addr] = data;
|
|
},
|
|
[&](const uint32_t addr) -> uint32_t {
|
|
std::cout << "[MOCKREGS] peek32(" << addr << ") => "
|
|
<< mock_reg_iface.memory.at(addr) << std::endl;
|
|
return mock_reg_iface.memory.at(addr);
|
|
},
|
|
[&](const uhd::time_spec_t& time) { mock_reg_iface.sleep_counter += time; },
|
|
"TEST::CPLD")
|
|
{
|
|
// nop
|
|
}
|
|
|
|
mock_reg_iface_type mock_reg_iface;
|
|
zbx_cpld_ctrl cpld;
|
|
};
|
|
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_cpld_ctrl_test, zbx_cpld_fixture)
|
|
{
|
|
cpld.set_scratch(23);
|
|
BOOST_CHECK_EQUAL(cpld.get_scratch(), 23);
|
|
|
|
cpld.pulse_lo_sync(0, {zbx_lo_t::TX0_LO1});
|
|
BOOST_CHECK_EQUAL(mock_reg_iface.memory[0x1024], 1);
|
|
mock_reg_iface.memory[0x1024] = 0;
|
|
// Make sure there are no caching issues:
|
|
cpld.pulse_lo_sync(0, {zbx_lo_t::TX0_LO1});
|
|
BOOST_CHECK_EQUAL(mock_reg_iface.memory[0x1024], 1);
|
|
// Now all:
|
|
cpld.pulse_lo_sync(0,
|
|
{zbx_lo_t::TX0_LO1,
|
|
zbx_lo_t::TX0_LO2,
|
|
zbx_lo_t::TX1_LO1,
|
|
zbx_lo_t::TX1_LO2,
|
|
zbx_lo_t::RX0_LO1,
|
|
zbx_lo_t::RX0_LO2,
|
|
zbx_lo_t::RX1_LO1,
|
|
zbx_lo_t::RX1_LO2});
|
|
BOOST_CHECK_EQUAL(mock_reg_iface.memory[0x1024], 0xFF);
|
|
mock_reg_iface.memory[0x1024] = 0;
|
|
cpld.set_lo_sync_bypass(true);
|
|
BOOST_CHECK_THROW(cpld.pulse_lo_sync(0, {zbx_lo_t::TX0_LO1}), uhd::runtime_error);
|
|
BOOST_CHECK_EQUAL(mock_reg_iface.memory[0x1024], 0x100);
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_tx_ant_override_rx_test, zbx_cpld_fixture)
|
|
{
|
|
cpld.set_rx_antenna_switches(
|
|
0, uhd::usrp::zbx::ATR_ADDR_RX, uhd::usrp::zbx::ANTENNA_TXRX);
|
|
|
|
cpld.set_tx_antenna_switches(
|
|
0, ATR_ADDR_0X, uhd::usrp::zbx::ANTENNA_TXRX, tx_amp::HIGHBAND);
|
|
cpld.set_tx_antenna_switches(
|
|
0, ATR_ADDR_RX, uhd::usrp::zbx::ANTENNA_TXRX, tx_amp::HIGHBAND);
|
|
cpld.set_tx_antenna_switches(
|
|
0, ATR_ADDR_TX, uhd::usrp::zbx::ANTENNA_TXRX, tx_amp::HIGHBAND);
|
|
cpld.set_tx_antenna_switches(
|
|
0, ATR_ADDR_XX, uhd::usrp::zbx::ANTENNA_TXRX, tx_amp::HIGHBAND);
|
|
|
|
// Make sure that configuring the TX antenna switches didn't disconnect the RX
|
|
// from the TX/RX port.
|
|
BOOST_CHECK_EQUAL(
|
|
(mock_reg_iface.memory[0x2000 + 4 * uhd::usrp::zbx::ATR_ADDR_RX] >> 20) & 0x3, 0);
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_tx_amp_test, zbx_cpld_fixture)
|
|
{
|
|
cpld.set_tx_antenna_switches(
|
|
0, 0, uhd::usrp::zbx::DEFAULT_TX_ANTENNA, tx_amp::HIGHBAND);
|
|
BOOST_CHECK(tx_amp::HIGHBAND == cpld.get_tx_amp_settings(0, 0, false));
|
|
mock_reg_iface.memory[0x2000] = 0;
|
|
BOOST_CHECK(tx_amp::HIGHBAND == cpld.get_tx_amp_settings(0, 0, false));
|
|
BOOST_CHECK(tx_amp::HIGHBAND != cpld.get_tx_amp_settings(0, 0, true));
|
|
BOOST_CHECK(tx_amp::BYPASS == cpld.get_tx_amp_settings(0, 0, false));
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_get_set_dsa_test, zbx_cpld_fixture)
|
|
{
|
|
// We only test the first table index
|
|
constexpr size_t dsa_table_index = 0;
|
|
for (const size_t chan : {0, 1}) {
|
|
const uint32_t tx_dsa_table_addr = 0x3000 + chan * 0x400;
|
|
const uint32_t rx_dsa_table_addr = 0x3800 + chan * 0x400;
|
|
|
|
auto& tx_dsa_reg = mock_reg_iface.memory[tx_dsa_table_addr];
|
|
auto& rx_dsa_reg = mock_reg_iface.memory[rx_dsa_table_addr];
|
|
|
|
// We'll skip DSA3A/B, because they work just like the rest and would
|
|
// make this test much longer and less readable without adding much test
|
|
// coverage.
|
|
for (const auto dsa :
|
|
{zbx_cpld_ctrl::dsa_type::DSA1, zbx_cpld_ctrl::dsa_type::DSA2}) {
|
|
const size_t tx_shift = (dsa == zbx_cpld_ctrl::dsa_type::DSA1) ? 0 : 8;
|
|
const size_t rx_shift = (dsa == zbx_cpld_ctrl::dsa_type::DSA1) ? 0 : 4;
|
|
// 0xB and 0xC are just random attenuation values. They are valid
|
|
// for both TX and RX.
|
|
cpld.set_tx_dsa(chan, dsa_table_index, dsa, 0xB);
|
|
BOOST_CHECK_EQUAL((tx_dsa_reg >> tx_shift) & 0x1F, 0xB);
|
|
tx_dsa_reg = 0x0C0C;
|
|
BOOST_CHECK_EQUAL(0xB, cpld.get_tx_dsa(chan, dsa_table_index, dsa, false));
|
|
BOOST_CHECK_EQUAL(0xC, cpld.get_tx_dsa(chan, dsa_table_index, dsa, true));
|
|
|
|
cpld.set_rx_dsa(chan, 0, dsa, 0xB);
|
|
BOOST_CHECK_EQUAL((rx_dsa_reg >> rx_shift) & 0xF, 0xB);
|
|
rx_dsa_reg = 0xCC;
|
|
BOOST_CHECK_EQUAL(0xB, cpld.get_rx_dsa(chan, dsa_table_index, dsa, false));
|
|
BOOST_CHECK_EQUAL(0xC, cpld.get_rx_dsa(chan, dsa_table_index, dsa, true));
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_set_from_table_test, zbx_cpld_fixture)
|
|
{
|
|
constexpr uint32_t tx_sel_addr = 0x4000;
|
|
constexpr size_t chan = 0;
|
|
constexpr uint8_t idx = 2;
|
|
|
|
auto& tx_table_select = mock_reg_iface.memory[tx_sel_addr + idx * 4];
|
|
cpld.set_tx_gain_switches(chan, idx, 23);
|
|
BOOST_REQUIRE_EQUAL(tx_table_select, 23);
|
|
}
|