uhd/host/tests/max287x_test.cpp
Martin Braun 52129c701d tests: Fix max287x_test compiler warnings
Previously, we had lambdas that would capture 'this' and then not use
it. Because on modern compilers (e.g., clang 18) this produces
a compiler warning, we remove the unnecessary captures.
2024-10-29 17:59:59 +01:00

208 lines
9.6 KiB
C++

//
// Copyright 2024 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
#include <uhdlib/usrp/common/max287x.hpp>
#include <boost/test/unit_test.hpp>
// Datasheet for max2871:
// https://www.analog.com/media/en/technical-documentation/data-sheets/MAX2871.pdf
// Used to confirm the proper register addresses and values
// Based on values set in gen_max2871_regs.py and the constructor of max2871
std::map<uint8_t, uint32_t> expected_init_values = {
{0, 0x003e8000},
{1, 0x2000fff9},
{2, 0x78006e42},
{3, 0x0100000b},
{4, 0x6080023c},
{5, 0x61400005},
};
// Using macro instead of function so that failures print the line associated with the
// call to UHD_CHECK_REGMAP rather than pointing out the line in UHD_CHECK_REGMAP itself
#define UHD_CHECK_REGMAP(lo, expected) \
{ \
std::map<uint8_t, uint32_t> actual; \
for (int i = 0; i < 6; i++) { \
actual.insert(std::pair<uint8_t, uint32_t>(i, lo->get_register(i))); \
} \
actual.insert(std::pair<uint8_t, uint32_t>(0, 0)); \
for (const auto& expected_r : expected) { \
std::stringstream exp_ss, act_ss; \
exp_ss << std::hex << expected_r.second; \
act_ss << std::hex << actual.at(expected_r.first); \
const std::string exp_str = \
"R" + std::to_string(expected_r.first) + " == 0x" + exp_ss.str(); \
const std::string act_str = \
"R" + std::to_string(expected_r.first) + " == 0x" + act_ss.str(); \
BOOST_CHECK_EQUAL(exp_str, act_str); \
} \
}
// Used to set the field of a register to use for an expected value
void set_field(uint32_t& reg, uint32_t mask, uint32_t shift, uint32_t value)
{
reg &= ~(mask << shift);
reg |= (value & mask) << shift;
}
// Test that the set_register and get_register functions work as expected for all
// writeable registers (non-address) and also that set_register works when masking
// for specific registers
BOOST_AUTO_TEST_CASE(max2871_set_get_register_test)
{
auto test_lo =
max287x_iface::make<max2871>([](const std::vector<uint32_t>&) { /* noop */ });
test_lo->set_register(0, 0xFFFFFFF8, 0x12345678);
test_lo->set_register(1, 0xFFFFFFF8, 0x12345678);
test_lo->set_register(2, 0xFFFFFFF8, 0x12345678);
test_lo->set_register(3, 0xFFFFFFF8, 0x12345678);
test_lo->set_register(4, 0xFFFFFFF8, 0x12345678);
test_lo->set_register(5, 0xFFFFFFF8, 0x12345678);
// Registers should differ only by the address bits of each register
std::map<uint8_t, uint32_t> expected_values = {
{0, 0x12345678},
{1, 0x12345679},
{2, 0x1234567a},
{3, 0x1234567b},
{4, 0x1234567c},
{5, 0x1234567d},
};
UHD_CHECK_REGMAP(test_lo, expected_values);
test_lo->set_register(3, 0x0F000000, 0xFFFFFFFF);
test_lo->set_register(5, 0x000FF000, 0xFFFFFFFF);
test_lo->set_register(1, 0xF0000000, 0xFFFFFFFF);
set_field(expected_values[3], 0xF, 24, 0XF);
set_field(expected_values[5], 0xFF, 12, 0XFF);
set_field(expected_values[1], 0xF, 28, 0XF);
UHD_CHECK_REGMAP(test_lo, expected_values);
}
// Test that registers are at the expected values after initialization
BOOST_AUTO_TEST_CASE(max2871_init_test)
{
auto test_lo =
max287x_iface::make<max2871>([](const std::vector<uint32_t>&) { /* noop */ });
UHD_CHECK_REGMAP(test_lo, expected_init_values);
}
// Test that functions that set output power function correctly
BOOST_AUTO_TEST_CASE(max2871_set_output_power_test)
{
auto test_lo =
max287x_iface::make<max2871>([](const std::vector<uint32_t>&) { /* noop */ });
// set_output_power should only affect RFOUTA Output Power (bits 4:3 of reg 4)
test_lo->set_output_power(max287x_iface::OUTPUT_POWER_5DBM);
auto expected_values = expected_init_values;
set_field(expected_values[4], 0x3, 3, max287x_iface::OUTPUT_POWER_5DBM);
UHD_CHECK_REGMAP(test_lo, expected_values);
test_lo->set_output_power(max287x_iface::OUTPUT_POWER_M1DBM);
set_field(expected_values[4], 0x3, 3, max287x_iface::OUTPUT_POWER_M1DBM);
UHD_CHECK_REGMAP(test_lo, expected_values);
// set_aux_output_power should only affect RFOUTB Output Power (bits 7:6 of reg 4)
test_lo->set_aux_output_power(max287x_iface::AUX_OUTPUT_POWER_5DBM);
set_field(expected_values[4], 0x3, 6, max287x_iface::AUX_OUTPUT_POWER_5DBM);
UHD_CHECK_REGMAP(test_lo, expected_values);
test_lo->set_aux_output_power(max287x_iface::AUX_OUTPUT_POWER_M1DBM);
set_field(expected_values[4], 0x3, 6, max287x_iface::AUX_OUTPUT_POWER_M1DBM);
UHD_CHECK_REGMAP(test_lo, expected_values);
// set_aux_output_power_enable should only affect RFOUTB Output Mode (bit 8 of reg 4)
test_lo->set_aux_output_power_enable(true);
set_field(expected_values[4], 0x1, 8, 1);
UHD_CHECK_REGMAP(test_lo, expected_values);
test_lo->set_aux_output_power_enable(false);
set_field(expected_values[4], 0x1, 8, 0);
UHD_CHECK_REGMAP(test_lo, expected_values);
}
// Test that registers that need to be set for phase synchronization are set correctly
// Also, test that phase synchronization only advertises as possible when in frac_n mode
BOOST_AUTO_TEST_CASE(max2871_phase_sync_test)
{
auto test_lo =
max287x_iface::make<max2871>([](const std::vector<uint32_t>&) { /* noop */ });
test_lo->set_frequency(2e9, 50e6, 50e6, true);
BOOST_CHECK_EQUAL(max2871_regs_t::SHUTDOWN_VAS_ENABLED,
static_cast<max2871_regs_t::shutdown_vas_t>(
(test_lo->get_register(3) >> 25) & 0x1));
BOOST_CHECK_EQUAL(max2871_regs_t::LOW_NOISE_AND_SPUR_LOW_SPUR_2,
static_cast<max2871_regs_t::low_noise_and_spur_t>(
(test_lo->get_register(2) >> 29) & 0x3));
BOOST_CHECK_EQUAL(max2871_regs_t::F01_AUTO,
static_cast<max2871_regs_t::f01_t>((test_lo->get_register(5) >> 24) & 0x1));
BOOST_CHECK_EQUAL(max2871_regs_t::AUX_OUTPUT_SELECT_FUNDAMENTAL,
static_cast<max2871_regs_t::aux_output_select_t>(
(test_lo->get_register(4) >> 9) & 0x1));
// For phase synchronization, ensure the following registers are set to the following
test_lo->config_for_sync(true);
test_lo->set_frequency(2e9, 50e6, 50e6, true);
BOOST_CHECK_EQUAL(max2871_regs_t::SHUTDOWN_VAS_DISABLED,
static_cast<max2871_regs_t::shutdown_vas_t>(
(test_lo->get_register(3) >> 25) & 0x1));
BOOST_CHECK_EQUAL(max2871_regs_t::LOW_NOISE_AND_SPUR_LOW_NOISE,
static_cast<max2871_regs_t::low_noise_and_spur_t>(
(test_lo->get_register(2) >> 29) & 0x3));
BOOST_CHECK_EQUAL(max2871_regs_t::F01_FRAC_N,
static_cast<max2871_regs_t::f01_t>((test_lo->get_register(5) >> 24) & 0x1));
BOOST_CHECK_EQUAL(max2871_regs_t::AUX_OUTPUT_SELECT_DIVIDED,
static_cast<max2871_regs_t::aux_output_select_t>(
(test_lo->get_register(4) >> 9) & 0x1));
test_lo->commit();
// Have configured for sync, but cannot sync in int_n mode
BOOST_CHECK(!test_lo->can_sync());
test_lo->set_frequency(2e9, 50e6, 50e6, false);
test_lo->commit();
// Now should be possible to sync in frac_n mode
BOOST_CHECK(test_lo->can_sync());
}
// Test that the registers that need to be set for int_n vs frac_n mode within
// the set_frequency function are set correctly
BOOST_AUTO_TEST_CASE(max2871_set_frequency_int_n_test)
{
auto test_lo =
max287x_iface::make<max2871>([](const std::vector<uint32_t>&) { /* noop */ });
// set_frequency with int_n = true, ensure that all registers that need to be set for
// int_n are set correctly (other arguments set arbitrarily for this test)
test_lo->set_frequency(2e9, 50e6, 50e6, true);
BOOST_CHECK_EQUAL(max2871_regs_t::FEEDBACK_SELECT_DIVIDED,
static_cast<max2871_regs_t::feedback_select_t>(
(test_lo->get_register(4) >> 23) & 0x1));
BOOST_CHECK_EQUAL(max2871_regs_t::CPL_DISABLED,
static_cast<max2871_regs_t::cpl_t>((test_lo->get_register(1) >> 29) & 0x3));
BOOST_CHECK_EQUAL(max2871_regs_t::LDF_INT_N,
static_cast<max2871_regs_t::ldf_t>((test_lo->get_register(2) >> 8) & 0x1));
BOOST_CHECK_EQUAL(max2871_regs_t::INT_N_MODE_INT_N,
static_cast<max2871_regs_t::int_n_mode_t>(
(test_lo->get_register(0) >> 31) & 0x1));
// set_frequency with int_n = false, ensure that all registers that need to be set for
// frac_n are set correctly (other arguments set arbitrarily for this test)
test_lo->set_frequency(2e9, 50e6, 50e6, false);
BOOST_CHECK_EQUAL(max2871_regs_t::FEEDBACK_SELECT_DIVIDED,
static_cast<max2871_regs_t::feedback_select_t>(
(test_lo->get_register(4) >> 23) & 0x1));
BOOST_CHECK_EQUAL(max2871_regs_t::CPL_ENABLED,
static_cast<max2871_regs_t::cpl_t>((test_lo->get_register(1) >> 29) & 0x3));
BOOST_CHECK_EQUAL(max2871_regs_t::LDF_FRAC_N,
static_cast<max2871_regs_t::ldf_t>((test_lo->get_register(2) >> 8) & 0x1));
BOOST_CHECK_EQUAL(max2871_regs_t::INT_N_MODE_FRAC_N,
static_cast<max2871_regs_t::int_n_mode_t>(
(test_lo->get_register(0) >> 31) & 0x1));
}