aboutsummaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
authorAaron Rossetto <aaron.rossetto@ni.com>2020-07-22 12:51:21 -0500
committerAaron Rossetto <aaron.rossetto@ni.com>2020-07-24 13:15:30 -0500
commita5fe0b071d7041f0539804cd16ada27d920bc96d (patch)
tree840f254f2f2d0165681706f7c539bdc48a52e67f /host
parent4b01628cad132db68ec1cc8cce211f2df0f62770 (diff)
downloaduhd-a5fe0b071d7041f0539804cd16ada27d920bc96d.tar.gz
uhd-a5fe0b071d7041f0539804cd16ada27d920bc96d.tar.bz2
uhd-a5fe0b071d7041f0539804cd16ada27d920bc96d.zip
rfnoc: Support instance overrides in set_properties()
This commit adds an enhancement to node_t::set_properties() in which the instance argument provided to the function (which normally applies to all properties in the key/value list) can be overridden on a per-property basis using a special syntax. 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 value passed via the instance parameter is ignored for that property. 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 name/instance pair is malformed, e.g. 'value:=10' or 'value:foobar=10', a runtime error is thrown.
Diffstat (limited to 'host')
-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;