summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Hilburn <ben.hilburn@ettus.com>2014-03-14 10:58:39 -0700
committerBen Hilburn <ben.hilburn@ettus.com>2014-03-14 10:58:39 -0700
commitbb90f235d65700aa6019a8f6cd38e67e984740f3 (patch)
treeb3d4856602d5340402a718f3961408e9fea83326
parentc34a548633d6e53479083175e99b127e638839b4 (diff)
parentb8d583b3b19c7030c6ecfcc284651755efe0326f (diff)
downloaduhd-bb90f235d65700aa6019a8f6cd38e67e984740f3.tar.gz
uhd-bb90f235d65700aa6019a8f6cd38e67e984740f3.tar.bz2
uhd-bb90f235d65700aa6019a8f6cd38e67e984740f3.zip
Merge branch 'origin/martin/subdev_spec_bug_B'
-rw-r--r--host/lib/usrp/multi_usrp.cpp11
-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
-rw-r--r--host/utils/uhd_cal_rx_iq_balance.cpp18
-rw-r--r--host/utils/uhd_cal_tx_dc_offset.cpp16
-rw-r--r--host/utils/uhd_cal_tx_iq_balance.cpp19
-rw-r--r--host/utils/usrp_cal_utils.hpp31
8 files changed, 221 insertions, 149 deletions
diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp
index d8322a39f..2e82e890e 100644
--- a/host/lib/usrp/multi_usrp.cpp
+++ b/host/lib/usrp/multi_usrp.cpp
@@ -1061,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);
@@ -1075,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 b20897fc6..466827380 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 1fb3676a0..0fe63e4a5 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;
diff --git a/host/utils/uhd_cal_rx_iq_balance.cpp b/host/utils/uhd_cal_rx_iq_balance.cpp
index 5fb494114..551da7544 100644
--- a/host/utils/uhd_cal_rx_iq_balance.cpp
+++ b/host/utils/uhd_cal_rx_iq_balance.cpp
@@ -20,6 +20,7 @@
#include <uhd/utils/safe_main.hpp>
#include <uhd/utils/paths.hpp>
#include <uhd/utils/algorithm.hpp>
+#include <uhd/utils/msg.hpp>
#include <uhd/usrp/multi_usrp.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
@@ -93,7 +94,7 @@ static double tune_rx_and_tx(uhd::usrp::multi_usrp::sptr usrp, const double rx_l
* Main
**********************************************************************/
int UHD_SAFE_MAIN(int argc, char *argv[]){
- std::string args;
+ std::string args, subdev, serial;
double tx_wave_ampl, tx_offset;
double freq_start, freq_stop, freq_step;
size_t nsamps;
@@ -102,7 +103,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
desc.add_options()
("help", "help message")
("verbose", "enable some verbose")
- ("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]")
+ ("args", po::value<std::string>(&args)->default_value(""), "Device address args [default = \"\"]")
+ ("subdev", po::value<std::string>(&subdev), "Subdevice specification (default: first subdevice, often 'A')")
("tx_wave_ampl", po::value<double>(&tx_wave_ampl)->default_value(0.7), "Transmit wave amplitude in counts")
("tx_offset", po::value<double>(&tx_offset)->default_value(.9344e6), "TX LO offset from the RX LO in Hz")
("freq_start", po::value<double>(&freq_start), "Frequency start in Hz (do not specify for default)")
@@ -129,6 +131,15 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
+ // Configure subdev
+ if (vm.count("subdev")) {
+ usrp->set_tx_subdev_spec(subdev);
+ usrp->set_rx_subdev_spec(subdev);
+ }
+ UHD_MSG(status) << "Running calibration for " << usrp->get_tx_subdev_name(0) << std::endl;
+ serial = get_serial(usrp, "tx");
+ UHD_MSG(status) << "Daughterboard serial: " << serial << std::endl;
+
//set the antennas to cal
if (not uhd::has(usrp->get_rx_antennas(), "CAL") or not uhd::has(usrp->get_tx_antennas(), "CAL")){
throw std::runtime_error("This board does not have the CAL antenna option, cannot self-calibrate.");
@@ -158,6 +169,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
if (not vm.count("freq_start")) freq_start = usrp->get_rx_freq_range().start() + 50e6;
if (not vm.count("freq_stop")) freq_stop = usrp->get_rx_freq_range().stop() - 50e6;
+ UHD_MSG(status) << boost::format("Calibration frequency range: %d MHz -> %d MHz") % (freq_start/1e6) % (freq_stop/1e6) << std::endl;
for (double rx_lo_i = freq_start; rx_lo_i <= freq_stop; rx_lo_i += freq_step){
const double rx_lo = tune_rx_and_tx(usrp, rx_lo_i, tx_offset);
@@ -238,7 +250,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
threads.interrupt_all();
threads.join_all();
- store_results(usrp, results, "RX", "rx", "iq");
+ store_results(results, "RX", "rx", "iq", serial);
return EXIT_SUCCESS;
}
diff --git a/host/utils/uhd_cal_tx_dc_offset.cpp b/host/utils/uhd_cal_tx_dc_offset.cpp
index c9cf757f4..eb82db826 100644
--- a/host/utils/uhd_cal_tx_dc_offset.cpp
+++ b/host/utils/uhd_cal_tx_dc_offset.cpp
@@ -20,6 +20,7 @@
#include <uhd/utils/safe_main.hpp>
#include <uhd/utils/paths.hpp>
#include <uhd/utils/algorithm.hpp>
+#include <uhd/utils/msg.hpp>
#include <uhd/usrp/multi_usrp.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
@@ -94,7 +95,7 @@ static double tune_rx_and_tx(uhd::usrp::multi_usrp::sptr usrp, const double tx_l
* Main
**********************************************************************/
int UHD_SAFE_MAIN(int argc, char *argv[]){
- std::string args;
+ std::string args, subdev, serial;
double tx_wave_freq, tx_wave_ampl, rx_offset;
double freq_start, freq_stop, freq_step;
size_t nsamps;
@@ -104,6 +105,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
("help", "help message")
("verbose", "enable some verbose")
("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]")
+ ("subdev", po::value<std::string>(&subdev), "Subdevice specification (default: first subdevice, often 'A')")
("tx_wave_freq", po::value<double>(&tx_wave_freq)->default_value(507.123e3), "Transmit wave frequency in Hz")
("tx_wave_ampl", po::value<double>(&tx_wave_ampl)->default_value(0.7), "Transmit wave amplitude in counts")
("rx_offset", po::value<double>(&rx_offset)->default_value(.9344e6), "RX LO offset from the TX LO in Hz")
@@ -131,6 +133,15 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
+ // Configure subdev
+ if (vm.count("subdev")) {
+ usrp->set_tx_subdev_spec(subdev);
+ usrp->set_rx_subdev_spec(subdev);
+ }
+ UHD_MSG(status) << "Running calibration for " << usrp->get_tx_subdev_name(0) << std::endl;
+ serial = get_serial(usrp, "tx");
+ UHD_MSG(status) << "Daughterboard serial: " << serial << std::endl;
+
//set the antennas to cal
if (not uhd::has(usrp->get_rx_antennas(), "CAL") or not uhd::has(usrp->get_tx_antennas(), "CAL")){
throw std::runtime_error("This board does not have the CAL antenna option, cannot self-calibrate.");
@@ -160,6 +171,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
if (not vm.count("freq_start")) freq_start = usrp->get_tx_freq_range().start() + 50e6;
if (not vm.count("freq_stop")) freq_stop = usrp->get_tx_freq_range().stop() - 50e6;
+ UHD_MSG(status) << boost::format("Calibration frequency range: %d MHz -> %d MHz") % (freq_start/1e6) % (freq_stop/1e6) << std::endl;
for (double tx_lo_i = freq_start; tx_lo_i <= freq_stop; tx_lo_i += freq_step){
const double tx_lo = tune_rx_and_tx(usrp, tx_lo_i, rx_offset);
@@ -235,7 +247,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
threads.interrupt_all();
threads.join_all();
- store_results(usrp, results, "TX", "tx", "dc");
+ store_results(results, "TX", "tx", "dc", serial);
return EXIT_SUCCESS;
}
diff --git a/host/utils/uhd_cal_tx_iq_balance.cpp b/host/utils/uhd_cal_tx_iq_balance.cpp
index 20d018edf..786aac061 100644
--- a/host/utils/uhd_cal_tx_iq_balance.cpp
+++ b/host/utils/uhd_cal_tx_iq_balance.cpp
@@ -20,6 +20,7 @@
#include <uhd/utils/safe_main.hpp>
#include <uhd/utils/paths.hpp>
#include <uhd/utils/algorithm.hpp>
+#include <uhd/utils/msg.hpp>
#include <uhd/usrp/multi_usrp.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
@@ -95,7 +96,7 @@ static double tune_rx_and_tx(uhd::usrp::multi_usrp::sptr usrp, const double tx_l
* Main
**********************************************************************/
int UHD_SAFE_MAIN(int argc, char *argv[]){
- std::string args;
+ std::string args, subdev, serial;
double tx_wave_freq, tx_wave_ampl, rx_offset;
double freq_start, freq_stop, freq_step;
size_t nsamps;
@@ -105,6 +106,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
("help", "help message")
("verbose", "enable some verbose")
("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]")
+ ("subdev", po::value<std::string>(&subdev), "Subdevice specification (default: first subdevice, often 'A')")
("tx_wave_freq", po::value<double>(&tx_wave_freq)->default_value(507.123e3), "Transmit wave frequency in Hz")
("tx_wave_ampl", po::value<double>(&tx_wave_ampl)->default_value(0.7), "Transmit wave amplitude in counts")
("rx_offset", po::value<double>(&rx_offset)->default_value(.9344e6), "RX LO offset from the TX LO in Hz")
@@ -122,7 +124,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
if (vm.count("help")){
std::cout << boost::format("USRP Generate TX IQ Balance Calibration Table %s") % desc << std::endl;
std::cout <<
- "This application measures leakage between RX and TX on an XCVR daughterboard to self-calibrate.\n"
+ "This application measures leakage between RX and TX on a daughterboard to self-calibrate.\n"
<< std::endl;
return EXIT_FAILURE;
}
@@ -132,6 +134,15 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
+ // Configure subdev
+ if (vm.count("subdev")) {
+ usrp->set_tx_subdev_spec(subdev);
+ usrp->set_rx_subdev_spec(subdev);
+ }
+ UHD_MSG(status) << "Running calibration for " << usrp->get_tx_subdev_name(0) << std::endl;
+ serial = get_serial(usrp, "tx");
+ UHD_MSG(status) << "Daughterboard serial: " << serial << std::endl;
+
//set the antennas to cal
if (not uhd::has(usrp->get_rx_antennas(), "CAL") or not uhd::has(usrp->get_tx_antennas(), "CAL")){
throw std::runtime_error("This board does not have the CAL antenna option, cannot self-calibrate.");
@@ -161,6 +172,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
if (not vm.count("freq_start")) freq_start = usrp->get_tx_freq_range().start() + 50e6;
if (not vm.count("freq_stop")) freq_stop = usrp->get_tx_freq_range().stop() - 50e6;
+ UHD_MSG(status) << boost::format("Calibration frequency range: %d MHz -> %d MHz") % (freq_start/1e6) % (freq_stop/1e6) << std::endl;
for (double tx_lo_i = freq_start; tx_lo_i <= freq_stop; tx_lo_i += freq_step){
const double tx_lo = tune_rx_and_tx(usrp, tx_lo_i, rx_offset);
@@ -241,7 +253,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
threads.interrupt_all();
threads.join_all();
- store_results(usrp, results, "TX", "tx", "iq");
+ store_results(results, "TX", "tx", "iq", serial);
return EXIT_SUCCESS;
}
+
diff --git a/host/utils/usrp_cal_utils.hpp b/host/utils/usrp_cal_utils.hpp
index 40626dfaa..5aff5e22f 100644
--- a/host/utils/usrp_cal_utils.hpp
+++ b/host/utils/usrp_cal_utils.hpp
@@ -179,27 +179,37 @@ static inline void write_samples_to_file(
outfile.close();
}
+
/***********************************************************************
- * Store data to file
+ * Retrieve d'board serial
**********************************************************************/
-static void store_results(
+static std::string get_serial(
uhd::usrp::multi_usrp::sptr usrp,
- const std::vector<result_t> &results,
- const std::string &XX,
- const std::string &xx,
- const std::string &what
+ const std::string &tx_rx
){
- //extract eeprom serial
uhd::property_tree::sptr tree = usrp->get_device()->get_tree();
- const uhd::fs_path db_path = "/mboards/0/dboards/A/" + xx + "_eeprom";
+ uhd::usrp::subdev_spec_t subdev_spec = usrp->get_rx_subdev_spec();
+ const uhd::fs_path db_path = "/mboards/0/dboards/" + subdev_spec[0].db_name + "/" + tx_rx + "_eeprom";
const uhd::usrp::dboard_eeprom_t db_eeprom = tree->access<uhd::usrp::dboard_eeprom_t>(db_path).get();
+ return db_eeprom.serial;
+}
+/***********************************************************************
+ * Store data to file
+ **********************************************************************/
+static void store_results(
+ const std::vector<result_t> &results,
+ const std::string &XX, // "TX" or "RX"
+ const std::string &xx, // "tx" or "rx"
+ const std::string &what, // Type of test, e.g. "iq",
+ const std::string &serial
+){
//make the calibration file path
fs::path cal_data_path = fs::path(uhd::get_app_path()) / ".uhd";
fs::create_directory(cal_data_path);
cal_data_path = cal_data_path / "cal";
fs::create_directory(cal_data_path);
- cal_data_path = cal_data_path / str(boost::format("%s_%s_cal_v0.2_%s.csv") % xx % what % db_eeprom.serial);
+ cal_data_path = cal_data_path / str(boost::format("%s_%s_cal_v0.2_%s.csv") % xx % what % serial);
if (fs::exists(cal_data_path)){
fs::rename(cal_data_path, cal_data_path.string() + str(boost::format(".%d") % time(NULL)));
}
@@ -207,7 +217,7 @@ static void store_results(
//fill the calibration file
std::ofstream cal_data(cal_data_path.string().c_str());
cal_data << boost::format("name, %s Frontend Calibration\n") % XX;
- cal_data << boost::format("serial, %s\n") % db_eeprom.serial;
+ cal_data << boost::format("serial, %s\n") % serial;
cal_data << boost::format("timestamp, %d\n") % time(NULL);
cal_data << boost::format("version, 0, 1\n");
cal_data << boost::format("DATA STARTS HERE\n");
@@ -259,3 +269,4 @@ static void capture_samples(
throw std::runtime_error("did not get all the samples requested");
}
}
+