diff options
author | Aaron Rossetto <aaron.rossetto@ni.com> | 2020-03-20 13:07:40 -0500 |
---|---|---|
committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2020-05-19 14:22:55 -0500 |
commit | 026ae4584d2dce4acd6154125b32b9ed43d6aaea (patch) | |
tree | 82f766ca2d5c7085fca17ffdbac42746cc06ca4f /host | |
parent | c1549b9f6a7c7d645689b420934b08ed46013a22 (diff) | |
download | uhd-026ae4584d2dce4acd6154125b32b9ed43d6aaea.tar.gz uhd-026ae4584d2dce4acd6154125b32b9ed43d6aaea.tar.bz2 uhd-026ae4584d2dce4acd6154125b32b9ed43d6aaea.zip |
tests: Added unit test for Vector IIR RFNoC block
Diffstat (limited to 'host')
-rw-r--r-- | host/tests/CMakeLists.txt | 4 | ||||
-rw-r--r-- | host/tests/rfnoc_block_tests/vector_iir_block_test.cpp | 221 |
2 files changed, 225 insertions, 0 deletions
diff --git a/host/tests/CMakeLists.txt b/host/tests/CMakeLists.txt index 3723119fa..d9f78465a 100644 --- a/host/tests/CMakeLists.txt +++ b/host/tests/CMakeLists.txt @@ -280,6 +280,10 @@ UHD_ADD_RFNOC_BLOCK_TEST( TARGET null_block_test.cpp ) +UHD_ADD_RFNOC_BLOCK_TEST( + TARGET vector_iir_block_test.cpp +) + UHD_ADD_NONAPI_TEST( TARGET "transport_test.cpp" EXTRA_SOURCES diff --git a/host/tests/rfnoc_block_tests/vector_iir_block_test.cpp b/host/tests/rfnoc_block_tests/vector_iir_block_test.cpp new file mode 100644 index 000000000..5fc1fd90e --- /dev/null +++ b/host/tests/rfnoc_block_tests/vector_iir_block_test.cpp @@ -0,0 +1,221 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#include "../rfnoc_graph_mock_nodes.hpp" +#include <uhd/rfnoc/actions.hpp> +#include <uhd/rfnoc/defaults.hpp> +#include <uhd/rfnoc/mock_block.hpp> +#include <uhd/rfnoc/multichan_register_iface.hpp> +#include <uhd/rfnoc/register_iface_holder.hpp> +#include <uhd/rfnoc/vector_iir_block_control.hpp> +#include <uhdlib/rfnoc/graph.hpp> +#include <uhdlib/rfnoc/node_accessor.hpp> +#include <uhdlib/utils/narrow.hpp> +#include <boost/test/unit_test.hpp> +#include <iostream> + +using namespace uhd::rfnoc; + +// Redeclare this here, since it's only defined outside of UHD_API +noc_block_base::make_args_t::~make_args_t() = default; + +constexpr size_t NUM_CHANS = 4; +constexpr uint16_t MAX_DELAY_LEN = 2047; +constexpr size_t DEFAULT_MTU = 8000; +constexpr double DEFAULT_ALPHA = 0.9; +constexpr double DEFAULT_BETA = 0.9; +constexpr uint16_t DEFAULT_DELAY = MAX_DELAY_LEN; + +/* + * This class extends mock_reg_iface_t, handling three particular registers + */ +class vector_iir_mock_reg_iface_t : public mock_reg_iface_t +{ +public: + vector_iir_mock_reg_iface_t(size_t num_chans, uint16_t max_delay) + : _num_chans(num_chans) + { + for (size_t chan = 0; chan < num_chans; chan++) { + _max_delays.push_back(max_delay); + _delays.push_back(0); + } + } + + virtual void _poke_cb( + uint32_t addr, uint32_t data, uhd::time_spec_t /*time*/, bool /*ack*/) + { + size_t chan = addr / vector_iir_block_control::REG_BLOCK_SIZE; + size_t offset = addr % vector_iir_block_control::REG_BLOCK_SIZE; + if (offset == vector_iir_block_control::REG_DELAY_OFFSET) { + _delays[chan] = static_cast<uint16_t>(data & 0xffff); + } + } + + virtual void _peek_cb(uint32_t addr, uhd::time_spec_t /*time*/) + { + size_t chan = addr / vector_iir_block_control::REG_BLOCK_SIZE; + size_t offset = addr % vector_iir_block_control::REG_BLOCK_SIZE; + if (offset == vector_iir_block_control::REG_DELAY_OFFSET) { + read_memory[addr] = (static_cast<uint32_t>(_max_delays.at(chan)) << 16) + | _delays.at(chan); + } + } + +private: + const size_t _num_chans; + std::vector<uint16_t> _max_delays; + std::vector<uint16_t> _delays; +}; + +/* + * vector_iir_block_fixture is a class which is instantiated before each test + * case is run. It sets up the block container, mock register interface, + * and vector_iir_block_control object, all of which are accessible to the test + * case. The instance of the object is destroyed at the end of each test + * case. + */ +struct vector_iir_block_fixture +{ + vector_iir_block_fixture() + : reg_iface( + std::make_shared<vector_iir_mock_reg_iface_t>(NUM_CHANS, MAX_DELAY_LEN)) + , block_container(get_mock_block(VECTOR_IIR_BLOCK, + NUM_CHANS, + NUM_CHANS, + uhd::device_addr_t(), + DEFAULT_MTU, + ANY_DEVICE, + reg_iface)) + , test_vector_iir(block_container.get_block<vector_iir_block_control>()) + { + node_accessor.init_props(test_vector_iir.get()); + } + + inline uint32_t calculate_alphabeta_register_value(double alphabeta) const + { + return uint32_t(alphabeta * pow(2, 31)); + } + + inline size_t calculate_register_address(size_t offset, size_t channel) const + { + return channel * vector_iir_block_control::REG_BLOCK_SIZE + offset; + } + + inline uint32_t check_poke_alpha(size_t channel) const + { + return reg_iface->write_memory.at(calculate_register_address( + vector_iir_block_control::REG_ALPHA_OFFSET, channel)); + } + + inline uint32_t check_poke_beta(size_t channel) const + { + return reg_iface->write_memory.at(calculate_register_address( + vector_iir_block_control::REG_BETA_OFFSET, channel)); + } + + inline uint16_t check_poke_delay(size_t channel) const + { + return reg_iface->write_memory.at(calculate_register_address( + vector_iir_block_control::REG_DELAY_OFFSET, channel)) + & 0xffff; + } + + inline uint16_t check_peek_max_delay(size_t channel) const + { + return static_cast<uint16_t>( + reg_iface->read_memory.at(calculate_register_address( + vector_iir_block_control::REG_DELAY_OFFSET, channel)) + >> 16); + } + + std::shared_ptr<vector_iir_mock_reg_iface_t> reg_iface; + mock_block_container block_container; + std::shared_ptr<vector_iir_block_control> test_vector_iir; + node_accessor_t node_accessor{}; +}; + +/* + * This test case ensures that the hardware is programmed correctly with + * defaults when the vector_iir block is constructed. + */ +BOOST_FIXTURE_TEST_CASE(vector_iir_test_construction, vector_iir_block_fixture) +{ + // Check that the registers were written with their expected initial + // values. + const uint32_t default_alpha_value = + calculate_alphabeta_register_value(DEFAULT_ALPHA); + const uint32_t default_beta_value = calculate_alphabeta_register_value(DEFAULT_BETA); + for (size_t chan = 0; chan < NUM_CHANS; chan++) { + BOOST_CHECK_EQUAL(check_poke_alpha(chan), default_alpha_value); + BOOST_CHECK_EQUAL(check_poke_beta(chan), default_beta_value); + BOOST_CHECK_EQUAL(check_poke_delay(chan), DEFAULT_DELAY); + BOOST_CHECK_EQUAL(check_peek_max_delay(chan), MAX_DELAY_LEN); + } +} + +/* + * This test case exercises the API and ensures that the registers are + * programmed appropriately. + */ +BOOST_FIXTURE_TEST_CASE(vector_iir_test_api, vector_iir_block_fixture) +{ + const uint32_t default_beta_value = calculate_alphabeta_register_value(DEFAULT_BETA); + for (size_t chan = 0; chan < NUM_CHANS; chan++) { + // Set alpha; ensure beta and delay remain unchanged + const double alpha = 0.25 + (0.1 * chan); + test_vector_iir->set_alpha(alpha, chan); + BOOST_CHECK_EQUAL(test_vector_iir->get_alpha(chan), alpha); + BOOST_CHECK_EQUAL( + check_poke_alpha(chan), calculate_alphabeta_register_value(alpha)); + BOOST_CHECK_EQUAL(check_poke_beta(chan), default_beta_value); + + // Set beta; ensure alpha and delay remain unchanged + const double beta = 0.6 - (0.1 * chan); + test_vector_iir->set_beta(beta, chan); + BOOST_CHECK_EQUAL(test_vector_iir->get_beta(chan), beta); + BOOST_CHECK_EQUAL( + check_poke_beta(chan), calculate_alphabeta_register_value(beta)); + BOOST_CHECK_EQUAL( + check_poke_alpha(chan), calculate_alphabeta_register_value(alpha)); + + // Set delay; ensure alpha and beta remain unchanged + const uint16_t delay = 500 + (100 * chan); + test_vector_iir->set_delay(delay, chan); + BOOST_CHECK_EQUAL(test_vector_iir->get_delay(chan), delay); + BOOST_CHECK_EQUAL(check_poke_delay(chan), delay); + BOOST_CHECK_EQUAL( + check_poke_beta(chan), calculate_alphabeta_register_value(beta)); + BOOST_CHECK_EQUAL( + check_poke_alpha(chan), calculate_alphabeta_register_value(alpha)); + + // Read max delay via API and make sure it agrees with the register + BOOST_CHECK_EQUAL( + test_vector_iir->get_max_delay(chan), check_peek_max_delay(chan)); + } +} + +/* + * This test case exercises the range checking performed on the vector IIR + * settings, ensuring that the appropriate exception is thrown when out of + * range. + */ +BOOST_FIXTURE_TEST_CASE(vector_iir_test_ranges, vector_iir_block_fixture) +{ + for (size_t chan = 0; chan < NUM_CHANS; chan++) { + BOOST_CHECK_THROW(test_vector_iir->set_alpha(-1.0, chan), uhd::value_error); + BOOST_CHECK_THROW(test_vector_iir->set_alpha(15.0, chan), uhd::value_error); + + BOOST_CHECK_THROW(test_vector_iir->set_beta(-6.0, chan), uhd::value_error); + BOOST_CHECK_THROW(test_vector_iir->set_beta(7.25, chan), uhd::value_error); + + BOOST_CHECK_THROW(test_vector_iir->set_delay(0, chan), uhd::value_error); + BOOST_CHECK_THROW(test_vector_iir->set_delay(12345, chan), uhd::value_error); + BOOST_CHECK_THROW( + test_vector_iir->set_delay(test_vector_iir->get_max_delay(chan) + 1, chan), + uhd::value_error); + } +} + |