aboutsummaryrefslogtreecommitdiffstats
path: root/host/tests
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2019-05-15 10:26:44 -0700
committerMartin Braun <martin.braun@ettus.com>2019-11-26 11:49:14 -0800
commitb8a6c64d6012ab1ec0b3b843fccec2d990d440a3 (patch)
tree31a99d71af5a6aa2db2a7c9f2a7d19986a2d3856 /host/tests
parentd6251df6347390e74784b2fbe116b0e64780547e (diff)
downloaduhd-b8a6c64d6012ab1ec0b3b843fccec2d990d440a3.tar.gz
uhd-b8a6c64d6012ab1ec0b3b843fccec2d990d440a3.tar.bz2
uhd-b8a6c64d6012ab1ec0b3b843fccec2d990d440a3.zip
rfnoc: Add action API
- Added action_info class - Allow to send actions from node to node - Allow to post actions into nodes - Allow to set default forwarding policies - Added unit tests
Diffstat (limited to 'host/tests')
-rw-r--r--host/tests/CMakeLists.txt13
-rw-r--r--host/tests/actions_test.cpp81
-rw-r--r--host/tests/rfnoc_graph_mock_nodes.hpp122
3 files changed, 214 insertions, 2 deletions
diff --git a/host/tests/CMakeLists.txt b/host/tests/CMakeLists.txt
index f31daed50..c308abdcb 100644
--- a/host/tests/CMakeLists.txt
+++ b/host/tests/CMakeLists.txt
@@ -246,6 +246,19 @@ UHD_INSTALL(TARGETS
COMPONENT tests
)
+add_executable(actions_test
+ actions_test.cpp
+ ${CMAKE_SOURCE_DIR}/lib/rfnoc/graph.cpp
+)
+target_link_libraries(actions_test uhd ${Boost_LIBRARIES})
+UHD_ADD_TEST(actions_test actions_test)
+UHD_INSTALL(TARGETS
+ actions_test
+ RUNTIME
+ DESTINATION ${PKG_LIB_DIR}/tests
+ COMPONENT tests
+)
+
########################################################################
# demo of a loadable module
########################################################################
diff --git a/host/tests/actions_test.cpp b/host/tests/actions_test.cpp
new file mode 100644
index 000000000..c0344eacf
--- /dev/null
+++ b/host/tests/actions_test.cpp
@@ -0,0 +1,81 @@
+//
+// Copyright 2019 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#include <uhd/rfnoc/node.hpp>
+#include <uhd/rfnoc/actions.hpp>
+#include <uhd/utils/log.hpp>
+#include <uhdlib/rfnoc/node_accessor.hpp>
+#include <uhdlib/rfnoc/prop_accessor.hpp>
+#include <uhdlib/rfnoc/graph.hpp>
+#include <boost/test/unit_test.hpp>
+#include <iostream>
+
+#include "rfnoc_graph_mock_nodes.hpp"
+
+
+const std::string STREAM_CMD_KEY = "stream_cmd";
+
+BOOST_AUTO_TEST_CASE(test_actions_single_node)
+{
+ node_accessor_t node_accessor{};
+
+ // Define some mock nodes:
+ mock_radio_node_t mock_radio(0);
+
+ auto stream_cmd = action_info::make(STREAM_CMD_KEY);
+ std::string cmd_payload = "START";
+ stream_cmd->payload = std::vector<uint8_t>(cmd_payload.begin(), cmd_payload.end());
+
+ auto other_cmd = action_info::make("FOO");
+
+ node_accessor.send_action(&mock_radio, {res_source_info::INPUT_EDGE, 0}, stream_cmd);
+ node_accessor.send_action(&mock_radio, {res_source_info::INPUT_EDGE, 0}, other_cmd);
+
+ mock_radio.update_fwd_policy(node_t::forwarding_policy_t::ONE_TO_ONE);
+ node_accessor.send_action(&mock_radio, {res_source_info::INPUT_EDGE, 0}, other_cmd);
+ mock_radio.update_fwd_policy(node_t::forwarding_policy_t::ONE_TO_FAN);
+ node_accessor.send_action(&mock_radio, {res_source_info::INPUT_EDGE, 0}, other_cmd);
+ mock_radio.update_fwd_policy(node_t::forwarding_policy_t::ONE_TO_ALL);
+ node_accessor.send_action(&mock_radio, {res_source_info::INPUT_EDGE, 0}, other_cmd);
+ mock_radio.update_fwd_policy(node_t::forwarding_policy_t::ONE_TO_ALL_IN);
+ node_accessor.send_action(&mock_radio, {res_source_info::INPUT_EDGE, 0}, other_cmd);
+ mock_radio.update_fwd_policy(node_t::forwarding_policy_t::ONE_TO_ALL_OUT);
+ node_accessor.send_action(&mock_radio, {res_source_info::INPUT_EDGE, 0}, other_cmd);
+}
+
+BOOST_AUTO_TEST_CASE(test_actions_simple_graph)
+{
+ node_accessor_t node_accessor{};
+ uhd::rfnoc::detail::graph_t graph{};
+
+ // Define some mock nodes:
+ mock_radio_node_t mock_rx_radio{0};
+ mock_ddc_node_t mock_ddc{};
+ mock_fifo_t mock_fifo{1};
+ mock_streamer_t mock_streamer{1};
+
+ // These init calls would normally be done by the framework
+ node_accessor.init_props(&mock_rx_radio);
+ node_accessor.init_props(&mock_ddc);
+ node_accessor.init_props(&mock_fifo);
+ node_accessor.init_props(&mock_streamer);
+
+ graph.connect(&mock_rx_radio, &mock_ddc, {0, 0, graph_edge_t::DYNAMIC, true});
+ graph.connect(&mock_ddc, &mock_fifo, {0, 0, graph_edge_t::DYNAMIC, true});
+ graph.connect(&mock_fifo, &mock_streamer, {0, 0, graph_edge_t::DYNAMIC, true});
+ graph.initialize();
+
+ // Force the DDC to actually set a decimation rate != 1
+ mock_streamer.set_property<double>("samp_rate", 10e6, 0);
+
+ uhd::stream_cmd_t num_samps_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
+ constexpr size_t NUM_SAMPS = 100;
+ num_samps_cmd.num_samps = NUM_SAMPS;
+
+ mock_streamer.issue_stream_cmd(num_samps_cmd, 0);
+ BOOST_CHECK_EQUAL(NUM_SAMPS * mock_ddc.get_property<int>("decim", 0),
+ mock_rx_radio.last_num_samps);
+}
diff --git a/host/tests/rfnoc_graph_mock_nodes.hpp b/host/tests/rfnoc_graph_mock_nodes.hpp
index 85e667ebd..a9d8d4e55 100644
--- a/host/tests/rfnoc_graph_mock_nodes.hpp
+++ b/host/tests/rfnoc_graph_mock_nodes.hpp
@@ -7,7 +7,9 @@
#ifndef INCLUDED_LIBUHD_TESTS_MOCK_NODES_HPP
#define INCLUDED_LIBUHD_TESTS_MOCK_NODES_HPP
+#include <uhd/rfnoc/defaults.hpp>
#include <uhd/rfnoc/node.hpp>
+#include <uhd/types/stream_cmd.hpp>
using namespace uhd::rfnoc;
@@ -82,9 +84,37 @@ public:
rssi_resolver_count++;
_rssi = static_cast<double>(rssi_resolver_count);
});
+
+
+ set_action_forwarding_policy(forwarding_policy_t::DROP);
+
+ register_action_handler(
+ "stream_cmd", [this](const res_source_info& src, action_info::sptr action) {
+ UHD_ASSERT_THROW(action->key == "stream_cmd");
+ const std::string cmd(action->payload.begin(), action->payload.end());
+ UHD_LOG_INFO(get_unique_id(),
+ "Received stream command: " << cmd << " to " << src.to_string());
+ if (cmd == "START") {
+ UHD_LOG_INFO(get_unique_id(), "Starting Stream!");
+ } else if (cmd == "STOP") {
+ UHD_LOG_INFO(get_unique_id(), "Stopping Stream!");
+ } else {
+ this->last_num_samps = std::stoul(cmd);
+ UHD_LOG_INFO(get_unique_id(),
+ "Streaming num samps: " << this->last_num_samps);
+ }
+ });
}
- std::string get_unique_id() const { return "MOCK_RADIO" + std::to_string(_radio_idx); }
+ void update_fwd_policy(forwarding_policy_t policy)
+ {
+ set_action_forwarding_policy(policy);
+ }
+
+ std::string get_unique_id() const
+ {
+ return "MOCK_RADIO" + std::to_string(_radio_idx);
+ }
size_t get_num_input_ports() const
{
@@ -101,6 +131,8 @@ public:
bool disable_samp_out_resolver = false;
double force_samp_out_value = 23e6;
+ size_t last_num_samps = 0;
+
private:
const size_t _radio_idx;
@@ -162,6 +194,31 @@ public:
decim = coerce_decim(int(samp_rate_in.get() / samp_rate_out.get()));
samp_rate_in = samp_rate_out.get() * decim.get();
});
+
+ register_action_handler(
+ "stream_cmd", [this](const res_source_info& src, action_info::sptr action) {
+ res_source_info dst_edge{
+ res_source_info::invert_edge(src.type), src.instance};
+ auto new_action = action_info::make(action->key);
+ std::string cmd(action->payload.begin(), action->payload.end());
+ if (cmd == "START" || cmd == "STOP") {
+ new_action->payload = action->payload;
+ } else {
+ unsigned long long num_samps = std::stoull(cmd);
+ if (src.type == res_source_info::OUTPUT_EDGE) {
+ num_samps *= _decim.get();
+ } else {
+ num_samps /= _decim.get();
+ }
+ std::string new_cmd = std::to_string(num_samps);
+ new_action->payload.insert(
+ new_action->payload.begin(), new_cmd.begin(), new_cmd.end());
+ }
+
+ UHD_LOG_INFO(get_unique_id(),
+ "Forwarding stream_cmd, decim is " << _decim.get());
+ post_action(dst_edge, new_action);
+ });
}
std::string get_unique_id() const { return "MOCK_DDC"; }
@@ -203,7 +260,7 @@ private:
/*! FIFO
*
- * Not much here -- we use it to test dynamic prop forwarding.
+ * Not much here -- we use it to test dynamic prop and action forwarding.
*/
class mock_fifo_t : public node_t
{
@@ -211,6 +268,7 @@ public:
mock_fifo_t(const size_t num_ports) : _num_ports(num_ports)
{
set_prop_forwarding_policy(forwarding_policy_t::ONE_TO_ONE);
+ set_action_forwarding_policy(forwarding_policy_t::ONE_TO_ONE);
}
std::string get_unique_id() const { return "MOCK_FIFO"; }
@@ -230,4 +288,64 @@ private:
const size_t _num_ports;
};
+/*! Streamer
+ *
+ * Not much here -- we use it to test dynamic prop and action forwarding.
+ */
+class mock_streamer_t : public node_t
+{
+public:
+ mock_streamer_t(const size_t num_ports) : _num_ports(num_ports)
+ {
+ set_prop_forwarding_policy(forwarding_policy_t::DROP);
+ set_action_forwarding_policy(forwarding_policy_t::DROP);
+ register_property(&_samp_rate_user);
+ register_property(&_samp_rate_in);
+ add_property_resolver({&_samp_rate_user}, {&_samp_rate_in}, [this]() {
+ UHD_LOG_INFO(get_unique_id(), "Calling resolver for `samp_rate_user'...");
+ _samp_rate_in = _samp_rate_user.get();
+ });
+ add_property_resolver({&_samp_rate_in}, {}, [this]() {
+ UHD_LOG_INFO(get_unique_id(), "Calling resolver for `samp_rate_in'...");
+ // nop
+ });
+ }
+
+ std::string get_unique_id() const
+ {
+ return "MOCK_STREAMER";
+ }
+
+ size_t get_num_input_ports() const
+ {
+ return _num_ports;
+ }
+
+ size_t get_num_output_ports() const
+ {
+ return _num_ports;
+ }
+
+ void issue_stream_cmd(uhd::stream_cmd_t stream_cmd, const size_t chan)
+ {
+ std::string cmd =
+ stream_cmd.stream_mode == uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS
+ ? "START"
+ : stream_cmd.stream_mode == uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS
+ ? "STOP"
+ : std::to_string(stream_cmd.num_samps);
+ auto scmd = action_info::make("stream_cmd");
+ scmd->payload.insert(scmd->payload.begin(), cmd.begin(), cmd.end());
+
+ post_action({res_source_info::INPUT_EDGE, chan}, scmd);
+ }
+
+private:
+ property_t<double> _samp_rate_user{
+ "samp_rate", 1e6, {res_source_info::USER}};
+ property_t<double> _samp_rate_in{
+ "samp_rate", 1e6, {res_source_info::INPUT_EDGE}};
+ const size_t _num_ports;
+};
+
#endif /* INCLUDED_LIBUHD_TESTS_MOCK_NODES_HPP */