diff --git a/host/lib/rfnoc/rfnoc_python.hpp b/host/lib/rfnoc/rfnoc_python.hpp index 2d30b0b3c..76b3c2b46 100644 --- a/host/lib/rfnoc/rfnoc_python.hpp +++ b/host/lib/rfnoc/rfnoc_python.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -280,6 +281,14 @@ void export_rfnoc(py::module& m) .def("get_sensors", &uhd::features::gps_iface::get_sensors) .def("send_cmd", &uhd::features::gps_iface::send_cmd); + py::class_(m, "ref_clk_calibration") + .def("set_ref_clk_tuning_word", + &uhd::features::ref_clk_calibration_iface::set_ref_clk_tuning_word) + .def("get_ref_clk_tuning_word", + &uhd::features::ref_clk_calibration_iface::get_ref_clk_tuning_word) + .def("store_ref_clk_tuning_word", + &uhd::features::ref_clk_calibration_iface::store_ref_clk_tuning_word); + py::class_(m, "filter_node") .def("get_rx_filter_names", &detail::filter_node::get_rx_filter_names) .def("get_rx_filter", &detail::filter_node::get_rx_filter) @@ -331,6 +340,12 @@ void export_rfnoc(py::module& m) [](mb_controller& self) { return &self.get_feature(); }, + py::return_value_policy::reference_internal) + .def( + "get_ref_clk_calibration", + [](mb_controller& self) { + return &self.get_feature(); + }, py::return_value_policy::reference_internal); py::class_(m, "timekeeper") diff --git a/host/tests/devtest/devtest_x410.py b/host/tests/devtest/devtest_x410.py index 937f0a4b0..12eafb0de 100644 --- a/host/tests/devtest/devtest_x410.py +++ b/host/tests/devtest/devtest_x410.py @@ -131,3 +131,4 @@ from list_sensors_test import ListSensorsTest from python_api_test import UhdPythonApiTest from rx_multi_spc_timed_commands_test import RxMultiSpcTimedCommandsTest from tx_multi_spc_timed_commands_test import TxMultiSpcTimedCommandsTest +from ref_clk_calibration_test import RefClkCalibrationTest diff --git a/host/tests/devtest/devtest_x420.py b/host/tests/devtest/devtest_x420.py index 89ef58056..cc865346a 100644 --- a/host/tests/devtest/devtest_x420.py +++ b/host/tests/devtest/devtest_x420.py @@ -90,3 +90,4 @@ from list_sensors_test import ListSensorsTest from python_api_test import UhdPythonApiTest from rx_multi_spc_timed_commands_test import RxMultiSpcTimedCommandsTest from tx_multi_spc_timed_commands_test import TxMultiSpcTimedCommandsTest +from ref_clk_calibration_test import RefClkCalibrationTest diff --git a/host/tests/devtest/devtest_x440.py b/host/tests/devtest/devtest_x440.py index 62b7470a2..25bf5e415 100644 --- a/host/tests/devtest/devtest_x440.py +++ b/host/tests/devtest/devtest_x440.py @@ -67,5 +67,6 @@ from list_sensors_test import ListSensorsTest from python_api_test import UhdPythonApiTest from rx_multi_spc_timed_commands_test import RxMultiSpcTimedCommandsTest from tx_multi_spc_timed_commands_test import TxMultiSpcTimedCommandsTest +from ref_clk_calibration_test import RefClkCalibrationTest from trigger_test import TxTriggerTest diff --git a/host/tests/devtest/ref_clk_calibration_test.py b/host/tests/devtest/ref_clk_calibration_test.py new file mode 100644 index 000000000..b0f210cc7 --- /dev/null +++ b/host/tests/devtest/ref_clk_calibration_test.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +# +# Copyright 2026 Ettus Research, a National Instruments Brand +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +"""Test the ref_clk_calibration feature.""" + +from uhd_test_base import UHDPythonTestCase + + +class RefClkCalibrationTest(UHDPythonTestCase): + """Test ref_clk_calibration feature. + + Reads the current tuning word and writes it back. Does not call + store_ref_clk_tuning_word to avoid modifying EEPROM during the test. + """ + + test_name = "RefClkCalibrationTest" + + def run_test(self, test_name, test_args): + """Run test and report results.""" + import uhd + + usrp = uhd.usrp.MultiUSRP(self.args_str) + ref_cal = usrp.get_mb_controller().get_ref_clk_calibration() + word = ref_cal.get_ref_clk_tuning_word() + self.log.info("Current ref_clk tuning word: 0x%X", word) + ref_cal.set_ref_clk_tuning_word(word) + + return {"passed": True}