From a5fe0b071d7041f0539804cd16ada27d920bc96d Mon Sep 17 00:00:00 2001 From: Aaron Rossetto Date: Wed, 22 Jul 2020 12:51:21 -0500 Subject: 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. --- host/tests/CMakeLists.txt | 1 + host/tests/rfnoc_node_test.cpp | 31 ++++++++++++++++++++++++++++--- host/tests/rfnoc_property_test.cpp | 13 +++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) (limited to 'host/tests') 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_prop_out{ "double_prop", 0.0, {res_source_info::OUTPUT_EDGE, 1}}; + property_t multi_instance_prop_0{ + "multi_instance_prop", 0.0, {res_source_info::USER, 0}}; + property_t 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("nonexistant_prop"), uhd::lookup_error); @@ -113,6 +119,20 @@ BOOST_AUTO_TEST_CASE(test_node_prop_access) BOOST_CHECK_EQUAL(TN1.get_property("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("multi_instance_prop", 0), 1.234); + BOOST_CHECK_EQUAL(TN1.get_property("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("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 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 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; -- cgit v1.2.3