diff options
author | Trung N Tran <trung.tran@ettus.com> | 2017-11-09 17:32:32 -0800 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2017-12-22 15:05:57 -0800 |
commit | 7df29f6ee62d44eaeed878700ddbaeeb1d7fda46 (patch) | |
tree | bc1ac0a1e4e09bd9ad3e6fbb23d7b459b9bf0449 | |
parent | b9a0cf1467e89000658f69089bb773722e41ea89 (diff) | |
download | uhd-7df29f6ee62d44eaeed878700ddbaeeb1d7fda46.tar.gz uhd-7df29f6ee62d44eaeed878700ddbaeeb1d7fda46.tar.bz2 uhd-7df29f6ee62d44eaeed878700ddbaeeb1d7fda46.zip |
mg: Add LO specific properties and methods
This change adds extra hooks to the property tree to make LOs accessible
thru the property tree.
These can be used by multi_usrp api.
Reviewed-By: Martin Braun <martin.braun@ettus.com>
4 files changed, 515 insertions, 57 deletions
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_constants.hpp b/host/lib/usrp/dboard/magnesium/magnesium_constants.hpp index 581b1cc97..94b7c52d2 100644 --- a/host/lib/usrp/dboard/magnesium/magnesium_constants.hpp +++ b/host/lib/usrp/dboard/magnesium/magnesium_constants.hpp @@ -13,6 +13,12 @@ static const size_t FPGPIO_MASTER_RADIO = 0; +static const double AD9371_MIN_FREQ = 300.0e6; // Hz +static const double AD9371_MAX_FREQ = 6.0e9; // Hz + +static const double ADF4351_MIN_FREQ = 35.0e6; +static const double ADF4351_MAX_FREQ = 4.4e9; + static const double MAGNESIUM_RADIO_RATE = 125e6; // Hz static const double MAGNESIUM_MIN_FREQ = 1e6; // Hz static const double MAGNESIUM_MAX_FREQ = 6e9; // Hz @@ -50,6 +56,11 @@ static const double MAGNESIUM_CENTER_FREQ = 2.5e9; // Hz static const std::vector<std::string> MAGNESIUM_RX_ANTENNAS = { "TX/RX", "RX2", "CAL", "LOCAL" }; +//! AD9371 LO (for direct conversion) +static const char* MAGNESIUM_LO1 = "rfic"; +//! Low-band LO (for IF conversion) +static const char* MAGNESIUM_LO2 = "low_synth"; + static const double MAGNESIUM_DEFAULT_BANDWIDTH = 40e6; // Hz TODO: fix // Note: MAGNESIUM_NUM_CHANS is independent of the number of chans per // RFNoC block. TODO: When we go to one radio per dboard, this comment can diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.cpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.cpp index db372ebfb..6d55662f4 100644 --- a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.cpp +++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.cpp @@ -18,6 +18,7 @@ #include <boost/make_shared.hpp> #include <boost/format.hpp> #include <sstream> +#include <cmath> using namespace uhd; using namespace uhd::usrp; @@ -178,7 +179,6 @@ void magnesium_radio_ctrl_impl::set_rx_antenna( const size_t chan ) { UHD_ASSERT_THROW(chan <= MAGNESIUM_NUM_CHANS); - std::lock_guard<std::mutex> l(_set_lock); if (std::find(MAGNESIUM_RX_ANTENNAS.begin(), MAGNESIUM_RX_ANTENNAS.end(), ant) == MAGNESIUM_RX_ANTENNAS.end()) { @@ -201,12 +201,10 @@ double magnesium_radio_ctrl_impl::set_tx_frequency( const double freq, const size_t chan ) { - // Note: There is only one LO per tx or TX, so changing frequency will - // affect the adjacent channel in the same direction. We have to make sure - // that getters will always tell the truth! This is true for low and high - // bands. + // FIXME bounds checking + clipping!!! UHD_LOG_TRACE(unique_id(), "set_tx_frequency(f=" << freq << ", chan=" << chan << ")"); + _desired_rf_freq[TX_DIRECTION]=freq; if (not _master) { const fs_path master_tx_fe_path = master_fe_base_path(_radio_slot) / fs_path("tx_frontends") / chan; @@ -223,26 +221,31 @@ double magnesium_radio_ctrl_impl::set_tx_frequency( // This way, if we tune channel 0 it will not put channel 1 into a bad // state. _update_tx_freq_switches(freq, _tx_bypass_amp, magnesium_cpld_ctrl::BOTH); - //double ad9371_freq = freq; - double if_freq = 0.0; - auto lo_iface = _tx_lo; + const std::string ad9371_source = this->get_tx_lo_source(MAGNESIUM_LO1, chan); + const std::string adf4351_source = this->get_tx_lo_source(MAGNESIUM_LO2, chan); + UHD_ASSERT_THROW(adf4351_source == "internal"); + double coerced_if_freq = freq; if (freq < MAGNESIUM_LOWBAND_FREQ) { // Low band - if_freq = MAGNESIUM_TX_IF_FREQ ; - const double lo_freq = if_freq - freq; - const bool int_n_mode = false; // FIXME no hardcode - //const double actual_lo_freq = - _lo_enable(lo_iface, lo_freq, _master_clock_rate, int_n_mode); - //ad9371_freq = actual_lo_freq - freq; + _is_low_band[TX_DIRECTION] = true; + const double desired_low_freq = MAGNESIUM_TX_IF_FREQ - freq; + coerced_if_freq = + this->set_tx_lo_freq(desired_low_freq, MAGNESIUM_LO2, chan) + freq; + UHD_LOG_TRACE(unique_id(), "coerced_if_freq = " << coerced_if_freq); } else { - _lo_disable(lo_iface); + _is_low_band[TX_DIRECTION] = false; + _lo_disable(_tx_lo); } + // external LO required to tune at 2xdesired_frequency. + const double desired_if_freq = (ad9371_source == "internal") ? + coerced_if_freq : + 2*coerced_if_freq; + + this->set_tx_lo_freq(desired_if_freq, MAGNESIUM_LO1, chan); - //const double actual_ad9371_freq = - _ad9371->set_frequency(freq, chan, TX_DIRECTION); - radio_ctrl_impl::set_tx_frequency(freq, chan) + this->_update_freq(chan, TX_DIRECTION); this->_update_gain(chan, TX_DIRECTION); - return freq; // FIXME calc the actual frequency + return radio_ctrl_impl::get_tx_frequency(chan); } void magnesium_radio_ctrl_impl::_update_gain( @@ -260,19 +263,37 @@ void magnesium_radio_ctrl_impl::_update_gain( this->_set_all_gain(this->_get_all_gain(chan, dir), freq, chan, dir); // now we need update gain on slave _tree->access<double>(slave_fe_path / "gains" / "all" / "value").update(); +} +void magnesium_radio_ctrl_impl::_update_freq( + const size_t chan, + const uhd::direction_t dir +) { + const double rf_freq = _is_low_band[dir] ? + _ad9371_freq[dir] - _adf4351_freq[dir] : + _ad9371_freq[dir]; + UHD_LOG_TRACE(unique_id(), + "RF freq = " << rf_freq); + UHD_ASSERT_THROW(rf_freq >= 0); + UHD_ASSERT_THROW( + std::abs(rf_freq - _desired_rf_freq[dir]) <= _master_clock_rate/2); + if (dir == RX_DIRECTION){ + radio_ctrl_impl::set_rx_frequency(rf_freq, chan); + }else if (dir == TX_DIRECTION){ + radio_ctrl_impl::set_tx_frequency(rf_freq, chan); + }else{ + UHD_THROW_INVALID_CODE_PATH(); + } } double magnesium_radio_ctrl_impl::set_rx_frequency( const double freq, const size_t chan ) { - // Note: There is only one LO per RX or TX, so changing frequency will - // affect the adjacent channel in the same direction. We have to make sure - // that getters will always tell the truth! This is true for low and high - // bands. + // FIXME bounds checking + clipping!!! UHD_LOG_TRACE(unique_id(), "set_rx_frequency(f=" << freq << ", chan=" << chan << ")"); + _desired_rf_freq[RX_DIRECTION]=freq; if (not _master) { const fs_path master_rx_fe_path = master_fe_base_path(_radio_slot) / fs_path("rx_frontends") / chan; @@ -288,26 +309,32 @@ double magnesium_radio_ctrl_impl::set_rx_frequency( // This way, if we tune channel 0 it will not put channel 1 into a bad // state. _update_rx_freq_switches(freq, _rx_bypass_lnas, magnesium_cpld_ctrl::BOTH); - //double ad9371_freq = freq; - double if_freq = 0.0; - auto lo_iface = _rx_lo; + const std::string ad9371_source = this->get_rx_lo_source(MAGNESIUM_LO1, chan); + const std::string adf4351_source = this->get_rx_lo_source(MAGNESIUM_LO2, chan); + UHD_ASSERT_THROW(adf4351_source == "internal"); + double coerced_if_freq = freq; if (freq < MAGNESIUM_LOWBAND_FREQ) { // Low band - if_freq = MAGNESIUM_RX_IF_FREQ ; - const double lo_freq = if_freq - freq; - const bool int_n_mode = false; // FIXME no hardcode - //const double actual_lo_freq = - _lo_enable(lo_iface, lo_freq, _master_clock_rate, int_n_mode); - //ad9371_freq = actual_lo_freq - freq; + _is_low_band[RX_DIRECTION] = true; + const double desired_low_freq = MAGNESIUM_RX_IF_FREQ - freq; + coerced_if_freq = + this->_set_rx_lo_freq(adf4351_source, MAGNESIUM_LO2, desired_low_freq, chan) + freq; + UHD_LOG_TRACE(unique_id(), "coerced_if_freq = " << coerced_if_freq); } else { - _lo_disable(lo_iface); + _is_low_band[RX_DIRECTION] = false; + _lo_disable(_rx_lo); } + // external LO required to tune at 2xdesired_frequency. + const double desired_if_freq = ad9371_source == "internal" ? + coerced_if_freq : + 2*coerced_if_freq; + + this->_set_rx_lo_freq(ad9371_source, MAGNESIUM_LO1, desired_if_freq, chan); - //const double actual_ad9371_freq = - _ad9371->set_frequency(freq, chan, RX_DIRECTION); - radio_ctrl_impl::set_rx_frequency(freq, chan); + this->_update_freq(chan, RX_DIRECTION); this->_update_gain(chan, RX_DIRECTION); - return freq; // FIXME calc the actual frequency + + return radio_ctrl_impl::get_rx_frequency(chan); } double magnesium_radio_ctrl_impl::get_tx_frequency( @@ -393,55 +420,304 @@ double magnesium_radio_ctrl_impl::set_rx_gain( std::vector<std::string> magnesium_radio_ctrl_impl::get_rx_lo_names( const size_t /*chan*/ ) { - return std::vector<std::string>{}; + return std::vector<std::string> {MAGNESIUM_LO1, MAGNESIUM_LO2}; } std::vector<std::string> magnesium_radio_ctrl_impl::get_rx_lo_sources( - const std::string &/*name*/, + const std::string &name, const size_t /*chan*/ ) { - return std::vector<std::string>{}; + if (name == MAGNESIUM_LO2){ + return std::vector<std::string> { "internal" }; + }else if (name == MAGNESIUM_LO1){ + return std::vector<std::string> { "internal", "external" }; + }else { + throw uhd::value_error("Could not find LO stage " + name); + } } freq_range_t magnesium_radio_ctrl_impl::get_rx_lo_freq_range( - const std::string &/*name*/, - const size_t /*chan*/ + const std::string & name, + const size_t /*chan*/ ) { - return freq_range_t{}; + if (name == MAGNESIUM_LO1){ + return freq_range_t{ADF4351_MIN_FREQ, ADF4351_MAX_FREQ}; + } + else if(name == MAGNESIUM_LO2){ + return freq_range_t{AD9371_MIN_FREQ, AD9371_MAX_FREQ}; + } + else { + throw uhd::value_error("Could not find LO stage " + name); + } } void magnesium_radio_ctrl_impl::set_rx_lo_source( - const std::string &/*src*/, - const std::string &/*name*/, - const size_t /*chan*/ + const std::string &src, + const std::string &name, + const size_t chan ) { + UHD_LOG_TRACE(unique_id(),"Attempting to set rx LO." <<"LO "<<name<<" to "<<src << " at "<<chan); + //TODO: checking what options are there std::lock_guard<std::mutex> l(_set_lock); - // FIXME + if (not _master) { + const fs_path master_rx_fe_path = + master_fe_base_path(_radio_slot) / fs_path("rx_frontends") / chan; + UHD_LOG_DEBUG(unique_id(), + "Slave setting lo source"); + _tree->access<std::string>(master_rx_fe_path / "los" / name /"source"/"value").set(src); + return; + } + UHD_LOG_TRACE(unique_id(), "Master set LO source." <<"LO "<<name<<" to "<<src << " at "<<chan); + + if (name == MAGNESIUM_LO1){ + _ad9371->set_lo_source(src, RX_DIRECTION); + }else{ + UHD_LOG_ERROR(unique_id(), "This LO " <<name <<" does not support set_lo_source to "<< src); + } } const std::string magnesium_radio_ctrl_impl::get_rx_lo_source( - const std::string &/*name*/, - const size_t /*chan*/ + const std::string &name, + const size_t chan ) { - return ""; // FIXME + if (not _master) { + const fs_path master_rx_fe_path = + master_fe_base_path(_radio_slot) / fs_path("rx_frontends") / chan; + UHD_LOG_DEBUG(unique_id(), "Slave getting lo source"); + return _tree->access<std::string>(master_rx_fe_path / "los" / name /"source"/"value").get(); + } + UHD_LOG_DEBUG(unique_id(),"Master getting lo source"); + if (name == MAGNESIUM_LO1){ + //TODO: should we use this from cache? + return _ad9371->get_lo_source(RX_DIRECTION); + } + return "internal"; +} + +double magnesium_radio_ctrl_impl::_set_rx_lo_freq( + const std::string source, + const std::string name, + const double freq, + const size_t chan +){ + double coerced_lo_freq = freq; + if (source != "internal"){ + UHD_LOG_WARNING(unique_id(),"LO source is not internal. This set frequency will be ignored"); + if(name == MAGNESIUM_LO1){ + // handle ad9371 external LO case + coerced_lo_freq = freq; + _ad9371_freq[RX_DIRECTION] = coerced_lo_freq; + } + }else { + if(name == MAGNESIUM_LO1){ + coerced_lo_freq = _ad9371->set_frequency(freq, chan, RX_DIRECTION); + _ad9371_freq[RX_DIRECTION] = coerced_lo_freq; + }else if (name == MAGNESIUM_LO2 ){ + // TODO: no hardcode the init_n_mode + coerced_lo_freq = _lo_enable(_rx_lo, freq, _master_clock_rate, false); + _adf4351_freq[RX_DIRECTION] = coerced_lo_freq; + }else { + UHD_LOG_WARNING(unique_id(), "There's no LO with this name of "<<name << " in the system. This set rx lo freq will be ignored"); + }; + } + return coerced_lo_freq; } double magnesium_radio_ctrl_impl::set_rx_lo_freq( - double /*freq*/, - const std::string &/*name*/, - const size_t /*chan*/ + double freq, + const std::string &name, + const size_t chan ) { + UHD_LOG_TRACE(unique_id(),"Setting rx lo frequency for " <<name << " with freq = " <<freq); std::lock_guard<std::mutex> l(_set_lock); - return 0.0; // FIXME + if (not _master) { + const fs_path master_rx_fe_path = + master_fe_base_path(_radio_slot) / fs_path("rx_frontends") / chan; + UHD_LOG_DEBUG(unique_id(), "Slave getting lo freq"); + return _tree->access<double>(master_rx_fe_path / "los" / name /"freq"/"value").set(freq).get(); + } + std::string source = this->get_rx_lo_source(name, chan); + const double coerced_lo_freq = this->_set_rx_lo_freq(source, name, freq, chan); + this->_update_freq(chan,TX_DIRECTION); + this->_update_gain(chan,RX_DIRECTION); + return coerced_lo_freq; } double magnesium_radio_ctrl_impl::get_rx_lo_freq( - const std::string &/*name*/, + const std::string & name, + const size_t chan +) { + + UHD_LOG_TRACE(unique_id(),"Getting rx lo frequency for " <<name); + if (not _master) { + const fs_path master_rx_fe_path = + master_fe_base_path(_radio_slot) / fs_path("rx_frontends") / chan; + UHD_LOG_DEBUG(unique_id(), "Slave getting lo freq"); + return _tree->access<double>(master_rx_fe_path / "los" / name /"freq"/"value").get(); + } + std::string source = this->get_rx_lo_source(name,chan); + if(name == MAGNESIUM_LO1){ + return _ad9371_freq[RX_DIRECTION]; + }else if (name == "adf4531" ){ + return _adf4351_freq[RX_DIRECTION]; + }else { + UHD_LOG_ERROR(unique_id(), "There's no LO with this name of "<<name << " in the system. This set rx lo freq will be ignored"); + } + UHD_THROW_INVALID_CODE_PATH(); +} + +//TX LO +std::vector<std::string> magnesium_radio_ctrl_impl::get_tx_lo_names( const size_t /*chan*/ ) { - return 0.0; // FIXME + return std::vector<std::string> {MAGNESIUM_LO1, MAGNESIUM_LO2}; } +std::vector<std::string> magnesium_radio_ctrl_impl::get_tx_lo_sources( + const std::string &name, + const size_t /*chan*/ +) { + if (name == MAGNESIUM_LO2){ + return std::vector<std::string> { "internal" }; + }else if (name == MAGNESIUM_LO1){ + return std::vector<std::string> { "internal", "external" }; + }else { + throw uhd::value_error("Could not find LO stage " + name); + } +} + +freq_range_t magnesium_radio_ctrl_impl::get_tx_lo_freq_range( + const std::string &name, + const size_t /*chan*/ +) { + if (name == MAGNESIUM_LO2){ + return freq_range_t{ADF4351_MIN_FREQ, ADF4351_MAX_FREQ}; + } + else if(name == MAGNESIUM_LO1){ + return freq_range_t{AD9371_MIN_FREQ, AD9371_MAX_FREQ}; + } + else { + throw uhd::value_error("Could not find LO stage " + name); + } +} + +void magnesium_radio_ctrl_impl::set_tx_lo_source( + const std::string &src, + const std::string &name, + const size_t chan +) { + UHD_LOG_TRACE(unique_id(),"Attempting to set tx LO." <<"LO "<<name<<" to "<<src << " at "<<chan); + //TODO: checking what options are there + std::lock_guard<std::mutex> l(_set_lock); + if (not _master) { + const fs_path master_tx_fe_path = + master_fe_base_path(_radio_slot) / fs_path("tx_frontends") / chan; + UHD_LOG_DEBUG(unique_id(), + "Slave setting lo source"); + _tree->access<std::string>(master_tx_fe_path / "los" / name /"source"/"value").set(src); + } + UHD_LOG_TRACE(unique_id(), "Master set LO source." <<"LO "<<name<<" to "<<src << " at "<<chan); + + + if (name == MAGNESIUM_LO1){ + _ad9371->set_lo_source(src, TX_DIRECTION); + }else{ + UHD_LOG_ERROR(unique_id(), "This LO " <<name <<" does not support set_lo_source to "<< src); + } +} + +const std::string magnesium_radio_ctrl_impl::get_tx_lo_source( + const std::string &name, + const size_t chan +) { + if (not _master) { + const fs_path master_tx_fe_path = + master_fe_base_path(_radio_slot) / fs_path("tx_frontends") / chan; + UHD_LOG_DEBUG(unique_id(), "Slave getting lo source"); + return _tree->access<std::string>(master_tx_fe_path / "los" / name /"source"/"value").get(); + } + UHD_LOG_DEBUG(unique_id(),"Master getting lo source"); + if (name == MAGNESIUM_LO1){ + //TODO: should we use this from cache? + return _ad9371->get_lo_source(TX_DIRECTION); + } + return "internal"; +} + +double magnesium_radio_ctrl_impl::_set_tx_lo_freq( + const std::string source, + const std::string name, + const double freq, + const size_t chan +){ + double coerced_lo_freq = freq; + if (source != "internal"){ + UHD_LOG_WARNING(unique_id(),"LO source is not internal. This set frequency will be ignored"); + if(name == MAGNESIUM_LO1){ + // handle ad9371 external LO case + coerced_lo_freq = freq; + _ad9371_freq[TX_DIRECTION] = coerced_lo_freq; + } + }else { + if(name == MAGNESIUM_LO1){ + coerced_lo_freq = _ad9371->set_frequency(freq, chan, TX_DIRECTION); + _ad9371_freq[TX_DIRECTION] = coerced_lo_freq; + }else if (name == MAGNESIUM_LO2 ){ + // TODO: no hardcode the int_n_mode + const bool int_n_mode = false; + coerced_lo_freq = _lo_enable(_tx_lo, freq, _master_clock_rate, int_n_mode); + _adf4351_freq[TX_DIRECTION] = coerced_lo_freq; + }else { + UHD_LOG_WARNING(unique_id(), "There's no LO with this name of "<<name << " in the system. This set tx lo freq will be ignored"); + }; + } + return coerced_lo_freq; +} + +double magnesium_radio_ctrl_impl::set_tx_lo_freq( + double freq, + const std::string &name, + const size_t chan +) { + UHD_LOG_TRACE(unique_id(),"Setting tx lo frequency for " <<name << " with freq = " <<freq); + if (not _master) { + const fs_path master_tx_fe_path = + master_fe_base_path(_radio_slot) / fs_path("tx_frontends") / chan; + UHD_LOG_DEBUG(unique_id(), "Slave getting lo freq"); + return _tree->access<double>(master_tx_fe_path / "los" / name /"freq"/"value").set(freq).get(); + } + std::string source = this->get_tx_lo_source(name,chan); + const double return_freq = this->_set_tx_lo_freq(source, name, freq, chan); + this->_update_freq(chan, TX_DIRECTION); + this->_update_gain(chan, TX_DIRECTION); + return return_freq; +} + +double magnesium_radio_ctrl_impl::get_tx_lo_freq( + const std::string & name, + const size_t chan +) { + UHD_LOG_TRACE(unique_id(),"Getting tx lo frequency for " <<name); + if (not _master) { + const fs_path master_tx_fe_path = + master_fe_base_path(_radio_slot) / fs_path("tx_frontends") / chan; + UHD_LOG_DEBUG(unique_id(), "Slave getting lo freq"); + return _tree->access<double>(master_tx_fe_path / "los" / name /"freq"/"value").get(); + } + std::string source = this->get_tx_lo_source(name,chan); + if(name == MAGNESIUM_LO1){ + return _ad9371_freq[TX_DIRECTION]; + }else if (name == MAGNESIUM_LO2){ + return _adf4351_freq[TX_DIRECTION]; + }else { + UHD_LOG_ERROR(unique_id(), "There's no LO with this name of "<<name << " in the system."); + }; + + UHD_THROW_INVALID_CODE_PATH(); +} + + + size_t magnesium_radio_ctrl_impl::get_chan_from_dboard_fe( const std::string &fe, const direction_t /* dir */ ) { diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.hpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.hpp index c4c07cf97..c68ec5ef9 100644 --- a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.hpp +++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.hpp @@ -62,6 +62,8 @@ public: double get_tx_frequency(const size_t chan); double set_tx_bandwidth(const double bandwidth, const size_t chan); double set_rx_bandwidth(const double bandwidth, const size_t chan); + + // RX LO std::vector<std::string> get_rx_lo_names(const size_t chan); std::vector<std::string> get_rx_lo_sources( const std::string &name, @@ -89,8 +91,38 @@ public: ); double get_rx_lo_freq(const std::string &name, const size_t chan); + // TX LO + std::vector<std::string> get_tx_lo_names(const size_t chan); + std::vector<std::string> get_tx_lo_sources( + const std::string &name, + const size_t chan + ); + freq_range_t get_tx_lo_freq_range( + const std::string &name, + const size_t chan + ); + + void set_tx_lo_source( + const std::string &src, + const std::string &name, + const size_t chan + ); + const std::string get_tx_lo_source( + const std::string &name, + const size_t chan + ); + + double set_tx_lo_freq( + double freq, + const std::string &name, + const size_t chan + ); + double get_tx_lo_freq(const std::string &name, const size_t chan); + + // gain double set_tx_gain(const double gain, const size_t chan); double set_rx_gain(const double gain, const size_t chan); + size_t get_chan_from_dboard_fe(const std::string &fe, const direction_t dir); std::string get_dboard_fe_from_chan(const size_t chan, const direction_t dir); @@ -171,6 +203,10 @@ private: void _update_gain(const size_t chan, direction_t dir); + void _update_freq( + const size_t chan, + const uhd::direction_t dir + ); /************************************************************************** * CPLD Controls (implemented in magnesium_radio_ctrl_cpld.cpp) *************************************************************************/ @@ -192,6 +228,19 @@ private: const std::string &ant ); + double _set_rx_lo_freq( + const std::string source, + const std::string name, + const double freq, + const size_t chan + ); + + double _set_tx_lo_freq( + const std::string source, + const std::string name, + const double freq, + const size_t chan + ); /************************************************************************** * Private attributes *************************************************************************/ @@ -243,7 +292,15 @@ private: //! Sampling rate, and also ref clock frequency for the lowband LOs. double _master_clock_rate = 1.0; - + //! Desired RF frequency + std::map<direction_t,double> _desired_rf_freq = { {RX_DIRECTION, 2.44e9}, {TX_DIRECTION, 2.44e9} }; + //! Coerced adf4351 frequency + //! Coerced ad9371 frequency + std::map<direction_t,double> _ad9371_freq = { {RX_DIRECTION, 2.44e9}, {TX_DIRECTION, 2.44e9} }; + //! Coerced adf4351 frequency + std::map<direction_t,double> _adf4351_freq = { {RX_DIRECTION, 2.44e9}, {TX_DIRECTION, 2.44e9} }; + //! Low band enable + std::map<direction_t,bool> _is_low_band = { {RX_DIRECTION, false}, {TX_DIRECTION, false} }; //! AD9371 gain double _ad9371_rx_gain = 0.0; double _ad9371_tx_gain = 0.0; @@ -266,6 +323,11 @@ private: {magnesium_cpld_ctrl::CHAN2, magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1} }; + + //! RX LO SOURCE + // NOTE for magnesium only ad9371 LO that can be connected to the external LO so we only need one var here + std::string _rx_lo_source = "internal"; + }; /* class radio_ctrl_impl */ }} /* namespace uhd::rfnoc */ diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_init.cpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_init.cpp index 191218133..1b9e7f90e 100644 --- a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_init.cpp +++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_init.cpp @@ -366,6 +366,115 @@ void magnesium_radio_ctrl_impl::_init_frontend_subtree( ); }) ; + //LO Specific + //RX LO + subtree->create<meta_range_t>(rx_fe_path / "los"/MAGNESIUM_LO1/"freq/range") + .set_publisher([this,chan_idx](){ + return this->get_rx_lo_freq_range(MAGNESIUM_LO1, chan_idx); + }) + ; + subtree->create<std::vector<std::string>>(rx_fe_path / "los"/MAGNESIUM_LO1/"source/options") + .set_publisher([this,chan_idx](){ + return this->get_rx_lo_sources(MAGNESIUM_LO1, chan_idx); + }) + ; + subtree->create<std::string>(rx_fe_path / "los"/MAGNESIUM_LO1/"source/value") + .add_coerced_subscriber([this,chan_idx](std::string src){ + this->set_rx_lo_source(src, MAGNESIUM_LO1,chan_idx); + }) + .set_publisher([this,chan_idx](){ + return this->get_rx_lo_source(MAGNESIUM_LO1, chan_idx); + }) + ; + subtree->create<double>(rx_fe_path / "los"/MAGNESIUM_LO1/"freq/value") + .set_publisher([this,chan_idx](){ + return this->get_rx_lo_freq(MAGNESIUM_LO1, chan_idx); + }) + .set_coercer([this,chan_idx](const double freq){ + return this->set_rx_lo_freq(freq, MAGNESIUM_LO1, chan_idx); + }) + ; + + subtree->create<meta_range_t>(rx_fe_path / "los"/MAGNESIUM_LO2/"freq/range") + .set_publisher([this,chan_idx](){ + return this->get_rx_lo_freq_range(MAGNESIUM_LO2, chan_idx); + }) + ; + subtree->create<std::vector<std::string>>(rx_fe_path / "los"/MAGNESIUM_LO2/"source/options") + .set_publisher([this,chan_idx](){ + return this->get_rx_lo_sources(MAGNESIUM_LO2, chan_idx); + }) + ; + + subtree->create<std::string>(rx_fe_path / "los"/MAGNESIUM_LO2/"source/value") + .add_coerced_subscriber([this,chan_idx](std::string src){ + this->set_rx_lo_source(src, MAGNESIUM_LO2, chan_idx); + }) + .set_publisher([this,chan_idx](){ + return this->get_rx_lo_source(MAGNESIUM_LO2, chan_idx); + }) + ; + subtree->create<double>(rx_fe_path / "los"/MAGNESIUM_LO2/"freq/value") + .set_publisher([this,chan_idx](){ + return this->get_rx_lo_freq(MAGNESIUM_LO2, chan_idx); + }) + .set_coercer([this,chan_idx](double freq){ + return this->set_rx_lo_freq(freq, MAGNESIUM_LO2, chan_idx); + }); + //TX LO + subtree->create<meta_range_t>(tx_fe_path / "los"/MAGNESIUM_LO1/"freq/range") + .set_publisher([this,chan_idx](){ + return this->get_rx_lo_freq_range(MAGNESIUM_LO1, chan_idx); + }) + ; + subtree->create<std::vector<std::string>>(tx_fe_path / "los"/MAGNESIUM_LO1/"source/options") + .set_publisher([this,chan_idx](){ + return this->get_tx_lo_sources(MAGNESIUM_LO1, chan_idx); + }) + ; + subtree->create<std::string>(tx_fe_path / "los"/MAGNESIUM_LO1/"source/value") + .add_coerced_subscriber([this,chan_idx](std::string src){ + this->set_tx_lo_source(src, MAGNESIUM_LO1, chan_idx); + }) + .set_publisher([this,chan_idx](){ + return this->get_tx_lo_source(MAGNESIUM_LO1, chan_idx); + }) + ; + subtree->create<double>(tx_fe_path / "los"/MAGNESIUM_LO1/"freq/value ") + .set_publisher([this,chan_idx](){ + return this->get_tx_lo_freq(MAGNESIUM_LO1, chan_idx); + }) + .set_coercer([this,chan_idx](double freq){ + return this->set_tx_lo_freq(freq, MAGNESIUM_LO1, chan_idx); + }) + ; + + subtree->create<meta_range_t>(tx_fe_path / "los"/MAGNESIUM_LO2/"freq/range") + .set_publisher([this,chan_idx](){ + return this->get_tx_lo_freq_range(MAGNESIUM_LO2,chan_idx); + }) + ; + subtree->create<std::vector<std::string>>(tx_fe_path / "los"/MAGNESIUM_LO2/"source/options") + .set_publisher([this,chan_idx](){ + return this->get_tx_lo_sources(MAGNESIUM_LO2, chan_idx); + }) + ; + + subtree->create<std::string>(tx_fe_path / "los"/MAGNESIUM_LO2/"source/value") + .add_coerced_subscriber([this,chan_idx](std::string src){ + this->set_tx_lo_source(src, MAGNESIUM_LO2, chan_idx); + }) + .set_publisher([this,chan_idx](){ + return this->get_tx_lo_source(MAGNESIUM_LO2, chan_idx); + }) + ; + subtree->create<double>(tx_fe_path / "los"/MAGNESIUM_LO2/"freq/value") + .set_publisher([this,chan_idx](){ + return this->get_tx_lo_freq(MAGNESIUM_LO2, chan_idx); + }) + .set_coercer([this,chan_idx](double freq){ + return this->set_tx_lo_freq(freq, MAGNESIUM_LO2, chan_idx); + }); } void magnesium_radio_ctrl_impl::_init_prop_tree() |