aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/dboard
diff options
context:
space:
mode:
authorTrung N Tran <trung.tran@ettus.com>2017-11-09 17:32:32 -0800
committerMartin Braun <martin.braun@ettus.com>2017-12-22 15:05:57 -0800
commit7df29f6ee62d44eaeed878700ddbaeeb1d7fda46 (patch)
treebc1ac0a1e4e09bd9ad3e6fbb23d7b459b9bf0449 /host/lib/usrp/dboard
parentb9a0cf1467e89000658f69089bb773722e41ea89 (diff)
downloaduhd-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>
Diffstat (limited to 'host/lib/usrp/dboard')
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_constants.hpp11
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.cpp388
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.hpp64
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_init.cpp109
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()