mirror of
https://github.com/EttusResearch/uhd.git
synced 2026-10-25 17:36:10 +00:00
1221 lines
54 KiB
C++
1221 lines
54 KiB
C++
//
|
|
// Copyright 2020 Ettus Research, a National Instruments Brand
|
|
//
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
//
|
|
|
|
#include "x4xx_radio_mock.hpp"
|
|
#include "x4xx_zbx_mpm_mock.hpp"
|
|
#include <uhd/features/complex_gain_iface.hpp>
|
|
#include <uhd/rfnoc/detail/graph.hpp>
|
|
#include <uhd/rfnoc/mock_block.hpp>
|
|
#include <uhd/rfnoc/mock_nodes.hpp>
|
|
#include <uhd/utils/log.hpp>
|
|
#include <uhd/utils/math.hpp>
|
|
#include <boost/test/unit_test.hpp>
|
|
#include <chrono>
|
|
#include <cstddef>
|
|
#include <iostream>
|
|
#include <thread>
|
|
|
|
using namespace uhd;
|
|
using namespace uhd::rfnoc;
|
|
using namespace uhd::rfnoc::test;
|
|
using namespace std::chrono_literals;
|
|
using namespace uhd::usrp::zbx;
|
|
using namespace uhd::experts;
|
|
|
|
/******************************************************************************
|
|
* RFNoC Graph Test
|
|
*
|
|
* This test case ensures that the Radio Block can be added to an RFNoC graph.
|
|
*****************************************************************************/
|
|
BOOST_FIXTURE_TEST_CASE(x400_radio_test_graph, x400_radio_fixture)
|
|
{
|
|
detail::graph_t graph{};
|
|
detail::graph_t::graph_edge_t edge_port_info0;
|
|
edge_port_info0.src_port = 0;
|
|
edge_port_info0.dst_port = 0;
|
|
edge_port_info0.is_forward_edge = true;
|
|
edge_port_info0.edge = detail::graph_t::graph_edge_t::DYNAMIC;
|
|
detail::graph_t::graph_edge_t edge_port_info1;
|
|
edge_port_info1.src_port = 1;
|
|
edge_port_info1.dst_port = 1;
|
|
edge_port_info1.is_forward_edge = true;
|
|
edge_port_info1.edge = detail::graph_t::graph_edge_t::DYNAMIC;
|
|
|
|
mock_radio_node_t mock_radio_block{0};
|
|
mock_terminator_t mock_sink_term(2, {}, "MOCK_SINK");
|
|
mock_terminator_t mock_source_term(2, {}, "MOCK_SOURCE");
|
|
|
|
UHD_LOG_INFO("TEST", "Priming mock block properties");
|
|
node_accessor.init_props(&mock_radio_block);
|
|
mock_source_term.set_edge_property<std::string>(
|
|
"type", "sc16", {res_source_info::OUTPUT_EDGE, 0});
|
|
mock_source_term.set_edge_property<std::string>(
|
|
"type", "sc16", {res_source_info::OUTPUT_EDGE, 1});
|
|
mock_sink_term.set_edge_property<std::string>(
|
|
"type", "sc16", {res_source_info::INPUT_EDGE, 0});
|
|
mock_sink_term.set_edge_property<std::string>(
|
|
"type", "sc16", {res_source_info::INPUT_EDGE, 1});
|
|
|
|
UHD_LOG_INFO("TEST", "Creating graph...");
|
|
graph.connect(&mock_source_term, test_radio.get(), edge_port_info0);
|
|
graph.connect(&mock_source_term, test_radio.get(), edge_port_info1);
|
|
graph.connect(test_radio.get(), &mock_sink_term, edge_port_info0);
|
|
graph.connect(test_radio.get(), &mock_sink_term, edge_port_info1);
|
|
UHD_LOG_INFO("TEST", "Committing graph...");
|
|
graph.commit();
|
|
UHD_LOG_INFO("TEST", "Commit complete.");
|
|
}
|
|
|
|
/******************************************************************************
|
|
* RFNoC atomic item size property test
|
|
*
|
|
* This test case ensures that the radio block propagates atomic item size correctly
|
|
*****************************************************************************/
|
|
BOOST_FIXTURE_TEST_CASE(x400_radio_test_prop_prop, x400_radio_fixture)
|
|
{
|
|
detail::graph_t graph{};
|
|
detail::graph_t::graph_edge_t edge_port_info0;
|
|
edge_port_info0.src_port = 0;
|
|
edge_port_info0.dst_port = 0;
|
|
edge_port_info0.is_forward_edge = true;
|
|
edge_port_info0.edge = detail::graph_t::graph_edge_t::DYNAMIC;
|
|
detail::graph_t::graph_edge_t edge_port_info1;
|
|
edge_port_info1.src_port = 1;
|
|
edge_port_info1.dst_port = 1;
|
|
edge_port_info1.is_forward_edge = true;
|
|
edge_port_info1.edge = detail::graph_t::graph_edge_t::DYNAMIC;
|
|
|
|
mock_terminator_t mock_sink_term(2, {}, "MOCK_SINK");
|
|
mock_terminator_t mock_source_term(2, {}, "MOCK_SOURCE");
|
|
|
|
UHD_LOG_INFO("TEST", "Priming mock block properties");
|
|
mock_source_term.set_edge_property<size_t>(
|
|
"atomic_item_size", 1, {res_source_info::OUTPUT_EDGE, 0});
|
|
mock_source_term.set_edge_property<size_t>(
|
|
"atomic_item_size", 1, {res_source_info::OUTPUT_EDGE, 1});
|
|
mock_source_term.set_edge_property<size_t>(
|
|
"mtu", 99, {res_source_info::OUTPUT_EDGE, 0});
|
|
mock_sink_term.set_edge_property<size_t>(
|
|
"atomic_item_size", 999, {res_source_info::INPUT_EDGE, 0});
|
|
mock_sink_term.set_edge_property<size_t>(
|
|
"atomic_item_size", 999, {res_source_info::INPUT_EDGE, 1});
|
|
|
|
UHD_LOG_INFO("TEST", "Creating graph...");
|
|
graph.connect(&mock_source_term, test_radio.get(), edge_port_info0);
|
|
graph.connect(&mock_source_term, test_radio.get(), edge_port_info1);
|
|
graph.connect(test_radio.get(), &mock_sink_term, edge_port_info0);
|
|
graph.connect(test_radio.get(), &mock_sink_term, edge_port_info1);
|
|
UHD_LOG_INFO("TEST", "Committing graph...");
|
|
graph.commit();
|
|
|
|
UHD_LOG_INFO("TEST", "Testing atomic item size propagation...");
|
|
|
|
// radio has a sample width of 32 bits (sc16) and spc of 1 by default
|
|
// this results in a atomic item size of 4 for the radio
|
|
// because property gets propagated immediately after setting in
|
|
// the committed graph we can check the result of the propagation
|
|
// at the mock edges
|
|
|
|
mock_source_term.set_edge_property<size_t>(
|
|
"atomic_item_size", 1, {res_source_info::OUTPUT_EDGE, 0});
|
|
BOOST_CHECK_EQUAL(mock_source_term.get_edge_property<size_t>(
|
|
"atomic_item_size", {res_source_info::OUTPUT_EDGE, 0}),
|
|
4);
|
|
|
|
mock_source_term.set_edge_property<size_t>(
|
|
"atomic_item_size", 4, {res_source_info::OUTPUT_EDGE, 1});
|
|
BOOST_CHECK_EQUAL(mock_source_term.get_edge_property<size_t>(
|
|
"atomic_item_size", {res_source_info::OUTPUT_EDGE, 1}),
|
|
4);
|
|
|
|
mock_source_term.set_edge_property<size_t>(
|
|
"atomic_item_size", 9, {res_source_info::OUTPUT_EDGE, 0});
|
|
BOOST_CHECK_EQUAL(mock_source_term.get_edge_property<size_t>(
|
|
"atomic_item_size", {res_source_info::OUTPUT_EDGE, 0}),
|
|
36);
|
|
|
|
mock_source_term.set_edge_property<size_t>(
|
|
"atomic_item_size", 10, {res_source_info::OUTPUT_EDGE, 1});
|
|
BOOST_CHECK_EQUAL(mock_source_term.get_edge_property<size_t>(
|
|
"atomic_item_size", {res_source_info::OUTPUT_EDGE, 1}),
|
|
20);
|
|
|
|
mock_source_term.set_edge_property<size_t>(
|
|
"mtu", 99, {res_source_info::OUTPUT_EDGE, 0});
|
|
mock_source_term.set_edge_property<size_t>(
|
|
"atomic_item_size", 25, {res_source_info::OUTPUT_EDGE, 0});
|
|
BOOST_CHECK_EQUAL(mock_source_term.get_edge_property<size_t>(
|
|
"atomic_item_size", {res_source_info::OUTPUT_EDGE, 0}),
|
|
96);
|
|
|
|
// repeat for sink
|
|
mock_sink_term.set_edge_property<size_t>(
|
|
"atomic_item_size", 1, {res_source_info::INPUT_EDGE, 0});
|
|
BOOST_CHECK_EQUAL(mock_sink_term.get_edge_property<size_t>(
|
|
"atomic_item_size", {res_source_info::INPUT_EDGE, 0}),
|
|
4);
|
|
|
|
mock_sink_term.set_edge_property<size_t>(
|
|
"atomic_item_size", 4, {res_source_info::INPUT_EDGE, 1});
|
|
BOOST_CHECK_EQUAL(mock_sink_term.get_edge_property<size_t>(
|
|
"atomic_item_size", {res_source_info::INPUT_EDGE, 1}),
|
|
4);
|
|
|
|
mock_sink_term.set_edge_property<size_t>(
|
|
"atomic_item_size", 7, {res_source_info::INPUT_EDGE, 0});
|
|
BOOST_CHECK_EQUAL(mock_sink_term.get_edge_property<size_t>(
|
|
"atomic_item_size", {res_source_info::INPUT_EDGE, 0}),
|
|
28);
|
|
BOOST_CHECK_EQUAL(test_radio->get_property<int>("spp", 0) % 7, 0);
|
|
|
|
mock_sink_term.set_edge_property<size_t>(
|
|
"atomic_item_size", 22, {res_source_info::INPUT_EDGE, 1});
|
|
BOOST_CHECK_EQUAL(mock_sink_term.get_edge_property<size_t>(
|
|
"atomic_item_size", {res_source_info::INPUT_EDGE, 1}),
|
|
44);
|
|
BOOST_CHECK_EQUAL(test_radio->get_property<int>("spp", 1) % 11, 0);
|
|
|
|
mock_sink_term.set_edge_property<size_t>(
|
|
"mtu", 179, {res_source_info::INPUT_EDGE, 0});
|
|
mock_sink_term.set_edge_property<size_t>(
|
|
"atomic_item_size", 46, {res_source_info::INPUT_EDGE, 0});
|
|
BOOST_CHECK_EQUAL(mock_sink_term.get_edge_property<size_t>(
|
|
"atomic_item_size", {res_source_info::INPUT_EDGE, 0}),
|
|
92);
|
|
BOOST_CHECK_EQUAL(test_radio->get_property<int>("spp", 0), 23);
|
|
|
|
test_radio->set_property<int>("spp", 3, 0);
|
|
BOOST_CHECK_EQUAL(test_radio->get_property<int>("spp", 0), 23);
|
|
test_radio->set_property<int>("spp", 24, 0);
|
|
BOOST_CHECK_EQUAL(test_radio->get_property<int>("spp", 0), 23);
|
|
|
|
// If we go higher, then there's no valid spp value that is both smaller than
|
|
// MTU *and* a multiple of AIS
|
|
UHD_LOG_INFO("TEST", "Expecting ERROR here VVV");
|
|
BOOST_REQUIRE_THROW(mock_sink_term.set_edge_property<size_t>(
|
|
"atomic_item_size", 47, {res_source_info::INPUT_EDGE, 0}),
|
|
uhd::resolve_error);
|
|
UHD_LOG_INFO("TEST", "Expecting ERROR here ^^^");
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_api_freq_tx_test, x400_radio_fixture)
|
|
{
|
|
const std::string log = "ZBX_API_TX_FREQUENCY_TEST";
|
|
const double ep = 10;
|
|
// TODO: consult step size
|
|
uhd::freq_range_t zbx_freq(ZBX_MIN_FREQ, ZBX_MAX_FREQ, 100e6);
|
|
for (size_t chan : {0, 1}) {
|
|
UHD_LOG_INFO(log, "BEGIN TEST: tx" << chan << " FREQ CHANGE (SET->RETURN)\n");
|
|
for (double iter = zbx_freq.start(); iter <= zbx_freq.stop();
|
|
iter += zbx_freq.step()) {
|
|
UHD_LOG_INFO(log, "Testing freq: " << iter);
|
|
|
|
const double freq = test_radio->set_tx_frequency(iter, chan);
|
|
BOOST_REQUIRE(abs(iter - freq) < ep);
|
|
}
|
|
|
|
UHD_LOG_INFO(log, "BEGIN TEST: tx" << chan << " FREQ CHANGE (SET->GET)\n");
|
|
for (double iter = zbx_freq.start(); iter <= zbx_freq.stop();
|
|
iter += zbx_freq.step()) {
|
|
UHD_LOG_INFO(log, "Testing freq: " << iter);
|
|
|
|
test_radio->set_tx_frequency(iter, chan);
|
|
const double freq = test_radio->get_tx_frequency(chan);
|
|
BOOST_REQUIRE(abs(iter - freq) < ep);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_api_freq_rx_test, x400_radio_fixture)
|
|
{
|
|
const std::string log = "ZBX_API_RX_FREQUENCY_TEST";
|
|
const double ep = 10;
|
|
// TODO: consult step size
|
|
uhd::freq_range_t zbx_freq(ZBX_MIN_FREQ, ZBX_MAX_FREQ, 100e6);
|
|
|
|
for (size_t chan : {0, 1}) {
|
|
UHD_LOG_INFO(log, "BEGIN TEST: rx" << chan << " FREQ CHANGE (SET->RETURN)\n");
|
|
for (double iter = zbx_freq.start(); iter <= zbx_freq.stop();
|
|
iter += zbx_freq.step()) {
|
|
UHD_LOG_INFO(log, "Testing freq: " << iter);
|
|
|
|
const double freq = test_radio->set_rx_frequency(iter, chan);
|
|
BOOST_REQUIRE(abs(iter - freq) < ep);
|
|
}
|
|
UHD_LOG_INFO(log, "BEGIN TEST: rx" << chan << " FREQ CHANGE (SET->GET\n");
|
|
for (double iter = zbx_freq.start(); iter <= zbx_freq.stop();
|
|
iter += zbx_freq.step()) {
|
|
UHD_LOG_INFO(log, "Testing freq: " << iter);
|
|
|
|
test_radio->set_rx_frequency(iter, chan);
|
|
const double freq = test_radio->get_rx_frequency(chan);
|
|
BOOST_REQUIRE(abs(iter - freq) < ep);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_frequency_test, x400_radio_fixture)
|
|
{
|
|
auto tree = test_radio->get_tree();
|
|
const std::string log = "ZBX_FREQUENCY_TEST";
|
|
const double ep = 10;
|
|
// TODO: consult step size
|
|
uhd::freq_range_t zbx_freq(ZBX_MIN_FREQ, ZBX_MAX_FREQ, 100e6);
|
|
|
|
for (auto fe_path : {
|
|
fs_path("dboard/tx_frontends/0"),
|
|
fs_path("dboard/tx_frontends/1"),
|
|
fs_path("dboard/rx_frontends/0"),
|
|
fs_path("dboard/rx_frontends/1"),
|
|
}) {
|
|
UHD_LOG_INFO(log, "BEGIN TEST: " << fe_path << " FREQ CHANGE\n");
|
|
for (double iter = zbx_freq.start(); iter <= zbx_freq.stop();
|
|
iter += zbx_freq.step()) {
|
|
UHD_LOG_INFO(log, "Testing freq: " << iter);
|
|
|
|
tree->access<double>(fe_path / "freq").set(iter);
|
|
|
|
const double ret_value = tree->access<double>(fe_path / "freq").get();
|
|
|
|
BOOST_REQUIRE(abs(iter - ret_value) < ep);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_api_tx_gain_test, x400_radio_fixture)
|
|
{
|
|
auto tree = test_radio->get_tree();
|
|
const std::string log = "ZBX TX GAIN TEST";
|
|
uhd::freq_range_t zbx_gain(TX_MIN_GAIN, TX_MAX_GAIN, 1);
|
|
|
|
for (size_t chan : {0, 1}) {
|
|
UHD_LOG_INFO(log, "BEGIN TEST: tx" << chan << " GAIN CHANGE (SET->RETURN)\n");
|
|
for (double iter = zbx_gain.start(); iter <= zbx_gain.stop();
|
|
iter += zbx_gain.step()) {
|
|
UHD_LOG_INFO(log, "Testing gain: " << iter);
|
|
|
|
const double ret_gain = test_radio->set_tx_gain(iter, chan);
|
|
|
|
BOOST_CHECK_EQUAL(iter, ret_gain);
|
|
}
|
|
UHD_LOG_INFO(log, "BEGIN TEST: tx" << chan << " GAIN CHANGE (SET->GET)\n");
|
|
for (double iter = zbx_gain.start(); iter <= zbx_gain.stop();
|
|
iter += zbx_gain.step()) {
|
|
UHD_LOG_INFO(log, "Testing gain: " << iter);
|
|
|
|
test_radio->set_tx_gain(iter, chan);
|
|
const double ret_gain = test_radio->get_tx_gain(chan);
|
|
|
|
BOOST_CHECK_EQUAL(iter, ret_gain);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_api_tx_gain_stage_test, x400_radio_fixture)
|
|
{
|
|
auto tree = test_radio->get_tree();
|
|
const std::string log = "ZBX API TX GAIN STAGE TEST";
|
|
|
|
for (size_t chan : {0, 1}) {
|
|
test_radio->set_tx_gain_profile(ZBX_GAIN_PROFILE_MANUAL, chan);
|
|
|
|
UHD_LOG_INFO(
|
|
log, "BEGIN TEST: tx" << chan << " GAIN STAGE CHANGE (SET->RETURN)\n");
|
|
for (auto gain_stage : ZBX_TX_GAIN_STAGES) {
|
|
if (gain_stage == ZBX_GAIN_STAGE_AMP) {
|
|
for (double amp : {ZBX_TX_LOWBAND_GAIN, ZBX_TX_HIGHBAND_GAIN}) {
|
|
UHD_LOG_INFO(log, "Testing dsa: " << amp);
|
|
const double ret_gain =
|
|
test_radio->set_tx_gain(amp, gain_stage, chan);
|
|
UHD_LOG_INFO(log, "return: " << ret_gain);
|
|
BOOST_CHECK_EQUAL(amp, ret_gain);
|
|
}
|
|
} else {
|
|
for (unsigned int iter = 0; iter <= ZBX_TX_DSA_MAX_ATT; iter++) {
|
|
UHD_LOG_INFO(log, "Testing dsa: " << iter);
|
|
const double ret_gain =
|
|
test_radio->set_tx_gain(iter, gain_stage, chan);
|
|
BOOST_CHECK_EQUAL(iter, ret_gain);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_api_tx_gain_stage_test_set_get, x400_radio_fixture)
|
|
{
|
|
auto tree = test_radio->get_tree();
|
|
const std::string log = "ZBX API TX GAIN STAGE TEST";
|
|
|
|
for (size_t chan : {0, 1}) {
|
|
test_radio->set_tx_gain_profile(ZBX_GAIN_PROFILE_MANUAL, chan);
|
|
UHD_LOG_INFO(log, "BEGIN TEST: tx" << chan << " GAIN STAGE CHANGE (SET->GET)\n");
|
|
for (auto gain_stage : ZBX_TX_GAIN_STAGES) {
|
|
if (gain_stage == ZBX_GAIN_STAGE_AMP) {
|
|
for (double amp :
|
|
{/*ZBX_TX_BYPASS_GAIN, currently disabled*/ ZBX_TX_LOWBAND_GAIN,
|
|
ZBX_TX_HIGHBAND_GAIN}) {
|
|
UHD_LOG_INFO(log, "Testing amp: " << amp);
|
|
test_radio->set_tx_gain(amp, gain_stage, chan);
|
|
const double ret_gain = test_radio->get_tx_gain(gain_stage, chan);
|
|
BOOST_CHECK_EQUAL(amp, ret_gain);
|
|
}
|
|
} else {
|
|
for (unsigned int iter = 0; iter <= ZBX_TX_DSA_MAX_ATT; iter++) {
|
|
UHD_LOG_INFO(log, "Testing dsa: " << iter);
|
|
test_radio->set_tx_gain(iter, gain_stage, chan);
|
|
const double ret_gain = test_radio->get_tx_gain(gain_stage, chan);
|
|
BOOST_CHECK_EQUAL(iter, ret_gain);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_api_rx_gain_test, x400_radio_fixture)
|
|
{
|
|
auto tree = test_radio->get_tree();
|
|
const std::string log = "ZBX RX API GAIN TEST";
|
|
uhd::freq_range_t zbx_gain(TX_MIN_GAIN, TX_MAX_GAIN, 1);
|
|
|
|
for (size_t chan : {0, 1}) {
|
|
UHD_LOG_INFO(log, "BEGIN TEST: rx" << chan << " GAIN CHANGE (SET->RETURN)\n");
|
|
for (double iter = zbx_gain.start(); iter <= zbx_gain.stop();
|
|
iter += zbx_gain.step()) {
|
|
UHD_LOG_INFO(log, "Testing gain: " << iter);
|
|
|
|
const double ret_gain = test_radio->set_rx_gain(iter, chan);
|
|
|
|
BOOST_CHECK_EQUAL(iter, ret_gain);
|
|
}
|
|
UHD_LOG_INFO(log, "BEGIN TEST: rx" << chan << " GAIN CHANGE (SET->GET)\n");
|
|
for (double iter = zbx_gain.start(); iter <= zbx_gain.stop();
|
|
iter += zbx_gain.step()) {
|
|
UHD_LOG_INFO(log, "Testing gain: " << iter);
|
|
|
|
test_radio->set_rx_gain(iter, chan);
|
|
const double ret_gain = test_radio->get_rx_gain(chan);
|
|
|
|
BOOST_CHECK_EQUAL(iter, ret_gain);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_api_rx_gain_stage_test, x400_radio_fixture)
|
|
{
|
|
auto tree = test_radio->get_tree();
|
|
const std::string log = "ZBX API RX GAIN STAGE TEST";
|
|
|
|
for (size_t chan : {0, 1}) {
|
|
test_radio->set_rx_gain_profile(ZBX_GAIN_PROFILE_MANUAL, chan);
|
|
|
|
UHD_LOG_INFO(
|
|
log, "BEGIN TEST: rx" << chan << " GAIN STAGE CHANGE (SET->RETURN)\n");
|
|
for (auto gain_stage : ZBX_RX_GAIN_STAGES) {
|
|
for (unsigned int iter = 0; iter <= ZBX_RX_DSA_MAX_ATT; iter++) {
|
|
UHD_LOG_INFO(log, "Testing dsa: " << gain_stage << " " << iter);
|
|
const double ret_gain = test_radio->set_rx_gain(iter, gain_stage, chan);
|
|
|
|
BOOST_CHECK_EQUAL(iter, ret_gain);
|
|
}
|
|
}
|
|
|
|
UHD_LOG_INFO(log, "BEGIN TEST: rx" << chan << " GAIN STAGE CHANGE (SET->GET)\n");
|
|
for (auto gain_stage : ZBX_RX_GAIN_STAGES) {
|
|
for (unsigned int iter = 0; iter <= ZBX_RX_DSA_MAX_ATT; iter++) {
|
|
UHD_LOG_INFO(log, "Testing " << gain_stage << " " << iter);
|
|
|
|
test_radio->set_rx_gain(iter, gain_stage, chan);
|
|
const double ret_gain = test_radio->get_rx_gain(gain_stage, chan);
|
|
|
|
BOOST_CHECK_EQUAL(iter, ret_gain);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_tx_gain_test, x400_radio_fixture)
|
|
{
|
|
auto tree = test_radio->get_tree();
|
|
const std::string log = "ZBX GAIN TEST";
|
|
uhd::freq_range_t zbx_gain(TX_MIN_GAIN, TX_MAX_GAIN, 1);
|
|
|
|
for (auto fe_path :
|
|
{fs_path("dboard/tx_frontends/0"), fs_path("dboard/tx_frontends/1")}) {
|
|
UHD_LOG_INFO(log, "BEGIN TEST: " << fe_path << " GAIN CHANGE\n");
|
|
for (double iter = zbx_gain.start(); iter <= zbx_gain.stop();
|
|
iter += zbx_gain.step()) {
|
|
UHD_LOG_INFO(log, "Testing gain: " << iter);
|
|
const auto gain_path = fe_path / "gains" / ZBX_GAIN_STAGE_ALL / "value";
|
|
tree->access<double>(gain_path).set(iter);
|
|
const double ret_gain = tree->access<double>(gain_path).get();
|
|
BOOST_CHECK_EQUAL(iter, ret_gain);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_rx_gain_test, x400_radio_fixture)
|
|
{
|
|
auto tree = test_radio->get_tree();
|
|
const std::string log = "ZBX GAIN TEST";
|
|
uhd::freq_range_t zbx_gain(RX_MIN_GAIN, RX_MAX_GAIN, 1);
|
|
|
|
for (auto fe_path :
|
|
{fs_path("dboard/rx_frontends/0"), fs_path("dboard/rx_frontends/1")}) {
|
|
UHD_LOG_INFO(log, "BEGIN TEST: " << fe_path << " GAIN CHANGE\n");
|
|
for (double iter = zbx_gain.start(); iter <= zbx_gain.stop();
|
|
iter += zbx_gain.step()) {
|
|
UHD_LOG_INFO(log, "Testing gain: " << iter);
|
|
const auto gain_path = fe_path / "gains" / ZBX_GAIN_STAGE_ALL / "value";
|
|
tree->access<double>(gain_path).set(iter);
|
|
const double ret_gain = tree->access<double>(gain_path).get();
|
|
BOOST_CHECK_EQUAL(iter, ret_gain);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Have to be careful about LO testing; it'll throw off the coerced frequency a bunch,
|
|
// possibly to illegal values like negative frequencies, and could make the gain API
|
|
// freak out. We use the center frequency to set initial mixer values, then try to test
|
|
// all LO's in the valid zbx range.
|
|
// TODO: expand this
|
|
const std::map<double, std::vector<std::array<double, 2>>> valid_lo_freq_map = {
|
|
{1e9, {{4.5e9, 4.5e9}, {5e9, 5e9}, {5.5e9, 5.5e9}, {6e9, 6e9}}},
|
|
{2e9, {{4.5e9, 4.5e9}, {5e9, 5e9}, {5.5e9, 5.5e9}, {6e9, 6e9}}}};
|
|
|
|
// TODO: More frequencies_are_equal issues, too much variance
|
|
BOOST_FIXTURE_TEST_CASE(zbx_api_tx_lo_test, x400_radio_fixture)
|
|
{
|
|
auto tree = test_radio->get_tree();
|
|
const std::string log = "ZBX TX TEST";
|
|
const double ep = 10;
|
|
|
|
for (size_t chan : {0, 1}) {
|
|
UHD_LOG_INFO(log, "BEGIN TEST: TX" << chan << " FREQ CHANGE (SET->RETURN)\n");
|
|
for (auto iter = valid_lo_freq_map.begin(); iter != valid_lo_freq_map.end();
|
|
iter++) {
|
|
for (auto iter_lo = iter->second.begin(); iter_lo != iter->second.end();
|
|
iter_lo++) {
|
|
// Just so we're clear about our value mapping
|
|
const double req_freq = iter->first;
|
|
const double req_lo1 = iter_lo->at(0);
|
|
const double req_lo2 = iter_lo->at(1);
|
|
|
|
UHD_LOG_INFO(log,
|
|
"Testing center freq " << req_freq / 1e6 << "MHz, lo1 freq "
|
|
<< req_lo1 / 1e6 << "MHz, lo2 freq "
|
|
<< req_lo2 / 1e6 << "MHz");
|
|
// Need to set center frequency first, it'll set all the mixer values
|
|
test_radio->set_tx_frequency(iter->first, chan);
|
|
const double lo1_ret =
|
|
test_radio->set_tx_lo_freq(iter_lo->at(0), ZBX_LO1, chan);
|
|
const double lo2_ret =
|
|
test_radio->set_tx_lo_freq(iter_lo->at(1), ZBX_LO2, chan);
|
|
// No use comparing set_tx_freq, we've already ran that test and
|
|
// get_tx_frequency would return who knows what at this point
|
|
BOOST_REQUIRE(abs(iter_lo->at(0) - lo1_ret) < ep);
|
|
BOOST_REQUIRE(abs(iter_lo->at(1) - lo2_ret) < ep);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_api_rx_lo_test, x400_radio_fixture)
|
|
{
|
|
auto tree = test_radio->get_tree();
|
|
const std::string log = "ZBX RX LO TEST";
|
|
const double ep = 10;
|
|
|
|
for (size_t chan : {0, 1}) {
|
|
UHD_LOG_INFO(log, "BEGIN TEST: RX" << chan << " FREQ CHANGE (SET->RETURN)\n");
|
|
for (auto iter = valid_lo_freq_map.begin(); iter != valid_lo_freq_map.end();
|
|
iter++) {
|
|
for (auto iter_lo = iter->second.begin(); iter_lo != iter->second.end();
|
|
iter_lo++) {
|
|
// Just so we're clear about our value mapping
|
|
const double req_freq = iter->first;
|
|
const double req_lo1 = iter_lo->at(0);
|
|
const double req_lo2 = iter_lo->at(1);
|
|
|
|
UHD_LOG_INFO(log,
|
|
"Testing center freq " << req_freq / 1e6 << "MHz, lo1 freq "
|
|
<< req_lo1 / 1e6 << "MHz, lo2 freq "
|
|
<< req_lo2 / 1e6 << "MHz");
|
|
// Need to set center frequency first, it'll set all the mixer values
|
|
test_radio->set_rx_frequency(iter->first, chan);
|
|
const double lo1_ret =
|
|
test_radio->set_rx_lo_freq(iter_lo->at(0), ZBX_LO1, chan);
|
|
const double lo2_ret =
|
|
test_radio->set_rx_lo_freq(iter_lo->at(1), ZBX_LO2, chan);
|
|
// No use comparing set_tx_freq, we've already ran that test and
|
|
// get_tx_frequency would return who knows what at this point
|
|
BOOST_REQUIRE(abs(iter_lo->at(0) - lo1_ret) < ep);
|
|
BOOST_REQUIRE(abs(iter_lo->at(1) - lo2_ret) < ep);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_lo_tree_test, x400_radio_fixture)
|
|
{
|
|
auto tree = test_radio->get_tree();
|
|
const std::string log = "ZBX LO1 TEST";
|
|
const double ep = 10;
|
|
|
|
for (auto fe_path : {
|
|
fs_path("dboard/tx_frontends/0"),
|
|
fs_path("dboard/tx_frontends/1"),
|
|
fs_path("dboard/rx_frontends/0"),
|
|
fs_path("dboard/rx_frontends/1"),
|
|
}) {
|
|
UHD_LOG_INFO(log, "BEGIN TEST: " << fe_path << " LO FREQ CHANGE (SET->RETURN)\n");
|
|
for (auto iter = valid_lo_freq_map.begin(); iter != valid_lo_freq_map.end();
|
|
iter++) {
|
|
for (auto iter_lo = iter->second.begin(); iter_lo != iter->second.end();
|
|
iter_lo++) {
|
|
// Just so we're clear about our value mapping
|
|
const double req_freq = iter->first;
|
|
const double req_lo1 = iter_lo->at(0);
|
|
const double req_lo2 = iter_lo->at(1);
|
|
UHD_LOG_INFO(log,
|
|
"Testing lo1 freq " << req_lo1 / 1e6 << "MHz, lo2 freq "
|
|
<< req_lo2 / 1e6 << "MHz at center frequency "
|
|
<< req_freq / 1e6 << "MHz");
|
|
tree->access<double>(fe_path / "freq").set(req_freq);
|
|
const double ret_lo1 =
|
|
tree->access<double>(fe_path / "los" / ZBX_LO1 / "freq" / "value")
|
|
.set(req_lo1)
|
|
.get();
|
|
const double ret_lo2 =
|
|
tree->access<double>(fe_path / "los" / ZBX_LO2 / "freq" / "value")
|
|
.set(req_lo2)
|
|
.get();
|
|
BOOST_REQUIRE(abs(req_lo1 - ret_lo1) < ep);
|
|
BOOST_REQUIRE(abs(req_lo2 - ret_lo2) < ep);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_custom_tx_tune_table_test, x400_radio_fixture)
|
|
{
|
|
auto tree = test_radio->get_tree();
|
|
constexpr size_t chan = 0;
|
|
constexpr double ep = 10.0;
|
|
|
|
test_radio->set_tx_frequency(4.4e9, chan);
|
|
|
|
BOOST_REQUIRE(abs(test_radio->get_tx_lo_freq(ZBX_LO2, chan) - 5447680000.0) < ep);
|
|
|
|
// Custom TX tune table to try. This table is identical to the normal table,
|
|
// except it only has one entry (4.03GHz-4.5GHz) and the IF2 frequency for
|
|
// that band is 10MHz lower (chosen arbitrarily)
|
|
// Turn clang-formatting off so it doesn't compress these tables into a mess.
|
|
// clang-format off
|
|
static const std::vector<zbx_tune_map_item_t> alternate_tx_tune_map = {
|
|
// | min_band_freq | max_band_freq | rf_fir | if1_fir | if2_fir | lo1_inj_side | lo2_inj_side | if1_freq_min | if1_freq_max | if2_freq_min | if2_freq_max |
|
|
{ 4030e6, 4500e6, 0, 1, 1, NONE, HIGH, 0, 0, 1050e6, 1050e6 },
|
|
};
|
|
|
|
// Turn clang-format back on just for posterity
|
|
// clang-format on
|
|
|
|
tree->access<std::vector<uhd::usrp::zbx::zbx_tune_map_item_t>>(
|
|
"dboard/tx_frontends/0/tune_table")
|
|
.set(alternate_tx_tune_map);
|
|
|
|
BOOST_REQUIRE(abs(test_radio->get_tx_lo_freq(ZBX_LO2, chan) - 5437440000.0) < ep);
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_custom_rx_tune_table_test, x400_radio_fixture)
|
|
{
|
|
auto tree = test_radio->get_tree();
|
|
constexpr size_t chan = 0;
|
|
constexpr double ep = 10.0;
|
|
|
|
test_radio->set_rx_frequency(4.4e9, chan);
|
|
|
|
BOOST_REQUIRE(abs(test_radio->get_rx_lo_freq(ZBX_LO2, chan) - 6236160000.0) < ep);
|
|
|
|
// Custom RX tune table to try. This table is identical to the normal table,
|
|
// except it only has one entry (4.2GHz-4.5GHz) and the IF2 frequency for
|
|
// that band is 10MHz lower (chosen arbitrarily)
|
|
// Turn clang-formatting off so it doesn't compress these tables into a mess.
|
|
// clang-format off
|
|
static const std::vector<zbx_tune_map_item_t> alternate_rx_tune_map = {
|
|
// | min_band_freq | max_band_freq | rf_fir | if1_fir | if2_fir | lo1_inj_side | lo2_inj_side | if1_freq_min | if1_freq_max | if2_freq_min | if2_freq_max |
|
|
{ 4200e6, 4500e6, 0, 2, 2, NONE, HIGH, 0, 0, 1840e6, 1840e6 },
|
|
};
|
|
|
|
// Turn clang-format back on just for posterity
|
|
// clang-format on
|
|
|
|
tree->access<std::vector<uhd::usrp::zbx::zbx_tune_map_item_t>>(
|
|
"dboard/rx_frontends/0/tune_table")
|
|
.set(alternate_rx_tune_map);
|
|
|
|
BOOST_REQUIRE(abs(test_radio->get_rx_lo_freq(ZBX_LO2, chan) - 6225920000.0) < ep);
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_ant_test, x400_radio_fixture)
|
|
{
|
|
auto tree = test_radio->get_tree();
|
|
std::string log = "ZBX RX ANTENNA TEST";
|
|
|
|
for (auto fe_path :
|
|
{fs_path("dboard/rx_frontends/0"), fs_path("dboard/rx_frontends/1")}) {
|
|
UHD_LOG_INFO(log, "BEGIN TEST: " << fe_path << " ANTENNA CHANGE\n");
|
|
for (auto iter : RX_ANTENNAS) {
|
|
UHD_LOG_INFO(log, "Testing Antenna: " << iter);
|
|
|
|
tree->access<std::string>(fe_path / "antenna/value").set(iter);
|
|
|
|
std::string ret_ant =
|
|
tree->access<std::string>(fe_path / "antenna/value").get();
|
|
BOOST_CHECK_EQUAL(iter, ret_ant);
|
|
}
|
|
}
|
|
for (size_t chan = 0; chan < 2; chan++) {
|
|
for (auto iter : RX_ANTENNAS) {
|
|
UHD_LOG_INFO(log, "Testing Antenna: " << iter);
|
|
|
|
test_radio->set_rx_antenna(iter, chan);
|
|
|
|
std::string ret_ant = test_radio->get_rx_antenna(chan);
|
|
BOOST_CHECK_EQUAL(iter, ret_ant);
|
|
}
|
|
}
|
|
log = "ZBX TX ANTENNA TEST";
|
|
for (auto fe_path :
|
|
{fs_path("dboard/tx_frontends/0"), fs_path("dboard/tx_frontends/1")}) {
|
|
UHD_LOG_INFO(log, "BEGIN TEST: " << fe_path << " ANTENNA CHANGE\n");
|
|
for (auto iter : TX_ANTENNAS) {
|
|
UHD_LOG_INFO(log, "Testing Antenna: " << iter);
|
|
|
|
tree->access<std::string>(fe_path / "antenna/value").set(iter);
|
|
|
|
std::string ret_ant =
|
|
tree->access<std::string>(fe_path / "antenna/value").get();
|
|
BOOST_CHECK_EQUAL(iter, ret_ant);
|
|
}
|
|
}
|
|
for (size_t chan = 0; chan < 2; chan++) {
|
|
for (auto iter : TX_ANTENNAS) {
|
|
UHD_LOG_INFO(log, "Testing Antenna: " << iter);
|
|
|
|
test_radio->set_tx_antenna(iter, chan);
|
|
|
|
std::string ret_ant = test_radio->get_tx_antenna(chan);
|
|
BOOST_CHECK_EQUAL(iter, ret_ant);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_freq_coercion_test, x400_radio_fixture)
|
|
{
|
|
auto tree = test_radio->get_tree();
|
|
const std::string log = "ZBX_FREQUENCY_COERCION_TEST";
|
|
const double ep = 10;
|
|
|
|
for (auto fe_path : {
|
|
fs_path("dboard/tx_frontends/0"),
|
|
fs_path("dboard/tx_frontends/1"),
|
|
fs_path("dboard/rx_frontends/0"),
|
|
fs_path("dboard/rx_frontends/1"),
|
|
}) {
|
|
UHD_LOG_INFO(log, "BEGIN TEST: " << fe_path << " FREQUENCY COERCION\n");
|
|
double ret_value =
|
|
tree->access<double>(fe_path / "freq").set(ZBX_MIN_FREQ - 1e6).get();
|
|
|
|
BOOST_REQUIRE(abs(ZBX_MIN_FREQ - ret_value) < ep);
|
|
|
|
ret_value = tree->access<double>(fe_path / "freq").set(ZBX_MAX_FREQ + 1e6).get();
|
|
|
|
BOOST_REQUIRE(abs(ZBX_MAX_FREQ - ret_value) < ep);
|
|
}
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_tx_gain_coercion_test, x400_radio_fixture)
|
|
{
|
|
auto tree = test_radio->get_tree();
|
|
const std::string log = "ZBX_GAIN_COERCION_TEST";
|
|
|
|
for (auto fe_path :
|
|
{fs_path("dboard/tx_frontends/0"), fs_path("dboard/tx_frontends/1")}) {
|
|
uhd::gain_range_t zbx_gain(TX_MIN_GAIN, TX_MAX_GAIN, 0.1);
|
|
UHD_LOG_INFO(log, "BEGIN TEST: " << fe_path << " TX GAIN COERCION\n");
|
|
for (double iter = zbx_gain.start(); iter <= zbx_gain.stop();
|
|
iter += zbx_gain.step()) {
|
|
const auto gain_path = fe_path / "gains" / ZBX_GAIN_STAGE_ALL / "value";
|
|
const double ret_val = tree->access<double>(gain_path).set(iter).get();
|
|
BOOST_CHECK_EQUAL(ret_val, std::round(iter));
|
|
}
|
|
}
|
|
for (auto fe_path :
|
|
{fs_path("dboard/rx_frontends/0"), fs_path("dboard/rx_frontends/1")}) {
|
|
uhd::gain_range_t zbx_gain(RX_MIN_GAIN, RX_MAX_GAIN, 0.1);
|
|
UHD_LOG_INFO(log, "BEGIN TEST: " << fe_path << " RX GAIN COERCION\n");
|
|
for (double iter = zbx_gain.start(); iter <= zbx_gain.stop();
|
|
iter += zbx_gain.step()) {
|
|
const auto gain_path = fe_path / "gains" / ZBX_GAIN_STAGE_ALL / "value";
|
|
const double ret_val = tree->access<double>(gain_path).set(iter).get();
|
|
BOOST_CHECK_EQUAL(ret_val, std::round(iter));
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_phase_sync_test, x400_radio_fixture)
|
|
{
|
|
auto tree = test_radio->get_tree();
|
|
const std::string log = "ZBX_PHASE_SYNC_TEST";
|
|
constexpr uint32_t lo_sync_addr = 0x1024 + 0x80000;
|
|
constexpr uint32_t nco_sync_addr = 0x88000;
|
|
constexpr uint32_t gearbox_addr = 0x88004;
|
|
auto& regs = reg_iface->read_memory;
|
|
// Set reset complete bit
|
|
regs[nco_sync_addr] = 1 << 1;
|
|
constexpr uint32_t nco_sync_val =
|
|
(uhd::rfnoc::x400::rfdc_control::DEFAULT_SYSREF_WAIT_CYCLES & 0xFF)
|
|
<< uhd::rfnoc::x400::rfdc_control::regmap::SYSREF_WAIT_LSB
|
|
| 1 << uhd::rfnoc::x400::rfdc_control::regmap::WRITE_SYSREF_WAIT
|
|
| 1 << uhd::rfnoc::x400::rfdc_control::regmap::NCO_RESET_DONE_MSB
|
|
| 1 << uhd::rfnoc::x400::rfdc_control::regmap::NCO_RESET_START_MSB;
|
|
|
|
UHD_LOG_INFO("TEST", "Setting 1 GHz defaults...");
|
|
// Confirm default
|
|
test_radio->set_rx_frequency(1e9, 0);
|
|
test_radio->set_rx_frequency(1e9, 1);
|
|
test_radio->set_tx_frequency(1e9, 0);
|
|
test_radio->set_tx_frequency(1e9, 1);
|
|
// Enable time stamp
|
|
UHD_LOG_INFO("TEST", "Enabling time stamp chan 0...");
|
|
test_radio->set_command_time(uhd::time_spec_t(2.0), 0);
|
|
// Don't pick the ZBX default frequency here
|
|
UHD_LOG_INFO("TEST", "Setting RX chan 0 to 2.3 GHz...");
|
|
test_radio->set_rx_frequency(2.3e9, 0);
|
|
// Check we synced RX LOs chan 0 and RX NCO chan 0, and ADC gearboxes
|
|
BOOST_CHECK_EQUAL(regs[lo_sync_addr], 0b11 << 4);
|
|
BOOST_CHECK_EQUAL(regs[nco_sync_addr], nco_sync_val);
|
|
BOOST_CHECK_EQUAL(regs[gearbox_addr], 1);
|
|
// Reset strobes
|
|
regs[lo_sync_addr] = 0;
|
|
regs[nco_sync_addr] = 1 << 1; // Set reset complete bit
|
|
regs[gearbox_addr] = 0;
|
|
UHD_LOG_INFO("TEST", "Enabling time stamp chan 1...");
|
|
test_radio->set_command_time(uhd::time_spec_t(2.0), 1);
|
|
UHD_LOG_INFO("TEST", "Setting RX chan 1 to 2.3 GHz...");
|
|
test_radio->set_rx_frequency(2.3e9, 1);
|
|
// Check we synced RX LOs chan 1 and RX NCO chan 1. ADC gearbox only gets
|
|
// reset once, and should be left untouched.
|
|
BOOST_CHECK_EQUAL(regs[lo_sync_addr], 0b11 << 6);
|
|
BOOST_CHECK_EQUAL(regs[nco_sync_addr], nco_sync_val);
|
|
BOOST_CHECK_EQUAL(regs[gearbox_addr], 0);
|
|
// Reset strobes
|
|
regs[lo_sync_addr] = 0;
|
|
regs[nco_sync_addr] = 1 << 1; // Set reset complete bit
|
|
regs[gearbox_addr] = 0;
|
|
UHD_LOG_INFO("TEST", "Setting TX chan 0 to 2.3 GHz...");
|
|
test_radio->set_tx_frequency(2.3e9, 0);
|
|
// Check we synced TX LOs chan 0 and TX NCO chan 0, and DAC gearboxes
|
|
BOOST_CHECK_EQUAL(regs[lo_sync_addr], 0x3 << 0);
|
|
BOOST_CHECK_EQUAL(regs[nco_sync_addr], nco_sync_val);
|
|
BOOST_CHECK_EQUAL(regs[gearbox_addr], 1 << 1);
|
|
// Reset strobe
|
|
regs[lo_sync_addr] = 0;
|
|
regs[nco_sync_addr] = 1 << 1; // Set reset complete bit
|
|
regs[gearbox_addr] = 0;
|
|
UHD_LOG_INFO("TEST", "Setting TX chan 1 to 2.3 GHz...");
|
|
test_radio->set_tx_frequency(2.3e9, 1);
|
|
// Check we synced TX LOs chan 1 and TX NCO chan 1. DAC gearbox only gets
|
|
// reset once, and should be left untouched.
|
|
BOOST_CHECK_EQUAL(regs[lo_sync_addr], 0xC << 0);
|
|
BOOST_CHECK_EQUAL(regs[nco_sync_addr], nco_sync_val);
|
|
BOOST_CHECK_EQUAL(regs[gearbox_addr], 0);
|
|
// Reset strobe
|
|
regs[lo_sync_addr] = 0;
|
|
regs[nco_sync_addr] = 0;
|
|
regs[gearbox_addr] = 0;
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(can_set_rfdc_test, x400_radio_fixture)
|
|
{
|
|
test_radio->set_tx_lo_freq(3.141e9, "rfdc", 1);
|
|
test_radio->get_tx_lo_freq("rfdc", 1);
|
|
|
|
test_radio->set_rx_lo_freq(2.141e9, "rfdc", 0);
|
|
test_radio->get_rx_lo_freq("rfdc", 0);
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_tx_power_api, x400_radio_fixture)
|
|
{
|
|
constexpr double tx_given_gain = 30;
|
|
constexpr double tx_given_power = -30;
|
|
|
|
auto tree = test_radio->get_tree();
|
|
const std::string log = "ZBX_TX_POWER_TRACKING_TEST";
|
|
auto tx_pwr_mgr = test_radio->get_pwr_mgr(TX_DIRECTION);
|
|
|
|
for (size_t chan = 0; chan < ZBX_NUM_CHANS; chan++) {
|
|
// Start in gain tracking mode
|
|
double gain_coerced = test_radio->set_tx_gain(tx_given_gain, chan);
|
|
BOOST_CHECK_EQUAL(gain_coerced, tx_given_gain);
|
|
for (const double freq : {6e+08, 1e+09, 2e+09, 3e+09, 4e+09, 5e+09, 6e+09}) {
|
|
// Setting a power reference should kick us into power tracking mode
|
|
test_radio->set_tx_power_reference(tx_given_power, chan);
|
|
|
|
test_radio->set_tx_frequency(freq, chan);
|
|
// If the tracking mode is properly set, we should not deviate much
|
|
// regarding power
|
|
const double pow_diff =
|
|
std::abs(tx_given_power - test_radio->get_tx_power_reference(chan));
|
|
BOOST_CHECK_MESSAGE(
|
|
pow_diff < 3.0, "power differential is too large: " << pow_diff);
|
|
|
|
// Back to gain mode
|
|
gain_coerced = test_radio->set_tx_gain(tx_given_gain, chan);
|
|
BOOST_CHECK_EQUAL(gain_coerced, tx_given_gain);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_rx_power_api, x400_radio_fixture)
|
|
{
|
|
constexpr double rx_given_gain = 30;
|
|
constexpr double rx_given_power = -30;
|
|
|
|
auto tree = test_radio->get_tree();
|
|
const std::string log = "ZBX_RX_POWER_TRACKING_TEST";
|
|
auto rx_pwr_mgr = test_radio->get_pwr_mgr(RX_DIRECTION);
|
|
|
|
for (size_t chan = 0; chan < ZBX_NUM_CHANS; chan++) {
|
|
// Start in gain tracking mode
|
|
double gain_coerced = test_radio->set_rx_gain(rx_given_gain, chan);
|
|
BOOST_REQUIRE_EQUAL(gain_coerced, rx_given_gain);
|
|
for (const double freq : {1e+09, 2e+09, 3e+09, 4e+09, 5e+09, 6e+09}) {
|
|
// Setting a power reference should kick us into power tracking mode
|
|
test_radio->set_rx_power_reference(rx_given_power, chan);
|
|
// Now go tune
|
|
test_radio->set_rx_frequency(freq, chan);
|
|
// If the tracking mode is properly set, we should match our expected criteria
|
|
// for power reference levels
|
|
const double actual_power = test_radio->get_rx_power_reference(chan);
|
|
const double pow_diff = std::abs(rx_given_power - actual_power);
|
|
BOOST_CHECK_MESSAGE(pow_diff < 3.0,
|
|
"power differential is too large ("
|
|
<< pow_diff << "): Expected close to: " << rx_given_power
|
|
<< " Actual: " << actual_power << " Frequency: " << (freq / 1e6));
|
|
|
|
gain_coerced = test_radio->set_rx_gain(rx_given_gain, chan);
|
|
BOOST_REQUIRE_EQUAL(gain_coerced, rx_given_gain);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_tx_lo_injection_locking, x400_radio_fixture)
|
|
{
|
|
auto tree = test_radio->get_tree();
|
|
|
|
// As of right now, we don't have a way to directly get the DB prc rate, this is the
|
|
// value of the prc map per DEFAULT_MCR, in the mock RPC server:db_0_get_db_prc_rate()
|
|
constexpr double db_prc_rate = 61.44e6;
|
|
constexpr double lo_step_size = db_prc_rate / ZBX_RELATIVE_LO_STEP_SIZE;
|
|
|
|
uhd::freq_range_t zbx_freq(ZBX_MIN_FREQ, ZBX_MAX_FREQ, 100e6);
|
|
|
|
for (double iter = zbx_freq.start(); iter <= zbx_freq.stop();
|
|
iter += zbx_freq.step()) {
|
|
for (const size_t chan : {0, 1}) {
|
|
test_radio->set_tx_frequency(iter, chan);
|
|
|
|
// The step alignment only applies to the desired LO frequency, the actual
|
|
// returned frequency may vary slightly
|
|
const double lo1_freq = std::round(test_radio->get_tx_lo_freq(ZBX_LO1, chan));
|
|
const double lo2_freq = std::round(test_radio->get_tx_lo_freq(ZBX_LO2, chan));
|
|
|
|
const double lo1_div = lo1_freq / lo_step_size;
|
|
const double lo2_div = lo2_freq / lo_step_size;
|
|
|
|
// Test whether our tuned frequencies align with the lo step size
|
|
BOOST_CHECK_EQUAL(std::floor(lo1_div), lo1_div);
|
|
BOOST_CHECK_EQUAL(std::floor(lo2_div), lo2_div);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_rx_lo_injection_locking, x400_radio_fixture)
|
|
{
|
|
auto tree = test_radio->get_tree();
|
|
|
|
// As of right now, we don't have a way to directly get the DB prc rate, this is the
|
|
// value of the prc map per DEFAULT_MCR, in the mock RPC server:db_0_get_db_prc_rate()
|
|
constexpr double db_prc_rate = 61.44e6;
|
|
constexpr double lo_step_size = db_prc_rate / ZBX_RELATIVE_LO_STEP_SIZE;
|
|
|
|
uhd::freq_range_t zbx_freq(ZBX_MIN_FREQ, ZBX_MAX_FREQ, 100e6);
|
|
|
|
for (double iter = zbx_freq.start(); iter <= zbx_freq.stop();
|
|
iter += zbx_freq.step()) {
|
|
for (const size_t chan : {0, 1}) {
|
|
test_radio->set_rx_frequency(iter, chan);
|
|
|
|
// The step alignment only applies to the desired LO frequency, the actual
|
|
// returned frequency may vary slightly
|
|
const double lo1_freq = std::round(test_radio->get_rx_lo_freq(ZBX_LO1, chan));
|
|
const double lo2_freq = std::round(test_radio->get_rx_lo_freq(ZBX_LO2, chan));
|
|
|
|
const double lo1_div = lo1_freq / lo_step_size;
|
|
const double lo2_div = lo2_freq / lo_step_size;
|
|
|
|
// Test whether our tuned frequencies align with the lo step size
|
|
BOOST_CHECK_EQUAL(std::floor(lo1_div), lo1_div);
|
|
BOOST_CHECK_EQUAL(std::floor(lo2_div), lo2_div);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_rx_gain_profile_test, x400_radio_fixture)
|
|
{
|
|
auto tree = test_radio->get_tree();
|
|
const std::string log = "ZBX_GAIN_PROFILE_TEST";
|
|
auto& regs = reg_iface->read_memory;
|
|
constexpr uint32_t current_config = radio_control_impl::regmap::PERIPH_BASE + 0x1000;
|
|
constexpr uint32_t rf_option = radio_control_impl::regmap::PERIPH_BASE + 0x1004;
|
|
constexpr uint32_t sw_config = radio_control_impl::regmap::PERIPH_BASE + 0x1008;
|
|
constexpr uint32_t rx0_dsa = radio_control_impl::regmap::PERIPH_BASE + 0x3800;
|
|
constexpr uint32_t rx0_table = radio_control_impl::regmap::PERIPH_BASE + 0x5800;
|
|
BOOST_CHECK_EQUAL(test_radio->get_rx_gain_profile(0), "default");
|
|
BOOST_CHECK_EQUAL(test_radio->get_tx_gain_profile(0), "default");
|
|
BOOST_CHECK_EQUAL(test_radio->get_rx_gain_profile(1), "default");
|
|
BOOST_CHECK_EQUAL(test_radio->get_tx_gain_profile(1), "default");
|
|
// Everything should be classic_atr
|
|
BOOST_CHECK_EQUAL(regs[0x81004], 0x01010101);
|
|
// Can't set gain stages in this profile
|
|
BOOST_REQUIRE_THROW(test_radio->set_rx_gain(10, "DSA1", 0), uhd::key_error);
|
|
BOOST_REQUIRE_THROW(test_radio->set_tx_gain(10, "DSA1", 0), uhd::key_error);
|
|
|
|
//** manual gain profile **
|
|
test_radio->set_rx_gain_profile("manual", 0);
|
|
// Must provide valid gain name in this profile
|
|
BOOST_REQUIRE_THROW(test_radio->set_rx_gain(23, 0), uhd::runtime_error);
|
|
BOOST_REQUIRE_THROW(test_radio->set_rx_gain(10, "banana", 0), uhd::key_error);
|
|
// Now manually set the DSAs
|
|
BOOST_CHECK_EQUAL(5, test_radio->set_rx_gain(5, "DSA1", 0));
|
|
BOOST_CHECK_EQUAL(5, test_radio->set_rx_gain(5, "DSA2", 0));
|
|
BOOST_CHECK_EQUAL(5, test_radio->set_rx_gain(5, "DSA3A", 0));
|
|
BOOST_CHECK_EQUAL(5, test_radio->set_rx_gain(5, "DSA3B", 0));
|
|
// Check the registers were written to correctly (gain 5 == att 10)
|
|
BOOST_CHECK_EQUAL(regs[rx0_dsa + 1 * 4], 0xAAAA);
|
|
BOOST_CHECK_EQUAL(regs[rx0_dsa + 3 * 4], 0xAAAA);
|
|
// Check the getters:
|
|
BOOST_CHECK_EQUAL(test_radio->get_rx_gain("DSA1", 0), 5);
|
|
BOOST_CHECK_EQUAL(test_radio->get_rx_gain("DSA2", 0), 5);
|
|
BOOST_CHECK_EQUAL(test_radio->get_rx_gain("DSA3A", 0), 5);
|
|
BOOST_CHECK_EQUAL(test_radio->get_rx_gain("DSA3B", 0), 5);
|
|
// Even in 'manual', we can load from the table. Let's create a table entry:
|
|
regs[rx0_table + 5 * 4] = 0x7777;
|
|
// Now, let it be loaded into RX and XX:
|
|
BOOST_CHECK_EQUAL(5, test_radio->set_rx_gain(5, "TABLE", 0));
|
|
BOOST_CHECK_EQUAL(regs[rx0_dsa + 1 * 4], 0x7777);
|
|
BOOST_CHECK_EQUAL(regs[rx0_dsa + 3 * 4], 0x7777);
|
|
// Note: If we read back the DSAs via get_rx_gain() now, they will still say
|
|
// 5. We might want to change that, but it will require extra peeks. The
|
|
// only good way to do that is to amend set_?x_gain() to do that peek when
|
|
// updating gains via table.
|
|
// Test DSA coercion
|
|
BOOST_CHECK_EQUAL(15, test_radio->set_rx_gain(39, "DSA1", 0));
|
|
BOOST_CHECK_EQUAL(0, test_radio->set_rx_gain(-17, "DSA1", 0));
|
|
|
|
// If we go back to 'default', we also reset the DSAs. That's because the
|
|
// desired, previously loaded default value will trigger the previous DSA
|
|
// values again.
|
|
UHD_LOG_INFO(log, "resetting to default");
|
|
test_radio->set_rx_gain_profile("default", 0);
|
|
BOOST_CHECK_EQUAL(0, test_radio->get_rx_gain("DSA1", 0));
|
|
|
|
//** table_noatr profile : **
|
|
UHD_LOG_INFO(log, "setting to table_noatr");
|
|
test_radio->set_rx_gain_profile("table_noatr", 0);
|
|
// This will set DSA config for chan 0 to 0 == SW_DEFINED
|
|
BOOST_CHECK_EQUAL(regs[rf_option], 0x01000101);
|
|
BOOST_CHECK_EQUAL(test_radio->get_rx_gain_profile(0), "table_noatr");
|
|
// Yup, this will also change TX gain profile; they're coupled.
|
|
BOOST_CHECK_EQUAL(test_radio->get_tx_gain_profile(0), "table_noatr");
|
|
BOOST_REQUIRE_THROW(test_radio->set_rx_gain(10, "all", 0), uhd::key_error);
|
|
BOOST_CHECK_EQUAL(8.0, test_radio->set_rx_gain(8, "TABLE", 0));
|
|
BOOST_CHECK_EQUAL(regs[sw_config], 0x80000);
|
|
// Returns the current config. Note the asymmetry to the previous API call.
|
|
// We can't, however, know which entry from the TABLE we used, so we just
|
|
// return the current config (which is the entry from the DSA table, not the
|
|
// TABLE it writes to).
|
|
BOOST_CHECK_EQUAL(0, test_radio->get_rx_gain("TABLE", 0));
|
|
// Let's pretend we're using config 7
|
|
regs[current_config] = 0x70000;
|
|
BOOST_CHECK_EQUAL(7, test_radio->get_rx_gain("TABLE", 0));
|
|
// And back
|
|
regs[current_config] = 0x00000;
|
|
// Now we fake an FPGA-gain-change transaction that UHD is unaware of. We
|
|
// keep the current config of 0, and update RX0_DSA*[0].
|
|
regs[rx0_dsa + 0 * 4] = 0x4444; // Turn it up to attenuation 4 == gain 11
|
|
BOOST_CHECK_EQUAL(11.0, test_radio->get_rx_gain("DSA1", 0));
|
|
|
|
//** table profile **
|
|
test_radio->set_rx_gain_profile("table", 0);
|
|
BOOST_CHECK_EQUAL(regs[rf_option], 0x01010101);
|
|
BOOST_CHECK_EQUAL(test_radio->get_rx_gain_profile(0), "table");
|
|
// Yup, this will also change TX gain profile; they're coupled.
|
|
BOOST_CHECK_EQUAL(test_radio->get_tx_gain_profile(0), "table");
|
|
// Create another table entry
|
|
regs[rx0_table + 23 * 4] = 0xBBBB;
|
|
BOOST_CHECK_EQUAL(23.0, test_radio->set_rx_gain(23, "TABLE", 0));
|
|
// get_rx_gain() for "TABLE" returns the current DSA table index, not actual gain
|
|
BOOST_CHECK_EQUAL(0.0, test_radio->get_rx_gain("TABLE", 0));
|
|
// This will update RX and XX registers (that's the difference to table_noatr)
|
|
BOOST_CHECK_EQUAL(regs[rx0_dsa + 1 * 4], 0xBBBB); // att 0xB == gain 4.0
|
|
BOOST_CHECK_EQUAL(regs[rx0_dsa + 3 * 4], 0xBBBB);
|
|
BOOST_CHECK_EQUAL(4.0, test_radio->get_rx_gain("DSA1", 0));
|
|
BOOST_CHECK_EQUAL(4.0, test_radio->get_rx_gain("DSA2", 0));
|
|
BOOST_CHECK_EQUAL(4.0, test_radio->get_rx_gain("DSA3A", 0));
|
|
BOOST_CHECK_EQUAL(4.0, test_radio->get_rx_gain("DSA3B", 0));
|
|
// Test table coercion
|
|
UHD_LOG_INFO(log, "Testing TABLE coercion");
|
|
BOOST_CHECK_EQUAL(0.0, test_radio->set_rx_gain(-17, "TABLE", 0));
|
|
BOOST_CHECK_EQUAL(255.0, test_radio->set_rx_gain(1e9, "TABLE", 0));
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_tx_gain_profile_test, x400_radio_fixture)
|
|
{
|
|
auto tree = test_radio->get_tree();
|
|
const std::string log = "ZBX_GAIN_PROFILE_TEST";
|
|
auto& regs = reg_iface->read_memory;
|
|
constexpr uint32_t current_config = radio_control_impl::regmap::PERIPH_BASE + 0x1000;
|
|
constexpr uint32_t rf_option = radio_control_impl::regmap::PERIPH_BASE + 0x1004;
|
|
constexpr uint32_t sw_config = radio_control_impl::regmap::PERIPH_BASE + 0x1008;
|
|
constexpr uint32_t tx0_dsa = radio_control_impl::regmap::PERIPH_BASE + 0x3000;
|
|
constexpr uint32_t tx0_table = radio_control_impl::regmap::PERIPH_BASE + 0x5000;
|
|
BOOST_CHECK_EQUAL(test_radio->get_rx_gain_profile(0), "default");
|
|
BOOST_CHECK_EQUAL(test_radio->get_tx_gain_profile(0), "default");
|
|
BOOST_CHECK_EQUAL(test_radio->get_rx_gain_profile(1), "default");
|
|
BOOST_CHECK_EQUAL(test_radio->get_tx_gain_profile(1), "default");
|
|
const double default_dsa1 = test_radio->get_tx_gain("DSA1", 0);
|
|
// Everything should be classic_atr
|
|
BOOST_CHECK_EQUAL(regs[0x81004], 0x01010101);
|
|
// Can't set gain stages in this profile
|
|
BOOST_REQUIRE_THROW(test_radio->set_rx_gain(10, "DSA1", 0), uhd::key_error);
|
|
BOOST_REQUIRE_THROW(test_radio->set_tx_gain(10, "DSA1", 0), uhd::key_error);
|
|
|
|
//** manual gain profile **
|
|
test_radio->set_tx_gain_profile("manual", 0);
|
|
// Must provide valid gain name in this profile
|
|
BOOST_REQUIRE_THROW(test_radio->set_tx_gain(23, 0), uhd::runtime_error);
|
|
BOOST_REQUIRE_THROW(test_radio->set_tx_gain(23, "all", 0), uhd::key_error);
|
|
BOOST_REQUIRE_THROW(test_radio->set_tx_gain(10, "banana", 0), uhd::key_error);
|
|
// Now manually set the DSAs
|
|
BOOST_CHECK_EQUAL(21, test_radio->set_tx_gain(21, "DSA1", 0));
|
|
BOOST_CHECK_EQUAL(21, test_radio->set_tx_gain(21, "DSA2", 0));
|
|
// Check the registers were written to correctly (gain 5 == att 10)
|
|
BOOST_CHECK_EQUAL(regs[tx0_dsa + 2 * 4], 0x0A0A);
|
|
BOOST_CHECK_EQUAL(regs[tx0_dsa + 3 * 4], 0x0A0A);
|
|
// Check the getters:
|
|
BOOST_CHECK_EQUAL(test_radio->get_tx_gain("DSA1", 0), 21);
|
|
BOOST_CHECK_EQUAL(test_radio->get_tx_gain("DSA2", 0), 21);
|
|
// Even in 'manual', we can load from the table. Let's create a table entry:
|
|
regs[tx0_table + 5 * 4] = 0x0707;
|
|
// Now, let it be loaded into RX and XX:
|
|
BOOST_CHECK_EQUAL(5, test_radio->set_tx_gain(5, "TABLE", 0));
|
|
BOOST_CHECK_EQUAL(regs[tx0_dsa + 2 * 4], 0x0707);
|
|
BOOST_CHECK_EQUAL(regs[tx0_dsa + 3 * 4], 0x0707);
|
|
// Note: If we read back the DSAs via get_tx_gain() now, they will still say
|
|
// 5. We might want to change that, but it will require extra peeks. The
|
|
// only good way to do that is to amend set_?x_gain() to do that peek when
|
|
// updating gains via table.
|
|
// Test DSA coercion
|
|
BOOST_CHECK_EQUAL(31, test_radio->set_tx_gain(39, "DSA1", 0));
|
|
BOOST_CHECK_EQUAL(0, test_radio->set_tx_gain(-17, "DSA1", 0));
|
|
|
|
// If we go back to 'default', we also reset the DSAs. That's because the
|
|
// desired, previously loaded default value will trigger the previous DSA
|
|
// values again.
|
|
UHD_LOG_INFO(log, "resetting to default");
|
|
test_radio->set_tx_gain_profile("default", 0);
|
|
BOOST_CHECK_EQUAL(default_dsa1, test_radio->get_tx_gain("DSA1", 0));
|
|
|
|
//** table_noatr profile : **
|
|
UHD_LOG_INFO(log, "setting to table_noatr");
|
|
test_radio->set_tx_gain_profile("table_noatr", 0);
|
|
// This will set DSA config for chan 0 to 0 == SW_DEFINED
|
|
BOOST_CHECK_EQUAL(regs[rf_option], 0x01000101);
|
|
BOOST_CHECK_EQUAL(test_radio->get_tx_gain_profile(0), "table_noatr");
|
|
// Yup, this will also change RX gain profile; they're coupled.
|
|
BOOST_CHECK_EQUAL(test_radio->get_rx_gain_profile(0), "table_noatr");
|
|
BOOST_REQUIRE_THROW(test_radio->set_tx_gain(10, "all", 0), uhd::key_error);
|
|
BOOST_CHECK_EQUAL(8.0, test_radio->set_tx_gain(8, "TABLE", 0));
|
|
BOOST_CHECK_EQUAL(regs[sw_config], 0x80000);
|
|
// Returns the current config. Note the asymmetry to the previous API call.
|
|
// We can't, however, know which entry from the TABLE we used, so we just
|
|
// return the current config (which is the entry from the DSA table, not the
|
|
// TABLE it writes to).
|
|
BOOST_CHECK_EQUAL(0, test_radio->get_tx_gain("TABLE", 0));
|
|
// Let's pretend we're using config 7
|
|
regs[current_config] = 0x70000;
|
|
BOOST_CHECK_EQUAL(7, test_radio->get_tx_gain("TABLE", 0));
|
|
// And back
|
|
regs[current_config] = 0x00000;
|
|
// Now we fake an FPGA-gain-change transaction that UHD is unaware of. We
|
|
// keep the current config of 0, and update TX0_DSA*[0].
|
|
regs[tx0_dsa + 0 * 4] = 0x0404; // Turn it up to attenuation 4 == gain 27
|
|
BOOST_CHECK_EQUAL(27.0, test_radio->get_tx_gain("DSA1", 0));
|
|
|
|
//** table profile **
|
|
test_radio->set_tx_gain_profile("table", 0);
|
|
BOOST_CHECK_EQUAL(regs[rf_option], 0x01010101);
|
|
BOOST_CHECK_EQUAL(test_radio->get_tx_gain_profile(0), "table");
|
|
// Yup, this will also change RX gain profile; they're coupled.
|
|
BOOST_CHECK_EQUAL(test_radio->get_rx_gain_profile(0), "table");
|
|
// Create another table entry
|
|
regs[tx0_table + 23 * 4] = 0x0B0B;
|
|
BOOST_CHECK_EQUAL(23.0, test_radio->set_tx_gain(23, "TABLE", 0));
|
|
// get_tx_gain() for "TABLE" returns the current DSA table index, not actual gain
|
|
BOOST_CHECK_EQUAL(0.0, test_radio->get_tx_gain("TABLE", 0));
|
|
// This will update RX and XX registers (that's the difference to table_noatr)
|
|
BOOST_CHECK_EQUAL(regs[tx0_dsa + 2 * 4], 0x0B0B); // att 0xB == gain 20.0
|
|
BOOST_CHECK_EQUAL(regs[tx0_dsa + 3 * 4], 0x0B0B);
|
|
BOOST_CHECK_EQUAL(20.0, test_radio->get_tx_gain("DSA1", 0));
|
|
BOOST_CHECK_EQUAL(20.0, test_radio->get_tx_gain("DSA2", 0));
|
|
// Test table coercion
|
|
UHD_LOG_INFO(log, "Testing TABLE coercion");
|
|
BOOST_CHECK_EQUAL(0.0, test_radio->set_tx_gain(-17, "TABLE", 0));
|
|
BOOST_CHECK_EQUAL(255.0, test_radio->set_tx_gain(1e9, "TABLE", 0));
|
|
}
|
|
|
|
|
|
BOOST_FIXTURE_TEST_CASE(zbx_complex_gain_test, x400_radio_fixture)
|
|
{
|
|
BOOST_ASSERT(test_radio->has_feature<uhd::features::tx_complex_gain_iface>());
|
|
BOOST_ASSERT(test_radio->has_feature<uhd::features::rx_complex_gain_iface>());
|
|
|
|
auto& tx_cgain = test_radio->get_feature<uhd::features::tx_complex_gain_iface>();
|
|
auto& rx_cgain = test_radio->get_feature<uhd::features::rx_complex_gain_iface>();
|
|
|
|
size_t chan = 0;
|
|
// Test setting gain coefficients
|
|
tx_cgain.set_gain_coeff({0.5, 0.5}, chan);
|
|
rx_cgain.set_gain_coeff({0.5, 0.5}, chan);
|
|
|
|
// Test getting gain coefficients
|
|
std::complex<double> expected_result{0.5, 0.5};
|
|
BOOST_CHECK_EQUAL(tx_cgain.get_gain_coeff(chan), expected_result);
|
|
BOOST_CHECK_EQUAL(rx_cgain.get_gain_coeff(chan), expected_result);
|
|
|
|
// Test out-of-bounds gain coefficients
|
|
BOOST_CHECK_THROW(tx_cgain.set_gain_coeff({2.0, -2.1}, chan), uhd::value_error);
|
|
BOOST_CHECK_THROW(rx_cgain.set_gain_coeff({-2.1, 2.0}, chan), uhd::value_error);
|
|
}
|
|
|
|
// TODO:
|
|
// - concurrent/consecutive configuration
|
|
// - Threading tests
|
|
// - Error cases
|