aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/usrp2
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp/usrp2')
-rw-r--r--host/lib/usrp/usrp2/clock_control.cpp156
-rw-r--r--host/lib/usrp/usrp2/clock_control.hpp60
-rw-r--r--host/lib/usrp/usrp2/dboard_iface.cpp279
-rw-r--r--host/lib/usrp/usrp2/dboard_impl.cpp15
-rw-r--r--host/lib/usrp/usrp2/dboard_interface.cpp280
-rw-r--r--host/lib/usrp/usrp2/dsp_impl.cpp28
-rw-r--r--host/lib/usrp/usrp2/fw_common.h7
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp153
-rw-r--r--host/lib/usrp/usrp2/mboard_impl.cpp67
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.cpp168
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.hpp103
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp84
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp47
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.hpp5
14 files changed, 909 insertions, 543 deletions
diff --git a/host/lib/usrp/usrp2/clock_control.cpp b/host/lib/usrp/usrp2/clock_control.cpp
new file mode 100644
index 000000000..dcd7ce9da
--- /dev/null
+++ b/host/lib/usrp/usrp2/clock_control.cpp
@@ -0,0 +1,156 @@
+//
+// 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 "usrp2_impl.hpp"
+#include "clock_control.hpp"
+#include "ad9510_regs.hpp"
+#include "usrp2_regs.hpp" //spi slave constants
+#include <boost/cstdint.hpp>
+
+using namespace uhd::usrp;
+
+/*!
+ * A usrp2 clock control specific to the ad9510 ic.
+ */
+class clock_control_ad9510 : public clock_control{
+public:
+ clock_control_ad9510(usrp2_iface::sptr iface){
+ _iface = iface;
+
+ _ad9510_regs.cp_current_setting = ad9510_regs_t::CP_CURRENT_SETTING_3_0MA;
+ this->write_reg(0x09);
+
+ // Setup the clock registers to 100MHz:
+ // This was already done by the firmware (or the host couldnt communicate).
+ // We could remove this part, and just leave it to the firmware.
+ // But why not leave it in for those who want to mess with clock settings?
+ // 100mhz = 10mhz/R * (P*B + A)
+
+ _ad9510_regs.pll_power_down = ad9510_regs_t::PLL_POWER_DOWN_NORMAL;
+ _ad9510_regs.prescaler_value = ad9510_regs_t::PRESCALER_VALUE_DIV2;
+ this->write_reg(0x0A);
+
+ _ad9510_regs.acounter = 0;
+ this->write_reg(0x04);
+
+ _ad9510_regs.bcounter_msb = 0;
+ _ad9510_regs.bcounter_lsb = 5;
+ this->write_reg(0x05);
+ this->write_reg(0x06);
+
+ _ad9510_regs.ref_counter_msb = 0;
+ _ad9510_regs.ref_counter_lsb = 1; // r divider = 1
+ this->write_reg(0x0B);
+ this->write_reg(0x0C);
+
+ /* regs will be updated in commands below */
+
+ this->enable_external_ref(false);
+ this->enable_rx_dboard_clock(false);
+ this->enable_tx_dboard_clock(false);
+
+ /* private clock enables, must be set here */
+ this->enable_dac_clock(true);
+ this->enable_adc_clock(true);
+
+ }
+
+ ~clock_control_ad9510(void){
+ /* private clock enables, must be set here */
+ this->enable_dac_clock(false);
+ this->enable_adc_clock(false);
+ }
+
+ //uses output clock 7 (cmos)
+ void enable_rx_dboard_clock(bool enb){
+ _ad9510_regs.power_down_lvds_cmos_out7 = enb? 0 : 1;
+ _ad9510_regs.lvds_cmos_select_out7 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT7_CMOS;
+ _ad9510_regs.output_level_lvds_out7 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT7_1_75MA;
+ this->write_reg(0x43);
+ this->update_regs();
+ }
+
+ //uses output clock 6 (cmos)
+ void enable_tx_dboard_clock(bool enb){
+ _ad9510_regs.power_down_lvds_cmos_out6 = enb? 0 : 1;
+ _ad9510_regs.lvds_cmos_select_out6 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT6_CMOS;
+ _ad9510_regs.output_level_lvds_out6 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT6_1_75MA;
+ this->write_reg(0x42);
+ this->update_regs();
+ }
+
+ /*!
+ * If we are to use an external reference, enable the charge pump.
+ * \param enb true to enable the CP
+ */
+ void enable_external_ref(bool enb){
+ _ad9510_regs.charge_pump_mode = (enb)?
+ ad9510_regs_t::CHARGE_PUMP_MODE_NORMAL :
+ ad9510_regs_t::CHARGE_PUMP_MODE_3STATE ;
+ _ad9510_regs.pll_mux_control = ad9510_regs_t::PLL_MUX_CONTROL_DLD_HIGH;
+ _ad9510_regs.pfd_polarity = ad9510_regs_t::PFD_POLARITY_POS;
+ this->write_reg(0x08);
+ this->update_regs();
+ }
+
+private:
+ /*!
+ * Write a single register to the spi regs.
+ * \param addr the address to write
+ */
+ void write_reg(boost::uint8_t addr){
+ boost::uint32_t data = _ad9510_regs.get_write_reg(addr);
+ _iface->transact_spi(SPI_SS_AD9510, spi_config_t::EDGE_RISE, data, 24, false /*no rb*/);
+ }
+
+ /*!
+ * Tells the ad9510 to latch the settings into the operational registers.
+ */
+ void update_regs(void){
+ _ad9510_regs.update_registers = 1;
+ this->write_reg(0x5a);
+ }
+
+ //uses output clock 3 (pecl)
+ void enable_dac_clock(bool enb){
+ _ad9510_regs.power_down_lvpecl_out3 = (enb)?
+ ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_NORMAL :
+ ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_SAFE_PD;
+ _ad9510_regs.output_level_lvpecl_out3 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT3_810MV;
+ this->write_reg(0x3F);
+ this->update_regs();
+ }
+
+ //uses output clock 4 (lvds)
+ void enable_adc_clock(bool enb){
+ _ad9510_regs.power_down_lvds_cmos_out4 = enb? 0 : 1;
+ _ad9510_regs.lvds_cmos_select_out4 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT4_LVDS;
+ _ad9510_regs.output_level_lvds_out4 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT4_1_75MA;
+ this->write_reg(0x40);
+ this->update_regs();
+ }
+
+ usrp2_iface::sptr _iface;
+ ad9510_regs_t _ad9510_regs;
+};
+
+/***********************************************************************
+ * Public make function for the ad9510 clock control
+ **********************************************************************/
+clock_control::sptr clock_control::make_ad9510(usrp2_iface::sptr iface){
+ return clock_control::sptr(new clock_control_ad9510(iface));
+}
diff --git a/host/lib/usrp/usrp2/clock_control.hpp b/host/lib/usrp/usrp2/clock_control.hpp
new file mode 100644
index 000000000..b64a53196
--- /dev/null
+++ b/host/lib/usrp/usrp2/clock_control.hpp
@@ -0,0 +1,60 @@
+//
+// 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_CLOCK_CONTROL_HPP
+#define INCLUDED_CLOCK_CONTROL_HPP
+
+#include "usrp2_iface.hpp"
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+
+class clock_control : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<clock_control> sptr;
+
+ /*!
+ * Make a clock config for the ad9510 ic.
+ * \param _iface a pointer to the usrp2 interface object
+ * \return a new clock control object
+ */
+ static sptr make_ad9510(usrp2_iface::sptr iface);
+
+ /*!
+ * Enable/disable the rx dboard clock.
+ * \param enb true to enable
+ */
+ virtual void enable_rx_dboard_clock(bool enb) = 0;
+
+ /*!
+ * Enable/disable the tx dboard clock.
+ * \param enb true to enable
+ */
+ virtual void enable_tx_dboard_clock(bool enb) = 0;
+
+ /*!
+ * Enable/disable external reference.
+ * \param enb true to enable
+ */
+ virtual void enable_external_ref(bool enb) = 0;
+
+ /*!
+ * TODO other clock control api here....
+ */
+
+};
+
+#endif /* INCLUDED_CLOCK_CONTROL_HPP */
diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp
new file mode 100644
index 000000000..2859a7981
--- /dev/null
+++ b/host/lib/usrp/usrp2/dboard_iface.cpp
@@ -0,0 +1,279 @@
+//
+// 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 "usrp2_iface.hpp"
+#include "clock_control.hpp"
+#include "usrp2_regs.hpp"
+#include <uhd/types/dict.hpp>
+#include <uhd/utils/assert.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/asio.hpp> //htonl and ntohl
+#include <boost/math/special_functions/round.hpp>
+#include <algorithm>
+
+using namespace uhd::usrp;
+
+class usrp2_dboard_iface : public dboard_iface{
+public:
+ usrp2_dboard_iface(usrp2_iface::sptr iface, clock_control::sptr clk_ctrl);
+ ~usrp2_dboard_iface(void);
+
+ void write_aux_dac(unit_t, int, float);
+ float read_aux_adc(unit_t, int);
+
+ void set_atr_reg(unit_t, atr_reg_t, boost::uint16_t);
+ void set_gpio_ddr(unit_t, boost::uint16_t);
+ boost::uint16_t read_gpio(unit_t);
+
+ void write_i2c(int, const byte_vector_t &);
+ byte_vector_t read_i2c(int, size_t);
+
+ double get_clock_rate(unit_t);
+ void set_clock_enabled(unit_t, bool);
+ bool get_clock_enabled(unit_t);
+
+ void write_spi(
+ unit_t unit,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits
+ );
+
+ boost::uint32_t read_write_spi(
+ unit_t unit,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits
+ );
+
+private:
+ usrp2_iface::sptr _iface;
+ clock_control::sptr _clk_ctrl;
+ boost::uint32_t _ddr_shadow;
+};
+
+/***********************************************************************
+ * Make Function
+ **********************************************************************/
+dboard_iface::sptr make_usrp2_dboard_iface(
+ usrp2_iface::sptr iface,
+ clock_control::sptr clk_ctrl
+){
+ return dboard_iface::sptr(new usrp2_dboard_iface(iface, clk_ctrl));
+}
+
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+usrp2_dboard_iface::usrp2_dboard_iface(usrp2_iface::sptr iface, clock_control::sptr clk_ctrl){
+ _iface = iface;
+ _clk_ctrl = clk_ctrl;
+ _ddr_shadow = 0;
+
+ //set the selection mux to use atr
+ boost::uint32_t new_sels = 0x0;
+ for(size_t i = 0; i < 16; i++){
+ new_sels |= FRF_GPIO_SEL_ATR << (i*2);
+ }
+ _iface->poke32(FR_GPIO_TX_SEL, new_sels);
+ _iface->poke32(FR_GPIO_RX_SEL, new_sels);
+}
+
+usrp2_dboard_iface::~usrp2_dboard_iface(void){
+ /* NOP */
+}
+
+/***********************************************************************
+ * Clocks
+ **********************************************************************/
+double usrp2_dboard_iface::get_clock_rate(unit_t){
+ return _iface->get_master_clock_freq();
+}
+
+void usrp2_dboard_iface::set_clock_enabled(unit_t unit, bool enb){
+ switch(unit){
+ case UNIT_RX:
+ _clk_ctrl->enable_rx_dboard_clock(enb);
+ return;
+ case UNIT_TX:
+ _clk_ctrl->enable_tx_dboard_clock(enb);
+ return;
+ }
+}
+
+/***********************************************************************
+ * GPIO
+ **********************************************************************/
+static int unit_to_shift(dboard_iface::unit_t unit){
+ switch(unit){
+ case dboard_iface::UNIT_RX: return 0;
+ case dboard_iface::UNIT_TX: return 16;
+ }
+ throw std::runtime_error("unknown unit type");
+}
+
+void usrp2_dboard_iface::set_gpio_ddr(unit_t unit, boost::uint16_t value){
+ _ddr_shadow = \
+ (_ddr_shadow & ~(0xffff << unit_to_shift(unit))) |
+ (boost::uint32_t(value) << unit_to_shift(unit));
+ _iface->poke32(FR_GPIO_DDR, _ddr_shadow);
+}
+
+boost::uint16_t usrp2_dboard_iface::read_gpio(unit_t unit){
+ return boost::uint16_t(_iface->peek32(FR_GPIO_IO) >> unit_to_shift(unit));
+}
+
+void usrp2_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 = boost::assign::map_list_of
+ (UNIT_RX, boost::assign::map_list_of
+ (ATR_REG_IDLE, FR_ATR_IDLE_RXSIDE)
+ (ATR_REG_TX_ONLY, FR_ATR_INTX_RXSIDE)
+ (ATR_REG_RX_ONLY, FR_ATR_INRX_RXSIDE)
+ (ATR_REG_FULL_DUPLEX, FR_ATR_FULL_RXSIDE)
+ )
+ (UNIT_TX, boost::assign::map_list_of
+ (ATR_REG_IDLE, FR_ATR_IDLE_TXSIDE)
+ (ATR_REG_TX_ONLY, FR_ATR_INTX_TXSIDE)
+ (ATR_REG_RX_ONLY, FR_ATR_INRX_TXSIDE)
+ (ATR_REG_FULL_DUPLEX, FR_ATR_FULL_TXSIDE)
+ )
+ ;
+ _iface->poke16(unit_to_atr_to_addr[unit][atr], value);
+}
+
+/***********************************************************************
+ * SPI
+ **********************************************************************/
+/*!
+ * Static function to convert a unit type enum
+ * to an over-the-wire value for the spi device.
+ * \param unit the dboard interface unit type enum
+ * \return an over the wire representation
+ */
+static boost::uint8_t unit_to_otw_spi_dev(dboard_iface::unit_t unit){
+ switch(unit){
+ case dboard_iface::UNIT_TX: return SPI_SS_TX_DB;
+ case dboard_iface::UNIT_RX: return SPI_SS_RX_DB;
+ }
+ throw std::invalid_argument("unknown unit type");
+}
+
+void usrp2_dboard_iface::write_spi(
+ unit_t unit,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits
+){
+ _iface->transact_spi(unit_to_otw_spi_dev(unit), config, data, num_bits, false /*no rb*/);
+}
+
+boost::uint32_t usrp2_dboard_iface::read_write_spi(
+ unit_t unit,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits
+){
+ return _iface->transact_spi(unit_to_otw_spi_dev(unit), config, data, num_bits, true /*rb*/);
+}
+
+/***********************************************************************
+ * I2C
+ **********************************************************************/
+void usrp2_dboard_iface::write_i2c(int i2c_addr, const byte_vector_t &buf){
+ //setup the out data
+ usrp2_ctrl_data_t out_data;
+ out_data.id = htonl(USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO);
+ out_data.data.i2c_args.addr = i2c_addr;
+ out_data.data.i2c_args.bytes = buf.size();
+
+ //limitation of i2c transaction size
+ ASSERT_THROW(buf.size() <= sizeof(out_data.data.i2c_args.data));
+
+ //copy in the data
+ std::copy(buf.begin(), buf.end(), out_data.data.i2c_args.data);
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
+ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE);
+}
+
+dboard_iface::byte_vector_t usrp2_dboard_iface::read_i2c(int i2c_addr, size_t num_bytes){
+ //setup the out data
+ usrp2_ctrl_data_t out_data;
+ out_data.id = htonl(USRP2_CTRL_ID_DO_AN_I2C_READ_FOR_ME_BRO);
+ out_data.data.i2c_args.addr = i2c_addr;
+ out_data.data.i2c_args.bytes = num_bytes;
+
+ //limitation of i2c transaction size
+ ASSERT_THROW(num_bytes <= sizeof(out_data.data.i2c_args.data));
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
+ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE);
+ ASSERT_THROW(in_data.data.i2c_args.addr = num_bytes);
+
+ //copy out the data
+ byte_vector_t result(num_bytes);
+ std::copy(in_data.data.i2c_args.data, in_data.data.i2c_args.data + num_bytes, result.begin());
+ return result;
+}
+
+/***********************************************************************
+ * Aux DAX/ADC
+ **********************************************************************/
+/*!
+ * Static function to convert a unit type enum
+ * to an over-the-wire value for the usrp2 control.
+ * \param unit the dboard interface unit type enum
+ * \return an over the wire representation
+ */
+static boost::uint8_t unit_to_otw(dboard_iface::unit_t unit){
+ switch(unit){
+ case dboard_iface::UNIT_TX: return USRP2_DIR_TX;
+ case dboard_iface::UNIT_RX: return USRP2_DIR_RX;
+ }
+ throw std::invalid_argument("unknown unit type");
+}
+
+void usrp2_dboard_iface::write_aux_dac(unit_t unit, int which, float value){
+ //setup the out data
+ usrp2_ctrl_data_t out_data;
+ out_data.id = htonl(USRP2_CTRL_ID_WRITE_THIS_TO_THE_AUX_DAC_BRO);
+ out_data.data.aux_args.dir = unit_to_otw(unit);
+ out_data.data.aux_args.which = which;
+ out_data.data.aux_args.value = htonl(boost::math::iround(4095*value/3.3));
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
+ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_DONE_WITH_THAT_AUX_DAC_DUDE);
+}
+
+float usrp2_dboard_iface::read_aux_adc(unit_t unit, int which){
+ //setup the out data
+ usrp2_ctrl_data_t out_data;
+ out_data.id = htonl(USRP2_CTRL_ID_READ_FROM_THIS_AUX_ADC_BRO);
+ out_data.data.aux_args.dir = unit_to_otw(unit);
+ out_data.data.aux_args.which = which;
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
+ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_DONE_WITH_THAT_AUX_ADC_DUDE);
+ return float(3.3*ntohl(in_data.data.aux_args.value)/4095);
+}
diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp
index d1515f2d5..fe74219d6 100644
--- a/host/lib/usrp/usrp2/dboard_impl.cpp
+++ b/host/lib/usrp/usrp2/dboard_impl.cpp
@@ -22,6 +22,9 @@
#include <uhd/usrp/dboard_props.hpp>
#include <uhd/utils/assert.hpp>
#include <boost/format.hpp>
+#include <boost/bind.hpp>
+#include <boost/asio.hpp> //htonl and ntohl
+#include <iostream>
using namespace uhd;
using namespace uhd::usrp;
@@ -33,7 +36,7 @@ void usrp2_impl::dboard_init(void){
//grab the dboard ids over the control line
usrp2_ctrl_data_t out_data;
out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_DBOARD_IDS_BRO);
- usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
+ usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THESE_ARE_MY_DBOARD_IDS_DUDE);
//extract the dboard ids an convert them
@@ -41,11 +44,11 @@ void usrp2_impl::dboard_init(void){
dboard_id_t tx_dboard_id = ntohs(in_data.data.dboard_ids.tx_id);
//create a new dboard interface and manager
- dboard_interface::sptr _dboard_interface(
- make_usrp2_dboard_interface(this)
+ dboard_iface::sptr _dboard_iface(
+ make_usrp2_dboard_iface(_iface, _clk_ctrl)
);
_dboard_manager = dboard_manager::make(
- rx_dboard_id, tx_dboard_id, _dboard_interface
+ rx_dboard_id, tx_dboard_id, _dboard_iface
);
//load dboards
@@ -81,7 +84,7 @@ void usrp2_impl::update_rx_mux_config(void){
rx_mux = (((rx_mux >> 0) & 0x3) << 2) | (((rx_mux >> 2) & 0x3) << 0);
}
- this->poke32(FR_DSP_RX_MUX, rx_mux);
+ _iface->poke32(FR_DSP_RX_MUX, rx_mux);
}
void usrp2_impl::update_tx_mux_config(void){
@@ -94,7 +97,7 @@ void usrp2_impl::update_tx_mux_config(void){
tx_mux = (((tx_mux >> 0) & 0x1) << 1) | (((tx_mux >> 1) & 0x1) << 0);
}
- this->poke32(FR_DSP_TX_MUX, tx_mux);
+ _iface->poke32(FR_DSP_TX_MUX, tx_mux);
}
/***********************************************************************
diff --git a/host/lib/usrp/usrp2/dboard_interface.cpp b/host/lib/usrp/usrp2/dboard_interface.cpp
deleted file mode 100644
index 6dd756420..000000000
--- a/host/lib/usrp/usrp2/dboard_interface.cpp
+++ /dev/null
@@ -1,280 +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 "usrp2_impl.hpp"
-#include "usrp2_regs.hpp"
-#include <uhd/types/dict.hpp>
-#include <uhd/utils/assert.hpp>
-#include <boost/assign/list_of.hpp>
-#include <algorithm>
-
-using namespace uhd::usrp;
-
-class usrp2_dboard_interface : public dboard_interface{
-public:
- usrp2_dboard_interface(usrp2_impl *impl);
- ~usrp2_dboard_interface(void);
-
- void write_aux_dac(unit_type_t, int, int);
- int read_aux_adc(unit_type_t, int);
-
- void set_atr_reg(gpio_bank_t, atr_reg_t, boost::uint16_t);
- void set_gpio_ddr(gpio_bank_t, boost::uint16_t);
- boost::uint16_t read_gpio(gpio_bank_t);
-
- void write_i2c(int, const byte_vector_t &);
- byte_vector_t read_i2c(int, size_t);
-
- double get_rx_clock_rate(void);
- double get_tx_clock_rate(void);
-
-private:
- byte_vector_t transact_spi(
- spi_dev_t, spi_edge_t, const byte_vector_t &, bool
- );
-
- usrp2_impl *_impl;
- boost::uint32_t _ddr_shadow;
-};
-
-/***********************************************************************
- * Make Function
- **********************************************************************/
-dboard_interface::sptr make_usrp2_dboard_interface(usrp2_impl *impl){
- return dboard_interface::sptr(new usrp2_dboard_interface(impl));
-}
-
-/***********************************************************************
- * Structors
- **********************************************************************/
-usrp2_dboard_interface::usrp2_dboard_interface(usrp2_impl *impl){
- _impl = impl;
- _ddr_shadow = 0;
-
- //set the selection mux to use atr
- boost::uint32_t new_sels = 0x0;
- for(size_t i = 0; i < 16; i++){
- new_sels |= FRF_GPIO_SEL_ATR << (i*2);
- }
- _impl->poke32(FR_GPIO_TX_SEL, new_sels);
- _impl->poke32(FR_GPIO_RX_SEL, new_sels);
-}
-
-usrp2_dboard_interface::~usrp2_dboard_interface(void){
- /* NOP */
-}
-
-/***********************************************************************
- * Clock Rates
- **********************************************************************/
-double usrp2_dboard_interface::get_rx_clock_rate(void){
- return _impl->get_master_clock_freq();
-}
-
-double usrp2_dboard_interface::get_tx_clock_rate(void){
- return _impl->get_master_clock_freq();
-}
-
-/***********************************************************************
- * GPIO
- **********************************************************************/
-static int bank_to_shift(dboard_interface::gpio_bank_t bank){
- switch(bank){
- case dboard_interface::GPIO_BANK_RX: return 0;
- case dboard_interface::GPIO_BANK_TX: return 16;
- }
- throw std::runtime_error("unknown gpio bank type");
-}
-
-void usrp2_dboard_interface::set_gpio_ddr(gpio_bank_t bank, boost::uint16_t value){
- _ddr_shadow = \
- (_ddr_shadow & ~(0xffff << bank_to_shift(bank))) |
- (boost::uint32_t(value) << bank_to_shift(bank));
- _impl->poke32(FR_GPIO_DDR, _ddr_shadow);
-}
-
-boost::uint16_t usrp2_dboard_interface::read_gpio(gpio_bank_t bank){
- return boost::uint16_t(_impl->peek32(FR_GPIO_IO) >> bank_to_shift(bank));
-}
-
-void usrp2_dboard_interface::set_atr_reg(gpio_bank_t bank, atr_reg_t atr, boost::uint16_t value){
- //define mapping of bank to atr regs to register address
- static const uhd::dict<
- gpio_bank_t, uhd::dict<atr_reg_t, boost::uint32_t>
- > bank_to_atr_to_addr = boost::assign::map_list_of
- (GPIO_BANK_RX, boost::assign::map_list_of
- (ATR_REG_IDLE, FR_ATR_IDLE_RXSIDE)
- (ATR_REG_TX_ONLY, FR_ATR_INTX_RXSIDE)
- (ATR_REG_RX_ONLY, FR_ATR_INRX_RXSIDE)
- (ATR_REG_FULL_DUPLEX, FR_ATR_FULL_RXSIDE)
- )
- (GPIO_BANK_TX, boost::assign::map_list_of
- (ATR_REG_IDLE, FR_ATR_IDLE_TXSIDE)
- (ATR_REG_TX_ONLY, FR_ATR_INTX_TXSIDE)
- (ATR_REG_RX_ONLY, FR_ATR_INRX_TXSIDE)
- (ATR_REG_FULL_DUPLEX, FR_ATR_FULL_TXSIDE)
- )
- ;
- _impl->poke16(bank_to_atr_to_addr[bank][atr], value);
-}
-
-/***********************************************************************
- * SPI
- **********************************************************************/
-/*!
- * Static function to convert a spi dev enum
- * to an over-the-wire value for the usrp2 control.
- * \param dev the dboard interface spi dev enum
- * \return an over the wire representation
- */
-static boost::uint8_t spi_dev_to_otw(dboard_interface::spi_dev_t dev){
- switch(dev){
- case uhd::usrp::dboard_interface::SPI_DEV_TX: return SPI_SS_TX_DB;
- case uhd::usrp::dboard_interface::SPI_DEV_RX: return SPI_SS_RX_DB;
- }
- throw std::invalid_argument("unknown spi device type");
-}
-
-/*!
- * Static function to convert a spi edge enum
- * to an over-the-wire value for the usrp2 control.
- * \param edge the dboard interface spi edge enum
- * \return an over the wire representation
- */
-static boost::uint8_t spi_edge_to_otw(dboard_interface::spi_edge_t edge){
- switch(edge){
- case uhd::usrp::dboard_interface::SPI_EDGE_RISE: return USRP2_CLK_EDGE_RISE;
- case uhd::usrp::dboard_interface::SPI_EDGE_FALL: return USRP2_CLK_EDGE_FALL;
- }
- throw std::invalid_argument("unknown spi edge type");
-}
-
-dboard_interface::byte_vector_t usrp2_dboard_interface::transact_spi(
- spi_dev_t dev,
- spi_edge_t edge,
- const byte_vector_t &buf,
- bool readback
-){
- //setup the out data
- usrp2_ctrl_data_t out_data;
- out_data.id = htonl(USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO);
- out_data.data.spi_args.dev = spi_dev_to_otw(dev);
- out_data.data.spi_args.edge = spi_edge_to_otw(edge);
- out_data.data.spi_args.readback = (readback)? 1 : 0;
- out_data.data.spi_args.bytes = buf.size();
-
- //limitation of spi transaction size
- ASSERT_THROW(buf.size() <= sizeof(out_data.data.spi_args.data));
-
- //copy in the data
- std::copy(buf.begin(), buf.end(), out_data.data.spi_args.data);
-
- //send and recv
- usrp2_ctrl_data_t in_data = _impl->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE);
- ASSERT_THROW(in_data.data.spi_args.bytes == buf.size());
-
- //copy out the data
- byte_vector_t result(buf.size());
- std::copy(in_data.data.spi_args.data, in_data.data.spi_args.data + buf.size(), result.begin());
- return result;
-}
-
-/***********************************************************************
- * I2C
- **********************************************************************/
-void usrp2_dboard_interface::write_i2c(int i2c_addr, const byte_vector_t &buf){
- //setup the out data
- usrp2_ctrl_data_t out_data;
- out_data.id = htonl(USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO);
- out_data.data.i2c_args.addr = i2c_addr;
- out_data.data.i2c_args.bytes = buf.size();
-
- //limitation of i2c transaction size
- ASSERT_THROW(buf.size() <= sizeof(out_data.data.i2c_args.data));
-
- //copy in the data
- std::copy(buf.begin(), buf.end(), out_data.data.i2c_args.data);
-
- //send and recv
- usrp2_ctrl_data_t in_data = _impl->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE);
-}
-
-dboard_interface::byte_vector_t usrp2_dboard_interface::read_i2c(int i2c_addr, size_t num_bytes){
- //setup the out data
- usrp2_ctrl_data_t out_data;
- out_data.id = htonl(USRP2_CTRL_ID_DO_AN_I2C_READ_FOR_ME_BRO);
- out_data.data.i2c_args.addr = i2c_addr;
- out_data.data.i2c_args.bytes = num_bytes;
-
- //limitation of i2c transaction size
- ASSERT_THROW(num_bytes <= sizeof(out_data.data.i2c_args.data));
-
- //send and recv
- usrp2_ctrl_data_t in_data = _impl->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE);
- ASSERT_THROW(in_data.data.i2c_args.addr = num_bytes);
-
- //copy out the data
- byte_vector_t result(num_bytes);
- std::copy(in_data.data.i2c_args.data, in_data.data.i2c_args.data + num_bytes, result.begin());
- return result;
-}
-
-/***********************************************************************
- * Aux DAX/ADC
- **********************************************************************/
-/*!
- * Static function to convert a unit type enum
- * to an over-the-wire value for the usrp2 control.
- * \param unit the dboard interface unit type enum
- * \return an over the wire representation
- */
-static boost::uint8_t spi_dev_to_otw(dboard_interface::unit_type_t unit){
- switch(unit){
- case uhd::usrp::dboard_interface::UNIT_TYPE_TX: return USRP2_DIR_TX;
- case uhd::usrp::dboard_interface::UNIT_TYPE_RX: return USRP2_DIR_RX;
- }
- throw std::invalid_argument("unknown unit type type");
-}
-
-void usrp2_dboard_interface::write_aux_dac(dboard_interface::unit_type_t unit, int which, int value){
- //setup the out data
- usrp2_ctrl_data_t out_data;
- out_data.id = htonl(USRP2_CTRL_ID_WRITE_THIS_TO_THE_AUX_DAC_BRO);
- out_data.data.aux_args.dir = spi_dev_to_otw(unit);
- out_data.data.aux_args.which = which;
- out_data.data.aux_args.value = htonl(value);
-
- //send and recv
- usrp2_ctrl_data_t in_data = _impl->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_DONE_WITH_THAT_AUX_DAC_DUDE);
-}
-
-int usrp2_dboard_interface::read_aux_adc(dboard_interface::unit_type_t unit, int which){
- //setup the out data
- usrp2_ctrl_data_t out_data;
- out_data.id = htonl(USRP2_CTRL_ID_READ_FROM_THIS_AUX_ADC_BRO);
- out_data.data.aux_args.dir = spi_dev_to_otw(unit);
- out_data.data.aux_args.which = which;
-
- //send and recv
- usrp2_ctrl_data_t in_data = _impl->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_DONE_WITH_THAT_AUX_ADC_DUDE);
- return ntohl(in_data.data.aux_args.value);
-}
diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp
index 92b55d029..204277ba7 100644
--- a/host/lib/usrp/usrp2/dsp_impl.cpp
+++ b/host/lib/usrp/usrp2/dsp_impl.cpp
@@ -20,6 +20,7 @@
#include <uhd/usrp/dsp_props.hpp>
#include <uhd/utils/assert.hpp>
#include <boost/format.hpp>
+#include <boost/bind.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/math/special_functions/round.hpp>
@@ -39,7 +40,8 @@ template <class T> T log2(T num){
* DDC Helper Methods
**********************************************************************/
static boost::uint32_t calculate_freq_word_and_update_actual_freq(double &freq, double clock_freq){
- double scale_factor = std::pow(2.0, 32);
+ ASSERT_THROW(std::abs(freq) < clock_freq/2.0);
+ static const double scale_factor = std::pow(2.0, 32);
//calculate the freq register word
boost::uint32_t freq_word = rint((freq / clock_freq) * scale_factor);
@@ -82,11 +84,11 @@ void usrp2_impl::init_ddc_config(void){
void usrp2_impl::update_ddc_config(void){
//set the decimation
- this->poke32(FR_DSP_RX_DECIM_RATE, _ddc_decim);
+ _iface->poke32(FR_DSP_RX_DECIM_RATE, _ddc_decim);
//set the scaling
static const boost::int16_t default_rx_scale_iq = 1024;
- this->poke32(FR_DSP_RX_SCALE_IQ,
+ _iface->poke32(FR_DSP_RX_SCALE_IQ,
calculate_iq_scale_word(default_rx_scale_iq, default_rx_scale_iq)
);
}
@@ -123,12 +125,10 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){
case DSP_PROP_FREQ_SHIFT:{
double new_freq = val.as<double>();
- 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
- this->poke32(FR_DSP_RX_FREQ,
- calculate_freq_word_and_update_actual_freq(_ddc_freq, get_master_clock_freq())
+ _iface->poke32(FR_DSP_RX_FREQ,
+ calculate_freq_word_and_update_actual_freq(new_freq, get_master_clock_freq())
);
+ _ddc_freq = new_freq; //shadow
}
return;
@@ -170,10 +170,10 @@ void usrp2_impl::update_duc_config(void){
boost::int16_t scale = rint((4096*std::pow(2, ceil(log2(interp_cubed))))/(1.65*interp_cubed));
//set the interpolation
- this->poke32(FR_DSP_TX_INTERP_RATE, _ddc_decim);
+ _iface->poke32(FR_DSP_TX_INTERP_RATE, _ddc_decim);
//set the scaling
- this->poke32(FR_DSP_TX_SCALE_IQ, calculate_iq_scale_word(scale, scale));
+ _iface->poke32(FR_DSP_TX_SCALE_IQ, calculate_iq_scale_word(scale, scale));
}
/***********************************************************************
@@ -208,12 +208,10 @@ void usrp2_impl::duc_set(const wax::obj &key, const wax::obj &val){
case DSP_PROP_FREQ_SHIFT:{
double new_freq = val.as<double>();
- 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
- this->poke32(FR_DSP_TX_FREQ,
- calculate_freq_word_and_update_actual_freq(_duc_freq, get_master_clock_freq())
+ _iface->poke32(FR_DSP_TX_FREQ,
+ calculate_freq_word_and_update_actual_freq(new_freq, get_master_clock_freq())
);
+ _duc_freq = new_freq; //shadow
}
return;
diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h
index 019f3b931..b600a2a70 100644
--- a/host/lib/usrp/usrp2/fw_common.h
+++ b/host/lib/usrp/usrp2/fw_common.h
@@ -110,10 +110,11 @@ typedef struct{
} dboard_ids;
struct {
_SINS_ uint8_t dev;
- _SINS_ uint8_t edge;
+ _SINS_ uint8_t miso_edge;
+ _SINS_ uint8_t mosi_edge;
_SINS_ uint8_t readback;
- _SINS_ uint8_t bytes;
- _SINS_ uint8_t data[sizeof(_SINS_ uint32_t)];
+ _SINS_ uint32_t data;
+ _SINS_ uint8_t num_bits;
} spi_args;
struct {
_SINS_ uint8_t addr;
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index a58e32619..367a1d9fb 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -15,9 +15,11 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include <complex>
-#include <boost/format.hpp>
#include "usrp2_impl.hpp"
+#include <uhd/transport/convert_types.hpp>
+#include <boost/format.hpp>
+#include <boost/asio.hpp> //htonl and ntohl
+#include <iostream>
using namespace uhd;
using namespace uhd::usrp;
@@ -25,101 +27,26 @@ using namespace uhd::transport;
namespace asio = boost::asio;
/***********************************************************************
- * Constants
- **********************************************************************/
-typedef std::complex<float> fc32_t;
-typedef std::complex<boost::int16_t> sc16_t;
-
-static const float shorts_per_float = float(1 << 15);
-static const float floats_per_short = float(1.0/shorts_per_float);
-
-/***********************************************************************
* Helper Functions
**********************************************************************/
void usrp2_impl::io_init(void){
+ //setup otw type
+ _otw_type.width = 16;
+ _otw_type.shift = 0;
+ _otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN;
+
//initially empty copy buffer
_rx_copy_buff = asio::buffer("", 0);
//send a small data packet so the usrp2 knows the udp source port
//and the maximum number of lines (32 bit words) per packet
+ managed_send_buffer::sptr send_buff = _data_transport->get_send_buff();
boost::uint32_t data[2] = {
htonl(USRP2_INVALID_VRT_HEADER),
htonl(_max_rx_samples_per_packet)
};
- _data_transport->send(asio::buffer(&data, sizeof(data)));
-}
-
-#define unrolled_loop(__inst, __len){ \
- size_t __i = 0; \
- for(; __i < (__len & ~0x3); __i+= 4){ \
- __inst(__i+0); __inst(__i+1); \
- __inst(__i+2); __inst(__i+3); \
- } \
- for(; __i < __len; __i++){ \
- __inst(__i); \
- } \
-}
-
-// 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(
- boost::uint32_t *usrp2_items,
- const fc32_t *host_floats,
- size_t num_samps
-){
- #define host_floats_to_usrp2_items_i(i){ \
- boost::uint16_t real = boost::int16_t(host_floats[i].real()*shorts_per_float); \
- boost::uint16_t imag = boost::int16_t(host_floats[i].imag()*shorts_per_float); \
- usrp2_items[i] = htonl((real << 16) | (imag << 0)); \
- }
- unrolled_loop(host_floats_to_usrp2_items_i, num_samps);
-}
-
-static inline void usrp2_items_to_host_floats(
- fc32_t *host_floats,
- const boost::uint32_t *usrp2_items,
- size_t num_samps
-){
- #define usrp2_items_to_host_floats_i(i){ \
- boost::uint32_t item = ntohl(usrp2_items[i]); \
- boost::int16_t real = boost::uint16_t(item >> 16); \
- boost::int16_t imag = boost::uint16_t(item >> 0); \
- host_floats[i] = fc32_t(float(real*floats_per_short), float(imag*floats_per_short)); \
- }
- unrolled_loop(usrp2_items_to_host_floats_i, num_samps);
-}
-
-static inline void host_items_to_usrp2_items(
- boost::uint32_t *usrp2_items,
- const boost::uint32_t *host_items,
- size_t num_samps
-){
- #define host_items_to_usrp2_items_i(i) usrp2_items[i] = htonl(host_items[i])
- if (is_big_endian){
- std::memcpy(usrp2_items, host_items, num_samps*sizeof(boost::uint32_t));
- }
- else{
- unrolled_loop(host_items_to_usrp2_items_i, num_samps);
- }
-}
-
-static inline void usrp2_items_to_host_items(
- boost::uint32_t *host_items,
- const boost::uint32_t *usrp2_items,
- size_t num_samps
-){
- #define usrp2_items_to_host_items_i(i) host_items[i] = ntohl(usrp2_items[i])
- if (is_big_endian){
- std::memcpy(host_items, usrp2_items, num_samps*sizeof(boost::uint32_t));
- }
- else{
- unrolled_loop(usrp2_items_to_host_items_i, num_samps);
- }
+ memcpy(send_buff->cast<void*>(), data, sizeof(data));
+ send_buff->done(sizeof(data));
}
/***********************************************************************
@@ -127,15 +54,15 @@ static inline void usrp2_items_to_host_items(
**********************************************************************/
void usrp2_impl::recv_raw(rx_metadata_t &metadata){
//do a receive
- _rx_smart_buff = _data_transport->recv();
+ _rx_smart_buff = _data_transport->get_recv_buff();
//unpack the vrt header
- size_t num_packet_words32 = asio::buffer_size(_rx_smart_buff->get())/sizeof(boost::uint32_t);
+ size_t num_packet_words32 = _rx_smart_buff->size()/sizeof(boost::uint32_t);
if (num_packet_words32 == 0){
_rx_copy_buff = boost::asio::buffer("", 0);
return; //must exit here after setting the buffer
}
- const boost::uint32_t *vrt_hdr = asio::buffer_cast<const boost::uint32_t *>(_rx_smart_buff->get());
+ const boost::uint32_t *vrt_hdr = _rx_smart_buff->cast<const boost::uint32_t *>();
size_t num_header_words32_out, num_payload_words32_out, packet_count_out;
try{
vrt::unpack(
@@ -144,7 +71,8 @@ void usrp2_impl::recv_raw(rx_metadata_t &metadata){
num_header_words32_out, //output
num_payload_words32_out, //output
num_packet_words32, //input
- packet_count_out //output
+ packet_count_out, //output
+ get_master_clock_freq()
);
}catch(const std::exception &e){
std::cerr << "bad vrt header: " << e.what() << std::endl;
@@ -176,10 +104,12 @@ size_t usrp2_impl::send(
){
tx_metadata_t metadata = metadata_; //rw copy to change later
- boost::uint32_t tx_mem[_mtu/sizeof(boost::uint32_t)];
- size_t num_samps = std::min(
+ transport::managed_send_buffer::sptr send_buff = _data_transport->get_send_buff();
+ boost::uint32_t *tx_mem = send_buff->cast<boost::uint32_t *>();
+ size_t num_samps = std::min(std::min(
asio::buffer_size(buff)/io_type.size,
- size_t(_max_tx_samples_per_packet)
+ size_t(_max_tx_samples_per_packet)),
+ send_buff->size()/io_type.size
);
//kill the end of burst flag if this is a fragment
@@ -196,25 +126,21 @@ size_t usrp2_impl::send(
num_header_words32, //output
num_samps, //input
num_packet_words32, //output
- packet_count //input
+ packet_count, //input
+ get_master_clock_freq()
);
boost::uint32_t *items = tx_mem + num_header_words32; //offset for data
- //copy the samples into the send buffer
- switch(io_type.tid){
- case io_type_t::COMPLEX_FLOAT32:
- host_floats_to_usrp2_items(items, asio::buffer_cast<const fc32_t*>(buff), num_samps);
- break;
- case io_type_t::COMPLEX_INT16:
- host_items_to_usrp2_items(items, asio::buffer_cast<const boost::uint32_t*>(buff), num_samps);
- break;
- default:
- throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%c\"") % io_type.tid));
- }
+ //copy-convert the samples into the send buffer
+ convert_io_type_to_otw_type(
+ asio::buffer_cast<const void*>(buff), io_type,
+ (void*)items, _otw_type,
+ num_samps
+ );
//send and return number of samples
- _data_transport->send(asio::buffer(tx_mem, num_packet_words32*sizeof(boost::uint32_t)));
+ send_buff->done(num_packet_words32*sizeof(boost::uint32_t));
return num_samps;
}
@@ -251,17 +177,12 @@ size_t usrp2_impl::recv(
metadata.fragment_offset = _fragment_offset_in_samps;
_fragment_offset_in_samps += num_samps; //set for next time
- //copy the samples from the recv buffer
- switch(io_type.tid){
- case io_type_t::COMPLEX_FLOAT32:
- usrp2_items_to_host_floats(asio::buffer_cast<fc32_t*>(buff), items, num_samps);
- break;
- case io_type_t::COMPLEX_INT16:
- usrp2_items_to_host_items(asio::buffer_cast<boost::uint32_t*>(buff), items, num_samps);
- break;
- default:
- throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%c\"") % io_type.tid));
- }
+ //copy-convert the samples from the recv buffer
+ convert_otw_type_to_io_type(
+ (const void*)items, _otw_type,
+ asio::buffer_cast<void*>(buff), io_type,
+ num_samps
+ );
//update the rx copy buffer to reflect the bytes copied
_rx_copy_buff = asio::buffer(
diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp
index 94ab88a6b..d7728238c 100644
--- a/host/lib/usrp/usrp2/mboard_impl.cpp
+++ b/host/lib/usrp/usrp2/mboard_impl.cpp
@@ -17,10 +17,14 @@
#include "usrp2_impl.hpp"
#include "usrp2_regs.hpp"
+#include "ad9777_regs.hpp"
#include <uhd/usrp/mboard_props.hpp>
#include <uhd/utils/assert.hpp>
#include <uhd/types/mac_addr.hpp>
#include <uhd/types/dict.hpp>
+#include <boost/bind.hpp>
+#include <boost/asio.hpp> //htonl and ntohl
+#include <boost/assign/list_of.hpp>
using namespace uhd;
using namespace uhd::usrp;
@@ -34,9 +38,31 @@ void usrp2_impl::mboard_init(void){
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);
+ _clk_ctrl = clock_control::make_ad9510(_iface);
+
+ //setup the ad9777 dac
+ ad9777_regs_t ad9777_regs;
+ ad9777_regs.x_1r_2r_mode = ad9777_regs_t::X_1R_2R_MODE_1R;
+ ad9777_regs.filter_interp_rate = ad9777_regs_t::FILTER_INTERP_RATE_4X;
+ ad9777_regs.mix_mode = ad9777_regs_t::MIX_MODE_REAL;
+ ad9777_regs.pll_divide_ratio = ad9777_regs_t::PLL_DIVIDE_RATIO_DIV1;
+ ad9777_regs.pll_state = ad9777_regs_t::PLL_STATE_OFF;
+ ad9777_regs.auto_cp_control = ad9777_regs_t::AUTO_CP_CONTROL_ENB;
+ //I dac values
+ ad9777_regs.idac_fine_gain_adjust = 0;
+ ad9777_regs.idac_coarse_gain_adjust = 0xf;
+ ad9777_regs.idac_offset_adjust_lsb = 0;
+ ad9777_regs.idac_offset_adjust_msb = 0;
+ //Q dac values
+ ad9777_regs.qdac_fine_gain_adjust = 0;
+ ad9777_regs.qdac_coarse_gain_adjust = 0xf;
+ ad9777_regs.qdac_offset_adjust_lsb = 0;
+ ad9777_regs.qdac_offset_adjust_msb = 0;
+ //write all regs
+ for(boost::uint8_t addr = 0; addr <= 0xC; addr++){
+ boost::uint16_t data = ad9777_regs.get_write_reg(addr);
+ _iface->transact_spi(SPI_SS_AD9777, spi_config_t::EDGE_RISE, data, 16, false /*no rb*/);
+ }
}
void usrp2_impl::init_clock_config(void){
@@ -67,19 +93,28 @@ void usrp2_impl::update_clock_config(void){
}
//set the pps flags
- this->poke32(FR_TIME64_FLAGS, pps_flags);
+ _iface->poke32(FR_TIME64_FLAGS, pps_flags);
+
+ //clock source ref 10mhz
+ switch(_clock_config.ref_source){
+ case clock_config_t::REF_INT : _iface->poke32(FR_CLOCK_CONTROL, 0x10); break;
+ case clock_config_t::REF_SMA : _iface->poke32(FR_CLOCK_CONTROL, 0x1C); break;
+ case clock_config_t::REF_MIMO: _iface->poke32(FR_CLOCK_CONTROL, 0x15); break;
+ }
- //TODO clock source ref 10mhz (spi ad9510)
+ //clock source ref 10mhz
+ bool use_external = _clock_config.ref_source != clock_config_t::REF_INT;
+ _clk_ctrl->enable_external_ref(use_external);
}
void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){
//set ticks and seconds
- this->poke32(FR_TIME64_SECS, time_spec.secs);
- this->poke32(FR_TIME64_TICKS, time_spec.ticks);
+ _iface->poke32(FR_TIME64_SECS, time_spec.secs);
+ _iface->poke32(FR_TIME64_TICKS, time_spec.get_ticks(get_master_clock_freq()));
//set the register to latch it all in
boost::uint32_t imm_flags = (now)? FRF_TIME64_LATCH_NOW : FRF_TIME64_LATCH_NEXT_PPS;
- this->poke32(FR_TIME64_IMM, imm_flags);
+ _iface->poke32(FR_TIME64_IMM, imm_flags);
}
void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){
@@ -88,7 +123,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){
out_data.id = htonl(USRP2_CTRL_ID_SEND_STREAM_COMMAND_FOR_ME_BRO);
out_data.data.stream_cmd.now = (stream_cmd.stream_now)? 1 : 0;
out_data.data.stream_cmd.secs = htonl(stream_cmd.time_spec.secs);
- out_data.data.stream_cmd.ticks = htonl(stream_cmd.time_spec.ticks);
+ out_data.data.stream_cmd.ticks = htonl(stream_cmd.time_spec.get_ticks(get_master_clock_freq()));
//set these to defaults, then change in the switch statement
out_data.data.stream_cmd.continuous = 0;
@@ -115,7 +150,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){
}
//send and recv
- usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
+ usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE);
}
@@ -134,7 +169,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
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);
+ usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE);
//extract the address
@@ -148,7 +183,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
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);
+ usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE);
//extract the address
@@ -190,10 +225,6 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
val = prop_names_t(1, "");
return;
- case MBOARD_PROP_CLOCK_RATE:
- val = double(get_master_clock_freq());
- return;
-
case MBOARD_PROP_RX_DSP:
ASSERT_THROW(name == "");
val = _rx_dsp_proxy->get_link();
@@ -236,7 +267,7 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){
std::copy(mac_addr.to_bytes(), mac_addr.to_bytes()+mac_addr_t::hlen, out_data.data.mac_addr);
//send and recv
- usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
+ usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE);
return;
}
@@ -248,7 +279,7 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){
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);
+ usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE);
return;
}
diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp
new file mode 100644
index 000000000..5c84fd8d3
--- /dev/null
+++ b/host/lib/usrp/usrp2/usrp2_iface.cpp
@@ -0,0 +1,168 @@
+//
+// 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 "usrp2_iface.hpp"
+#include <uhd/utils/assert.hpp>
+#include <uhd/types/dict.hpp>
+#include <boost/thread.hpp>
+#include <boost/asio.hpp> //used for htonl and ntohl
+#include <boost/assign/list_of.hpp>
+#include <stdexcept>
+
+using namespace uhd;
+using namespace uhd::usrp;
+
+class usrp2_iface_impl : public usrp2_iface{
+public:
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+ usrp2_iface_impl(transport::udp_simple::sptr ctrl_transport){
+ _ctrl_transport = ctrl_transport;
+ }
+
+ ~usrp2_iface_impl(void){
+ /* NOP */
+ }
+
+/***********************************************************************
+ * Peek and Poke
+ **********************************************************************/
+ void poke32(boost::uint32_t addr, boost::uint32_t data){
+ return this->poke<boost::uint32_t>(addr, data);
+ }
+
+ boost::uint32_t peek32(boost::uint32_t addr){
+ return this->peek<boost::uint32_t>(addr);
+ }
+
+ void poke16(boost::uint32_t addr, boost::uint16_t data){
+ return this->poke<boost::uint16_t>(addr, data);
+ }
+
+ boost::uint16_t peek16(boost::uint32_t addr){
+ return this->peek<boost::uint16_t>(addr);
+ }
+
+/***********************************************************************
+ * SPI
+ **********************************************************************/
+ boost::uint32_t transact_spi(
+ int which_slave,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits,
+ bool readback
+ ){
+ static const uhd::dict<spi_config_t::edge_t, int> spi_edge_to_otw = boost::assign::map_list_of
+ (spi_config_t::EDGE_RISE, USRP2_CLK_EDGE_RISE)
+ (spi_config_t::EDGE_FALL, USRP2_CLK_EDGE_FALL)
+ ;
+
+ //setup the out data
+ usrp2_ctrl_data_t out_data;
+ out_data.id = htonl(USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO);
+ out_data.data.spi_args.dev = which_slave;
+ out_data.data.spi_args.miso_edge = spi_edge_to_otw[config.miso_edge];
+ out_data.data.spi_args.mosi_edge = spi_edge_to_otw[config.mosi_edge];
+ out_data.data.spi_args.readback = (readback)? 1 : 0;
+ out_data.data.spi_args.num_bits = num_bits;
+ out_data.data.spi_args.data = htonl(data);
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data);
+ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE);
+
+ return ntohl(out_data.data.spi_args.data);
+ }
+
+/***********************************************************************
+ * Send/Recv over control
+ **********************************************************************/
+ usrp2_ctrl_data_t ctrl_send_and_recv(const usrp2_ctrl_data_t &out_data){
+ boost::mutex::scoped_lock lock(_ctrl_mutex);
+
+ //fill in the seq number and send
+ usrp2_ctrl_data_t out_copy = out_data;
+ out_copy.seq = htonl(++_ctrl_seq_num);
+ _ctrl_transport->send(boost::asio::buffer(&out_copy, sizeof(usrp2_ctrl_data_t)));
+
+ //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) 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");
+ }
+
+/***********************************************************************
+ * Master Clock! Ahhhhh
+ **********************************************************************/
+ double get_master_clock_freq(void){
+ return 100e6;
+ }
+
+private:
+ //this lovely lady makes it all possible
+ transport::udp_simple::sptr _ctrl_transport;
+
+ //used in send/recv
+ boost::mutex _ctrl_mutex;
+ boost::uint32_t _ctrl_seq_num;
+
+/***********************************************************************
+ * Private Templated Peek and Poke
+ **********************************************************************/
+ template <class T> void poke(boost::uint32_t addr, T data){
+ //setup the out data
+ usrp2_ctrl_data_t out_data;
+ out_data.id = htonl(USRP2_CTRL_ID_POKE_THIS_REGISTER_FOR_ME_BRO);
+ out_data.data.poke_args.addr = htonl(addr);
+ out_data.data.poke_args.data = htonl(boost::uint32_t(data));
+ out_data.data.poke_args.num_bytes = sizeof(T);
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data);
+ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE);
+ }
+
+ template <class T> T peek(boost::uint32_t addr){
+ //setup the out data
+ usrp2_ctrl_data_t out_data;
+ out_data.id = htonl(USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO);
+ out_data.data.poke_args.addr = htonl(addr);
+ out_data.data.poke_args.num_bytes = sizeof(T);
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data);
+ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE);
+ return T(ntohl(out_data.data.poke_args.data));
+ }
+
+};
+
+/***********************************************************************
+ * Public make function for usrp2 interface
+ **********************************************************************/
+usrp2_iface::sptr usrp2_iface::make(transport::udp_simple::sptr ctrl_transport){
+ return usrp2_iface::sptr(new usrp2_iface_impl(ctrl_transport));
+}
diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp
new file mode 100644
index 000000000..1298d87f1
--- /dev/null
+++ b/host/lib/usrp/usrp2/usrp2_iface.hpp
@@ -0,0 +1,103 @@
+//
+// 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_USRP2_IFACE_HPP
+#define INCLUDED_USRP2_IFACE_HPP
+
+#include <uhd/transport/udp_simple.hpp>
+#include <uhd/usrp/dboard_iface.hpp> //spi config
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+#include <boost/cstdint.hpp>
+#include "fw_common.h"
+
+/*!
+ * The usrp2 interface class:
+ * Provides a set of functions to implementation layer.
+ * Including spi, peek, poke, control...
+ */
+class usrp2_iface : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<usrp2_iface> sptr;
+
+ /*!
+ * Make a new usrp2 interface with the control transport.
+ * \param ctrl_transport the udp transport object
+ * \return a new usrp2 interface object
+ */
+ static sptr make(uhd::transport::udp_simple::sptr ctrl_transport);
+
+ /*!
+ * Perform a control transaction.
+ * \param data a control data struct
+ * \return the result control data
+ */
+ virtual usrp2_ctrl_data_t ctrl_send_and_recv(const usrp2_ctrl_data_t &data) = 0;
+
+ /*!
+ * Write a register (32 bits)
+ * \param addr the address
+ * \param data the 32bit data
+ */
+ virtual void poke32(boost::uint32_t addr, boost::uint32_t data) = 0;
+
+ /*!
+ * Read a register (32 bits)
+ * \param addr the address
+ * \return the 32bit data
+ */
+ virtual boost::uint32_t peek32(boost::uint32_t addr) = 0;
+
+ /*!
+ * Write a register (16 bits)
+ * \param addr the address
+ * \param data the 16bit data
+ */
+ virtual void poke16(boost::uint32_t addr, boost::uint16_t data) = 0;
+
+ /*!
+ * Read a register (16 bits)
+ * \param addr the address
+ * \return the 16bit data
+ */
+ virtual boost::uint16_t peek16(boost::uint32_t addr) = 0;
+
+ /*!
+ * Perform an spi transaction.
+ * \param which_slave the slave device number
+ * \param config spi config args
+ * \param data the bits to write
+ * \param num_bits how many bits in data
+ * \param readback true to readback a value
+ * \return spi data if readback set
+ */
+ virtual boost::uint32_t transact_spi(
+ int which_slave,
+ const uhd::usrp::spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits,
+ bool readback
+ ) = 0;
+
+ /*!
+ * Get the master clock frequency.
+ * \return the frequency in Hz
+ */
+ virtual double get_master_clock_freq(void) = 0;
+};
+
+#endif /* INCLUDED_USRP2_IFACE_HPP */
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index a7be2da8c..3bdc5bd02 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -15,15 +15,18 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+#include "usrp2_impl.hpp"
#include <uhd/transport/if_addrs.hpp>
+#include <uhd/transport/udp_simple.hpp>
#include <uhd/usrp/device_props.hpp>
#include <uhd/utils/assert.hpp>
#include <uhd/utils/static.hpp>
+#include <boost/assign/list_of.hpp>
#include <boost/format.hpp>
#include <boost/foreach.hpp>
#include <boost/bind.hpp>
+#include <boost/asio.hpp> //htonl and ntohl
#include <iostream>
-#include "usrp2_impl.hpp"
using namespace uhd;
using namespace uhd::usrp;
@@ -60,7 +63,6 @@ uhd::device_addrs_t usrp2::find(const device_addr_t &hint){
}
//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);
udp_simple::sptr udp_transport = udp_simple::make_broadcast(
hint["addr"], ctrl_port
@@ -127,9 +129,11 @@ usrp2_impl::usrp2_impl(
udp_simple::sptr ctrl_transport,
udp_zero_copy::sptr data_transport
){
- _ctrl_transport = ctrl_transport;
_data_transport = data_transport;
+ //make a new interface for usrp2 stuff
+ _iface = usrp2_iface::make(ctrl_transport);
+
//load the allowed decim/interp rates
//_USRP2_RATES = range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4)
_allowed_decim_and_interp_rates.clear();
@@ -168,80 +172,6 @@ usrp2_impl::~usrp2_impl(void){
}
/***********************************************************************
- * Misc Access Methods
- **********************************************************************/
-double usrp2_impl::get_master_clock_freq(void){
- return 100e6;
-}
-
-template <class T> void impl_poke(usrp2_impl *impl, boost::uint32_t addr, T data){
- //setup the out data
- usrp2_ctrl_data_t out_data;
- out_data.id = htonl(USRP2_CTRL_ID_POKE_THIS_REGISTER_FOR_ME_BRO);
- out_data.data.poke_args.addr = htonl(addr);
- out_data.data.poke_args.data = htonl(boost::uint32_t(data));
- out_data.data.poke_args.num_bytes = sizeof(T);
-
- //send and recv
- usrp2_ctrl_data_t in_data = impl->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE);
-}
-
-template <class T> T impl_peek(usrp2_impl *impl, boost::uint32_t addr){
- //setup the out data
- usrp2_ctrl_data_t out_data;
- out_data.id = htonl(USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO);
- out_data.data.poke_args.addr = htonl(addr);
- out_data.data.poke_args.num_bytes = sizeof(T);
-
- //send and recv
- usrp2_ctrl_data_t in_data = impl->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE);
- return T(ntohl(out_data.data.poke_args.data));
-}
-
-
-void usrp2_impl::poke32(boost::uint32_t addr, boost::uint32_t data){
- return impl_poke<boost::uint32_t>(this, addr, data);
-}
-
-boost::uint32_t usrp2_impl::peek32(boost::uint32_t addr){
- return impl_peek<boost::uint32_t>(this, addr);
-}
-
-void usrp2_impl::poke16(boost::uint32_t addr, boost::uint16_t data){
- return impl_poke<boost::uint16_t>(this, addr, data);
-}
-
-boost::uint16_t usrp2_impl::peek16(boost::uint32_t addr){
- return impl_peek<boost::uint16_t>(this, addr);
-}
-
-/***********************************************************************
- * Control Send/Recv
- **********************************************************************/
-usrp2_ctrl_data_t usrp2_impl::ctrl_send_and_recv(const usrp2_ctrl_data_t &out_data){
- boost::mutex::scoped_lock lock(_ctrl_mutex);
-
- //fill in the seq number and send
- usrp2_ctrl_data_t out_copy = out_data;
- out_copy.seq = htonl(++_ctrl_seq_num);
- _ctrl_transport->send(boost::asio::buffer(&out_copy, sizeof(usrp2_ctrl_data_t)));
-
- //loop until we get the packet or timeout
- while(true){
- usrp2_ctrl_data_t in_data;
- 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");
-}
-
-/***********************************************************************
* Device Properties
**********************************************************************/
void usrp2_impl::get(const wax::obj &key_, wax::obj &val){
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index baa6530b8..dbcee367b 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -18,29 +18,29 @@
#ifndef INCLUDED_USRP2_IMPL_HPP
#define INCLUDED_USRP2_IMPL_HPP
+#include "usrp2_iface.hpp"
+#include "clock_control.hpp"
#include <uhd/usrp/usrp2.hpp>
#include <uhd/types/dict.hpp>
+#include <uhd/types/otw_type.hpp>
#include <uhd/types/stream_cmd.hpp>
#include <uhd/types/clock_config.hpp>
-#include <boost/asio.hpp>
-#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
-#include <boost/assign/list_of.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"
-
-class usrp2_impl; //dummy class declaration
/*!
* Make a usrp2 dboard interface.
- * \param impl a pointer to the usrp2 impl object
+ * \param iface the usrp2 interface object
+ * \param clk_ctrl the clock control object
* \return a sptr to a new dboard interface
*/
-uhd::usrp::dboard_interface::sptr make_usrp2_dboard_interface(usrp2_impl *impl);
+uhd::usrp::dboard_iface::sptr make_usrp2_dboard_iface(
+ usrp2_iface::sptr iface,
+ clock_control::sptr clk_ctrl
+);
/*!
* Simple wax obj proxy class:
@@ -99,28 +99,23 @@ public:
~usrp2_impl(void);
- //performs a control transaction
- usrp2_ctrl_data_t ctrl_send_and_recv(const usrp2_ctrl_data_t &);
-
- //peek and poke registers
- void poke32(boost::uint32_t addr, boost::uint32_t data);
- boost::uint32_t peek32(boost::uint32_t addr);
-
- void poke16(boost::uint32_t addr, boost::uint16_t data);
- boost::uint16_t peek16(boost::uint32_t addr);
-
- //misc access methods
- double get_master_clock_freq(void);
-
//the io interface
size_t send(const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const uhd::io_type_t &);
size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const uhd::io_type_t &);
private:
+ double get_master_clock_freq(void){
+ return _iface->get_master_clock_freq();
+ }
+
//device properties interface
void get(const wax::obj &, wax::obj &);
void set(const wax::obj &, const wax::obj &);
+ //interfaces
+ clock_control::sptr _clk_ctrl;
+ usrp2_iface::sptr _iface;
+
//the raw io interface (samples are in the usrp2 native format)
void recv_raw(uhd::rx_metadata_t &);
uhd::dict<boost::uint32_t, size_t> _tx_stream_id_to_packet_seq;
@@ -136,19 +131,15 @@ private:
(_mtu - _hdrs)/sizeof(boost::uint32_t) -
uhd::transport::vrt::max_header_words32
;
- uhd::transport::smart_buffer::sptr _rx_smart_buff;
+ uhd::transport::managed_recv_buffer::sptr _rx_smart_buff;
boost::asio::const_buffer _rx_copy_buff;
size_t _fragment_offset_in_samps;
+ uhd::otw_type_t _otw_type;
void io_init(void);
//udp transports for control and data
- uhd::transport::udp_simple::sptr _ctrl_transport;
uhd::transport::udp_zero_copy::sptr _data_transport;
- //private vars for dealing with send/recv control
- boost::uint32_t _ctrl_seq_num;
- boost::mutex _ctrl_mutex;
-
//methods and shadows for clock configuration
uhd::clock_config_t _clock_config;
void init_clock_config(void);
diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp
index 77d9f4ad9..0e2a18756 100644
--- a/host/lib/usrp/usrp2/usrp2_regs.hpp
+++ b/host/lib/usrp/usrp2/usrp2_regs.hpp
@@ -62,6 +62,11 @@
#define SPI_SS_TX_DB 128
/////////////////////////////////////////////////
+// Misc Control
+////////////////////////////////////////////////
+#define FR_CLOCK_CONTROL _SR_ADDR(0)
+
+/////////////////////////////////////////////////
// VITA49 64 bit time (write only)
////////////////////////////////////////////////
/*!