aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp')
-rw-r--r--host/lib/usrp/b200/b200_impl.cpp2
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_3000.cpp67
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_3000.hpp5
-rw-r--r--host/lib/usrp/multi_usrp.cpp51
-rw-r--r--host/lib/usrp/x300/x300_impl.cpp84
-rw-r--r--host/lib/usrp/x300/x300_impl.hpp41
-rw-r--r--host/lib/usrp/x300/x300_io_impl.cpp150
7 files changed, 213 insertions, 187 deletions
diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp
index 8ed8e99af..74e61143b 100644
--- a/host/lib/usrp/b200/b200_impl.cpp
+++ b/host/lib/usrp/b200/b200_impl.cpp
@@ -510,7 +510,7 @@ void b200_impl::setup_radio(const size_t dspno)
// create rx dsp control objects
////////////////////////////////////////////////////////////////////
perif.framer = rx_vita_core_3000::make(perif.ctrl, TOREG(SR_RX_CTRL));
- perif.ddc = rx_dsp_core_3000::make(perif.ctrl, TOREG(SR_RX_DSP));
+ perif.ddc = rx_dsp_core_3000::make(perif.ctrl, TOREG(SR_RX_DSP), true /*is_b200?*/);
perif.ddc->set_link_rate(10e9/8); //whatever
_tree->access<double>(mb_path / "tick_rate")
.subscribe(boost::bind(&rx_vita_core_3000::set_tick_rate, perif.framer, _1))
diff --git a/host/lib/usrp/cores/rx_dsp_core_3000.cpp b/host/lib/usrp/cores/rx_dsp_core_3000.cpp
index 67d0be017..86846667f 100644
--- a/host/lib/usrp/cores/rx_dsp_core_3000.cpp
+++ b/host/lib/usrp/cores/rx_dsp_core_3000.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011-2013 Ettus Research LLC
+// Copyright 2011-2014 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -48,9 +48,10 @@ class rx_dsp_core_3000_impl : public rx_dsp_core_3000{
public:
rx_dsp_core_3000_impl(
wb_iface::sptr iface,
- const size_t dsp_base
+ const size_t dsp_base,
+ const bool is_b200
):
- _iface(iface), _dsp_base(dsp_base)
+ _iface(iface), _dsp_base(dsp_base), _is_b200(is_b200)
{
// previously uninitialized - assuming zero for all
_link_rate = _host_extra_scaling = _fxpt_scalar_correction = 0.0;
@@ -119,32 +120,43 @@ public:
hb1 = 1;
decim /= 2;
}
- if (decim % 2 == 0){
+ //the third half-band is not supported by the B200
+ if (decim % 2 == 0 && !_is_b200){
hb2 = 1;
decim /= 2;
}
- // Encode Halfband config for setting register programming.
- if (hb2) { // Implies HB1 and HB0 also asserted
- hb_enable=3;
- } else if (hb1) { // Implies HB0 is also asserted
- hb_enable=2;
- } else if (hb0) {
- hb_enable=1;
- } else {
- hb_enable=0;
- }
-
- _iface->poke32(REG_DSP_RX_DECIM, (hb_enable << 8) | (decim & 0xff));
-
- if (decim > 1 and hb0 == 0 and hb1 == 0 and hb2 == 0)
- {
- UHD_MSG(warning) << boost::format(
- "The requested decimation is odd; the user should expect passband CIC rolloff.\n"
- "Select an even decimation to ensure that a halfband filter is enabled.\n"
- "Decimations factorable by 4 will enable 2 halfbands, those factorable by 8 will enable 3 halfbands.\n"
- "decimation = dsp_rate/samp_rate -> %d = (%f MHz)/(%f MHz)\n"
- ) % decim_rate % (_tick_rate/1e6) % (rate/1e6);
+ if (_is_b200) {
+ _iface->poke32(REG_DSP_RX_DECIM, (hb1 << 9) | (hb0 << 8) | (decim & 0xff));
+
+ if (decim > 1 and hb0 == 0 and hb1 == 0) {
+ UHD_MSG(warning) << boost::format(
+ "The requested decimation is odd; the user should expect CIC rolloff.\n"
+ "Select an even decimation to ensure that a halfband filter is enabled.\n"
+ "decimation = dsp_rate/samp_rate -> %d = (%f MHz)/(%f MHz)\n"
+ ) % decim_rate % (_tick_rate/1e6) % (rate/1e6);
+ }
+ } else {
+ // Encode Halfband config for setting register programming.
+ if (hb2) { // Implies HB1 and HB0 also asserted
+ hb_enable=3;
+ } else if (hb1) { // Implies HB0 is also asserted
+ hb_enable=2;
+ } else if (hb0) {
+ hb_enable=1;
+ } else {
+ hb_enable=0;
+ }
+ _iface->poke32(REG_DSP_RX_DECIM, (hb_enable << 8) | (decim & 0xff));
+
+ if (decim > 1 and hb0 == 0 and hb1 == 0 and hb2 == 0) {
+ UHD_MSG(warning) << boost::format(
+ "The requested decimation is odd; the user should expect passband CIC rolloff.\n"
+ "Select an even decimation to ensure that a halfband filter is enabled.\n"
+ "Decimations factorable by 4 will enable 2 halfbands, those factorable by 8 will enable 3 halfbands.\n"
+ "decimation = dsp_rate/samp_rate -> %d = (%f MHz)/(%f MHz)\n"
+ ) % decim_rate % (_tick_rate/1e6) % (rate/1e6);
+ }
}
// Calculate CIC decimation (i.e., without halfband decimators)
@@ -223,11 +235,12 @@ public:
private:
wb_iface::sptr _iface;
const size_t _dsp_base;
+ const bool _is_b200; //TODO: Obsolete this when we switch to the new DDC on the B200
double _tick_rate, _link_rate;
double _scaling_adjustment, _dsp_extra_scaling, _host_extra_scaling, _fxpt_scalar_correction;
};
-rx_dsp_core_3000::sptr rx_dsp_core_3000::make(wb_iface::sptr iface, const size_t dsp_base)
+rx_dsp_core_3000::sptr rx_dsp_core_3000::make(wb_iface::sptr iface, const size_t dsp_base, const bool is_b200 /* = false */)
{
- return sptr(new rx_dsp_core_3000_impl(iface, dsp_base));
+ return sptr(new rx_dsp_core_3000_impl(iface, dsp_base, is_b200));
}
diff --git a/host/lib/usrp/cores/rx_dsp_core_3000.hpp b/host/lib/usrp/cores/rx_dsp_core_3000.hpp
index 02e5587a2..f35e1e3d3 100644
--- a/host/lib/usrp/cores/rx_dsp_core_3000.hpp
+++ b/host/lib/usrp/cores/rx_dsp_core_3000.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011-2013 Ettus Research LLC
+// Copyright 2011-2014 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -33,7 +33,8 @@ public:
static sptr make(
uhd::wb_iface::sptr iface,
- const size_t dsp_base
+ const size_t dsp_base,
+ const bool is_b200 = false //TODO: Obsolete this when we switch to the new DDC on the B200
);
virtual void set_mux(const std::string &mode, const bool fe_swapped = false) = 0;
diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp
index 182e774fc..2e82e890e 100644
--- a/host/lib/usrp/multi_usrp.cpp
+++ b/host/lib/usrp/multi_usrp.cpp
@@ -35,14 +35,20 @@ using namespace uhd::usrp;
const std::string multi_usrp::ALL_GAINS = "";
-UHD_INLINE std::string string_vector_to_string(std::vector<std::string> values, std::string delimeter = std::string(" "))
+UHD_INLINE std::string string_vector_to_string(std::vector<std::string> values, std::string delimiter = std::string(" "))
{
std::string out = "";
for (std::vector<std::string>::iterator iter = values.begin(); iter != values.end(); iter++)
- out += delimeter + *iter;
+ {
+ out += (iter != values.begin() ? delimiter : "") + *iter;
+ }
return out;
}
+#define THROW_GAIN_NAME_ERROR(name,chan,dir) throw uhd::exception::runtime_error( \
+ (boost::format("%s: gain \"%s\" not found for channel %d.\nAvailable gains: %s\n") % \
+ __FUNCTION__ % name % chan % string_vector_to_string(get_##dir##_gain_names(chan))).str());
+
/***********************************************************************
* Helper methods
**********************************************************************/
@@ -671,10 +677,7 @@ public:
try {
return rx_gain_group(chan)->set_value(gain, name);
} catch (uhd::key_error &e) {
- std::stringstream err;
- err << __FUNCTION__ << "(\"" << name << "\"): gain not found.\n" <<
- "Available gains: " << string_vector_to_string(get_rx_gain_names(chan)) << std::endl;
- throw uhd::exception::runtime_error(err.str());
+ THROW_GAIN_NAME_ERROR(name,chan,rx);
}
}
@@ -682,10 +685,7 @@ public:
try {
return rx_gain_group(chan)->get_value(name);
} catch (uhd::key_error &e) {
- std::stringstream err;
- err << __FUNCTION__ << "(\"" << name << "\"): gain not found.\n" <<
- "Available gains: " << string_vector_to_string(get_rx_gain_names(chan)) << std::endl;
- throw uhd::exception::runtime_error(err.str());
+ THROW_GAIN_NAME_ERROR(name,chan,rx);
}
}
@@ -693,10 +693,7 @@ public:
try {
return rx_gain_group(chan)->get_range(name);
} catch (uhd::key_error &e) {
- std::stringstream err;
- err << __FUNCTION__ << "(\"" << name << "\"): gain not found.\n" <<
- "Available gains: " << string_vector_to_string(get_rx_gain_names(chan)) << std::endl;
- throw uhd::exception::runtime_error(err.str());
+ THROW_GAIN_NAME_ERROR(name,chan,rx);
}
}
@@ -861,10 +858,7 @@ public:
try {
return tx_gain_group(chan)->set_value(gain, name);
} catch (uhd::key_error &e) {
- std::stringstream err;
- err << __FUNCTION__ << "(\"" << name << "\"): gain not found.\n" <<
- "Available gains: " << string_vector_to_string(get_rx_gain_names(chan)) << std::endl;
- throw uhd::exception::runtime_error(err.str());
+ THROW_GAIN_NAME_ERROR(name,chan,tx);
}
}
@@ -872,10 +866,7 @@ public:
try {
return tx_gain_group(chan)->get_value(name);
} catch (uhd::key_error &e) {
- std::stringstream err;
- err << __FUNCTION__ << "(\"" << name << "\"): gain not found.\n" <<
- "Available gains: " << string_vector_to_string(get_rx_gain_names(chan)) << std::endl;
- throw uhd::exception::runtime_error(err.str());
+ THROW_GAIN_NAME_ERROR(name,chan,tx);
}
}
@@ -883,10 +874,7 @@ public:
try {
return tx_gain_group(chan)->get_range(name);
} catch (uhd::key_error &e) {
- std::stringstream err;
- err << __FUNCTION__ << "(\"" << name << "\"): gain not found.\n" <<
- "Available gains: " << string_vector_to_string(get_rx_gain_names(chan)) << std::endl;
- throw uhd::exception::runtime_error(err.str());
+ THROW_GAIN_NAME_ERROR(name,chan,tx);
}
}
@@ -1073,6 +1061,12 @@ private:
fs_path rx_dsp_root(const size_t chan)
{
mboard_chan_pair mcp = rx_chan_to_mcp(chan);
+ if (_tree->exists(mb_root(mcp.mboard) / "rx_chan_dsp_mapping")) {
+ std::vector<size_t> map = _tree->access<std::vector<size_t> >(mb_root(mcp.mboard) / "rx_chan_dsp_mapping").get();
+ UHD_ASSERT_THROW(map.size() >= mcp.chan);
+ mcp.chan = map[mcp.chan];
+ }
+
try
{
const std::string name = _tree->list(mb_root(mcp.mboard) / "rx_dsps").at(mcp.chan);
@@ -1087,6 +1081,11 @@ private:
fs_path tx_dsp_root(const size_t chan)
{
mboard_chan_pair mcp = tx_chan_to_mcp(chan);
+ if (_tree->exists(mb_root(mcp.mboard) / "tx_chan_dsp_mapping")) {
+ std::vector<size_t> map = _tree->access<std::vector<size_t> >(mb_root(mcp.mboard) / "tx_chan_dsp_mapping").get();
+ UHD_ASSERT_THROW(map.size() >= mcp.chan);
+ mcp.chan = map[mcp.chan];
+ }
try
{
const std::string name = _tree->list(mb_root(mcp.mboard) / "tx_dsps").at(mcp.chan);
diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp
index 298844db6..48b9e9bd4 100644
--- a/host/lib/usrp/x300/x300_impl.cpp
+++ b/host/lib/usrp/x300/x300_impl.cpp
@@ -458,8 +458,6 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)
}
}
- const std::vector<std::string> DB_NAMES = boost::assign::list_of("A")("B");
-
//create basic communication
UHD_MSG(status) << "Setup basic communication..." << std::endl;
if (mb.xport_path == "nirio") {
@@ -664,8 +662,8 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)
// setup radios
////////////////////////////////////////////////////////////////////
UHD_MSG(status) << "Initialize Radio control..." << std::endl;
- this->setup_radio(mb_i, 0, DB_NAMES[0]);
- this->setup_radio(mb_i, 1, DB_NAMES[1]);
+ this->setup_radio(mb_i, "A");
+ this->setup_radio(mb_i, "B");
////////////////////////////////////////////////////////////////////
// front panel gpio
@@ -732,10 +730,13 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)
////////////////////////////////////////////////////////////////////
// create frontend mapping
////////////////////////////////////////////////////////////////////
+ std::vector<size_t> default_map(2, 0); default_map[1] = 1;
+ _tree->create<std::vector<size_t> >(mb_path / "rx_chan_dsp_mapping").set(default_map);
+ _tree->create<std::vector<size_t> >(mb_path / "tx_chan_dsp_mapping").set(default_map);
_tree->create<subdev_spec_t>(mb_path / "rx_subdev_spec")
- .subscribe(boost::bind(&x300_impl::update_rx_subdev_spec, this, mb_i, _1));
+ .subscribe(boost::bind(&x300_impl::update_subdev_spec, this, "rx", mb_i, _1));
_tree->create<subdev_spec_t>(mb_path / "tx_subdev_spec")
- .subscribe(boost::bind(&x300_impl::update_tx_subdev_spec, this, mb_i, _1));
+ .subscribe(boost::bind(&x300_impl::update_subdev_spec, this, "tx", mb_i, _1));
////////////////////////////////////////////////////////////////////
// and do the misc mboard sensors
@@ -824,20 +825,20 @@ static void check_adc(wb_iface::sptr iface, const boost::uint32_t val)
UHD_ASSERT_THROW(adc_rb == val);
}
-void x300_impl::setup_radio(const size_t mb_i, const size_t i, const std::string &db_name)
+void x300_impl::setup_radio(const size_t mb_i, const std::string &slot_name)
{
const fs_path mb_path = "/mboards/"+boost::lexical_cast<std::string>(mb_i);
+ const size_t radio_index = _mb[mb_i].get_radio_index(slot_name);
mboard_members_t &mb = _mb[mb_i];
- radio_perifs_t &perif = mb.radio_perifs[i];
- const size_t dspno = i;
+ radio_perifs_t &perif = mb.radio_perifs[radio_index];
////////////////////////////////////////////////////////////////////
// radio control
////////////////////////////////////////////////////////////////////
- uint8_t dest = (i == 0)? X300_XB_DST_R0 : X300_XB_DST_R1;
+ uint8_t dest = (radio_index == 0)? X300_XB_DST_R0 : X300_XB_DST_R1;
boost::uint32_t ctrl_sid;
both_xports_t xport = this->make_transport(mb_i, dest, X300_RADIO_DEST_PREFIX_CTRL, device_addr_t(), ctrl_sid);
- perif.ctrl = radio_ctrl_core_3000::make(mb.if_pkt_is_big_endian, xport.recv, xport.send, ctrl_sid, db_name);
+ perif.ctrl = radio_ctrl_core_3000::make(mb.if_pkt_is_big_endian, xport.recv, xport.send, ctrl_sid, slot_name);
perif.ctrl->poke32(TOREG(SR_MISC_OUTS), (1 << 2)); //reset adc + dac
perif.ctrl->poke32(TOREG(SR_MISC_OUTS), (1 << 1) | (1 << 0)); //out of reset + dac enable
@@ -883,20 +884,20 @@ void x300_impl::setup_radio(const size_t mb_i, const size_t i, const std::string
////////////////////////////////////////////////////////////////
// create codec control objects
////////////////////////////////////////////////////////////////
- _tree->create<int>(mb_path / "rx_codecs" / db_name / "gains"); //phony property so this dir exists
- _tree->create<int>(mb_path / "tx_codecs" / db_name / "gains"); //phony property so this dir exists
- _tree->create<std::string>(mb_path / "rx_codecs" / db_name / "name").set("ads62p48");
- _tree->create<std::string>(mb_path / "tx_codecs" / db_name / "name").set("ad9146");
+ _tree->create<int>(mb_path / "rx_codecs" / slot_name / "gains"); //phony property so this dir exists
+ _tree->create<int>(mb_path / "tx_codecs" / slot_name / "gains"); //phony property so this dir exists
+ _tree->create<std::string>(mb_path / "rx_codecs" / slot_name / "name").set("ads62p48");
+ _tree->create<std::string>(mb_path / "tx_codecs" / slot_name / "name").set("ad9146");
- _tree->create<meta_range_t>(mb_path / "rx_codecs" / db_name / "gains" / "digital" / "range").set(meta_range_t(0, 6.0, 0.5));
- _tree->create<double>(mb_path / "rx_codecs" / db_name / "gains" / "digital" / "value")
+ _tree->create<meta_range_t>(mb_path / "rx_codecs" / slot_name / "gains" / "digital" / "range").set(meta_range_t(0, 6.0, 0.5));
+ _tree->create<double>(mb_path / "rx_codecs" / slot_name / "gains" / "digital" / "value")
.subscribe(boost::bind(&x300_adc_ctrl::set_gain, perif.adc, _1)).set(0);
////////////////////////////////////////////////////////////////////
// front end corrections
////////////////////////////////////////////////////////////////////
perif.rx_fe = rx_frontend_core_200::make(perif.ctrl, TOREG(SR_RX_FRONT));
- const fs_path rx_fe_path = mb_path / "rx_frontends" / db_name;
+ const fs_path rx_fe_path = mb_path / "rx_frontends" / slot_name;
_tree->create<std::complex<double> >(rx_fe_path / "dc_offset" / "value")
.coerce(boost::bind(&rx_frontend_core_200::set_dc_offset, perif.rx_fe, _1))
.set(std::complex<double>(0.0, 0.0));
@@ -908,7 +909,7 @@ void x300_impl::setup_radio(const size_t mb_i, const size_t i, const std::string
.set(std::complex<double>(0.0, 0.0));
perif.tx_fe = tx_frontend_core_200::make(perif.ctrl, TOREG(SR_TX_FRONT));
- const fs_path tx_fe_path = mb_path / "tx_frontends" / db_name;
+ const fs_path tx_fe_path = mb_path / "tx_frontends" / slot_name;
_tree->create<std::complex<double> >(tx_fe_path / "dc_offset" / "value")
.coerce(boost::bind(&tx_frontend_core_200::set_dc_offset, perif.tx_fe, _1))
.set(std::complex<double>(0.0, 0.0));
@@ -927,12 +928,12 @@ void x300_impl::setup_radio(const size_t mb_i, const size_t i, const std::string
_tree->access<double>(mb_path / "tick_rate")
.subscribe(boost::bind(&rx_vita_core_3000::set_tick_rate, perif.framer, _1))
.subscribe(boost::bind(&rx_dsp_core_3000::set_tick_rate, perif.ddc, _1));
- const fs_path rx_dsp_path = mb_path / "rx_dsps" / str(boost::format("%u") % dspno);
+ const fs_path rx_dsp_path = mb_path / "rx_dsps" / str(boost::format("%u") % radio_index);
_tree->create<meta_range_t>(rx_dsp_path / "rate" / "range")
.publish(boost::bind(&rx_dsp_core_3000::get_host_rates, perif.ddc));
_tree->create<double>(rx_dsp_path / "rate" / "value")
.coerce(boost::bind(&rx_dsp_core_3000::set_host_rate, perif.ddc, _1))
- .subscribe(boost::bind(&x300_impl::update_rx_samp_rate, this, boost::ref(mb), dspno, _1))
+ .subscribe(boost::bind(&x300_impl::update_rx_samp_rate, this, boost::ref(mb), radio_index, _1))
.set(1e6);
_tree->create<double>(rx_dsp_path / "freq" / "value")
.coerce(boost::bind(&rx_dsp_core_3000::set_freq, perif.ddc, _1))
@@ -951,12 +952,12 @@ void x300_impl::setup_radio(const size_t mb_i, const size_t i, const std::string
_tree->access<double>(mb_path / "tick_rate")
.subscribe(boost::bind(&tx_vita_core_3000::set_tick_rate, perif.deframer, _1))
.subscribe(boost::bind(&tx_dsp_core_3000::set_tick_rate, perif.duc, _1));
- const fs_path tx_dsp_path = mb_path / "tx_dsps" / str(boost::format("%u") % dspno);
+ const fs_path tx_dsp_path = mb_path / "tx_dsps" / str(boost::format("%u") % radio_index);
_tree->create<meta_range_t>(tx_dsp_path / "rate" / "range")
.publish(boost::bind(&tx_dsp_core_3000::get_host_rates, perif.duc));
_tree->create<double>(tx_dsp_path / "rate" / "value")
.coerce(boost::bind(&tx_dsp_core_3000::set_host_rate, perif.duc, _1))
- .subscribe(boost::bind(&x300_impl::update_tx_samp_rate, this, boost::ref(mb), dspno, _1))
+ .subscribe(boost::bind(&x300_impl::update_tx_samp_rate, this, boost::ref(mb), radio_index, _1))
.set(1e6);
_tree->create<double>(tx_dsp_path / "freq" / "value")
.coerce(boost::bind(&tx_dsp_core_3000::set_freq, perif.duc, _1))
@@ -975,14 +976,15 @@ void x300_impl::setup_radio(const size_t mb_i, const size_t i, const std::string
////////////////////////////////////////////////////////////////////
// create RF frontend interfacing
////////////////////////////////////////////////////////////////////
- const size_t j = (db_name == "B")? 0x2 : 0x0;
- _tree->create<dboard_eeprom_t>(mb_path / "dboards" / db_name / "rx_eeprom")
+ const fs_path db_path = (mb_path / "dboards" / slot_name);
+ const size_t j = (slot_name == "B")? 0x2 : 0x0;
+ _tree->create<dboard_eeprom_t>(db_path / "rx_eeprom")
.set(mb.db_eeproms[X300_DB0_RX_EEPROM | j])
.subscribe(boost::bind(&x300_impl::set_db_eeprom, this, mb.zpu_i2c, (0x50 | X300_DB0_RX_EEPROM | j), _1));
- _tree->create<dboard_eeprom_t>(mb_path / "dboards" / db_name / "tx_eeprom")
+ _tree->create<dboard_eeprom_t>(db_path / "tx_eeprom")
.set(mb.db_eeproms[X300_DB0_TX_EEPROM | j])
.subscribe(boost::bind(&x300_impl::set_db_eeprom, this, mb.zpu_i2c, (0x50 | X300_DB0_TX_EEPROM | j), _1));
- _tree->create<dboard_eeprom_t>(mb_path / "dboards" / db_name / "gdb_eeprom")
+ _tree->create<dboard_eeprom_t>(db_path / "gdb_eeprom")
.set(mb.db_eeproms[X300_DB0_GDB_EEPROM | j])
.subscribe(boost::bind(&x300_impl::set_db_eeprom, this, mb.zpu_i2c, (0x50 | X300_DB0_GDB_EEPROM | j), _1));
@@ -994,33 +996,33 @@ void x300_impl::setup_radio(const size_t mb_i, const size_t i, const std::string
db_config.tx_spi_slaveno = DB_TX_SEN;
db_config.i2c = mb.zpu_i2c;
db_config.clock = mb.clock;
- db_config.which_rx_clk = (db_name == "A")? X300_CLOCK_WHICH_DB0_RX : X300_CLOCK_WHICH_DB1_RX;
- db_config.which_tx_clk = (db_name == "A")? X300_CLOCK_WHICH_DB0_TX : X300_CLOCK_WHICH_DB1_TX;
- db_config.dboard_slot = (db_name == "A")? 0 : 1;
- _dboard_ifaces[db_name] = x300_make_dboard_iface(db_config);
+ db_config.which_rx_clk = (slot_name == "A")? X300_CLOCK_WHICH_DB0_RX : X300_CLOCK_WHICH_DB1_RX;
+ db_config.which_tx_clk = (slot_name == "A")? X300_CLOCK_WHICH_DB0_TX : X300_CLOCK_WHICH_DB1_TX;
+ db_config.dboard_slot = (slot_name == "A")? 0 : 1;
+ _dboard_ifaces[db_path] = x300_make_dboard_iface(db_config);
//create a new dboard manager
- _tree->create<dboard_iface::sptr>(mb_path / "dboards" / db_name / "iface").set(_dboard_ifaces[db_name]);
- _dboard_managers[db_name] = dboard_manager::make(
+ _tree->create<dboard_iface::sptr>(db_path / "iface").set(_dboard_ifaces[db_path]);
+ _dboard_managers[db_path] = dboard_manager::make(
mb.db_eeproms[X300_DB0_RX_EEPROM | j].id,
mb.db_eeproms[X300_DB0_TX_EEPROM | j].id,
mb.db_eeproms[X300_DB0_GDB_EEPROM | j].id,
- _dboard_ifaces[db_name],
- _tree->subtree(mb_path / "dboards" / db_name)
+ _dboard_ifaces[db_path],
+ _tree->subtree(db_path)
);
//now that dboard is created -- register into rx antenna event
- const std::string fe_name = _tree->list(mb_path / "dboards" / db_name / "rx_frontends").front();
- _tree->access<std::string>(mb_path / "dboards" / db_name / "rx_frontends" / fe_name / "antenna" / "value")
- .subscribe(boost::bind(&x300_impl::update_atr_leds, this, mb.radio_perifs[i].leds, _1));
- this->update_atr_leds(mb.radio_perifs[i].leds, ""); //init anyway, even if never called
+ const std::string fe_name = _tree->list(db_path / "rx_frontends").front();
+ _tree->access<std::string>(db_path / "rx_frontends" / fe_name / "antenna" / "value")
+ .subscribe(boost::bind(&x300_impl::update_atr_leds, this, mb.radio_perifs[radio_index].leds, _1));
+ this->update_atr_leds(mb.radio_perifs[radio_index].leds, ""); //init anyway, even if never called
//bind frontend corrections to the dboard freq props
- const fs_path db_rx_fe_path = mb_path / "dboards" / db_name / "rx_frontends";
+ const fs_path db_rx_fe_path = db_path / "rx_frontends";
BOOST_FOREACH(const std::string &name, _tree->list(db_rx_fe_path))
{
_tree->access<double>(db_rx_fe_path / name / "freq" / "value")
- .subscribe(boost::bind(&x300_impl::set_rx_fe_corrections, this, mb_path, db_name, _1));
+ .subscribe(boost::bind(&x300_impl::set_rx_fe_corrections, this, mb_path, slot_name, _1));
}
}
diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp
index 264fc10b6..1e159ef38 100644
--- a/host/lib/usrp/x300/x300_impl.hpp
+++ b/host/lib/usrp/x300/x300_impl.hpp
@@ -82,8 +82,8 @@ static const double X300_DEFAULT_SYSREF_RATE = 10e6;
#define X300_XB_DST_E0 0
#define X300_XB_DST_E1 1
-#define X300_XB_DST_R0 2
-#define X300_XB_DST_R1 3
+#define X300_XB_DST_R0 2 // Radio 0 -> Slot A
+#define X300_XB_DST_R1 3 // Radio 1 -> Slot B
#define X300_XB_DST_CE0 4
#define X300_XB_DST_CE1 5
#define X300_XB_DST_CE2 5
@@ -191,12 +191,13 @@ private:
i2c_core_100_wb32::sptr zpu_i2c;
//perifs in each radio
- radio_perifs_t radio_perifs[2];
+ radio_perifs_t radio_perifs[2]; //!< This is hardcoded s.t. radio_perifs[0] points to slot A and [1] to B
uhd::usrp::dboard_eeprom_t db_eeproms[8];
-
- //per mboard frontend mapping
- uhd::usrp::subdev_spec_t rx_fe_map;
- uhd::usrp::subdev_spec_t tx_fe_map;
+ //! Return the index of a radio component, given a slot name. This means DSPs, radio_perifs
+ size_t get_radio_index(const std::string &slot_name) {
+ UHD_ASSERT_THROW(slot_name == "A" or slot_name == "B");
+ return slot_name == "A" ? 0 : 1;
+ }
//other perifs on mboard
x300_clock_ctrl::sptr clock;
@@ -222,7 +223,20 @@ private:
void register_loopback_self_test(uhd::wb_iface::sptr iface);
- void setup_radio(const size_t, const size_t which_radio, const std::string &db_name);
+ /*! \brief Initialize the radio component on a given slot.
+ *
+ * Call this function once per slot (A and B) and motherboard to initialize all the radio components.
+ * This will:
+ * - Reset and init DACs and ADCs
+ * - Setup controls for DAC, ADC, SPI and LEDs
+ * - Self test ADC
+ * - Sync DACs (for MIMO)
+ * - Initialize the property tree for control objects etc. (gain, rate...)
+ *
+ * \param mb_i Motherboard index
+ * \param slot_name Slot name (A or B).
+ */
+ void setup_radio(const size_t, const std::string &slot_name);
size_t _sid_framer;
struct sid_config_t
@@ -288,8 +302,15 @@ private:
void set_rx_fe_corrections(const uhd::fs_path &mb_path, const std::string &fe_name, const double lo_freq);
- void update_rx_subdev_spec(const size_t, const uhd::usrp::subdev_spec_t &spec);
- void update_tx_subdev_spec(const size_t, const uhd::usrp::subdev_spec_t &spec);
+ /*! Update the IQ MUX settings for the radio peripheral according to given subdev spec.
+ *
+ * Also checks if the given subdev is valid for this device and updates the channel to DSP mapping.
+ *
+ * \param tx_rx "tx" or "rx", depending where you're setting the subdev spec
+ * \param mb_i Mainboard index number.
+ * \param spec Subdev spec
+ */
+ void update_subdev_spec(const std::string &tx_rx, const size_t mb_i, const uhd::usrp::subdev_spec_t &spec);
void set_tick_rate(mboard_members_t &, const double);
void update_tick_rate(mboard_members_t &, const double);
diff --git a/host/lib/usrp/x300/x300_io_impl.cpp b/host/lib/usrp/x300/x300_io_impl.cpp
index 00a31b8d6..84f96d9f5 100644
--- a/host/lib/usrp/x300/x300_io_impl.cpp
+++ b/host/lib/usrp/x300/x300_io_impl.cpp
@@ -77,75 +77,50 @@ void x300_impl::update_tx_samp_rate(mboard_members_t &mb, const size_t dspno, co
/***********************************************************************
* Setup dboard muxing for IQ
**********************************************************************/
-void x300_impl::update_rx_subdev_spec(const size_t mb_i, const subdev_spec_t &spec)
+void x300_impl::update_subdev_spec(const std::string &tx_rx, const size_t mb_i, const subdev_spec_t &spec)
{
+ UHD_ASSERT_THROW(tx_rx == "tx" or tx_rx == "rx");
const std::string mb_name = boost::lexical_cast<std::string>(mb_i);
- fs_path root = "/mboards/"+mb_name+"/dboards";
+ fs_path mb_root = "/mboards/" + mb_name;
//sanity checking
- validate_subdev_spec(_tree, spec, "rx", mb_name);
+ validate_subdev_spec(_tree, spec, tx_rx, mb_name);
UHD_ASSERT_THROW(spec.size() <= 2);
- if (spec.size() > 0) UHD_ASSERT_THROW(spec[0].db_name == "A");
- if (spec.size() > 1) UHD_ASSERT_THROW(spec[1].db_name == "B");
-
- //setup mux for this spec
- for (size_t i = 0; i < 2; i++)
+ if (spec.size() == 1) {
+ UHD_ASSERT_THROW(spec[0].db_name == "A" || spec[0].db_name == "B");
+ }
+ if (spec.size() == 2) {
+ UHD_ASSERT_THROW(
+ (spec[0].db_name == "A" && spec[1].db_name == "B") ||
+ (spec[0].db_name == "B" && spec[1].db_name == "A")
+ );
+ }
+
+ std::vector<size_t> chan_to_dsp_map(spec.size(), 0);
+ // setup mux for this spec
+ for (size_t i = 0; i < spec.size(); i++)
{
- //extract db name
- const std::string db_name = (i == 0)? "A" : "B";
- if (i < spec.size()) UHD_ASSERT_THROW(spec[i].db_name == db_name);
-
- //extract fe name
- std::string fe_name;
- if (i < spec.size()) fe_name = spec[i].sd_name;
- else fe_name = _tree->list(root / db_name / "rx_frontends").front();
+ const int radio_idx = _mb[mb_i].get_radio_index(spec[i].db_name);
+ chan_to_dsp_map[i] = radio_idx;
//extract connection
- const std::string conn = _tree->access<std::string>(root / db_name / "rx_frontends" / fe_name / "connection").get();
-
- //swap condition
- const bool fe_swapped = (conn == "QI" or conn == "Q");
- _mb[mb_i].radio_perifs[i].ddc->set_mux(conn, fe_swapped);
- //see usrp/io_impl.cpp if multiple DSPs share the frontend:
- _mb[mb_i].radio_perifs[i].rx_fe->set_mux(fe_swapped);
+ const std::string conn = _tree->access<std::string>(mb_root / "dboards" / spec[i].db_name / (tx_rx + "_frontends") / spec[i].sd_name / "connection").get();
+
+ if (tx_rx == "tx") {
+ //swap condition
+ _mb[mb_i].radio_perifs[radio_idx].tx_fe->set_mux(conn);
+ } else {
+ //swap condition
+ const bool fe_swapped = (conn == "QI" or conn == "Q");
+ _mb[mb_i].radio_perifs[radio_idx].ddc->set_mux(conn, fe_swapped);
+ //see usrp/io_impl.cpp if multiple DSPs share the frontend:
+ _mb[mb_i].radio_perifs[radio_idx].rx_fe->set_mux(fe_swapped);
+ }
}
- _mb[mb_i].rx_fe_map = spec;
+ _tree->access<std::vector<size_t> >(mb_root / (tx_rx + "_chan_dsp_mapping")).set(chan_to_dsp_map);
}
-void x300_impl::update_tx_subdev_spec(const size_t mb_i, const subdev_spec_t &spec)
-{
- const std::string mb_name = boost::lexical_cast<std::string>(mb_i);
- fs_path root = "/mboards/"+mb_name+"/dboards";
-
- //sanity checking
- validate_subdev_spec(_tree, spec, "tx", mb_name);
- UHD_ASSERT_THROW(spec.size() <= 2);
- if (spec.size() > 0) UHD_ASSERT_THROW(spec[0].db_name == "A");
- if (spec.size() > 1) UHD_ASSERT_THROW(spec[1].db_name == "B");
-
- //set the mux for this spec
- for (size_t i = 0; i < 2; i++)
- {
- //extract db name
- const std::string db_name = (i == 0)? "A" : "B";
- if (i < spec.size()) UHD_ASSERT_THROW(spec[i].db_name == db_name);
-
- //extract fe name
- std::string fe_name;
- if (i < spec.size()) fe_name = spec[i].sd_name;
- else fe_name = _tree->list(root / db_name / "tx_frontends").front();
-
- //extract connection
- const std::string conn = _tree->access<std::string>(root / db_name / "tx_frontends" / fe_name / "connection").get();
-
- //swap condition
- _mb[mb_i].radio_perifs[i].tx_fe->set_mux(conn);
-
- }
-
- _mb[mb_i].tx_fe_map = spec;
-}
/***********************************************************************
* VITA stuff
@@ -375,16 +350,24 @@ rx_streamer::sptr x300_impl::get_rx_stream(const uhd::stream_args_t &args_)
boost::shared_ptr<sph::recv_packet_streamer> my_streamer;
for (size_t stream_i = 0; stream_i < args.channels.size(); stream_i++)
{
+ // Find the mainboard and subdev that corresponds to channel args.channels[stream_i]
const size_t chan = args.channels[stream_i];
- size_t mb_chan = chan, mb_index = 0;
- BOOST_FOREACH(mboard_members_t &mb, _mb)
- {
- if (mb_chan < mb.rx_fe_map.size()) break;
- else mb_chan -= mb.rx_fe_map.size();
- mb_index++;
+ size_t mb_chan = chan, mb_index;
+ for (mb_index = 0; mb_index < _mb.size(); mb_index++) {
+ const subdev_spec_t &curr_subdev_spec =
+ _tree->access<subdev_spec_t>("/mboards/" + boost::lexical_cast<std::string>(mb_index) / "rx_subdev_spec").get();
+ if (mb_chan < curr_subdev_spec.size()) {
+ break;
+ } else {
+ mb_chan -= curr_subdev_spec.size();
+ }
}
+
+ // Find the DSP that corresponds to this mainboard and subdev
mboard_members_t &mb = _mb[mb_index];
- radio_perifs_t &perif = mb.radio_perifs[mb_chan];
+ const size_t radio_index = _tree->access<std::vector<size_t> >("/mboards/" + boost::lexical_cast<std::string>(mb_index) / "rx_chan_dsp_mapping")
+ .get().at(mb_chan);
+ radio_perifs_t &perif = mb.radio_perifs[radio_index];
//setup the dsp transport hints (default to a large recv buff)
device_addr_t device_addr = mb.recv_args;
@@ -405,7 +388,7 @@ rx_streamer::sptr x300_impl::get_rx_stream(const uhd::stream_args_t &args_)
}
//allocate sid and create transport
- uint8_t dest = (mb_chan == 0)? X300_XB_DST_R0 : X300_XB_DST_R1;
+ uint8_t dest = (radio_index == 0)? X300_XB_DST_R0 : X300_XB_DST_R1;
boost::uint32_t data_sid;
UHD_LOG << "creating rx stream " << device_addr.to_string() << std::endl;
both_xports_t xport = this->make_transport(mb_index, dest, X300_RADIO_DEST_PREFIX_RX, device_addr, data_sid);
@@ -419,9 +402,9 @@ rx_streamer::sptr x300_impl::get_rx_stream(const uhd::stream_args_t &args_)
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
- sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
;
- const size_t bpp = xport.recv->get_recv_frame_size() - hdr_size;
- const size_t bpi = convert::get_bytes_per_item(args.otw_format);
- const size_t spp = unsigned(args.args.cast<double>("spp", bpp/bpi));
+ const size_t bpp = xport.recv->get_recv_frame_size() - hdr_size; // bytes per packet
+ const size_t bpi = convert::get_bytes_per_item(args.otw_format); // bytes per item
+ const size_t spp = unsigned(args.args.cast<double>("spp", bpp/bpi)); // samples per packet
//make the new streamer given the samples per packet
if (not my_streamer) my_streamer = boost::make_shared<sph::recv_packet_streamer>(spp);
@@ -488,12 +471,12 @@ rx_streamer::sptr x300_impl::get_rx_stream(const uhd::stream_args_t &args_)
);
//Store a weak pointer to prevent a streamer->x300_impl->streamer circular dependency
- mb.rx_streamers[mb_chan] = boost::weak_ptr<sph::recv_packet_streamer>(my_streamer);
+ mb.rx_streamers[radio_index] = boost::weak_ptr<sph::recv_packet_streamer>(my_streamer);
//sets all tick and samp rates on this streamer
const fs_path mb_path = "/mboards/"+boost::lexical_cast<std::string>(mb_index);
_tree->access<double>(mb_path / "tick_rate").update();
- _tree->access<double>(mb_path / "rx_dsps" / boost::lexical_cast<std::string>(mb_chan) / "rate" / "value").update();
+ _tree->access<double>(mb_path / "rx_dsps" / boost::lexical_cast<std::string>(radio_index) / "rate" / "value").update();
}
return my_streamer;
@@ -552,22 +535,29 @@ tx_streamer::sptr x300_impl::get_tx_stream(const uhd::stream_args_t &args_)
boost::shared_ptr<sph::send_packet_streamer> my_streamer;
for (size_t stream_i = 0; stream_i < args.channels.size(); stream_i++)
{
+ // Find the mainboard and subdev that corresponds to channel args.channels[stream_i]
const size_t chan = args.channels[stream_i];
- size_t mb_chan = chan, mb_index = 0;
- BOOST_FOREACH(mboard_members_t &mb, _mb)
- {
- if (mb_chan < mb.tx_fe_map.size()) break;
- else mb_chan -= mb.tx_fe_map.size();
- mb_index++;
+ size_t mb_chan = chan, mb_index;
+ for (mb_index = 0; mb_index < _mb.size(); mb_index++) {
+ const subdev_spec_t &curr_subdev_spec =
+ _tree->access<subdev_spec_t>("/mboards/" + boost::lexical_cast<std::string>(mb_index) / "tx_subdev_spec").get();
+ if (mb_chan < curr_subdev_spec.size()) {
+ break;
+ } else {
+ mb_chan -= curr_subdev_spec.size();
+ }
}
+ // Find the DSP that corresponds to this mainboard and subdev
mboard_members_t &mb = _mb[mb_index];
- radio_perifs_t &perif = mb.radio_perifs[mb_chan];
+ const size_t radio_index = _tree->access<std::vector<size_t> >("/mboards/" + boost::lexical_cast<std::string>(mb_index) / "tx_chan_dsp_mapping")
+ .get().at(mb_chan);
+ radio_perifs_t &perif = mb.radio_perifs[radio_index];
//setup the dsp transport hints (TODO)
device_addr_t device_addr = mb.send_args;
//allocate sid and create transport
- uint8_t dest = (mb_chan == 0)? X300_XB_DST_R0 : X300_XB_DST_R1;
+ uint8_t dest = (radio_index == 0)? X300_XB_DST_R0 : X300_XB_DST_R1;
boost::uint32_t data_sid;
UHD_LOG << "creating tx stream " << device_addr.to_string() << std::endl;
both_xports_t xport = this->make_transport(mb_index, dest, X300_RADIO_DEST_PREFIX_TX, device_addr, data_sid);
@@ -640,12 +630,12 @@ tx_streamer::sptr x300_impl::get_tx_stream(const uhd::stream_args_t &args_)
my_streamer->set_enable_trailer(false); //TODO not implemented trailer support yet
//Store a weak pointer to prevent a streamer->x300_impl->streamer circular dependency
- mb.tx_streamers[mb_chan] = boost::weak_ptr<sph::send_packet_streamer>(my_streamer);
+ mb.tx_streamers[radio_index] = boost::weak_ptr<sph::send_packet_streamer>(my_streamer);
//sets all tick and samp rates on this streamer
const fs_path mb_path = "/mboards/"+boost::lexical_cast<std::string>(mb_index);
_tree->access<double>(mb_path / "tick_rate").update();
- _tree->access<double>(mb_path / "tx_dsps" / boost::lexical_cast<std::string>(mb_chan) / "rate" / "value").update();
+ _tree->access<double>(mb_path / "tx_dsps" / boost::lexical_cast<std::string>(radio_index) / "rate" / "value").update();
}
return my_streamer;