aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/include/uhd/rfnoc/node.hpp21
-rw-r--r--host/include/uhd/rfnoc/property.hpp3
-rw-r--r--host/lib/rfnoc/node.cpp21
-rw-r--r--host/tests/CMakeLists.txt1
-rw-r--r--host/tests/rfnoc_node_test.cpp31
-rw-r--r--host/tests/rfnoc_property_test.cpp13
6 files changed, 85 insertions, 5 deletions
diff --git a/host/include/uhd/rfnoc/node.hpp b/host/include/uhd/rfnoc/node.hpp
index b26546643..9d66c516a 100644
--- a/host/include/uhd/rfnoc/node.hpp
+++ b/host/include/uhd/rfnoc/node.hpp
@@ -135,6 +135,27 @@ public:
*
* Property resolution happens after all properties have been updated.
*
+ * This function allows the client to override the \p instance parameter
+ * for each property key/value pair passed in via the \p props parameter.
+ * If the key consists of the property name, followed by a colon (':') and
+ * then a number, the number following the colon is used to determine
+ * which instance of the property this set pertains to, and the \p
+ * instance parameter is ignored for that property. (Note that if the key
+ * does not have the colon and instance number override syntax, then
+ * \p instance is still used to determine which instance of the property
+ * to set. For example, in the following call:
+ *
+ * node->set_properties("dog=10,cat:2=5,bird:0=0.5", 1)
+ *
+ * instance 1 of node's 'dog' property is set to 10, the 1 coming from the
+ * instance parameter, instance 2 of the node's 'cat' property is set to
+ * 5 due to the override syntax provided in the string, and instance 0 of
+ * the node's 'bird' property is set to 0.5 due to its override.
+ *
+ * If the instance override is malformed, that is, there is no
+ * number following the colon, or the number cannot be parsed as an
+ * integer, a value_error is thrown.
+ *
* If a key in \p props is not a valid property of this block, a warning is
* logged, but no error is raised.
*/
diff --git a/host/include/uhd/rfnoc/property.hpp b/host/include/uhd/rfnoc/property.hpp
index a1e877440..a5c7246d1 100644
--- a/host/include/uhd/rfnoc/property.hpp
+++ b/host/include/uhd/rfnoc/property.hpp
@@ -36,6 +36,9 @@ public:
property_base_t(const std::string& id, const res_source_info& source_info)
: _id(id), _source_info(source_info)
{
+ if(_id.find(':') != std::string::npos) {
+ throw uhd::value_error("Property ID `" + _id + "' contains invalid character!");
+ }
}
//! Gets the ID (name) of this property
diff --git a/host/lib/rfnoc/node.cpp b/host/lib/rfnoc/node.cpp
index 0abbb0d3b..062645b93 100644
--- a/host/lib/rfnoc/node.cpp
+++ b/host/lib/rfnoc/node.cpp
@@ -48,11 +48,28 @@ std::vector<std::string> node_t::get_property_ids() const
void node_t::set_properties(const uhd::device_addr_t& props, const size_t instance)
{
for (const auto& key : props.keys()) {
+ std::string local_key = key;
+ size_t local_instance = instance;
+ const size_t colon_pos = key.find(':');
+ if (colon_pos != std::string::npos) {
+ // Extract the property ID and instance
+ local_key = key.substr(0, colon_pos);
+ std::string instance_part = key.substr(colon_pos + 1);
+ try {
+ local_instance = std::stoi(instance_part);
+ } catch (...) {
+ // If no number, or an invalid number is specified after the
+ // colon, throw a value_error.
+ throw uhd::value_error("Property id `" + local_key
+ + "' contains a malformed instance override!");
+ }
+ }
+
property_base_t* prop_ref =
- _find_property({res_source_info::USER, instance}, key);
+ _find_property({res_source_info::USER, local_instance}, local_key);
if (!prop_ref) {
RFNOC_LOG_WARNING("set_properties() cannot set property `"
- << key << "': No such property.");
+ << local_key << "': No such property.");
continue;
}
auto prop_access = _request_property_access(prop_ref, property_base_t::RW);
diff --git a/host/tests/CMakeLists.txt b/host/tests/CMakeLists.txt
index e06d4c6df..daf9f2976 100644
--- a/host/tests/CMakeLists.txt
+++ b/host/tests/CMakeLists.txt
@@ -46,6 +46,7 @@ set(test_sources
narrow_cast_test.cpp
property_test.cpp
ranges_test.cpp
+ rfnoc_node_test.cpp
scope_exit_test.cpp
sensors_test.cpp
soft_reg_test.cpp
diff --git a/host/tests/rfnoc_node_test.cpp b/host/tests/rfnoc_node_test.cpp
index b90835081..283d0bf38 100644
--- a/host/tests/rfnoc_node_test.cpp
+++ b/host/tests/rfnoc_node_test.cpp
@@ -21,6 +21,8 @@ public:
std::cout << "Calling clean callback for user prop" << std::endl;
this->user_prop_cb_called = true;
});
+ register_property(&multi_instance_prop_0);
+ register_property(&multi_instance_prop_1);
register_property(&_double_prop_in);
register_property(&_double_prop_out);
@@ -80,6 +82,10 @@ private:
"double_prop", 0.0, {res_source_info::INPUT_EDGE, 0}};
property_t<double> _double_prop_out{
"double_prop", 0.0, {res_source_info::OUTPUT_EDGE, 1}};
+ property_t<double> multi_instance_prop_0{
+ "multi_instance_prop", 0.0, {res_source_info::USER, 0}};
+ property_t<double> multi_instance_prop_1{
+ "multi_instance_prop", 0.0, {res_source_info::USER, 1}};
const size_t _num_input_ports;
const size_t _num_output_ports;
@@ -102,7 +108,7 @@ BOOST_AUTO_TEST_CASE(test_node_prop_access)
BOOST_CHECK(TN1.get_unique_id() != TN2.get_unique_id());
auto user_prop_ids = TN1.get_property_ids();
- BOOST_REQUIRE_EQUAL(user_prop_ids.size(), 1);
+ BOOST_REQUIRE_EQUAL(user_prop_ids.size(), 3);
BOOST_CHECK_EQUAL(user_prop_ids[0], "double_prop");
BOOST_REQUIRE_THROW(TN1.get_property<int>("nonexistant_prop"), uhd::lookup_error);
@@ -113,6 +119,20 @@ BOOST_AUTO_TEST_CASE(test_node_prop_access)
BOOST_CHECK_EQUAL(TN1.get_property<double>("double_prop"), 0.0);
+ // Check that set_properties() works with the override specification
+ TN1.set_properties(
+ uhd::device_addr_t("multi_instance_prop:0=1.234,multi_instance_prop:1=-5.678"),
+ 5);
+ BOOST_CHECK_EQUAL(TN1.get_property<double>("multi_instance_prop", 0), 1.234);
+ BOOST_CHECK_EQUAL(TN1.get_property<double>("multi_instance_prop", 1), -5.678);
+
+ // And check that it throws an exception with a bad override specification
+ BOOST_REQUIRE_THROW(
+ TN1.set_properties(uhd::device_addr_t("multi_instance_prop:")), uhd::value_error);
+ BOOST_REQUIRE_THROW(
+ TN1.set_properties(uhd::device_addr_t("multi_instance_prop:chicken")),
+ uhd::value_error);
+
BOOST_REQUIRE_THROW(TN1.set_property<int>("nonexistant_prop", 5), uhd::lookup_error);
// If this next test fails, RTTI is not available. There might be cases when
// that's expected, and when we encounter those we'll reconsider the test.
@@ -131,8 +151,13 @@ BOOST_AUTO_TEST_CASE(test_node_accessor)
return (prop->get_src_info().type == res_source_info::USER);
});
- BOOST_CHECK_EQUAL(user_props.size(), 1);
- BOOST_CHECK_EQUAL((*user_props.begin())->get_id(), "double_prop");
+ BOOST_CHECK_EQUAL(user_props.size(), 3);
+ std::map<std::string, int> prop_count;
+ for (const auto& prop : user_props) {
+ prop_count[prop->get_id()]++;
+ }
+ BOOST_CHECK_EQUAL(prop_count["double_prop"], 1);
+ BOOST_CHECK_EQUAL(prop_count["multi_instance_prop"], 2);
BOOST_CHECK((*user_props.begin())->get_src_info().type == res_source_info::USER);
BOOST_CHECK(!TN1.user_prop_cb_called);
diff --git a/host/tests/rfnoc_property_test.cpp b/host/tests/rfnoc_property_test.cpp
index eb22424b1..d1a8ba981 100644
--- a/host/tests/rfnoc_property_test.cpp
+++ b/host/tests/rfnoc_property_test.cpp
@@ -65,6 +65,19 @@ BOOST_AUTO_TEST_CASE(test_get_set)
BOOST_CHECK(prop_i.is_dirty());
}
+BOOST_AUTO_TEST_CASE(test_valid_names)
+{
+ bool value_error_caught = false;
+ try {
+ property_t<int> prop_i{"int_prop:0", 10, {res_source_info::USER, 0}};
+ } catch(const uhd::value_error& e) {
+ value_error_caught = true;
+ } catch(...) {
+ }
+
+ BOOST_CHECK(value_error_caught);
+}
+
BOOST_AUTO_TEST_CASE(test_lock)
{
prop_accessor_t prop_accessor;