aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp')
-rw-r--r--host/lib/usrp/dboard/basic.cpp270
-rw-r--r--host/lib/usrp/dboard/dboards.hpp53
-rw-r--r--host/lib/usrp/dboard_id.cpp34
-rw-r--r--host/lib/usrp/dboard_manager.cpp163
-rw-r--r--host/lib/usrp/usrp1e/usrp1e_impl.cpp11
-rw-r--r--host/lib/usrp/usrp2/dboard_impl.cpp13
-rw-r--r--host/lib/usrp/usrp2/dsp_impl.cpp71
-rw-r--r--host/lib/usrp/usrp2/fw_common.h14
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp329
-rw-r--r--host/lib/usrp/usrp2/mboard_impl.cpp125
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp82
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp37
12 files changed, 757 insertions, 445 deletions
diff --git a/host/lib/usrp/dboard/basic.cpp b/host/lib/usrp/dboard/basic.cpp
index f39ebff2f..095b77ce1 100644
--- a/host/lib/usrp/dboard/basic.cpp
+++ b/host/lib/usrp/dboard/basic.cpp
@@ -15,42 +15,282 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include "dboards.hpp"
+#include <uhd/utils.hpp>
+#include <uhd/props.hpp>
+#include <uhd/usrp/dboard_base.hpp>
+#include <uhd/usrp/dboard_manager.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/format.hpp>
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace boost::assign;
/***********************************************************************
- * Basic RX dboard
+ * The basic and lf boards:
+ * They share a common class because only the frequency bounds differ.
**********************************************************************/
-basic_rx::basic_rx(ctor_args_t const& args) : rx_dboard_base(args){
- /* NOP */
+class basic_rx : public rx_dboard_base{
+public:
+ basic_rx(ctor_args_t const& args, freq_t max_freq);
+ ~basic_rx(void);
+
+ void rx_get(const wax::obj &key, wax::obj &val);
+ void rx_set(const wax::obj &key, const wax::obj &val);
+
+private:
+ freq_t _max_freq;
+};
+
+class basic_tx : public tx_dboard_base{
+public:
+ basic_tx(ctor_args_t const& args, freq_t max_freq);
+ ~basic_tx(void);
+
+ void tx_get(const wax::obj &key, wax::obj &val);
+ void tx_set(const wax::obj &key, const wax::obj &val);
+
+private:
+ freq_t _max_freq;
+};
+
+/***********************************************************************
+ * Register the basic and LF dboards
+ **********************************************************************/
+static dboard_base::sptr make_basic_rx(dboard_base::ctor_args_t const& args){
+ return dboard_base::sptr(new basic_rx(args, 90e9));
+}
+
+static dboard_base::sptr make_basic_tx(dboard_base::ctor_args_t const& args){
+ return dboard_base::sptr(new basic_tx(args, 90e9));
+}
+
+static dboard_base::sptr make_lf_rx(dboard_base::ctor_args_t const& args){
+ return dboard_base::sptr(new basic_rx(args, 32e6));
+}
+
+static dboard_base::sptr make_lf_tx(dboard_base::ctor_args_t const& args){
+ return dboard_base::sptr(new basic_tx(args, 32e6));
+}
+
+STATIC_BLOCK(reg_dboards){
+ dboard_manager::register_dboard(0x0000, &make_basic_tx, "Basic TX", list_of(""));
+ dboard_manager::register_dboard(0x0001, &make_basic_rx, "Basic RX", list_of("a")("b")("ab"));
+ dboard_manager::register_dboard(0x000e, &make_lf_tx, "LF TX", list_of(""));
+ dboard_manager::register_dboard(0x000f, &make_lf_rx, "LF RX", list_of("a")("b")("ab"));
+}
+
+/***********************************************************************
+ * Basic and LF RX dboard
+ **********************************************************************/
+basic_rx::basic_rx(ctor_args_t const& args, freq_t max_freq) : rx_dboard_base(args){
+ _max_freq = max_freq;
+ // set the gpios to safe values (all inputs)
+ get_interface()->set_gpio_ddr(dboard_interface::GPIO_RX_BANK, 0x0000, 0xffff);
}
basic_rx::~basic_rx(void){
/* NOP */
}
-void basic_rx::rx_get(const wax::obj &, wax::obj &){
- /* TODO */
+void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+ case SUBDEV_PROP_NAME:
+ val = std::string(str(boost::format("%s:%s")
+ % dboard_id::to_string(get_rx_id())
+ % get_subdev_name()
+ ));
+ return;
+
+ case SUBDEV_PROP_OTHERS:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ val = gain_t(0);
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ val = gain_range_t(0, 0, 0);
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = freq_t(0);
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = freq_range_t(+_max_freq, -_max_freq);
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = std::string("");
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ val = prop_names_t(1, ""); //vector of 1 empty string
+ return;
+
+ case SUBDEV_PROP_ENABLED:
+ val = true; //always enabled
+ return;
+
+ case SUBDEV_PROP_QUADRATURE:
+ val = (get_subdev_name() == "ab"); //only quadrature in ab mode
+ return;
+
+ case SUBDEV_PROP_IQ_SWAPPED:
+ case SUBDEV_PROP_SPECTRUM_INVERTED:
+ case SUBDEV_PROP_LO_INTERFERES:
+ val = false;
+ return;
+ }
}
-void basic_rx::rx_set(const wax::obj &, const wax::obj &){
- /* TODO */
+void basic_rx::rx_set(const wax::obj &key_, const wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+
+ case SUBDEV_PROP_GAIN:
+ ASSERT_THROW(val.as<gain_t>() == gain_t(0));
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ ASSERT_THROW(val.as<std::string>() == std::string(""));
+ return;
+
+ case SUBDEV_PROP_ENABLED:
+ return; // it wont do you much good, but you can set it
+
+ case SUBDEV_PROP_NAME:
+ case SUBDEV_PROP_OTHERS:
+ case SUBDEV_PROP_GAIN_RANGE:
+ case SUBDEV_PROP_GAIN_NAMES:
+ case SUBDEV_PROP_FREQ:
+ case SUBDEV_PROP_FREQ_RANGE:
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ case SUBDEV_PROP_QUADRATURE:
+ case SUBDEV_PROP_IQ_SWAPPED:
+ case SUBDEV_PROP_SPECTRUM_INVERTED:
+ case SUBDEV_PROP_LO_INTERFERES:
+ throw std::runtime_error(str(boost::format(
+ "Error: trying to set read-only property on %s subdev"
+ ) % dboard_id::to_string(get_rx_id())));
+ }
}
/***********************************************************************
- * Basic TX dboard
+ * Basic and LF TX dboard
**********************************************************************/
-basic_tx::basic_tx(ctor_args_t const& args) : tx_dboard_base(args){
- /* NOP */
+basic_tx::basic_tx(ctor_args_t const& args, freq_t max_freq) : tx_dboard_base(args){
+ _max_freq = max_freq;
+ // set the gpios to safe values (all inputs)
+ get_interface()->set_gpio_ddr(dboard_interface::GPIO_TX_BANK, 0x0000, 0xffff);
}
basic_tx::~basic_tx(void){
/* NOP */
}
-void basic_tx::tx_get(const wax::obj &, wax::obj &){
- /* TODO */
+void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+ case SUBDEV_PROP_NAME:
+ val = dboard_id::to_string(get_tx_id());
+ return;
+
+ case SUBDEV_PROP_OTHERS:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ val = gain_t(0);
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ val = gain_range_t(0, 0, 0);
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = freq_t(0);
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = freq_range_t(+_max_freq, -_max_freq);
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = std::string("");
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ val = prop_names_t(1, ""); //vector of 1 empty string
+ return;
+
+ case SUBDEV_PROP_ENABLED:
+ val = true; //always enabled
+ return;
+
+ case SUBDEV_PROP_QUADRATURE:
+ val = true;
+ return;
+
+ case SUBDEV_PROP_IQ_SWAPPED:
+ case SUBDEV_PROP_SPECTRUM_INVERTED:
+ case SUBDEV_PROP_LO_INTERFERES:
+ val = false;
+ return;
+ }
}
-void basic_tx::tx_set(const wax::obj &, const wax::obj &){
- /* TODO */
+void basic_tx::tx_set(const wax::obj &key_, const wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+
+ case SUBDEV_PROP_GAIN:
+ ASSERT_THROW(val.as<gain_t>() == gain_t(0));
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ ASSERT_THROW(val.as<std::string>() == std::string(""));
+ return;
+
+ case SUBDEV_PROP_ENABLED:
+ return; // it wont do you much good, but you can set it
+
+ case SUBDEV_PROP_NAME:
+ case SUBDEV_PROP_OTHERS:
+ case SUBDEV_PROP_GAIN_RANGE:
+ case SUBDEV_PROP_GAIN_NAMES:
+ case SUBDEV_PROP_FREQ:
+ case SUBDEV_PROP_FREQ_RANGE:
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ case SUBDEV_PROP_QUADRATURE:
+ case SUBDEV_PROP_IQ_SWAPPED:
+ case SUBDEV_PROP_SPECTRUM_INVERTED:
+ case SUBDEV_PROP_LO_INTERFERES:
+ throw std::runtime_error(str(boost::format(
+ "Error: trying to set read-only property on %s subdev"
+ ) % dboard_id::to_string(get_tx_id())));
+ }
}
diff --git a/host/lib/usrp/dboard/dboards.hpp b/host/lib/usrp/dboard/dboards.hpp
deleted file mode 100644
index 79b90d593..000000000
--- a/host/lib/usrp/dboard/dboards.hpp
+++ /dev/null
@@ -1,53 +0,0 @@
-//
-// Copyright 2010 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
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//
-
-#ifndef INCLUDED_LOCAL_DBOARDS_HPP
-#define INCLUDED_LOCAL_DBOARDS_HPP
-
-#include <uhd/usrp/dboard_base.hpp>
-
-using namespace uhd::usrp;
-
-/***********************************************************************
- * The basic boards:
- **********************************************************************/
-class basic_rx : public rx_dboard_base{
-public:
- static dboard_base::sptr make(ctor_args_t const& args){
- return dboard_base::sptr(new basic_rx(args));
- }
- basic_rx(ctor_args_t const& args);
- ~basic_rx(void);
-
- void rx_get(const wax::obj &key, wax::obj &val);
- void rx_set(const wax::obj &key, const wax::obj &val);
-};
-
-class basic_tx : public tx_dboard_base{
-public:
- static dboard_base::sptr make(ctor_args_t const& args){
- return dboard_base::sptr(new basic_tx(args));
- }
- basic_tx(ctor_args_t const& args);
- ~basic_tx(void);
-
- void tx_get(const wax::obj &key, wax::obj &val);
- void tx_set(const wax::obj &key, const wax::obj &val);
-
-};
-
-#endif /* INCLUDED_LOCAL_DBOARDS_HPP */
diff --git a/host/lib/usrp/dboard_id.cpp b/host/lib/usrp/dboard_id.cpp
deleted file mode 100644
index d2ef7cd7d..000000000
--- a/host/lib/usrp/dboard_id.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-//
-// Copyright 2010 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
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//
-
-#include <uhd/usrp/dboard_id.hpp>
-#include <boost/format.hpp>
-#include <uhd/dict.hpp>
-
-using namespace uhd::usrp;
-
-std::string dboard_id::to_string(const dboard_id_t &id){
- //map the dboard ids to string representations
- uhd::dict<dboard_id_t, std::string> id_to_str;
- id_to_str[ID_NONE] = "none";
- id_to_str[ID_BASIC_TX] = "basic tx";
- id_to_str[ID_BASIC_RX] = "basic rx";
-
- //get the string representation
- std::string name = (id_to_str.has_key(id))? id_to_str[id] : "unknown";
- return str(boost::format("%s (0x%.4x)") % name % id);
-}
diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp
index cce239f3e..eeabbda99 100644
--- a/host/lib/usrp/dboard_manager.cpp
+++ b/host/lib/usrp/dboard_manager.cpp
@@ -16,87 +16,49 @@
//
#include <uhd/usrp/dboard_manager.hpp>
+#include <uhd/gain_handler.hpp>
#include <uhd/utils.hpp>
#include <uhd/dict.hpp>
-#include <boost/assign/list_of.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/format.hpp>
+#include <boost/bind.hpp>
#include <boost/foreach.hpp>
-#include "dboard/dboards.hpp"
using namespace uhd;
using namespace uhd::usrp;
-using namespace boost::assign;
-
-/***********************************************************************
- * register internal dboards
- *
- * Register internal/known dboards located in this build tree.
- * Each board should have entries below mapping an id to a constructor.
- * The xcvr type boards should register both rx and tx sides.
- *
- * This function will be called before new boards are registered.
- * This allows for internal boards to be externally overridden.
- * This function will also be called when creating a new dboard_manager
- * to ensure that the maps are filled with the entries below.
- **********************************************************************/
-static void register_internal_dboards(void){
- //ensure that this function can only be called once per instance
- static bool called = false;
- if (called) return; called = true;
- //register the known dboards (dboard id, constructor, subdev names)
- dboard_manager::register_subdevs(ID_BASIC_TX, &basic_tx::make, list_of(""));
- dboard_manager::register_subdevs(ID_BASIC_RX, &basic_rx::make, list_of("a")("b")("ab"));
-}
/***********************************************************************
* storage and registering for dboards
**********************************************************************/
-typedef boost::tuple<dboard_manager::dboard_ctor_t, prop_names_t> args_t;
+//dboard registry tuple: dboard constructor, canonical name, subdev names
+typedef boost::tuple<dboard_manager::dboard_ctor_t, std::string, prop_names_t> args_t;
//map a dboard id to a dboard constructor
-static uhd::dict<dboard_id_t, args_t> id_to_args_map;
+typedef uhd::dict<dboard_id_t, args_t> id_to_args_map_t;
+STATIC_INSTANCE(id_to_args_map_t, get_id_to_args_map)
-void dboard_manager::register_subdevs(
+void dboard_manager::register_dboard(
dboard_id_t dboard_id,
dboard_ctor_t dboard_ctor,
+ const std::string &name,
const prop_names_t &subdev_names
){
- register_internal_dboards(); //always call first
- id_to_args_map[dboard_id] = args_t(dboard_ctor, subdev_names);
+ //std::cout << "registering: " << name << std::endl;
+ if (get_id_to_args_map().has_key(dboard_id)){
+ throw std::runtime_error(str(boost::format(
+ "The dboard id 0x%.4x is already registered to %s."
+ ) % dboard_id % dboard_id::to_string(dboard_id)));
+ }
+ get_id_to_args_map()[dboard_id] = args_t(dboard_ctor, name, subdev_names);
}
-/***********************************************************************
- * dboard manager implementation class
- **********************************************************************/
-class dboard_manager_impl : public dboard_manager{
-
-public:
- dboard_manager_impl(
- dboard_id_t rx_dboard_id,
- dboard_id_t tx_dboard_id,
- dboard_interface::sptr interface
- );
- ~dboard_manager_impl(void);
-
- //dboard_interface
- prop_names_t get_rx_subdev_names(void);
- prop_names_t get_tx_subdev_names(void);
- wax::obj get_rx_subdev(const std::string &subdev_name);
- wax::obj get_tx_subdev(const std::string &subdev_name);
-
-private:
- //list of rx and tx dboards in this dboard_manager
- //each dboard here is actually a subdevice proxy
- //the subdevice proxy is internal to the cpp file
- uhd::dict<std::string, wax::obj> _rx_dboards;
- uhd::dict<std::string, wax::obj> _tx_dboards;
- dboard_interface::sptr _interface;
- void set_nice_gpio_pins(void);
-};
+std::string dboard_id::to_string(const dboard_id_t &id){
+ std::string name = (get_id_to_args_map().has_key(id))? get_id_to_args_map()[id].get<1>() : "unknown";
+ return str(boost::format("%s (0x%.4x)") % name % id);
+}
/***********************************************************************
- * internal helper classes
+ * internal helper classe
**********************************************************************/
/*!
* A special wax proxy object that forwards calls to a subdev.
@@ -110,7 +72,17 @@ public:
//structors
subdev_proxy(dboard_base::sptr subdev, type_t type)
: _subdev(subdev), _type(type){
- /* NOP */
+ //initialize gain props struct
+ gain_handler::props_t gain_props;
+ gain_props.value = SUBDEV_PROP_GAIN;
+ gain_props.range = SUBDEV_PROP_GAIN_RANGE;
+ gain_props.names = SUBDEV_PROP_GAIN_NAMES;
+
+ //make a new gain handler
+ _gain_handler = gain_handler::make(
+ this->get_link(), gain_props,
+ boost::bind(&gain_handler::is_equal<subdev_prop_t>, _1, _2)
+ );
}
~subdev_proxy(void){
@@ -118,11 +90,13 @@ public:
}
private:
+ gain_handler::sptr _gain_handler;
dboard_base::sptr _subdev;
type_t _type;
//forward the get calls to the rx or tx
void get(const wax::obj &key, wax::obj &val){
+ if (_gain_handler->intercept_get(key, val)) return;
switch(_type){
case RX_TYPE: return _subdev->rx_get(key, val);
case TX_TYPE: return _subdev->tx_get(key, val);
@@ -131,6 +105,7 @@ private:
//forward the set calls to the rx or tx
void set(const wax::obj &key, const wax::obj &val){
+ if (_gain_handler->intercept_set(key, val)) return;
switch(_type){
case RX_TYPE: return _subdev->rx_set(key, val);
case TX_TYPE: return _subdev->tx_set(key, val);
@@ -139,6 +114,35 @@ private:
};
/***********************************************************************
+ * dboard manager implementation class
+ **********************************************************************/
+class dboard_manager_impl : public dboard_manager{
+
+public:
+ dboard_manager_impl(
+ dboard_id_t rx_dboard_id,
+ dboard_id_t tx_dboard_id,
+ dboard_interface::sptr interface
+ );
+ ~dboard_manager_impl(void);
+
+ //dboard_interface
+ prop_names_t get_rx_subdev_names(void);
+ prop_names_t get_tx_subdev_names(void);
+ wax::obj get_rx_subdev(const std::string &subdev_name);
+ wax::obj get_tx_subdev(const std::string &subdev_name);
+
+private:
+ //list of rx and tx dboards in this dboard_manager
+ //each dboard here is actually a subdevice proxy
+ //the subdevice proxy is internal to the cpp file
+ uhd::dict<std::string, subdev_proxy::sptr> _rx_dboards;
+ uhd::dict<std::string, subdev_proxy::sptr> _tx_dboards;
+ dboard_interface::sptr _interface;
+ void set_nice_gpio_pins(void);
+};
+
+/***********************************************************************
* make routine for dboard manager
**********************************************************************/
dboard_manager::sptr dboard_manager::make(
@@ -160,16 +164,16 @@ static args_t get_dboard_args(
){
//special case, its rx and the none id (0xffff)
if (xx_type == "rx" and dboard_id == ID_NONE){
- return args_t(&basic_rx::make, list_of("ab"));
+ return get_dboard_args(0x0001, xx_type);
}
//special case, its tx and the none id (0xffff)
if (xx_type == "tx" and dboard_id == ID_NONE){
- return args_t(&basic_tx::make, list_of(""));
+ return get_dboard_args(0x0000, xx_type);
}
//verify that there is a registered constructor for this id
- if (not id_to_args_map.has_key(dboard_id)){
+ if (not get_id_to_args_map().has_key(dboard_id)){
throw std::runtime_error(str(
boost::format("Unregistered %s dboard id: %s")
% xx_type % dboard_id::to_string(dboard_id)
@@ -177,7 +181,7 @@ static args_t get_dboard_args(
}
//return the dboard args for this id
- return id_to_args_map[dboard_id];
+ return get_id_to_args_map()[dboard_id];
}
dboard_manager_impl::dboard_manager_impl(
@@ -185,14 +189,13 @@ dboard_manager_impl::dboard_manager_impl(
dboard_id_t tx_dboard_id,
dboard_interface::sptr interface
){
- register_internal_dboards(); //always call first
_interface = interface;
- dboard_ctor_t rx_dboard_ctor; prop_names_t rx_subdevs;
- boost::tie(rx_dboard_ctor, rx_subdevs) = get_dboard_args(rx_dboard_id, "rx");
+ dboard_ctor_t rx_dboard_ctor; std::string rx_name; prop_names_t rx_subdevs;
+ boost::tie(rx_dboard_ctor, rx_name, rx_subdevs) = get_dboard_args(rx_dboard_id, "rx");
- dboard_ctor_t tx_dboard_ctor; prop_names_t tx_subdevs;
- boost::tie(tx_dboard_ctor, tx_subdevs) = get_dboard_args(tx_dboard_id, "tx");
+ dboard_ctor_t tx_dboard_ctor; std::string tx_name; prop_names_t tx_subdevs;
+ boost::tie(tx_dboard_ctor, tx_name, tx_subdevs) = get_dboard_args(tx_dboard_id, "tx");
//initialize the gpio pins before creating subdevs
set_nice_gpio_pins();
@@ -200,16 +203,16 @@ dboard_manager_impl::dboard_manager_impl(
//make xcvr subdevs (make one subdev for both rx and tx dboards)
if (rx_dboard_ctor == tx_dboard_ctor){
ASSERT_THROW(rx_subdevs == tx_subdevs);
- BOOST_FOREACH(std::string name, rx_subdevs){
+ BOOST_FOREACH(std::string subdev, rx_subdevs){
dboard_base::sptr xcvr_dboard = rx_dboard_ctor(
- dboard_base::ctor_args_t(name, interface, rx_dboard_id, tx_dboard_id)
+ dboard_base::ctor_args_t(subdev, interface, rx_dboard_id, tx_dboard_id)
);
//create a rx proxy for this xcvr board
- _rx_dboards[name] = subdev_proxy::sptr(
+ _rx_dboards[subdev] = subdev_proxy::sptr(
new subdev_proxy(xcvr_dboard, subdev_proxy::RX_TYPE)
);
//create a tx proxy for this xcvr board
- _tx_dboards[name] = subdev_proxy::sptr(
+ _tx_dboards[subdev] = subdev_proxy::sptr(
new subdev_proxy(xcvr_dboard, subdev_proxy::TX_TYPE)
);
}
@@ -218,22 +221,22 @@ dboard_manager_impl::dboard_manager_impl(
//make tx and rx subdevs (separate subdevs for rx and tx dboards)
else{
//make the rx subdevs
- BOOST_FOREACH(std::string name, rx_subdevs){
+ BOOST_FOREACH(std::string subdev, rx_subdevs){
dboard_base::sptr rx_dboard = rx_dboard_ctor(
- dboard_base::ctor_args_t(name, interface, rx_dboard_id, ID_NONE)
+ dboard_base::ctor_args_t(subdev, interface, rx_dboard_id, ID_NONE)
);
//create a rx proxy for this rx board
- _rx_dboards[name] = subdev_proxy::sptr(
+ _rx_dboards[subdev] = subdev_proxy::sptr(
new subdev_proxy(rx_dboard, subdev_proxy::RX_TYPE)
);
}
//make the tx subdevs
- BOOST_FOREACH(std::string name, tx_subdevs){
+ BOOST_FOREACH(std::string subdev, tx_subdevs){
dboard_base::sptr tx_dboard = tx_dboard_ctor(
- dboard_base::ctor_args_t(name, interface, ID_NONE, tx_dboard_id)
+ dboard_base::ctor_args_t(subdev, interface, ID_NONE, tx_dboard_id)
);
//create a tx proxy for this tx board
- _tx_dboards[name] = subdev_proxy::sptr(
+ _tx_dboards[subdev] = subdev_proxy::sptr(
new subdev_proxy(tx_dboard, subdev_proxy::TX_TYPE)
);
}
@@ -257,7 +260,7 @@ wax::obj dboard_manager_impl::get_rx_subdev(const std::string &subdev_name){
str(boost::format("Unknown rx subdev name %s") % subdev_name)
);
//get a link to the rx subdev proxy
- return wax::cast<subdev_proxy::sptr>(_rx_dboards[subdev_name])->get_link();
+ return _rx_dboards[subdev_name]->get_link();
}
wax::obj dboard_manager_impl::get_tx_subdev(const std::string &subdev_name){
@@ -265,7 +268,7 @@ wax::obj dboard_manager_impl::get_tx_subdev(const std::string &subdev_name){
str(boost::format("Unknown tx subdev name %s") % subdev_name)
);
//get a link to the tx subdev proxy
- return wax::cast<subdev_proxy::sptr>(_tx_dboards[subdev_name])->get_link();
+ return _tx_dboards[subdev_name]->get_link();
}
void dboard_manager_impl::set_nice_gpio_pins(void){
diff --git a/host/lib/usrp/usrp1e/usrp1e_impl.cpp b/host/lib/usrp/usrp1e/usrp1e_impl.cpp
index 93265ab17..441f6d060 100644
--- a/host/lib/usrp/usrp1e/usrp1e_impl.cpp
+++ b/host/lib/usrp/usrp1e/usrp1e_impl.cpp
@@ -15,18 +15,23 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include <unistd.h>
+#include <uhd/utils.hpp>
#include <boost/format.hpp>
+#include <boost/filesystem.hpp>
#include "usrp1e_impl.hpp"
using namespace uhd;
using namespace uhd::usrp;
+STATIC_BLOCK(register_usrp1e_device){
+ device::register_device(&usrp1e::discover, &usrp1e::make);
+}
+
/***********************************************************************
* Helper Functions
**********************************************************************/
static bool file_exists(const std::string &file_path){
- return access(file_path.c_str(), F_OK) == 0;
+ return boost::filesystem::exists(file_path);
}
/***********************************************************************
@@ -40,7 +45,6 @@ device_addrs_t usrp1e::discover(const device_addr_t &device_addr){
if (not file_exists(device_addr["node"])) return usrp1e_addrs;
device_addr_t new_addr;
new_addr["name"] = "USRP1E";
- new_addr["type"] = "usrp1e";
new_addr["node"] = device_addr["node"];
usrp1e_addrs.push_back(new_addr);
}
@@ -52,7 +56,6 @@ device_addrs_t usrp1e::discover(const device_addr_t &device_addr){
if (not file_exists(node)) continue;
device_addr_t new_addr;
new_addr["name"] = "USRP1E";
- new_addr["type"] = "usrp1e";
new_addr["node"] = node;
usrp1e_addrs.push_back(new_addr);
}
diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp
index 32c64f541..6d957436e 100644
--- a/host/lib/usrp/usrp2/dboard_impl.cpp
+++ b/host/lib/usrp/usrp2/dboard_impl.cpp
@@ -16,6 +16,7 @@
//
#include <uhd/utils.hpp>
+#include <boost/format.hpp>
#include "usrp2_impl.hpp"
#include "dboard_interface.hpp"
@@ -70,7 +71,7 @@ void usrp2_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){
boost::tie(key, name) = extract_named_prop(key_);
//handle the get request conditioned on the key
- switch(wax::cast<dboard_prop_t>(key)){
+ switch(key.as<dboard_prop_t>()){
case DBOARD_PROP_NAME:
val = std::string("usrp2 dboard (rx unit)");
return;
@@ -83,8 +84,8 @@ void usrp2_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){
val = _dboard_manager->get_rx_subdev_names();
return;
- case DBOARD_PROP_CODEC:
- throw std::runtime_error("unhandled prop in usrp2 dboard");
+ //case DBOARD_PROP_CODEC:
+ // throw std::runtime_error("unhandled prop in usrp2 dboard");
}
}
@@ -100,7 +101,7 @@ void usrp2_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){
boost::tie(key, name) = extract_named_prop(key_);
//handle the get request conditioned on the key
- switch(wax::cast<dboard_prop_t>(key)){
+ switch(key.as<dboard_prop_t>()){
case DBOARD_PROP_NAME:
val = std::string("usrp2 dboard (tx unit)");
return;
@@ -113,8 +114,8 @@ void usrp2_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){
val = _dboard_manager->get_tx_subdev_names();
return;
- case DBOARD_PROP_CODEC:
- throw std::runtime_error("unhandled prop in usrp2 dboard");
+ //case DBOARD_PROP_CODEC:
+ // throw std::runtime_error("unhandled prop in usrp2 dboard");
}
}
diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp
index 22c00d99a..7520c1757 100644
--- a/host/lib/usrp/usrp2/dsp_impl.cpp
+++ b/host/lib/usrp/usrp2/dsp_impl.cpp
@@ -16,11 +16,15 @@
//
#include <uhd/utils.hpp>
+#include <boost/format.hpp>
#include <boost/assign/list_of.hpp>
#include "usrp2_impl.hpp"
using namespace uhd;
+static const size_t default_decim = 16;
+static const size_t default_interp = 16;
+
/***********************************************************************
* DDC Helper Methods
**********************************************************************/
@@ -36,6 +40,10 @@ static uint32_t calculate_freq_word_and_update_actual_freq(freq_t &freq, freq_t
return freq_word;
}
+static uint32_t calculate_iq_scale_word(int16_t i, int16_t q){
+ return (uint16_t(i) << 16) | (uint16_t(q) << 0);
+}
+
void usrp2_impl::init_ddc_config(void){
//create the ddc in the rx dsp dict
_rx_dsps["ddc0"] = wax_obj_proxy(
@@ -44,7 +52,7 @@ void usrp2_impl::init_ddc_config(void){
);
//initial config and update
- _ddc_decim = 16;
+ _ddc_decim = default_decim;
_ddc_freq = 0;
update_ddc_config();
@@ -61,6 +69,10 @@ void usrp2_impl::update_ddc_config(void){
calculate_freq_word_and_update_actual_freq(_ddc_freq, get_master_clock_freq())
);
out_data.data.ddc_args.decim = htonl(_ddc_decim);
+ static const uint32_t default_rx_scale_iq = 1024;
+ out_data.data.ddc_args.scale_iq = htonl(
+ calculate_iq_scale_word(default_rx_scale_iq, default_rx_scale_iq)
+ );
//send and recv
usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
@@ -74,6 +86,7 @@ void usrp2_impl::update_ddc_enabled(void){
out_data.data.streaming.enabled = (_ddc_enabled)? 1 : 0;
out_data.data.streaming.secs = htonl(_ddc_stream_at.secs);
out_data.data.streaming.ticks = htonl(_ddc_stream_at.ticks);
+ out_data.data.streaming.samples = htonl(_max_rx_samples_per_packet);
//send and recv
usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
@@ -89,7 +102,7 @@ void usrp2_impl::update_ddc_enabled(void){
void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){
//handle the case where the key is an expected dsp property
if (key.type() == typeid(dsp_prop_t)){
- switch(wax::cast<dsp_prop_t>(key)){
+ switch(key.as<dsp_prop_t>()){
case DSP_PROP_NAME:
val = std::string("usrp2 ddc0");
return;
@@ -98,7 +111,7 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){
prop_names_t others = boost::assign::list_of
("rate")
("decim")
- ("decim_rates")
+ ("decims")
("freq")
("enabled")
("stream_at")
@@ -110,7 +123,7 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){
}
//handle string-based properties specific to this dsp
- std::string key_name = wax::cast<std::string>(key);
+ std::string key_name = key.as<std::string>();
if (key_name == "rate"){
val = get_master_clock_freq();
return;
@@ -119,7 +132,7 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){
val = _ddc_decim;
return;
}
- else if (key_name == "decim_rates"){
+ else if (key_name == "decims"){
val = _allowed_decim_and_interp_rates;
return;
}
@@ -139,20 +152,19 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){
void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){
//handle string-based properties specific to this dsp
- std::string key_name = wax::cast<std::string>(key);
+ std::string key_name = key.as<std::string>();
if (key_name == "decim"){
- size_t new_decim = wax::cast<size_t>(val);
- ASSERT_THROW(std::has(
- _allowed_decim_and_interp_rates.begin(),
- _allowed_decim_and_interp_rates.end(),
- new_decim
- ));
+ size_t new_decim = val.as<size_t>();
+ assert_has(
+ _allowed_decim_and_interp_rates,
+ new_decim, "usrp2 decimation"
+ );
_ddc_decim = new_decim; //shadow
update_ddc_config();
return;
}
else if (key_name == "freq"){
- freq_t new_freq = wax::cast<freq_t>(val);
+ freq_t new_freq = val.as<freq_t>();
ASSERT_THROW(new_freq <= get_master_clock_freq()/2.0);
ASSERT_THROW(new_freq >= -get_master_clock_freq()/2.0);
_ddc_freq = new_freq; //shadow
@@ -160,13 +172,13 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){
return;
}
else if (key_name == "enabled"){
- bool new_enabled = wax::cast<bool>(val);
+ bool new_enabled = val.as<bool>();
_ddc_enabled = new_enabled; //shadow
update_ddc_enabled();
return;
}
else if (key_name == "stream_at"){
- time_spec_t new_stream_at = wax::cast<time_spec_t>(val);
+ time_spec_t new_stream_at = val.as<time_spec_t>();
_ddc_stream_at = new_stream_at; //shadow
//update_ddc_enabled(); //dont update from here
return;
@@ -188,7 +200,7 @@ void usrp2_impl::init_duc_config(void){
);
//initial config and update
- _duc_interp = 16;
+ _duc_interp = default_interp;
_duc_freq = 0;
update_duc_config();
}
@@ -209,7 +221,9 @@ void usrp2_impl::update_duc_config(void){
calculate_freq_word_and_update_actual_freq(_duc_freq, get_master_clock_freq())
);
out_data.data.duc_args.interp = htonl(_duc_interp);
- out_data.data.duc_args.scale_iq = htonl(scale);
+ out_data.data.duc_args.scale_iq = htonl(
+ calculate_iq_scale_word(scale, scale)
+ );
//send and recv
usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
@@ -222,7 +236,7 @@ void usrp2_impl::update_duc_config(void){
void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){
//handle the case where the key is an expected dsp property
if (key.type() == typeid(dsp_prop_t)){
- switch(wax::cast<dsp_prop_t>(key)){
+ switch(key.as<dsp_prop_t>()){
case DSP_PROP_NAME:
val = std::string("usrp2 duc0");
return;
@@ -231,7 +245,7 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){
prop_names_t others = boost::assign::list_of
("rate")
("interp")
- ("interp_rates")
+ ("interps")
("freq")
;
val = others;
@@ -241,7 +255,7 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){
}
//handle string-based properties specific to this dsp
- std::string key_name = wax::cast<std::string>(key);
+ std::string key_name = key.as<std::string>();
if (key_name == "rate"){
val = get_master_clock_freq();
return;
@@ -250,7 +264,7 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){
val = _duc_interp;
return;
}
- else if (key_name == "interp_rates"){
+ else if (key_name == "interps"){
val = _allowed_decim_and_interp_rates;
return;
}
@@ -266,20 +280,19 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){
void usrp2_impl::duc_set(const wax::obj &key, const wax::obj &val){
//handle string-based properties specific to this dsp
- std::string key_name = wax::cast<std::string>(key);
+ std::string key_name = key.as<std::string>();
if (key_name == "interp"){
- size_t new_interp = wax::cast<size_t>(val);
- ASSERT_THROW(std::has(
- _allowed_decim_and_interp_rates.begin(),
- _allowed_decim_and_interp_rates.end(),
- new_interp
- ));
+ size_t new_interp = val.as<size_t>();
+ assert_has(
+ _allowed_decim_and_interp_rates,
+ new_interp, "usrp2 interpolation"
+ );
_duc_interp = new_interp; //shadow
update_duc_config();
return;
}
else if (key_name == "freq"){
- freq_t new_freq = wax::cast<freq_t>(val);
+ freq_t new_freq = val.as<freq_t>();
ASSERT_THROW(new_freq <= get_master_clock_freq()/2.0);
ASSERT_THROW(new_freq >= -get_master_clock_freq()/2.0);
_duc_freq = new_freq; //shadow
diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h
index 3def8ddaa..10c1ef8cf 100644
--- a/host/lib/usrp/usrp2/fw_common.h
+++ b/host/lib/usrp/usrp2/fw_common.h
@@ -27,6 +27,10 @@
extern "C" {
#endif
+// size of the vrt header and trailer to the host
+#define USRP2_HOST_RX_VRT_HEADER_WORDS32 5
+#define USRP2_HOST_RX_VRT_TRAILER_WORDS32 1 //FIXME fpga sets wrong header size when no trailer present
+
// udp ports for the usrp2 communication
// Dynamic and/or private ports: 49152-65535
#define USRP2_UDP_CTRL_PORT 49152
@@ -87,6 +91,9 @@ typedef enum{
USRP2_CTRL_ID_SETUP_THIS_DUC_FOR_ME_BRO,
USRP2_CTRL_ID_TOTALLY_SETUP_THE_DUC_DUDE,
+ USRP2_CTRL_ID_GOT_A_NEW_TIME_FOR_YOU_BRO,
+ USRP2_CTRL_ID_SWEET_I_GOT_THAT_TIME_DUDE,
+
USRP2_CTRL_ID_PEACE_OUT
} usrp2_ctrl_id_t;
@@ -168,18 +175,25 @@ typedef struct{
struct {
uint32_t freq_word;
uint32_t decim;
+ uint32_t scale_iq;
} ddc_args;
struct {
uint8_t enabled;
uint8_t _pad[3];
uint32_t secs;
uint32_t ticks;
+ uint32_t samples;
} streaming;
struct {
uint32_t freq_word;
uint32_t interp;
uint32_t scale_iq;
} duc_args;
+ struct {
+ uint32_t secs;
+ uint32_t ticks;
+ uint8_t now;
+ } time_args;
} data;
} usrp2_ctrl_data_t;
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index 43334ddc6..cc7746720 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -16,12 +16,13 @@
//
#include <complex>
-#include <boost/shared_array.hpp>
#include <boost/format.hpp>
#include "usrp2_impl.hpp"
using namespace uhd;
using namespace uhd::usrp;
+using namespace uhd::transport;
+namespace asio = boost::asio;
/***********************************************************************
* Constants
@@ -29,214 +30,228 @@ using namespace uhd::usrp;
typedef std::complex<float> fc32_t;
typedef std::complex<int16_t> sc16_t;
-static const float float_scale_factor = pow(2.0, 15);
-
-//max length with header, stream id, seconds, fractional seconds
-static const size_t max_vrt_header_words = 5;
+static const float shorts_per_float = pow(2.0, 15);
+static const float floats_per_short = 1.0/shorts_per_float;
/***********************************************************************
* Helper Functions
**********************************************************************/
-static inline void host_floats_to_usrp2_shorts(
- int16_t *usrp2_shorts,
- const float *host_floats,
- size_t num_samps
-){
- for(size_t i = 0; i < num_samps; i++){
- usrp2_shorts[i] = htons(int16_t(host_floats[i]*float_scale_factor));
- }
+void usrp2_impl::io_init(void){
+ //initially empty copy buffer
+ _rx_copy_buff = asio::buffer("", 0);
+
+ //send a small data packet so the usrp2 knows the udp source port
+ uint32_t zero_data = 0;
+ _data_transport->send(asio::buffer(&zero_data, sizeof(zero_data)));
+}
+
+#define unrolled_loop(__i, __len, __inst) {\
+ size_t __i = 0; \
+ while(__i < (__len & ~0x7)){ \
+ __inst; __i++; __inst; __i++; \
+ __inst; __i++; __inst; __i++; \
+ __inst; __i++; __inst; __i++; \
+ __inst; __i++; __inst; __i++; \
+ } \
+ while(__i < __len){ \
+ __inst; __i++;\
+ } \
}
-static inline void usrp2_shorts_to_host_floats(
- float *host_floats,
- const int16_t *usrp2_shorts,
+// set a boolean flag that indicates the endianess
+#ifdef HAVE_BIG_ENDIAN
+static const bool is_big_endian = true;
+#else
+static const bool is_big_endian = false;
+#endif
+
+static inline void host_floats_to_usrp2_items(
+ uint32_t *usrp2_items,
+ const fc32_t *host_floats,
size_t num_samps
){
- for(size_t i = 0; i < num_samps; i++){
- host_floats[i] = float(ntohs(usrp2_shorts[i])/float_scale_factor);
- }
+ unrolled_loop(i, num_samps,{
+ uint16_t real = host_floats[i].real()*shorts_per_float;
+ uint16_t imag = host_floats[i].imag()*shorts_per_float;
+ usrp2_items[i] = htonl((real << 16) | (imag << 0));
+ });
}
-static inline void host_shorts_to_usrp2_shorts(
- int16_t *usrp2_shorts,
- const int16_t *host_shorts,
+static inline void usrp2_items_to_host_floats(
+ fc32_t *host_floats,
+ const uint32_t *usrp2_items,
size_t num_samps
){
- for(size_t i = 0; i < num_samps; i++){
- usrp2_shorts[i] = htons(host_shorts[i]);
- }
+ unrolled_loop(i, num_samps,{
+ uint32_t item = ntohl(usrp2_items[i]);
+ int16_t real = item >> 16;
+ int16_t imag = item >> 0;
+ host_floats[i] = fc32_t(real*floats_per_short, imag*floats_per_short);
+ });
}
-static inline void usrp2_shorts_to_host_shorts(
- int16_t *host_shorts,
- const int16_t *usrp2_shorts,
+static inline void host_items_to_usrp2_items(
+ uint32_t *usrp2_items,
+ const uint32_t *host_items,
size_t num_samps
){
- for(size_t i = 0; i < num_samps; i++){
- host_shorts[i] = ntohs(usrp2_shorts[i]);
+ if (is_big_endian){
+ std::memcpy(usrp2_items, host_items, num_samps*sizeof(uint32_t));
+ }
+ else{
+ unrolled_loop(i, num_samps, usrp2_items[i] = htonl(host_items[i]));
}
}
-/***********************************************************************
- * Send Raw Data
- **********************************************************************/
-size_t usrp2_impl::send_raw(
- const boost::asio::const_buffer &buff,
- const uhd::metadata_t &metadata
+static inline void usrp2_items_to_host_items(
+ uint32_t *host_items,
+ const uint32_t *usrp2_items,
+ size_t num_samps
){
- std::vector<boost::asio::const_buffer> buffs(2);
- uint32_t vrt_hdr[max_vrt_header_words];
- uint32_t vrt_hdr_flags = 0;
- size_t num_vrt_hdr_words = 1;
-
- //load the vrt header and flags
- if(metadata.has_stream_id){
- vrt_hdr_flags |= (0x1 << 28); //IF Data packet with Stream Identifier
- vrt_hdr[num_vrt_hdr_words++] = htonl(metadata.stream_id);
+ if (is_big_endian){
+ std::memcpy(host_items, usrp2_items, num_samps*sizeof(uint32_t));
}
- if(metadata.has_time_spec){
- vrt_hdr_flags |= (0x3 << 22) | (0x1 << 20); //TSI: Other, TSF: Sample Count Timestamp
- vrt_hdr[num_vrt_hdr_words++] = htonl(metadata.time_spec.secs);
- vrt_hdr[num_vrt_hdr_words++] = htonl(metadata.time_spec.ticks);
- vrt_hdr[num_vrt_hdr_words++] = 0; //unused part of fractional seconds
+ else{
+ unrolled_loop(i, num_samps, host_items[i] = ntohl(usrp2_items[i]));
}
- vrt_hdr_flags |= (metadata.start_of_burst)? (0x1 << 25) : 0;
- vrt_hdr_flags |= (metadata.end_of_burst)? (0x1 << 24) : 0;
-
- //fill in complete header word
- vrt_hdr[0] = htonl(vrt_hdr_flags |
- ((_stream_id_to_packet_seq[metadata.stream_id]++ & 0xf) << 16) |
- ((boost::asio::buffer_size(buff)/sizeof(uint32_t)) & 0xffff)
- );
-
- //load the buffer vector
- size_t vrt_hdr_size = num_vrt_hdr_words*sizeof(uint32_t);
- buffs[0] = boost::asio::buffer(&vrt_hdr, vrt_hdr_size);
- buffs[1] = buff;
-
- //send and return number of samples
- return (_data_transport->send(buffs) - vrt_hdr_size)/sizeof(sc16_t);
}
/***********************************************************************
* Receive Raw Data
**********************************************************************/
-size_t usrp2_impl::recv_raw(
- const boost::asio::mutable_buffer &buff,
- uhd::metadata_t &metadata
-){
- //load the buffer vector
- std::vector<boost::asio::mutable_buffer> buffs(2);
- uint32_t vrt_hdr[max_vrt_header_words];
- buffs[0] = boost::asio::buffer(vrt_hdr, max_vrt_header_words);
- buffs[1] = buff;
+void usrp2_impl::recv_raw(rx_metadata_t &metadata){
+ //do a receive
+ _rx_smart_buff = _data_transport->recv();
- //receive into the buffers
- size_t bytes_recvd = _data_transport->recv(buffs);
+ //unpack the vrt header
+ size_t num_packet_words32 = asio::buffer_size(_rx_smart_buff->get())/sizeof(uint32_t);
+ if (num_packet_words32 == 0){
+ _rx_copy_buff = boost::asio::buffer("", 0);
+ return; //must exit here after setting the buffer
+ }
+ const uint32_t *vrt_hdr = asio::buffer_cast<const uint32_t *>(_rx_smart_buff->get());
+ size_t num_header_words32_out, num_payload_words32_out, packet_count_out;
+ try{
+ vrt::unpack(
+ metadata, //output
+ vrt_hdr, //input
+ num_header_words32_out, //output
+ num_payload_words32_out, //output
+ num_packet_words32, //input
+ packet_count_out //output
+ );
+ }catch(const std::exception &e){
+ std::cerr << "bad vrt header: " << e.what() << std::endl;
+ _rx_copy_buff = boost::asio::buffer("", 0);
+ return; //must exit here after setting the buffer
+ }
- //failure case
- if (bytes_recvd < max_vrt_header_words*sizeof(uint32_t)) return 0;
+ //handle the packet count / sequence number
+ size_t expected_packet_count = _rx_stream_id_to_packet_seq[metadata.stream_id];
+ if (packet_count_out != expected_packet_count){
+ std::cerr << "bad packet count: " << packet_count_out << std::endl;
+ }
+ _rx_stream_id_to_packet_seq[metadata.stream_id] = (packet_count_out+1)%16;
- //unpack the vrt header
- metadata = uhd::metadata_t();
- uint32_t vrt_header = ntohl(vrt_hdr[0]);
- metadata.has_stream_id = true;
- metadata.stream_id = ntohl(vrt_hdr[1]);
- metadata.has_time_spec = true;
- metadata.time_spec.secs = ntohl(vrt_hdr[2]);
- metadata.time_spec.ticks = ntohl(vrt_hdr[3]);
-
- //return the number of samples received
- size_t num_words = vrt_header & 0xffff;
- return (num_words*sizeof(uint32_t))/sizeof(sc16_t);
+ //setup the rx buffer to point to the data
+ _rx_copy_buff = asio::buffer(
+ vrt_hdr + num_header_words32_out,
+ num_payload_words32_out*sizeof(uint32_t)
+ );
}
/***********************************************************************
* Send Data
**********************************************************************/
size_t usrp2_impl::send(
- const boost::asio::const_buffer &buff,
- const uhd::metadata_t &metadata,
+ const asio::const_buffer &buff,
+ const tx_metadata_t &metadata,
const std::string &type
){
- if (type == "fc32"){
- size_t num_samps = boost::asio::buffer_size(buff)/sizeof(fc32_t);
- boost::shared_array<sc16_t> raw_mem(new sc16_t[num_samps]);
- boost::asio::mutable_buffer raw_buff(raw_mem.get(), num_samps*sizeof(sc16_t));
-
- host_floats_to_usrp2_shorts(
- boost::asio::buffer_cast<int16_t*>(raw_buff),
- boost::asio::buffer_cast<const float*>(buff),
- num_samps*2 //double for complex
- );
-
- return send_raw(raw_buff, metadata);
+ uint32_t tx_mem[_mtu/sizeof(uint32_t)];
+ uint32_t *items = tx_mem + vrt::max_header_words32; //offset for data
+ size_t num_samps = _max_tx_samples_per_packet;
+
+ //calculate the number of samples to be copied
+ //and copy the samples into the send buffer
+ if (type == "32fc"){
+ num_samps = std::min(asio::buffer_size(buff)/sizeof(fc32_t), num_samps);
+ host_floats_to_usrp2_items(items, asio::buffer_cast<const fc32_t*>(buff), num_samps);
+ }
+ else if (type == "16sc"){
+ num_samps = std::min(asio::buffer_size(buff)/sizeof(sc16_t), num_samps);
+ host_items_to_usrp2_items(items, asio::buffer_cast<const uint32_t*>(buff), num_samps);
+ }
+ else{
+ throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type));
}
- if (type == "sc16"){
- #ifdef HAVE_BIG_ENDIAN
- return send_raw(buff, metadata);
- #else
- size_t num_samps = boost::asio::buffer_size(buff)/sizeof(sc16_t);
- boost::shared_array<sc16_t> raw_mem(new sc16_t[num_samps]);
- boost::asio::mutable_buffer raw_buff(raw_mem.get(), num_samps*sizeof(sc16_t));
-
- host_shorts_to_usrp2_shorts(
- boost::asio::buffer_cast<int16_t*>(raw_buff),
- boost::asio::buffer_cast<const int16_t*>(buff),
- num_samps*2 //double for complex
- );
+ uint32_t vrt_hdr[vrt::max_header_words32];
+ size_t num_header_words32, num_packet_words32;
+ size_t packet_count = _tx_stream_id_to_packet_seq[metadata.stream_id]++;
+
+ //pack metadata into a vrt header
+ vrt::pack(
+ metadata, //input
+ vrt_hdr, //output
+ num_header_words32, //output
+ num_samps, //input
+ num_packet_words32, //output
+ packet_count //input
+ );
- return send_raw(raw_buff, metadata);
- #endif
- }
+ //copy in the vrt header (yes we left space)
+ items -= num_header_words32;
+ std::memcpy(items, vrt_hdr, num_header_words32*sizeof(uint32_t));
- throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type));
+ //send and return number of samples
+ _data_transport->send(asio::buffer(items, num_packet_words32*sizeof(uint32_t)));
+ return num_samps;
}
/***********************************************************************
* Receive Data
**********************************************************************/
size_t usrp2_impl::recv(
- const boost::asio::mutable_buffer &buff,
- uhd::metadata_t &metadata,
+ const asio::mutable_buffer &buff,
+ rx_metadata_t &metadata,
const std::string &type
){
- if (type == "fc32"){
- size_t num_samps = boost::asio::buffer_size(buff)/sizeof(fc32_t);
- boost::shared_array<sc16_t> raw_mem(new sc16_t[num_samps]);
- boost::asio::mutable_buffer raw_buff(raw_mem.get(), num_samps*sizeof(sc16_t));
-
- num_samps = recv_raw(raw_buff, metadata);
-
- usrp2_shorts_to_host_floats(
- boost::asio::buffer_cast<float*>(buff),
- boost::asio::buffer_cast<const int16_t*>(raw_buff),
- num_samps*2 //double for complex
- );
-
- return num_samps;
+ //perform a receive if no rx data is waiting to be copied
+ if (asio::buffer_size(_rx_copy_buff) == 0){
+ recv_raw(metadata);
+ }
+ //otherwise flag the metadata to show that is is a fragment
+ else{
+ metadata = rx_metadata_t();
+ metadata.is_fragment = true;
}
- if (type == "sc16"){
- #ifdef HAVE_BIG_ENDIAN
- return recv_raw(buff, metadata);
- #else
- size_t num_samps = boost::asio::buffer_size(buff)/sizeof(sc16_t);
- boost::shared_array<sc16_t> raw_mem(new sc16_t[num_samps]);
- boost::asio::mutable_buffer raw_buff(raw_mem.get(), num_samps*sizeof(sc16_t));
-
- num_samps = recv_raw(raw_buff, metadata);
-
- usrp2_shorts_to_host_shorts(
- boost::asio::buffer_cast<int16_t*>(buff),
- boost::asio::buffer_cast<const int16_t*>(raw_buff),
- num_samps*2 //double for complex
- );
-
- return num_samps;
- #endif
+ //extract the number of samples available to copy
+ //and a pointer into the usrp2 received items memory
+ size_t bytes_to_copy = asio::buffer_size(_rx_copy_buff);
+ if (bytes_to_copy == 0) return 0; //nothing to receive
+ size_t num_samps = bytes_to_copy/sizeof(uint32_t);
+ const uint32_t *items = asio::buffer_cast<const uint32_t*>(_rx_copy_buff);
+
+ //calculate the number of samples to be copied
+ //and copy the samples from the recv buffer
+ if (type == "32fc"){
+ num_samps = std::min(asio::buffer_size(buff)/sizeof(fc32_t), num_samps);
+ usrp2_items_to_host_floats(asio::buffer_cast<fc32_t*>(buff), items, num_samps);
+ }
+ else if (type == "16sc"){
+ num_samps = std::min(asio::buffer_size(buff)/sizeof(sc16_t), num_samps);
+ usrp2_items_to_host_items(asio::buffer_cast<uint32_t*>(buff), items, num_samps);
}
+ else{
+ throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%s\"") % type));
+ }
+
+ //update the rx copy buffer to reflect the bytes copied
+ _rx_copy_buff = asio::buffer(
+ items + num_samps, bytes_to_copy - num_samps*sizeof(uint32_t)
+ );
- throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%s\"") % type));
+ return num_samps;
}
diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp
index cc73b229c..4b15c7f3e 100644
--- a/host/lib/usrp/usrp2/mboard_impl.cpp
+++ b/host/lib/usrp/usrp2/mboard_impl.cpp
@@ -16,6 +16,7 @@
//
#include <uhd/utils.hpp>
+#include <boost/assign/list_of.hpp>
#include "usrp2_impl.hpp"
using namespace uhd;
@@ -28,6 +29,10 @@ void usrp2_impl::mboard_init(void){
boost::bind(&usrp2_impl::mboard_get, this, _1, _2),
boost::bind(&usrp2_impl::mboard_set, this, _1, _2)
);
+
+ //set the time on the usrp2 as close as possible to the system utc time
+ boost::posix_time::ptime now(boost::posix_time::microsec_clock::universal_time());
+ set_time_spec(time_spec_t(now, get_master_clock_freq()), true);
}
void usrp2_impl::init_clock_config(void){
@@ -64,6 +69,19 @@ void usrp2_impl::update_clock_config(void){
ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_GOT_THE_NEW_CLOCK_CONFIG_DUDE);
}
+void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){
+ //setup the out data
+ usrp2_ctrl_data_t out_data;
+ out_data.id = htonl(USRP2_CTRL_ID_GOT_A_NEW_TIME_FOR_YOU_BRO);
+ out_data.data.time_args.secs = htonl(time_spec.secs);
+ out_data.data.time_args.ticks = htonl(time_spec.ticks);
+ out_data.data.time_args.now = (now)? 1 : 0;
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
+ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_SWEET_I_GOT_THAT_TIME_DUDE);
+}
+
/***********************************************************************
* MBoard Get Properties
**********************************************************************/
@@ -71,17 +89,54 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
wax::obj key; std::string name;
boost::tie(key, name) = extract_named_prop(key_);
+ //handle the other props
+ if (key.type() == typeid(std::string)){
+ if (key.as<std::string>() == "mac-addr"){
+ //setup the out data
+ usrp2_ctrl_data_t out_data;
+ out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_MAC_ADDR_BRO);
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
+ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE);
+
+ //extract the address
+ val = reinterpret_cast<mac_addr_t*>(in_data.data.mac_addr)->to_string();
+ return;
+ }
+
+ if (key.as<std::string>() == "ip-addr"){
+ //setup the out data
+ usrp2_ctrl_data_t out_data;
+ out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO);
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
+ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE);
+
+ //extract the address
+ val = boost::asio::ip::address_v4(ntohl(in_data.data.ip_addr)).to_string();
+ return;
+ }
+ }
+
//handle the get request conditioned on the key
- switch(wax::cast<mboard_prop_t>(key)){
+ switch(key.as<mboard_prop_t>()){
case MBOARD_PROP_NAME:
val = std::string("usrp2 mboard");
return;
- case MBOARD_PROP_OTHERS:
- val = prop_names_t(); //empty other props
+ case MBOARD_PROP_OTHERS:{
+ prop_names_t others = boost::assign::list_of
+ ("mac-addr")
+ ("ip-addr")
+ ;
+ val = others;
+ }
return;
case MBOARD_PROP_RX_DBOARD:
+ ASSERT_THROW(_rx_dboards.has_key(name));
val = _rx_dboards[name].get_link();
return;
@@ -90,6 +145,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
return;
case MBOARD_PROP_TX_DBOARD:
+ ASSERT_THROW(_tx_dboards.has_key(name));
val = _tx_dboards[name].get_link();
return;
@@ -97,17 +153,12 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
val = prop_names_t(_tx_dboards.get_keys());
return;
- case MBOARD_PROP_MTU:
- // FIXME we dont know the real MTU...
- // give them something to fragment about
- val = size_t(1500);
- return;
-
case MBOARD_PROP_CLOCK_RATE:
val = freq_t(get_master_clock_freq());
return;
case MBOARD_PROP_RX_DSP:
+ ASSERT_THROW(_rx_dsps.has_key(name));
val = _rx_dsps[name].get_link();
return;
@@ -116,6 +167,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
return;
case MBOARD_PROP_TX_DSP:
+ ASSERT_THROW(_tx_dsps.has_key(name));
val = _tx_dsps[name].get_link();
return;
@@ -154,36 +206,73 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
* MBoard Set Properties
**********************************************************************/
void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){
+ //handle the other props
+ if (key.type() == typeid(std::string)){
+ if (key.as<std::string>() == "mac-addr"){
+ //setup the out data
+ usrp2_ctrl_data_t out_data;
+ out_data.id = htonl(USRP2_CTRL_ID_HERE_IS_A_NEW_MAC_ADDR_BRO);
+ mac_addr_t mac_addr(val.as<std::string>());
+ std::memcpy(out_data.data.mac_addr, &mac_addr, sizeof(mac_addr_t));
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
+ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE);
+ return;
+ }
+
+ if (key.as<std::string>() == "ip-addr"){
+ //setup the out data
+ usrp2_ctrl_data_t out_data;
+ out_data.id = htonl(USRP2_CTRL_ID_HERE_IS_A_NEW_IP_ADDR_BRO);
+ out_data.data.ip_addr = htonl(boost::asio::ip::address_v4::from_string(val.as<std::string>()).to_ulong());
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
+ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE);
+ return;
+ }
+ }
+
//handle the get request conditioned on the key
- switch(wax::cast<mboard_prop_t>(key)){
+ switch(key.as<mboard_prop_t>()){
case MBOARD_PROP_PPS_SOURCE:{
- std::string name = wax::cast<std::string>(val);
- ASSERT_THROW(_pps_source_dict.has_key(name));
+ std::string name = val.as<std::string>();
+ assert_has(_pps_source_dict.get_keys(), name, "usrp2 pps source");
_pps_source = name; //shadow
update_clock_config();
}
return;
case MBOARD_PROP_PPS_POLARITY:{
- std::string name = wax::cast<std::string>(val);
- ASSERT_THROW(_pps_polarity_dict.has_key(name));
+ std::string name = val.as<std::string>();
+ assert_has(_pps_polarity_dict.get_keys(), name, "usrp2 pps polarity");
_pps_polarity = name; //shadow
update_clock_config();
}
return;
case MBOARD_PROP_REF_SOURCE:{
- std::string name = wax::cast<std::string>(val);
- ASSERT_THROW(_ref_source_dict.has_key(name));
+ std::string name = val.as<std::string>();
+ assert_has(_ref_source_dict.get_keys(), name, "usrp2 reference source");
_ref_source = name; //shadow
update_clock_config();
}
return;
+ case MBOARD_PROP_TIME_NOW:{
+ set_time_spec(val.as<time_spec_t>(), true);
+ return;
+ }
+
+ case MBOARD_PROP_TIME_NEXT_PPS:{
+ set_time_spec(val.as<time_spec_t>(), false);
+ return;
+ }
+
case MBOARD_PROP_NAME:
case MBOARD_PROP_OTHERS:
- case MBOARD_PROP_MTU:
case MBOARD_PROP_CLOCK_RATE:
case MBOARD_PROP_RX_DSP:
case MBOARD_PROP_RX_DSP_NAMES:
@@ -195,8 +284,6 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){
case MBOARD_PROP_TX_DBOARD_NAMES:
case MBOARD_PROP_PPS_SOURCE_NAMES:
case MBOARD_PROP_REF_SOURCE_NAMES:
- case MBOARD_PROP_TIME_NOW:
- case MBOARD_PROP_TIME_NEXT_PPS:
throw std::runtime_error("Error: trying to set read-only property on usrp2 mboard");
}
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index 5aa5d6e8d..e1371a094 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -23,6 +23,12 @@
using namespace uhd;
using namespace uhd::usrp;
+using namespace uhd::transport;
+namespace asio = boost::asio;
+
+STATIC_BLOCK(register_usrp2_device){
+ device::register_device(&usrp2::discover, &usrp2::make);
+}
/***********************************************************************
* Discovery over the udp transport
@@ -30,30 +36,26 @@ using namespace uhd::usrp;
uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){
device_addrs_t usrp2_addrs;
+ if (not hint.has_key("addr")) return usrp2_addrs;
+
//create a udp transport to communicate
//TODO if an addr is not provided, search all interfaces?
std::string ctrl_port = boost::lexical_cast<std::string>(USRP2_UDP_CTRL_PORT);
- transport::udp::sptr udp_transport = \
- transport::udp::make(hint["addr"], ctrl_port, true);
+ udp_simple::sptr udp_transport = udp_simple::make_broadcast(
+ hint["addr"], ctrl_port
+ );
//send a hello control packet
usrp2_ctrl_data_t ctrl_data_out;
ctrl_data_out.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO);
udp_transport->send(boost::asio::buffer(&ctrl_data_out, sizeof(ctrl_data_out)));
- //loop and recieve until the time is up
- size_t num_timeouts = 0;
+ //loop and recieve until the timeout
while(true){
usrp2_ctrl_data_t ctrl_data_in;
- size_t len = udp_transport->recv(
- boost::asio::buffer(&ctrl_data_in, sizeof(ctrl_data_in))
- );
+ size_t len = udp_transport->recv(asio::buffer(&ctrl_data_in, sizeof(ctrl_data_in)));
//std::cout << len << "\n";
- if (len < sizeof(usrp2_ctrl_data_t)){
- //sleep a little so we dont burn cpu
- if (num_timeouts++ > 50) break;
- boost::this_thread::sleep(boost::posix_time::milliseconds(1));
- }else{
+ if (len >= sizeof(usrp2_ctrl_data_t)){
//handle the received data
switch(ntohl(ctrl_data_in.id)){
case USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE:
@@ -61,12 +63,14 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){
boost::asio::ip::address_v4 ip_addr(ntohl(ctrl_data_in.data.ip_addr));
device_addr_t new_addr;
new_addr["name"] = "USRP2";
- new_addr["type"] = "usrp2";
+ new_addr["transport"] = "udp";
new_addr["addr"] = ip_addr.to_string();
usrp2_addrs.push_back(new_addr);
- break;
+ //dont break here, it will exit the while loop
+ //just continue on to the next loop iteration
}
}
+ if (len == 0) break; //timeout
}
return usrp2_addrs;
@@ -75,16 +79,18 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){
/***********************************************************************
* Make
**********************************************************************/
-#define num2str(num) (boost::lexical_cast<std::string>(num))
+template <class T> std::string num2str(T num){
+ return boost::lexical_cast<std::string>(num);
+}
device::sptr usrp2::make(const device_addr_t &device_addr){
//create a control transport
- transport::udp::sptr ctrl_transport = transport::udp::make(
+ udp_simple::sptr ctrl_transport = udp_simple::make_connected(
device_addr["addr"], num2str(USRP2_UDP_CTRL_PORT)
);
//create a data transport
- transport::udp::sptr data_transport = transport::udp::make(
+ udp_zero_copy::sptr data_transport = udp_zero_copy::make(
device_addr["addr"], num2str(USRP2_UDP_DATA_PORT)
);
@@ -98,8 +104,8 @@ device::sptr usrp2::make(const device_addr_t &device_addr){
* Structors
**********************************************************************/
usrp2_impl::usrp2_impl(
- transport::udp::sptr ctrl_transport,
- transport::udp::sptr data_transport
+ udp_simple::sptr ctrl_transport,
+ udp_zero_copy::sptr data_transport
){
_ctrl_transport = ctrl_transport;
_data_transport = data_transport;
@@ -132,9 +138,8 @@ usrp2_impl::usrp2_impl(
//init the tx and rx dboards (do last)
dboard_init();
- //send a small data packet so the usrp2 knows the udp source port
- uint32_t zero_data = 0;
- _data_transport->send(boost::asio::buffer(&zero_data, sizeof(zero_data)));
+ //init the send and recv io
+ io_init();
}
@@ -160,24 +165,15 @@ usrp2_ctrl_data_t usrp2_impl::ctrl_send_and_recv(const usrp2_ctrl_data_t &out_da
out_copy.seq = htonl(++_ctrl_seq_num);
_ctrl_transport->send(boost::asio::buffer(&out_copy, sizeof(usrp2_ctrl_data_t)));
- //loop and recieve until the time is up
- size_t num_timeouts = 0;
+ //loop until we get the packet or timeout
while(true){
usrp2_ctrl_data_t in_data;
- size_t len = _ctrl_transport->recv(
- boost::asio::buffer(&in_data, sizeof(in_data))
- );
- if (len < sizeof(usrp2_ctrl_data_t)){
- //sleep a little so we dont burn cpu
- if (num_timeouts++ > 50) break;
- boost::this_thread::sleep(boost::posix_time::milliseconds(1));
- }else{
- //handle the received data
- if (ntohl(in_data.seq) == _ctrl_seq_num){
- return in_data;
- }
- //didnt get seq, continue on...
+ size_t len = _ctrl_transport->recv(asio::buffer(&in_data, sizeof(in_data)));
+ if (len >= sizeof(usrp2_ctrl_data_t) and ntohl(in_data.seq) == _ctrl_seq_num){
+ return in_data;
}
+ if (len == 0) break; //timeout
+ //didnt get seq or bad packet, continue looking...
}
throw std::runtime_error("usrp2 no control response");
}
@@ -190,18 +186,28 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){
boost::tie(key, name) = extract_named_prop(key_);
//handle the get request conditioned on the key
- switch(wax::cast<device_prop_t>(key)){
+ switch(key.as<device_prop_t>()){
case DEVICE_PROP_NAME:
val = std::string("usrp2 device");
return;
case DEVICE_PROP_MBOARD:
+ ASSERT_THROW(_mboards.has_key(name));
val = _mboards[name].get_link();
return;
case DEVICE_PROP_MBOARD_NAMES:
val = prop_names_t(_mboards.get_keys());
return;
+
+ case DEVICE_PROP_MAX_RX_SAMPLES:
+ val = size_t(_max_rx_samples_per_packet);
+ return;
+
+ case DEVICE_PROP_MAX_TX_SAMPLES:
+ val = size_t(_max_tx_samples_per_packet);
+ return;
+
}
}
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index 9a4c42d42..fc713c2bf 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -22,7 +22,9 @@
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
-#include <uhd/transport/udp.hpp>
+#include <uhd/transport/vrt.hpp>
+#include <uhd/transport/udp_simple.hpp>
+#include <uhd/transport/udp_zero_copy.hpp>
#include <uhd/usrp/dboard_manager.hpp>
#include "fw_common.h"
@@ -81,8 +83,8 @@ public:
* \param data_transport the udp transport for data
*/
usrp2_impl(
- uhd::transport::udp::sptr ctrl_transport,
- uhd::transport::udp::sptr data_transport
+ uhd::transport::udp_simple::sptr ctrl_transport,
+ uhd::transport::udp_zero_copy::sptr data_transport
);
~usrp2_impl(void);
@@ -98,18 +100,32 @@ public:
double get_master_clock_freq(void);
//the io interface
- size_t send(const boost::asio::const_buffer &, const uhd::metadata_t &, const std::string &);
- size_t recv(const boost::asio::mutable_buffer &, uhd::metadata_t &, const std::string &);
+ size_t send(const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const std::string &);
+ size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const std::string &);
private:
//the raw io interface (samples are in the usrp2 native format)
- size_t send_raw(const boost::asio::const_buffer &, const uhd::metadata_t &);
- size_t recv_raw(const boost::asio::mutable_buffer &, uhd::metadata_t &);
- uhd::dict<uint32_t, size_t> _stream_id_to_packet_seq;
+ void recv_raw(uhd::rx_metadata_t &);
+ uhd::dict<uint32_t, size_t> _tx_stream_id_to_packet_seq;
+ uhd::dict<uint32_t, size_t> _rx_stream_id_to_packet_seq;
+ static const size_t _mtu = 1500; //FIXME we have no idea
+ static const size_t _hdrs = (2 + 14 + 20 + 8); //size of headers (pad, eth, ip, udp)
+ static const size_t _max_rx_samples_per_packet =
+ (_mtu - _hdrs)/sizeof(uint32_t) -
+ USRP2_HOST_RX_VRT_HEADER_WORDS32 -
+ USRP2_HOST_RX_VRT_TRAILER_WORDS32
+ ;
+ static const size_t _max_tx_samples_per_packet =
+ (_mtu - _hdrs)/sizeof(uint32_t) -
+ uhd::transport::vrt::max_header_words32
+ ;
+ uhd::transport::smart_buffer::sptr _rx_smart_buff;
+ boost::asio::const_buffer _rx_copy_buff;
+ void io_init(void);
//udp transports for control and data
- uhd::transport::udp::sptr _ctrl_transport;
- uhd::transport::udp::sptr _data_transport;
+ uhd::transport::udp_simple::sptr _ctrl_transport;
+ uhd::transport::udp_zero_copy::sptr _data_transport;
//private vars for dealing with send/recv control
uint32_t _ctrl_seq_num;
@@ -119,6 +135,7 @@ private:
std::string _pps_source, _pps_polarity, _ref_source;
void init_clock_config(void);
void update_clock_config(void);
+ void set_time_spec(const uhd::time_spec_t &time_spec, bool now);
//mappings from clock config strings to over the wire enums
uhd::dict<std::string, usrp2_pps_source_t> _pps_source_dict;