aboutsummaryrefslogtreecommitdiffstats
path: root/host/include
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2019-11-27 21:36:46 -0800
committeratrnati <54334261+atrnati@users.noreply.github.com>2020-01-29 08:57:25 -0600
commit0a49a8844a65698b11fe979441a97939dad80044 (patch)
tree30bbd6fb82c17abf7db4627250f3586a8d6fb175 /host/include
parent25b434ae858dd476e13738e0acaa9edeb019cee4 (diff)
downloaduhd-0a49a8844a65698b11fe979441a97939dad80044.tar.gz
uhd-0a49a8844a65698b11fe979441a97939dad80044.tar.bz2
uhd-0a49a8844a65698b11fe979441a97939dad80044.zip
rfnoc: Create mock factory
This is an API that allows creating mock block controllers, to write unit tests for block controllers. See rfnoc_blocks_test for an example how to use them.
Diffstat (limited to 'host/include')
-rw-r--r--host/include/uhd/rfnoc/mock_block.hpp193
1 files changed, 193 insertions, 0 deletions
diff --git a/host/include/uhd/rfnoc/mock_block.hpp b/host/include/uhd/rfnoc/mock_block.hpp
new file mode 100644
index 000000000..18c614d07
--- /dev/null
+++ b/host/include/uhd/rfnoc/mock_block.hpp
@@ -0,0 +1,193 @@
+//
+// Copyright 2019 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#ifndef INCLUDED_LIBUHD_MOCK_BLOCK_HPP
+#define INCLUDED_LIBUHD_MOCK_BLOCK_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/property_tree.hpp>
+#include <uhd/rfnoc/defaults.hpp>
+#include <uhd/rfnoc/noc_block_base.hpp>
+#include <uhd/rfnoc/register_iface.hpp>
+#include <uhd/types/time_spec.hpp>
+#include <uhd/utils/log.hpp>
+#include <unordered_map>
+#include <boost/format.hpp>
+#include <vector>
+
+namespace uhd { namespace rfnoc {
+
+/*! Mock version of a register interface
+ *
+ * This can be used for mock blocks, usually for the sake of unit testing.
+ */
+class UHD_API mock_reg_iface_t : public register_iface
+{
+public:
+ mock_reg_iface_t() = default;
+ virtual ~mock_reg_iface_t() = default;
+
+ /**************************************************************************
+ * API
+ *************************************************************************/
+ void poke32(uint32_t addr, uint32_t data, uhd::time_spec_t time, bool ack)
+ {
+ write_memory[addr] = data;
+ _poke_cb(addr, data, time, ack);
+ }
+
+ void multi_poke32(const std::vector<uint32_t> addrs,
+ const std::vector<uint32_t> data,
+ uhd::time_spec_t time,
+ bool ack)
+ {
+ if (addrs.size() != data.size()) {
+ throw uhd::value_error("addrs and data vectors must be of the same length");
+ }
+ for (size_t i = 0; i < addrs.size(); i++) {
+ poke32(addrs[i], data[i], time, ack);
+ }
+ }
+
+ void block_poke32(uint32_t first_addr,
+ const std::vector<uint32_t> data,
+ uhd::time_spec_t timestamp,
+ bool ack)
+ {
+ for (size_t i = 0; i < data.size(); i++) {
+ poke32(first_addr + 4 * i, data[i], timestamp, ack);
+ }
+ }
+
+ uint32_t peek32(uint32_t addr, uhd::time_spec_t time)
+ {
+ _peek_cb(addr, time);
+ try {
+ return read_memory.at(addr);
+ } catch (const std::out_of_range&) {
+ throw uhd::runtime_error(
+ str(boost::format("No data defined for address: 0x%04X") % addr));
+ }
+ }
+
+ std::vector<uint32_t> block_peek32(
+ uint32_t first_addr, size_t length, uhd::time_spec_t time)
+ {
+ std::vector<uint32_t> result(length, 0);
+ for (size_t i = 0; i < length; ++i) {
+ result[i] = peek32(first_addr + i * 4, time);
+ }
+ return result;
+ }
+
+ void poll32(uint32_t addr,
+ uint32_t data,
+ uint32_t mask,
+ uhd::time_spec_t /* timeout */,
+ uhd::time_spec_t time = uhd::time_spec_t::ASAP,
+ bool /* ack */ = false)
+ {
+ if (force_timeout) {
+ throw uhd::op_timeout("timeout");
+ }
+
+ if ((peek32(addr, time) & mask) == data) {
+ UHD_LOG_INFO("MOCK_REG_IFACE", "poll32() successful at addr " << addr);
+ } else {
+ UHD_LOG_INFO("MOCK_REG_IFACE", "poll32() not successful at addr " << addr);
+ }
+ }
+
+ void sleep(uhd::time_spec_t /*duration*/, bool /*ack*/)
+ {
+ // nop
+ }
+
+ void register_async_msg_validator(async_msg_validator_t /*callback_f*/)
+ {
+ // nop
+ }
+
+ void register_async_msg_handler(async_msg_callback_t /*callback_f*/)
+ {
+ // nop
+ }
+
+ void set_policy(const std::string& name, const uhd::device_addr_t& args)
+ {
+ UHD_LOG_INFO("MOCK_REG_IFACE",
+ "Requested to set policy for " << name << " to " << args.to_string());
+ }
+
+ uint16_t get_src_epid() const
+ {
+ return 0;
+ }
+
+ uint16_t get_port_num() const
+ {
+ return 0;
+ }
+
+ bool force_timeout = false;
+
+ //! All pokes end up writing to this map
+ std::unordered_map<uint32_t, uint32_t> read_memory;
+ //! All peeks read from this map. A peek will fail if the address has not
+ // been previously set.
+ std::unordered_map<uint32_t, uint32_t> write_memory;
+
+protected:
+ virtual void _poke_cb(
+ uint32_t /*addr*/, uint32_t /*data*/, uhd::time_spec_t /*time*/, bool /*ack*/)
+ {
+ }
+
+ virtual void _peek_cb(uint32_t /*addr*/, uhd::time_spec_t /*time*/) {}
+};
+
+/*! Container for all the items required for running a mock block
+ */
+struct UHD_API mock_block_container
+{
+ friend class get_mock_block;
+ //! Reference to the register interface object
+ std::shared_ptr<mock_reg_iface_t> reg_iface;
+
+ //! Reference to the prop tree object the block sees
+ uhd::property_tree::sptr tree;
+
+ //! Use this to retrieve a reference to the block controller. Make sure that
+ // the register space is appropiately primed before doing so.
+ template<typename block_type = noc_block_base>
+ std::shared_ptr<block_type> get_block()
+ {
+ return std::dynamic_pointer_cast<block_type>(factory(std::move(make_args)));
+ }
+
+ //! Factory to get the block. Use get_block() instead.
+ std::function<noc_block_base::sptr(noc_block_base::make_args_ptr)> factory;
+
+ // Note: The make args would ideally be captured by the factory function,
+ // but std::functions need to be CopyConstructible, and this struct doesn't,
+ // so it needs to live out here in the open.
+ noc_block_base::make_args_ptr make_args;
+
+};
+
+/*! Factory function for mock block controllers
+ */
+UHD_API mock_block_container get_mock_block(const noc_id_t noc_id,
+ const size_t num_inputs = 1,
+ const size_t num_outputs = 1,
+ const uhd::device_addr_t& args = uhd::device_addr_t(),
+ const size_t mtu = 8000,
+ const device_type_t device_id = ANY_DEVICE);
+
+
+}}; // namespace uhd::rfnoc
+
+#endif /* INCLUDED_LIBUHD_MOCK_BLOCK_HPP */