summaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/e100
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp/e100')
-rw-r--r--host/lib/usrp/e100/dboard_iface.cpp71
-rw-r--r--host/lib/usrp/e100/e100_impl.cpp92
-rw-r--r--host/lib/usrp/e100/e100_impl.hpp21
-rw-r--r--host/lib/usrp/e100/e100_regs.hpp42
-rw-r--r--host/lib/usrp/e100/io_impl.cpp240
5 files changed, 222 insertions, 244 deletions
diff --git a/host/lib/usrp/e100/dboard_iface.cpp b/host/lib/usrp/e100/dboard_iface.cpp
index d45577bd9..6afc7bc48 100644
--- a/host/lib/usrp/e100/dboard_iface.cpp
+++ b/host/lib/usrp/e100/dboard_iface.cpp
@@ -15,7 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include "wb_iface.hpp"
+#include "gpio_core_200.hpp"
#include <uhd/types/serial.hpp>
#include "e100_regs.hpp"
#include "clock_ctrl.hpp"
@@ -45,13 +45,11 @@ public:
_spi_iface = spi_iface;
_clock = clock;
_codec = codec;
+ _gpio = gpio_core_200::make(_wb_iface, E100_REG_SR_ADDR(UE_SR_GPIO), E100_REG_RB_GPIO);
//init the clock rate shadows
this->set_clock_rate(UNIT_RX, _clock->get_fpga_clock_rate());
this->set_clock_rate(UNIT_TX, _clock->get_fpga_clock_rate());
-
- _wb_iface->poke16(E100_REG_GPIO_RX_DBG, 0);
- _wb_iface->poke16(E100_REG_GPIO_TX_DBG, 0);
}
~e100_dboard_iface(void){
@@ -104,6 +102,7 @@ private:
spi_iface::sptr _spi_iface;
e100_clock_ctrl::sptr _clock;
e100_codec_ctrl::sptr _codec;
+ gpio_core_200::sptr _gpio;
};
/***********************************************************************
@@ -160,77 +159,27 @@ double e100_dboard_iface::get_codec_rate(unit_t){
* GPIO
**********************************************************************/
void e100_dboard_iface::_set_pin_ctrl(unit_t unit, boost::uint16_t value){
- UHD_ASSERT_THROW(GPIO_SEL_ATR == 1); //make this assumption
- switch(unit){
- case UNIT_RX: _wb_iface->poke16(E100_REG_GPIO_RX_SEL, value); return;
- case UNIT_TX: _wb_iface->poke16(E100_REG_GPIO_TX_SEL, value); return;
- }
+ return _gpio->set_pin_ctrl(unit, value);
}
void e100_dboard_iface::_set_gpio_ddr(unit_t unit, boost::uint16_t value){
- switch(unit){
- case UNIT_RX: _wb_iface->poke16(E100_REG_GPIO_RX_DDR, value); return;
- case UNIT_TX: _wb_iface->poke16(E100_REG_GPIO_TX_DDR, value); return;
- }
+ return _gpio->set_gpio_ddr(unit, value);
}
void e100_dboard_iface::_set_gpio_out(unit_t unit, boost::uint16_t value){
- switch(unit){
- case UNIT_RX: _wb_iface->poke16(E100_REG_GPIO_RX_IO, value); return;
- case UNIT_TX: _wb_iface->poke16(E100_REG_GPIO_TX_IO, value); return;
- }
+ return _gpio->set_gpio_out(unit, value);
}
boost::uint16_t e100_dboard_iface::read_gpio(unit_t unit){
- switch(unit){
- case UNIT_RX: return _wb_iface->peek16(E100_REG_GPIO_RX_IO);
- case UNIT_TX: return _wb_iface->peek16(E100_REG_GPIO_TX_IO);
- default: UHD_THROW_INVALID_CODE_PATH();
- }
+ return _gpio->read_gpio(unit);
}
void e100_dboard_iface::_set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t value){
- //define mapping of unit to atr regs to register address
- static const uhd::dict<
- unit_t, uhd::dict<atr_reg_t, boost::uint32_t>
- > unit_to_atr_to_addr = map_list_of
- (UNIT_RX, map_list_of
- (ATR_REG_IDLE, E100_REG_ATR_IDLE_RXSIDE)
- (ATR_REG_TX_ONLY, E100_REG_ATR_INTX_RXSIDE)
- (ATR_REG_RX_ONLY, E100_REG_ATR_INRX_RXSIDE)
- (ATR_REG_FULL_DUPLEX, E100_REG_ATR_FULL_RXSIDE)
- )
- (UNIT_TX, map_list_of
- (ATR_REG_IDLE, E100_REG_ATR_IDLE_TXSIDE)
- (ATR_REG_TX_ONLY, E100_REG_ATR_INTX_TXSIDE)
- (ATR_REG_RX_ONLY, E100_REG_ATR_INRX_TXSIDE)
- (ATR_REG_FULL_DUPLEX, E100_REG_ATR_FULL_TXSIDE)
- )
- ;
- _wb_iface->poke16(unit_to_atr_to_addr[unit][atr], value);
+ return _gpio->set_atr_reg(unit, atr, value);
}
-void e100_dboard_iface::set_gpio_debug(unit_t unit, int which){
- //set this unit to all outputs
- this->set_gpio_ddr(unit, 0xffff);
-
- //calculate the debug selections
- boost::uint32_t dbg_sels = 0x0;
- int sel = (which == 0)? GPIO_SEL_DEBUG_0 : GPIO_SEL_DEBUG_1;
- for(size_t i = 0; i < 16; i++) dbg_sels |= sel << i;
-
- //set the debug on and which debug selection
- switch(unit){
- case UNIT_RX:
- _wb_iface->poke16(E100_REG_GPIO_RX_DBG, 0xffff);
- _wb_iface->poke16(E100_REG_GPIO_RX_SEL, dbg_sels);
- return;
-
- case UNIT_TX:
- _wb_iface->poke16(E100_REG_GPIO_TX_DBG, 0xffff);
- _wb_iface->poke16(E100_REG_GPIO_TX_SEL, dbg_sels);
- return;
- }
+void e100_dboard_iface::set_gpio_debug(unit_t, int){
+ throw uhd::not_implemented_error("no set_gpio_debug implemented");
}
/***********************************************************************
diff --git a/host/lib/usrp/e100/e100_impl.cpp b/host/lib/usrp/e100/e100_impl.cpp
index 564a05a7e..c0a8f46f3 100644
--- a/host/lib/usrp/e100/e100_impl.cpp
+++ b/host/lib/usrp/e100/e100_impl.cpp
@@ -106,6 +106,7 @@ UHD_STATIC_BLOCK(register_e100_device){
* Structors
**********************************************************************/
e100_impl::e100_impl(const uhd::device_addr_t &device_addr){
+ _tree = property_tree::make();
//setup the main interface into fpga
const std::string node = device_addr["node"];
@@ -167,15 +168,7 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){
);
//check that the compatibility is correct
- const boost::uint16_t fpga_compat_num = _fpga_ctrl->peek16(E100_REG_MISC_COMPAT);
- if (fpga_compat_num != E100_FPGA_COMPAT_NUM){
- throw uhd::runtime_error(str(boost::format(
- "\nPlease update the FPGA image for your device.\n"
- "See the application notes for USRP E-Series for instructions.\n"
- "Expected FPGA compatibility number 0x%x, but got 0x%x:\n"
- "The FPGA build is not compatible with the host code build."
- ) % E100_FPGA_COMPAT_NUM % fpga_compat_num));
- }
+ this->check_fpga_compat();
////////////////////////////////////////////////////////////////////
// Create controller objects
@@ -187,7 +180,6 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){
////////////////////////////////////////////////////////////////////
// Initialize the properties tree
////////////////////////////////////////////////////////////////////
- _tree = property_tree::make();
_tree->create<std::string>("/name").set("E-Series Device");
const fs_path mb_path = "/mboards/0";
_tree->create<std::string>(mb_path / "name").set(str(boost::format("%s (euewanee)") % model));
@@ -250,12 +242,31 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){
////////////////////////////////////////////////////////////////////
_rx_fe = rx_frontend_core_200::make(_fpga_ctrl, E100_REG_SR_ADDR(UE_SR_RX_FRONT));
_tx_fe = tx_frontend_core_200::make(_fpga_ctrl, E100_REG_SR_ADDR(UE_SR_TX_FRONT));
- //TODO lots of properties to expose here for frontends
+
_tree->create<subdev_spec_t>(mb_path / "rx_subdev_spec")
.subscribe(boost::bind(&e100_impl::update_rx_subdev_spec, this, _1));
_tree->create<subdev_spec_t>(mb_path / "tx_subdev_spec")
.subscribe(boost::bind(&e100_impl::update_tx_subdev_spec, this, _1));
+ const fs_path rx_fe_path = mb_path / "rx_frontends" / "A";
+ const fs_path tx_fe_path = mb_path / "tx_frontends" / "A";
+
+ _tree->create<std::complex<double> >(rx_fe_path / "dc_offset" / "value")
+ .coerce(boost::bind(&rx_frontend_core_200::set_dc_offset, _rx_fe, _1))
+ .set(std::complex<double>(0.0, 0.0));
+ _tree->create<bool>(rx_fe_path / "dc_offset" / "enable")
+ .subscribe(boost::bind(&rx_frontend_core_200::set_dc_offset_auto, _rx_fe, _1))
+ .set(true);
+ _tree->create<std::complex<double> >(rx_fe_path / "iq_balance" / "value")
+ .subscribe(boost::bind(&rx_frontend_core_200::set_iq_balance, _rx_fe, _1))
+ .set(std::complex<double>(0.0, 0.0));
+ _tree->create<std::complex<double> >(tx_fe_path / "dc_offset" / "value")
+ .coerce(boost::bind(&tx_frontend_core_200::set_dc_offset, _tx_fe, _1))
+ .set(std::complex<double>(0.0, 0.0));
+ _tree->create<std::complex<double> >(tx_fe_path / "iq_balance" / "value")
+ .subscribe(boost::bind(&tx_frontend_core_200::set_iq_balance, _tx_fe, _1))
+ .set(std::complex<double>(0.0, 0.0));
+
////////////////////////////////////////////////////////////////////
// create rx dsp control objects
////////////////////////////////////////////////////////////////////
@@ -270,9 +281,12 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){
_tree->access<double>(mb_path / "tick_rate")
.subscribe(boost::bind(&rx_dsp_core_200::set_tick_rate, _rx_dsps[dspno], _1));
fs_path rx_dsp_path = mb_path / str(boost::format("rx_dsps/%u") % dspno);
+ _tree->create<meta_range_t>(rx_dsp_path / "rate/range")
+ .publish(boost::bind(&rx_dsp_core_200::get_host_rates, _rx_dsps[dspno]));
_tree->create<double>(rx_dsp_path / "rate/value")
+ .set(1e6) //some default
.coerce(boost::bind(&rx_dsp_core_200::set_host_rate, _rx_dsps[dspno], _1))
- .subscribe(boost::bind(&e100_impl::update_rx_samp_rate, this, _1));
+ .subscribe(boost::bind(&e100_impl::update_rx_samp_rate, this, dspno, _1));
_tree->create<double>(rx_dsp_path / "freq/value")
.coerce(boost::bind(&rx_dsp_core_200::set_freq, _rx_dsps[dspno], _1));
_tree->create<meta_range_t>(rx_dsp_path / "freq/range")
@@ -290,9 +304,12 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){
_tx_dsp->set_link_rate(E100_TX_LINK_RATE_BPS);
_tree->access<double>(mb_path / "tick_rate")
.subscribe(boost::bind(&tx_dsp_core_200::set_tick_rate, _tx_dsp, _1));
+ _tree->create<meta_range_t>(mb_path / "tx_dsps/0/rate/range")
+ .publish(boost::bind(&tx_dsp_core_200::get_host_rates, _tx_dsp));
_tree->create<double>(mb_path / "tx_dsps/0/rate/value")
+ .set(1e6) //some default
.coerce(boost::bind(&tx_dsp_core_200::set_host_rate, _tx_dsp, _1))
- .subscribe(boost::bind(&e100_impl::update_tx_samp_rate, this, _1));
+ .subscribe(boost::bind(&e100_impl::update_tx_samp_rate, this, 0, _1));
_tree->create<double>(mb_path / "tx_dsps/0/freq/value")
.coerce(boost::bind(&tx_dsp_core_200::set_freq, _tx_dsp, _1));
_tree->create<meta_range_t>(mb_path / "tx_dsps/0/freq/range")
@@ -353,22 +370,9 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){
_dboard_iface = make_e100_dboard_iface(_fpga_ctrl, _fpga_i2c_ctrl, _fpga_spi_ctrl, _clock_ctrl, _codec_ctrl);
_tree->create<dboard_iface::sptr>(mb_path / "dboards/A/iface").set(_dboard_iface);
_dboard_manager = dboard_manager::make(
- rx_db_eeprom.id,
- ((gdb_eeprom.id == dboard_id_t::none())? tx_db_eeprom : gdb_eeprom).id,
- _dboard_iface
+ rx_db_eeprom.id, tx_db_eeprom.id, gdb_eeprom.id,
+ _dboard_iface, _tree->subtree(mb_path / "dboards/A")
);
- BOOST_FOREACH(const std::string &name, _dboard_manager->get_rx_subdev_names()){
- dboard_manager::populate_prop_tree_from_subdev(
- _tree->subtree(mb_path / "dboards/A/rx_frontends" / name),
- _dboard_manager->get_rx_subdev(name)
- );
- }
- BOOST_FOREACH(const std::string &name, _dboard_manager->get_tx_subdev_names()){
- dboard_manager::populate_prop_tree_from_subdev(
- _tree->subtree(mb_path / "dboards/A/tx_frontends" / name),
- _dboard_manager->get_tx_subdev(name)
- );
- }
//initialize io handling
this->io_init();
@@ -376,19 +380,13 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){
////////////////////////////////////////////////////////////////////
// do some post-init tasks
////////////////////////////////////////////////////////////////////
- _tree->access<double>(mb_path / "tick_rate").update() //update and then subscribe the clock callback
- .subscribe(boost::bind(&e100_clock_ctrl::set_fpga_clock_rate, _clock_ctrl, _1));
+ this->update_rates();
- //and now that the tick rate is set, init the host rates to something
- BOOST_FOREACH(const std::string &name, _tree->list(mb_path / "rx_dsps")){
- _tree->access<double>(mb_path / "rx_dsps" / name / "rate" / "value").set(1e6);
- }
- BOOST_FOREACH(const std::string &name, _tree->list(mb_path / "tx_dsps")){
- _tree->access<double>(mb_path / "tx_dsps" / name / "rate" / "value").set(1e6);
- }
+ _tree->access<double>(mb_path / "tick_rate") //now subscribe the clock rate setter
+ .subscribe(boost::bind(&e100_clock_ctrl::set_fpga_clock_rate, _clock_ctrl, _1));
- _tree->access<subdev_spec_t>(mb_path / "rx_subdev_spec").set(subdev_spec_t("A:"+_dboard_manager->get_rx_subdev_names()[0]));
- _tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(subdev_spec_t("A:"+_dboard_manager->get_tx_subdev_names()[0]));
+ _tree->access<subdev_spec_t>(mb_path / "rx_subdev_spec").set(subdev_spec_t("A:" + _tree->list(mb_path / "dboards/A/rx_frontends").at(0)));
+ _tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(subdev_spec_t("A:" + _tree->list(mb_path / "dboards/A/tx_frontends").at(0)));
_tree->access<std::string>(mb_path / "clock_source/value").set("internal");
_tree->access<std::string>(mb_path / "time_source/value").set("none");
@@ -436,3 +434,19 @@ sensor_value_t e100_impl::get_ref_locked(void){
const bool lock = _clock_ctrl->get_locked();
return sensor_value_t("Ref", lock, "locked", "unlocked");
}
+
+void e100_impl::check_fpga_compat(void){
+ const boost::uint32_t fpga_compat_num = _fpga_ctrl->peek32(E100_REG_RB_COMPAT);
+ boost::uint16_t fpga_major = fpga_compat_num >> 16, fpga_minor = fpga_compat_num & 0xffff;
+ if (fpga_major == 0){ //old version scheme
+ fpga_major = fpga_minor;
+ fpga_minor = 0;
+ }
+ if (fpga_major != E100_FPGA_COMPAT_NUM){
+ throw uhd::runtime_error(str(boost::format(
+ "Expected FPGA compatibility number %d, but got %d:\n"
+ "The FPGA build is not compatible with the host code build."
+ ) % int(E100_FPGA_COMPAT_NUM) % fpga_major));
+ }
+ _tree->create<std::string>("/mboards/0/fpga_version").set(str(boost::format("%u.%u") % fpga_major % fpga_minor));
+}
diff --git a/host/lib/usrp/e100/e100_impl.hpp b/host/lib/usrp/e100/e100_impl.hpp
index 4b2ec5ee0..f3e481b93 100644
--- a/host/lib/usrp/e100/e100_impl.hpp
+++ b/host/lib/usrp/e100/e100_impl.hpp
@@ -33,11 +33,10 @@
#include <uhd/usrp/mboard_eeprom.hpp>
#include <uhd/usrp/gps_ctrl.hpp>
#include <uhd/types/sensors.hpp>
-#include <uhd/types/otw_type.hpp>
-#include <uhd/types/clock_config.hpp>
#include <uhd/types/stream_cmd.hpp>
#include <uhd/usrp/dboard_manager.hpp>
#include <uhd/transport/zero_copy.hpp>
+#include <boost/weak_ptr.hpp>
#ifndef INCLUDED_E100_IMPL_HPP
#define INCLUDED_E100_IMPL_HPP
@@ -49,7 +48,7 @@ static const double E100_RX_LINK_RATE_BPS = 166e6/3/2*2;
static const double E100_TX_LINK_RATE_BPS = 166e6/3/1*2;
static const std::string E100_I2C_DEV_NODE = "/dev/i2c-3";
static const std::string E100_UART_DEV_NODE = "/dev/ttyO0";
-static const boost::uint16_t E100_FPGA_COMPAT_NUM = 0x06;
+static const boost::uint16_t E100_FPGA_COMPAT_NUM = 0x08;
static const boost::uint32_t E100_RX_SID_BASE = 2;
static const boost::uint32_t E100_TX_ASYNC_SID = 1;
static const double E100_DEFAULT_CLOCK_RATE = 64e6;
@@ -78,11 +77,9 @@ public:
~e100_impl(void);
//the io interface
- size_t send(const send_buffs_type &, size_t, const uhd::tx_metadata_t &, const uhd::io_type_t &, send_mode_t, double);
- size_t recv(const recv_buffs_type &, size_t, uhd::rx_metadata_t &, const uhd::io_type_t &, recv_mode_t, double);
+ uhd::rx_streamer::sptr get_rx_stream(const uhd::stream_args_t &args);
+ uhd::tx_streamer::sptr get_tx_stream(const uhd::stream_args_t &args);
bool recv_async_msg(uhd::async_metadata_t &, double);
- size_t get_max_send_samps_per_packet(void) const;
- size_t get_max_recv_samps_per_packet(void) const;
private:
uhd::property_tree::sptr _tree;
@@ -110,7 +107,6 @@ private:
uhd::usrp::dboard_iface::sptr _dboard_iface;
//handle io stuff
- uhd::otw_type_t _rx_otw_type, _tx_otw_type;
UHD_PIMPL_DECL(io_impl) _io_impl;
void io_init(void);
@@ -119,16 +115,21 @@ private:
return _tree;
}
+ std::vector<boost::weak_ptr<uhd::rx_streamer> > _rx_streamers;
+ std::vector<boost::weak_ptr<uhd::tx_streamer> > _tx_streamers;
+
double update_rx_codec_gain(const double); //sets A and B at once
void set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &);
void set_db_eeprom(const std::string &, const uhd::usrp::dboard_eeprom_t &);
void update_tick_rate(const double rate);
- void update_rx_samp_rate(const double rate);
- void update_tx_samp_rate(const double rate);
+ void update_rx_samp_rate(const size_t, const double rate);
+ void update_tx_samp_rate(const size_t, const double rate);
+ void update_rates(void);
void update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &);
void update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &);
void update_clock_source(const std::string &);
uhd::sensor_value_t get_ref_locked(void);
+ void check_fpga_compat(void);
};
diff --git a/host/lib/usrp/e100/e100_regs.hpp b/host/lib/usrp/e100/e100_regs.hpp
index 28ef707dc..f24f5895b 100644
--- a/host/lib/usrp/e100/e100_regs.hpp
+++ b/host/lib/usrp/e100/e100_regs.hpp
@@ -31,7 +31,6 @@
#define E100_REG_MISC_RX_LEN E100_REG_MISC_BASE + 10
#define E100_REG_MISC_TX_LEN E100_REG_MISC_BASE + 12
#define E100_REG_MISC_XFER_RATE E100_REG_MISC_BASE + 14
-#define E100_REG_MISC_COMPAT E100_REG_MISC_BASE + 16
/////////////////////////////////////////////////////
// Slave 1 -- UART
@@ -67,43 +66,6 @@
#define E100_REG_ERR_BUFF E100_REG_SLAVE(5)
-////////////////////////////////////////////////
-// Slave 4 -- GPIO
-
-#define E100_REG_GPIO_BASE E100_REG_SLAVE(4)
-
-#define E100_REG_GPIO_RX_IO E100_REG_GPIO_BASE + 0
-#define E100_REG_GPIO_TX_IO E100_REG_GPIO_BASE + 2
-#define E100_REG_GPIO_RX_DDR E100_REG_GPIO_BASE + 4
-#define E100_REG_GPIO_TX_DDR E100_REG_GPIO_BASE + 6
-#define E100_REG_GPIO_RX_SEL E100_REG_GPIO_BASE + 8
-#define E100_REG_GPIO_TX_SEL E100_REG_GPIO_BASE + 10
-#define E100_REG_GPIO_RX_DBG E100_REG_GPIO_BASE + 12
-#define E100_REG_GPIO_TX_DBG E100_REG_GPIO_BASE + 14
-
-//possible bit values for sel when dbg is 0:
-#define GPIO_SEL_SW 0 // if pin is an output, set by software in the io reg
-#define GPIO_SEL_ATR 1 // if pin is an output, set by ATR logic
-
-//possible bit values for sel when dbg is 1:
-#define GPIO_SEL_DEBUG_0 0 // if pin is an output, debug lines from FPGA fabric
-#define GPIO_SEL_DEBUG_1 1 // if pin is an output, debug lines from FPGA fabric
-
-///////////////////////////////////////////////////
-// Slave 6 -- ATR Controller
-// 16 regs
-
-#define E100_REG_ATR_BASE E100_REG_SLAVE(6)
-
-#define E100_REG_ATR_IDLE_RXSIDE E100_REG_ATR_BASE + 0
-#define E100_REG_ATR_IDLE_TXSIDE E100_REG_ATR_BASE + 2
-#define E100_REG_ATR_INTX_RXSIDE E100_REG_ATR_BASE + 4
-#define E100_REG_ATR_INTX_TXSIDE E100_REG_ATR_BASE + 6
-#define E100_REG_ATR_INRX_RXSIDE E100_REG_ATR_BASE + 8
-#define E100_REG_ATR_INRX_TXSIDE E100_REG_ATR_BASE + 10
-#define E100_REG_ATR_FULL_RXSIDE E100_REG_ATR_BASE + 12
-#define E100_REG_ATR_FULL_TXSIDE E100_REG_ATR_BASE + 14
-
///////////////////////////////////////////////////
// Slave 7 -- Readback Mux 32
@@ -115,6 +77,8 @@
#define E100_REG_RB_TIME_PPS_TICKS E100_REG_RB_MUX_32_BASE + 12
#define E100_REG_RB_MISC_TEST32 E100_REG_RB_MUX_32_BASE + 16
#define E100_REG_RB_ERR_STATUS E100_REG_RB_MUX_32_BASE + 20
+#define E100_REG_RB_COMPAT E100_REG_RB_MUX_32_BASE + 24
+#define E100_REG_RB_GPIO E100_REG_RB_MUX_32_BASE + 28
////////////////////////////////////////////////////
// Slave 8 -- Settings Bus
@@ -141,6 +105,8 @@
#define UE_SR_CLEAR_TX_FIFO 62 // 1 reg
#define UE_SR_GLOBAL_RESET 63 // 1 reg
+#define UE_SR_GPIO 128
+
#define E100_REG_SR_ADDR(n) (E100_REG_SLAVE(8) + (4*(n)))
#define E100_REG_SR_MISC_TEST32 E100_REG_SR_ADDR(UE_SR_REG_TEST32)
diff --git a/host/lib/usrp/e100/io_impl.cpp b/host/lib/usrp/e100/io_impl.cpp
index 0b81c1a86..3b0828b45 100644
--- a/host/lib/usrp/e100/io_impl.cpp
+++ b/host/lib/usrp/e100/io_impl.cpp
@@ -35,6 +35,7 @@
#include <fcntl.h> //open, close
#include <sstream>
#include <fstream>
+#include <boost/make_shared.hpp>
using namespace uhd;
using namespace uhd::usrp;
@@ -60,10 +61,6 @@ struct e100_impl::io_impl{
//which is after the states and booty which may hold managed buffers.
recv_packet_demuxer::sptr demuxer;
- //state management for the vrt packet handler code
- sph::recv_packet_handler recv_handler;
- sph::send_packet_handler send_handler;
-
//a pirate's life is the life for me!
void recv_pirate_loop(
spi_iface::sptr //keep a sptr to iface which shares gpio147
@@ -159,16 +156,6 @@ void e100_impl::io_impl::handle_irq(void){
**********************************************************************/
void e100_impl::io_init(void){
- //setup rx otw type
- _rx_otw_type.width = 16;
- _rx_otw_type.shift = 0;
- _rx_otw_type.byteorder = uhd::otw_type_t::BO_LITTLE_ENDIAN;
-
- //setup tx otw type
- _tx_otw_type.width = 16;
- _tx_otw_type.shift = 0;
- _tx_otw_type.byteorder = uhd::otw_type_t::BO_LITTLE_ENDIAN;
-
//create new io impl
_io_impl = UHD_PIMPL_MAKE(io_impl, ());
_io_impl->demuxer = recv_packet_demuxer::make(_data_transport, _rx_dsps.size(), E100_RX_SID_BASE);
@@ -178,6 +165,10 @@ void e100_impl::io_init(void){
_fpga_ctrl->poke32(E100_REG_CLEAR_RX, 0);
_fpga_ctrl->poke32(E100_REG_CLEAR_TX, 0);
+ //allocate streamer weak ptrs containers
+ _rx_streamers.resize(_rx_dsps.size());
+ _tx_streamers.resize(1/*known to be 1 dsp*/);
+
//prepare the async msg buffer for incoming messages
_fpga_ctrl->poke32(E100_REG_SR_ERR_CTRL, 1 << 0); //clear
while ((_fpga_ctrl->peek32(E100_REG_RB_ERR_STATUS) & (1 << 2)) == 0){} //wait for idle
@@ -187,37 +178,58 @@ void e100_impl::io_init(void){
_io_impl->pirate_task = task::make(boost::bind(
&e100_impl::io_impl::recv_pirate_loop, _io_impl.get(), _aux_spi_iface
));
-
- //init some handler stuff
- _io_impl->recv_handler.set_vrt_unpacker(&vrt::if_hdr_unpack_le);
- _io_impl->recv_handler.set_converter(_rx_otw_type);
- _io_impl->send_handler.set_vrt_packer(&vrt::if_hdr_pack_le);
- _io_impl->send_handler.set_converter(_tx_otw_type);
- _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet());
}
void e100_impl::update_tick_rate(const double rate){
_io_impl->tick_rate = rate;
- boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock();
- _io_impl->recv_handler.set_tick_rate(rate);
- boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock();
- _io_impl->send_handler.set_tick_rate(rate);
+
+ //update the tick rate on all existing streamers -> thread safe
+ for (size_t i = 0; i < _rx_streamers.size(); i++){
+ boost::shared_ptr<sph::recv_packet_streamer> my_streamer =
+ boost::dynamic_pointer_cast<sph::recv_packet_streamer>(_rx_streamers[i].lock());
+ if (my_streamer.get() == NULL) continue;
+ my_streamer->set_tick_rate(rate);
+ }
+ for (size_t i = 0; i < _tx_streamers.size(); i++){
+ boost::shared_ptr<sph::send_packet_streamer> my_streamer =
+ boost::dynamic_pointer_cast<sph::send_packet_streamer>(_tx_streamers[i].lock());
+ if (my_streamer.get() == NULL) continue;
+ my_streamer->set_tick_rate(rate);
+ }
}
-void e100_impl::update_rx_samp_rate(const double rate){
- boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock();
- _io_impl->recv_handler.set_samp_rate(rate);
- const double adj = _rx_dsps.front()->get_scaling_adjustment();
- _io_impl->recv_handler.set_scale_factor(adj/32767.);
+void e100_impl::update_rx_samp_rate(const size_t dspno, const double rate){
+ boost::shared_ptr<sph::recv_packet_streamer> my_streamer =
+ boost::dynamic_pointer_cast<sph::recv_packet_streamer>(_rx_streamers[dspno].lock());
+ if (my_streamer.get() == NULL) return;
+
+ my_streamer->set_samp_rate(rate);
+ const double adj = _rx_dsps[dspno]->get_scaling_adjustment();
+ my_streamer->set_scale_factor(adj);
+}
+
+void e100_impl::update_tx_samp_rate(const size_t dspno, const double rate){
+ boost::shared_ptr<sph::send_packet_streamer> my_streamer =
+ boost::dynamic_pointer_cast<sph::send_packet_streamer>(_tx_streamers[dspno].lock());
+ if (my_streamer.get() == NULL) return;
+
+ my_streamer->set_samp_rate(rate);
}
-void e100_impl::update_tx_samp_rate(const double rate){
- boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock();
- _io_impl->send_handler.set_samp_rate(rate);
+void e100_impl::update_rates(void){
+ const fs_path mb_path = "/mboards/0";
+ _tree->access<double>(mb_path / "tick_rate").update();
+
+ //and now that the tick rate is set, init the host rates to something
+ BOOST_FOREACH(const std::string &name, _tree->list(mb_path / "rx_dsps")){
+ _tree->access<double>(mb_path / "rx_dsps" / name / "rate" / "value").update();
+ }
+ BOOST_FOREACH(const std::string &name, _tree->list(mb_path / "tx_dsps")){
+ _tree->access<double>(mb_path / "tx_dsps" / name / "rate" / "value").update();
+ }
}
void e100_impl::update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){
- boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock();
fs_path root = "/mboards/0/dboards";
//sanity checking
@@ -231,22 +243,9 @@ void e100_impl::update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){
_rx_dsps[i]->set_mux(conn, fe_swapped);
}
_rx_fe->set_mux(fe_swapped);
-
- //resize for the new occupancy
- _io_impl->recv_handler.resize(spec.size());
-
- //bind new callbacks for the handler
- for (size_t i = 0; i < _io_impl->recv_handler.size(); i++){
- _rx_dsps[i]->set_nsamps_per_packet(get_max_recv_samps_per_packet()); //seems to be a good place to set this
- _io_impl->recv_handler.set_xport_chan_get_buff(i, boost::bind(
- &recv_packet_demuxer::get_recv_buff, _io_impl->demuxer, i, _1
- ));
- _io_impl->recv_handler.set_overflow_handler(i, boost::bind(&rx_dsp_core_200::handle_overflow, _rx_dsps[i]));
- }
}
void e100_impl::update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){
- boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock();
fs_path root = "/mboards/0/dboards";
//sanity checking
@@ -255,73 +254,122 @@ void e100_impl::update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){
//set the mux for this spec
const std::string conn = _tree->access<std::string>(root / spec[0].db_name / "tx_frontends" / spec[0].sd_name / "connection").get();
_tx_fe->set_mux(conn);
+}
- //resize for the new occupancy
- _io_impl->send_handler.resize(spec.size());
-
- //bind new callbacks for the handler
- for (size_t i = 0; i < _io_impl->send_handler.size(); i++){
- _io_impl->send_handler.set_xport_chan_get_buff(i, boost::bind(
- &zero_copy_if::get_send_buff, _data_transport, _1
- ));
- }
+/***********************************************************************
+ * Async Recv
+ **********************************************************************/
+bool e100_impl::recv_async_msg(
+ async_metadata_t &async_metadata, double timeout
+){
+ boost::this_thread::disable_interruption di; //disable because the wait can throw
+ return _io_impl->async_msg_fifo.pop_with_timed_wait(async_metadata, timeout);
}
/***********************************************************************
- * Data Send
+ * Receive streamer
**********************************************************************/
-size_t e100_impl::get_max_send_samps_per_packet(void) const{
+rx_streamer::sptr e100_impl::get_rx_stream(const uhd::stream_args_t &args_){
+ stream_args_t args = args_;
+
+ //setup defaults for unspecified values
+ args.otw_format = args.otw_format.empty()? "sc16" : args.otw_format;
+ args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels;
+ const unsigned sc8_scalar = unsigned(args.args.cast<double>("scalar", 0x400));
+
+ //calculate packet size
static const size_t hdr_size = 0
+ vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
+ + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
;
- size_t bpp = _data_transport->get_send_frame_size() - hdr_size;
- return bpp/_tx_otw_type.get_sample_size();
-}
+ const size_t bpp = _data_transport->get_recv_frame_size() - hdr_size;
+ const size_t spp = bpp/convert::get_bytes_per_item(args.otw_format);
+
+ //make the new streamer given the samples per packet
+ boost::shared_ptr<sph::recv_packet_streamer> my_streamer = boost::make_shared<sph::recv_packet_streamer>(spp);
+
+ //init some streamer stuff
+ my_streamer->resize(args.channels.size());
+ my_streamer->set_vrt_unpacker(&vrt::if_hdr_unpack_le);
+
+ //set the converter
+ uhd::convert::id_type id;
+ id.input_format = args.otw_format + "_item32_le";
+ id.num_inputs = 1;
+ id.output_format = args.cpu_format;
+ id.num_outputs = 1;
+ my_streamer->set_converter(id);
+
+ //bind callbacks for the handler
+ for (size_t chan_i = 0; chan_i < args.channels.size(); chan_i++){
+ const size_t dsp = args.channels[chan_i];
+ _rx_dsps[dsp]->set_nsamps_per_packet(spp); //seems to be a good place to set this
+ _rx_dsps[dsp]->set_format(args.otw_format, sc8_scalar);
+ my_streamer->set_xport_chan_get_buff(chan_i, boost::bind(
+ &recv_packet_demuxer::get_recv_buff, _io_impl->demuxer, dsp, _1
+ ));
+ my_streamer->set_overflow_handler(chan_i, boost::bind(
+ &rx_dsp_core_200::handle_overflow, _rx_dsps[dsp]
+ ));
+ _rx_streamers[dsp] = my_streamer; //store weak pointer
+ }
-size_t e100_impl::send(
- const send_buffs_type &buffs, size_t nsamps_per_buff,
- const tx_metadata_t &metadata, const io_type_t &io_type,
- send_mode_t send_mode, double timeout
-){
- return _io_impl->send_handler.send(
- buffs, nsamps_per_buff,
- metadata, io_type,
- send_mode, timeout
- );
+ //sets all tick and samp rates on this streamer
+ this->update_rates();
+
+ return my_streamer;
}
/***********************************************************************
- * Data Recv
+ * Transmit streamer
**********************************************************************/
-size_t e100_impl::get_max_recv_samps_per_packet(void) const{
+tx_streamer::sptr e100_impl::get_tx_stream(const uhd::stream_args_t &args_){
+ stream_args_t args = args_;
+
+ //setup defaults for unspecified values
+ args.otw_format = args.otw_format.empty()? "sc16" : args.otw_format;
+ args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels;
+
+ if (args.otw_format != "sc16"){
+ throw uhd::value_error("USRP TX cannot handle requested wire format: " + args.otw_format);
+ }
+
+ //calculate packet size
static const size_t hdr_size = 0
+ vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
- + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
;
- size_t bpp = _data_transport->get_recv_frame_size() - hdr_size;
- return bpp/_rx_otw_type.get_sample_size();
-}
+ static const size_t bpp = _data_transport->get_send_frame_size() - hdr_size;
+ const size_t spp = bpp/convert::get_bytes_per_item(args.otw_format);
+
+ //make the new streamer given the samples per packet
+ boost::shared_ptr<sph::send_packet_streamer> my_streamer = boost::make_shared<sph::send_packet_streamer>(spp);
+
+ //init some streamer stuff
+ my_streamer->resize(args.channels.size());
+ my_streamer->set_vrt_packer(&vrt::if_hdr_pack_le);
+
+ //set the converter
+ uhd::convert::id_type id;
+ id.input_format = args.cpu_format;
+ id.num_inputs = 1;
+ id.output_format = args.otw_format + "_item32_le";
+ id.num_outputs = 1;
+ my_streamer->set_converter(id);
+
+ //bind callbacks for the handler
+ for (size_t chan_i = 0; chan_i < args.channels.size(); chan_i++){
+ const size_t dsp = args.channels[chan_i];
+ UHD_ASSERT_THROW(dsp == 0); //always 0
+ my_streamer->set_xport_chan_get_buff(chan_i, boost::bind(
+ &zero_copy_if::get_send_buff, _data_transport, _1
+ ));
+ _tx_streamers[dsp] = my_streamer; //store weak pointer
+ }
-size_t e100_impl::recv(
- const recv_buffs_type &buffs, size_t nsamps_per_buff,
- rx_metadata_t &metadata, const io_type_t &io_type,
- recv_mode_t recv_mode, double timeout
-){
- return _io_impl->recv_handler.recv(
- buffs, nsamps_per_buff,
- metadata, io_type,
- recv_mode, timeout
- );
-}
+ //sets all tick and samp rates on this streamer
+ this->update_rates();
-/***********************************************************************
- * Async Recv
- **********************************************************************/
-bool e100_impl::recv_async_msg(
- async_metadata_t &async_metadata, double timeout
-){
- boost::this_thread::disable_interruption di; //disable because the wait can throw
- return _io_impl->async_msg_fifo.pop_with_timed_wait(async_metadata, timeout);
+ return my_streamer;
}