aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/dboard/zbx/zbx_lo_ctrl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp/dboard/zbx/zbx_lo_ctrl.cpp')
-rw-r--r--host/lib/usrp/dboard/zbx/zbx_lo_ctrl.cpp162
1 files changed, 162 insertions, 0 deletions
diff --git a/host/lib/usrp/dboard/zbx/zbx_lo_ctrl.cpp b/host/lib/usrp/dboard/zbx/zbx_lo_ctrl.cpp
new file mode 100644
index 000000000..1af665207
--- /dev/null
+++ b/host/lib/usrp/dboard/zbx/zbx_lo_ctrl.cpp
@@ -0,0 +1,162 @@
+//
+// Copyright 2020 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#include <uhd/exception.hpp>
+#include <uhd/utils/log.hpp>
+#include <uhdlib/usrp/dboard/zbx/zbx_lo_ctrl.hpp>
+#include <thread>
+
+namespace uhd { namespace usrp { namespace zbx {
+
+zbx_lo_ctrl::zbx_lo_ctrl(zbx_lo_t lo,
+ lmx2572_iface::write_fn_t&& poke16,
+ lmx2572_iface::read_fn_t&& peek16,
+ lmx2572_iface::sleep_fn_t&& sleep,
+ const double default_frequency,
+ const double db_prc_rate,
+ const bool testing_mode_enabled)
+ : _lo(lo)
+ , _log_id(ZBX_LO_LOG_ID.at(lo))
+ , _freq(default_frequency)
+ , _db_prc_rate(db_prc_rate)
+ , _testing_mode_enabled(testing_mode_enabled)
+{
+ _lmx = lmx2572_iface::make(std::move(poke16), std::move(peek16), std::move(sleep));
+ UHD_ASSERT_THROW(_lmx);
+ UHD_LOG_TRACE(_log_id, "LO initialized...");
+ _lmx->reset();
+
+ set_lo_port_enabled(true);
+ // In ZBX, we always run the LOs in sync mode. It is theoretically possible
+ // to not do so, but we gain nothing by doing that.
+ _lmx->set_sync_mode(true);
+ set_lo_freq(LMX2572_DEFAULT_FREQ);
+ wait_for_lo_lock();
+}
+
+double zbx_lo_ctrl::set_lo_freq(const double freq)
+{
+ UHD_ASSERT_THROW(_lmx);
+ UHD_LOG_TRACE(_log_id, "Setting LO frequency " << freq / 1e6 << " MHz");
+
+ _freq = _lmx->set_frequency(freq,
+ _db_prc_rate,
+ false /*TODO: get_spur_dodging()*/);
+ _lmx->commit();
+ return _freq;
+}
+
+double zbx_lo_ctrl::get_lo_freq()
+{
+ return _freq;
+}
+
+void zbx_lo_ctrl::wait_for_lo_lock()
+{
+ UHD_LOG_TRACE(_log_id, "Waiting for LO lock, " << ZBX_LO_LOCK_TIMEOUT_MS << " ms");
+ const auto timeout = std::chrono::steady_clock::now()
+ + std::chrono::milliseconds(ZBX_LO_LOCK_TIMEOUT_MS);
+ while (std::chrono::steady_clock::now() < timeout && !get_lock_status()) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ }
+ if (!get_lock_status()) {
+ // If we can't lock our LO, this could be a lot of possible issues
+ throw uhd::runtime_error(_log_id + " has failed to lock!");
+ }
+}
+
+bool zbx_lo_ctrl::get_lock_status()
+{
+ return _lmx->get_lock_status();
+}
+
+void zbx_lo_ctrl::set_lo_port_enabled(bool enable)
+{
+ UHD_LOG_TRACE(_log_id,
+ "Enabling LO " << (_testing_mode_enabled ? "test" : "output") << " port");
+
+ // We want to set the output port regardless of test mode being enabled
+ _lmx->set_output_enable(_get_output_port(false), enable);
+
+ if (_testing_mode_enabled && enable) {
+ // If testing mode is enabled, also set the test port
+ _lmx->set_output_enable(_get_output_port(true), true);
+ } else {
+ // If testing mode is disabled, test port should be disabled
+ _lmx->set_output_enable(_get_output_port(true), false);
+ _lmx->set_mux_input(
+ _get_output_port(true), lmx2572_iface::mux_in_t::HIGH_IMPEDANCE);
+ }
+
+ _lmx->set_enabled(enable);
+ _lmx->commit();
+}
+
+bool zbx_lo_ctrl::get_lo_port_enabled()
+{
+ return _lmx->get_enabled();
+}
+
+void zbx_lo_ctrl::set_lo_test_mode_enabled(bool enable)
+{
+ _testing_mode_enabled = enable;
+ set_lo_port_enabled(get_lo_port_enabled());
+}
+
+bool zbx_lo_ctrl::get_lo_test_mode_enabled()
+{
+ return _testing_mode_enabled;
+}
+
+zbx_lo_t zbx_lo_ctrl::lo_string_to_enum(
+ const uhd::direction_t trx, const size_t channel, const std::string name)
+{
+ if (trx == TX_DIRECTION) {
+ if (channel == 0) {
+ if (name == ZBX_LO1) {
+ return zbx_lo_t::TX0_LO1;
+ } else if (name == ZBX_LO2) {
+ return zbx_lo_t::TX0_LO2;
+ }
+ } else if (channel == 1) {
+ if (name == ZBX_LO1) {
+ return zbx_lo_t::TX1_LO1;
+ } else if (name == ZBX_LO2) {
+ return zbx_lo_t::TX1_LO2;
+ }
+ }
+ } else {
+ if (channel == 0) {
+ if (name == ZBX_LO1) {
+ return zbx_lo_t::RX0_LO1;
+ } else if (name == ZBX_LO2) {
+ return zbx_lo_t::RX0_LO2;
+ }
+ } else if (channel == 1) {
+ if (name == ZBX_LO1) {
+ return zbx_lo_t::RX1_LO1;
+ } else if (name == ZBX_LO2) {
+ return zbx_lo_t::RX1_LO2;
+ }
+ }
+ }
+ UHD_THROW_INVALID_CODE_PATH();
+}
+
+lmx2572_iface::output_t zbx_lo_ctrl::_get_output_port(bool testing_mode)
+{
+ // Note: The LO output ports here are dependent to the LO and zbx hardware
+ // configuration, in no particular order (zbx radio configuration output vs.
+ // test port output)
+ if (!testing_mode) {
+ // Rev B has all LO outputs on Port A
+ return lmx2572_iface::output_t::RF_OUTPUT_A;
+ } else {
+ return lmx2572_iface::output_t::RF_OUTPUT_B;
+ }
+}
+
+}}} // namespace uhd::usrp::zbx