diff options
Diffstat (limited to 'host/lib/usrp2')
-rw-r--r-- | host/lib/usrp2/CMakeLists.txt | 28 | ||||
-rw-r--r-- | host/lib/usrp2/clock_ctrl.cpp | 377 | ||||
-rw-r--r-- | host/lib/usrp2/clock_ctrl.hpp | 109 | ||||
-rw-r--r-- | host/lib/usrp2/codec_ctrl.cpp | 216 | ||||
-rw-r--r-- | host/lib/usrp2/codec_ctrl.hpp | 68 | ||||
-rw-r--r-- | host/lib/usrp2/dboard_iface.cpp | 350 | ||||
-rw-r--r-- | host/lib/usrp2/fw_common.h | 154 | ||||
-rw-r--r-- | host/lib/usrp2/io_impl.cpp | 422 | ||||
-rw-r--r-- | host/lib/usrp2/usrp2_clk_regs.hpp | 87 | ||||
-rw-r--r-- | host/lib/usrp2/usrp2_iface.cpp | 412 | ||||
-rw-r--r-- | host/lib/usrp2/usrp2_iface.hpp | 80 | ||||
-rw-r--r-- | host/lib/usrp2/usrp2_impl.cpp | 673 | ||||
-rw-r--r-- | host/lib/usrp2/usrp2_impl.hpp | 134 | ||||
-rw-r--r-- | host/lib/usrp2/usrp2_regs.hpp | 221 |
14 files changed, 0 insertions, 3331 deletions
diff --git a/host/lib/usrp2/CMakeLists.txt b/host/lib/usrp2/CMakeLists.txt deleted file mode 100644 index d16976060..000000000 --- a/host/lib/usrp2/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright 2011 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/>. -# - -######################################################################## -# This file included, use CMake directory variables -######################################################################## -LIBUHD_APPEND_SOURCES( - ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_impl.cpp -) diff --git a/host/lib/usrp2/clock_ctrl.cpp b/host/lib/usrp2/clock_ctrl.cpp deleted file mode 100644 index 66c7a6c28..000000000 --- a/host/lib/usrp2/clock_ctrl.cpp +++ /dev/null @@ -1,377 +0,0 @@ -// -// Copyright 2010-2011 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 "clock_ctrl.hpp" -#include "ad9510_regs.hpp" -#include "usrp2_regs.hpp" //spi slave constants -#include "usrp2_clk_regs.hpp" -#include <uhd/utils/safe_call.hpp> -#include <uhd/utils/assert_has.hpp> -#include <boost/cstdint.hpp> -#include <boost/lexical_cast.hpp> -#include <boost/math/special_functions/round.hpp> -#include <iostream> - -using namespace uhd; - -static const bool enb_test_clk = false; - -/*! - * A usrp2 clock control specific to the ad9510 ic. - */ -class usrp2_clock_ctrl_impl : public usrp2_clock_ctrl{ -public: - usrp2_clock_ctrl_impl(usrp2_iface::sptr iface){ - _iface = iface; - clk_regs = usrp2_clk_regs_t(_iface->get_rev()); - - _ad9510_regs.cp_current_setting = ad9510_regs_t::CP_CURRENT_SETTING_3_0MA; - this->write_reg(clk_regs.pll_3); - - // 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(clk_regs.pll_4); - - _ad9510_regs.acounter = 0; - this->write_reg(clk_regs.acounter); - - _ad9510_regs.bcounter_msb = 0; - _ad9510_regs.bcounter_lsb = 5; - this->write_reg(clk_regs.bcounter_msb); - this->write_reg(clk_regs.bcounter_lsb); - - _ad9510_regs.ref_counter_msb = 0; - _ad9510_regs.ref_counter_lsb = 1; // r divider = 1 - this->write_reg(clk_regs.ref_counter_msb); - this->write_reg(clk_regs.ref_counter_lsb); - - /* regs will be updated in commands below */ - - this->enable_external_ref(false); - this->enable_rx_dboard_clock(false); - this->enable_tx_dboard_clock(false); - this->enable_mimo_clock_out(false); - - /* private clock enables, must be set here */ - this->enable_dac_clock(true); - this->enable_adc_clock(true); - this->enable_test_clock(enb_test_clk); - } - - ~usrp2_clock_ctrl_impl(void){UHD_SAFE_CALL( - //power down clock outputs - this->enable_external_ref(false); - this->enable_rx_dboard_clock(false); - this->enable_tx_dboard_clock(false); - this->enable_dac_clock(false); - this->enable_adc_clock(false); - this->enable_mimo_clock_out(false); - this->enable_test_clock(false); - )} - - void enable_mimo_clock_out(bool enb){ - //calculate the low and high dividers - size_t divider = size_t(this->get_master_clock_rate()/10e6); - size_t high = divider/2; - size_t low = divider - high; - - switch(clk_regs.exp){ - case 2: //U2 rev 3 - _ad9510_regs.power_down_lvpecl_out2 = enb? - ad9510_regs_t::POWER_DOWN_LVPECL_OUT2_NORMAL : - ad9510_regs_t::POWER_DOWN_LVPECL_OUT2_SAFE_PD; - _ad9510_regs.output_level_lvpecl_out2 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT2_810MV; - //set the registers (divider - 1) - _ad9510_regs.divider_low_cycles_out2 = low - 1; - _ad9510_regs.divider_high_cycles_out2 = high - 1; - _ad9510_regs.bypass_divider_out2 = 0; - break; - - case 5: //U2 rev 4 - _ad9510_regs.power_down_lvds_cmos_out5 = enb? 0 : 1; - _ad9510_regs.lvds_cmos_select_out5 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT5_LVDS; - _ad9510_regs.output_level_lvds_out5 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT5_1_75MA; - //set the registers (divider - 1) - _ad9510_regs.divider_low_cycles_out5 = low - 1; - _ad9510_regs.divider_high_cycles_out5 = high - 1; - _ad9510_regs.bypass_divider_out5 = 0; - break; - - case 6: //U2+ - _ad9510_regs.power_down_lvds_cmos_out6 = enb? 0 : 1; - _ad9510_regs.lvds_cmos_select_out6 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT6_LVDS; - _ad9510_regs.output_level_lvds_out6 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT6_1_75MA; - //set the registers (divider - 1) - _ad9510_regs.divider_low_cycles_out6 = low - 1; - _ad9510_regs.divider_high_cycles_out6 = high - 1; - _ad9510_regs.bypass_divider_out5 = 0; - break; - - default: - break; - } - this->write_reg(clk_regs.output(clk_regs.exp)); - this->write_reg(clk_regs.div_lo(clk_regs.exp)); - this->update_regs(); - } - - //uses output clock 7 (cmos) - void enable_rx_dboard_clock(bool enb){ - switch(_iface->get_rev()) { - case usrp2_iface::USRP_N200_R4: - case usrp2_iface::USRP_N210_R4: - _ad9510_regs.power_down_lvds_cmos_out7 = enb? 0 : 1; - _ad9510_regs.lvds_cmos_select_out7 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT7_LVDS; - _ad9510_regs.output_level_lvds_out7 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT7_1_75MA; - this->write_reg(clk_regs.output(clk_regs.rx_db)); - this->update_regs(); - break; - default: - _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(clk_regs.output(clk_regs.rx_db)); - this->update_regs(); - break; - } - } - - void set_rate_rx_dboard_clock(double rate){ - assert_has(get_rates_rx_dboard_clock(), rate, "rx dboard clock rate"); - size_t divider = size_t(get_master_clock_rate()/rate); - //bypass when the divider ratio is one - _ad9510_regs.bypass_divider_out7 = (divider == 1)? 1 : 0; - //calculate the low and high dividers - size_t high = divider/2; - size_t low = divider - high; - //set the registers (divider - 1) - _ad9510_regs.divider_low_cycles_out7 = low - 1; - _ad9510_regs.divider_high_cycles_out7 = high - 1; - //write the registers - this->write_reg(clk_regs.div_lo(clk_regs.rx_db)); - this->write_reg(clk_regs.div_hi(clk_regs.rx_db)); - this->update_regs(); - } - - std::vector<double> get_rates_rx_dboard_clock(void){ - std::vector<double> rates; - for (size_t i = 1; i <= 16+16; i++) rates.push_back(get_master_clock_rate()/i); - return rates; - } - - //uses output clock 6 (cmos) on USRP2 and output clock 5 (cmos) on USRP2+ - void enable_tx_dboard_clock(bool enb){ - switch(clk_regs.tx_db) { - case 5: //USRP2+ - _ad9510_regs.power_down_lvds_cmos_out5 = enb? 0 : 1; - _ad9510_regs.lvds_cmos_select_out5 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT5_CMOS; - _ad9510_regs.output_level_lvds_out5 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT5_1_75MA; - break; - case 6: //USRP2 - _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; - break; - } - - this->write_reg(clk_regs.output(clk_regs.tx_db)); - this->update_regs(); - } - - void set_rate_tx_dboard_clock(double rate){ - assert_has(get_rates_tx_dboard_clock(), rate, "tx dboard clock rate"); - size_t divider = size_t(get_master_clock_rate()/rate); - //bypass when the divider ratio is one - _ad9510_regs.bypass_divider_out6 = (divider == 1)? 1 : 0; - //calculate the low and high dividers - size_t high = divider/2; - size_t low = divider - high; - - switch(clk_regs.tx_db) { - case 5: //USRP2+ - _ad9510_regs.bypass_divider_out5 = (divider == 1)? 1 : 0; - _ad9510_regs.divider_low_cycles_out5 = low - 1; - _ad9510_regs.divider_high_cycles_out5 = high - 1; - break; - case 6: //USRP2 - //bypass when the divider ratio is one - _ad9510_regs.bypass_divider_out6 = (divider == 1)? 1 : 0; - //set the registers (divider - 1) - _ad9510_regs.divider_low_cycles_out6 = low - 1; - _ad9510_regs.divider_high_cycles_out6 = high - 1; - break; - } - - //write the registers - this->write_reg(clk_regs.div_hi(clk_regs.tx_db)); - this->write_reg(clk_regs.div_lo(clk_regs.tx_db)); - this->update_regs(); - } - - std::vector<double> get_rates_tx_dboard_clock(void){ - return get_rates_rx_dboard_clock(); //same master clock, same dividers... - } - - void enable_test_clock(bool enb) { - _ad9510_regs.power_down_lvpecl_out0 = enb? - ad9510_regs_t::POWER_DOWN_LVPECL_OUT0_NORMAL : - ad9510_regs_t::POWER_DOWN_LVPECL_OUT0_SAFE_PD; - _ad9510_regs.output_level_lvpecl_out0 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT0_810MV; - _ad9510_regs.divider_low_cycles_out0 = 0; - _ad9510_regs.divider_high_cycles_out0 = 0; - _ad9510_regs.bypass_divider_out0 = 1; - this->write_reg(0x3c); - this->write_reg(0x48); - this->write_reg(0x49); - } - - /*! - * 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(clk_regs.pll_2); - this->update_regs(); - } - - double get_master_clock_rate(void){ - return 100e6; - } - - void set_mimo_clock_delay(double delay) { - //delay_val is a 5-bit value (0-31) for fine control - //the equations below determine delay for a given ramp current, # of caps and fine delay register - //delay range: - //range_ns = 200*((caps+3)/i_ramp_ua)*1.3286 - //offset (zero delay): - //offset_ns = 0.34 + (1600 - i_ramp_ua)*1e-4 + ((caps-1)/ramp)*6 - //delay_ns = offset_ns + range_ns * delay / 31 - - int delay_val = boost::math::iround(delay/9.744e-9*31); - - if(delay_val == 0) { - switch(clk_regs.exp) { - case 5: - _ad9510_regs.delay_control_out5 = 1; - break; - case 6: - _ad9510_regs.delay_control_out6 = 1; - break; - default: - break; //delay not supported on U2 rev 3 - } - } else { - switch(clk_regs.exp) { - case 5: - _ad9510_regs.delay_control_out5 = 0; - _ad9510_regs.ramp_current_out5 = ad9510_regs_t::RAMP_CURRENT_OUT5_200UA; - _ad9510_regs.ramp_capacitor_out5 = ad9510_regs_t::RAMP_CAPACITOR_OUT5_4CAPS; - _ad9510_regs.delay_fine_adjust_out5 = delay_val; - this->write_reg(0x34); - this->write_reg(0x35); - this->write_reg(0x36); - break; - case 6: - _ad9510_regs.delay_control_out6 = 0; - _ad9510_regs.ramp_current_out6 = ad9510_regs_t::RAMP_CURRENT_OUT6_200UA; - _ad9510_regs.ramp_capacitor_out6 = ad9510_regs_t::RAMP_CAPACITOR_OUT6_4CAPS; - _ad9510_regs.delay_fine_adjust_out6 = delay_val; - this->write_reg(0x38); - this->write_reg(0x39); - this->write_reg(0x3A); - break; - default: - break; - } - } - } - -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->write_spi(SPI_SS_AD9510, spi_config_t::EDGE_RISE, data, 24); - } - - /*! - * Tells the ad9510 to latch the settings into the operational registers. - */ - void update_regs(void){ - _ad9510_regs.update_registers = 1; - this->write_reg(clk_regs.update); - } - - //uses output clock 3 (pecl) - //this is the same between USRP2 and USRP2+ and doesn't get a switch statement - 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; - _ad9510_regs.bypass_divider_out3 = 1; - this->write_reg(clk_regs.output(clk_regs.dac)); - this->write_reg(clk_regs.div_hi(clk_regs.dac)); - this->update_regs(); - } - - //uses output clock 4 (lvds) on USRP2 and output clock 2 (lvpecl) on USRP2+ - void enable_adc_clock(bool enb){ - switch(clk_regs.adc) { - case 2: - _ad9510_regs.power_down_lvpecl_out2 = enb? ad9510_regs_t::POWER_DOWN_LVPECL_OUT2_NORMAL : ad9510_regs_t::POWER_DOWN_LVPECL_OUT2_SAFE_PD; - _ad9510_regs.output_level_lvpecl_out2 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT2_500MV; - _ad9510_regs.bypass_divider_out2 = 1; - break; - case 4: - _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; - _ad9510_regs.bypass_divider_out4 = 1; - break; - } - - this->write_reg(clk_regs.output(clk_regs.adc)); - this->write_reg(clk_regs.div_hi(clk_regs.adc)); - this->update_regs(); - } - - usrp2_iface::sptr _iface; - - usrp2_clk_regs_t clk_regs; - ad9510_regs_t _ad9510_regs; -}; - -/*********************************************************************** - * Public make function for the ad9510 clock control - **********************************************************************/ -usrp2_clock_ctrl::sptr usrp2_clock_ctrl::make(usrp2_iface::sptr iface){ - return sptr(new usrp2_clock_ctrl_impl(iface)); -} diff --git a/host/lib/usrp2/clock_ctrl.hpp b/host/lib/usrp2/clock_ctrl.hpp deleted file mode 100644 index 9ccbc959e..000000000 --- a/host/lib/usrp2/clock_ctrl.hpp +++ /dev/null @@ -1,109 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_CLOCK_CTRL_HPP -#define INCLUDED_CLOCK_CTRL_HPP - -#include "usrp2_iface.hpp" -#include <boost/shared_ptr.hpp> -#include <boost/utility.hpp> -#include <vector> - -class usrp2_clock_ctrl : boost::noncopyable{ -public: - typedef boost::shared_ptr<usrp2_clock_ctrl> 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(usrp2_iface::sptr iface); - - /*! - * Get the master clock frequency for the fpga. - * \return the clock frequency in Hz - */ - virtual double get_master_clock_rate(void) = 0; - - /*! - * Enable/disable the rx dboard clock. - * \param enb true to enable - */ - virtual void enable_rx_dboard_clock(bool enb) = 0; - - /*! - * Set the clock rate on the rx dboard clock. - * \param rate the new clock rate - * \throw exception when rate invalid - */ - virtual void set_rate_rx_dboard_clock(double rate) = 0; - - /*! - * Get a list of possible rx dboard clock rates. - * \return a list of clock rates in Hz - */ - virtual std::vector<double> get_rates_rx_dboard_clock(void) = 0; - - /*! - * Enable/disable the tx dboard clock. - * \param enb true to enable - */ - virtual void enable_tx_dboard_clock(bool enb) = 0; - - /*! - * Set the clock rate on the tx dboard clock. - * \param rate the new clock rate - * \throw exception when rate invalid - */ - virtual void set_rate_tx_dboard_clock(double rate) = 0; - - /*! - * Get a list of possible tx dboard clock rates. - * \return a list of clock rates in Hz - */ - virtual std::vector<double> get_rates_tx_dboard_clock(void) = 0; - - /*! - * Enable/disable external reference. - * \param enb true to enable - */ - virtual void enable_external_ref(bool enb) = 0; - - /*! - * Enable/disable test clock output. - * \param enb true to enable - */ - virtual void enable_test_clock(bool enb) = 0; - - /*! - * Enable/disable the ref clock output over the serdes cable. - * \param enb true to enable - */ - virtual void enable_mimo_clock_out(bool enb) = 0; - - /*! - * Set the output delay of the mimo clock - * Used to synchronise daisy-chained USRPs over the MIMO cable - * Can also be used to adjust delay for uneven reference cable lengths - * \param delay the clock delay in seconds - */ - virtual void set_mimo_clock_delay(double delay) = 0; - -}; - -#endif /* INCLUDED_CLOCK_CTRL_HPP */ diff --git a/host/lib/usrp2/codec_ctrl.cpp b/host/lib/usrp2/codec_ctrl.cpp deleted file mode 100644 index 06bf83b15..000000000 --- a/host/lib/usrp2/codec_ctrl.cpp +++ /dev/null @@ -1,216 +0,0 @@ -// -// Copyright 2010-2011 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 "codec_ctrl.hpp" -#include "ad9777_regs.hpp" -#include "ads62p44_regs.hpp" -#include "usrp2_regs.hpp" -#include <uhd/utils/log.hpp> -#include <uhd/utils/safe_call.hpp> -#include <uhd/exception.hpp> -#include <boost/cstdint.hpp> -#include <boost/foreach.hpp> - -using namespace uhd; - -/*! - * A usrp2 codec control specific to the ad9777 ic. - */ -class usrp2_codec_ctrl_impl : public usrp2_codec_ctrl{ -public: - usrp2_codec_ctrl_impl(usrp2_iface::sptr iface){ - _iface = iface; - - //setup the ad9777 dac - _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_COMPLEX; - _ad9777_regs.pll_divide_ratio = ad9777_regs_t::PLL_DIVIDE_RATIO_DIV1; - _ad9777_regs.pll_state = ad9777_regs_t::PLL_STATE_ON; - _ad9777_regs.auto_cp_control = ad9777_regs_t::AUTO_CP_CONTROL_AUTO; - //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++){ - this->send_ad9777_reg(addr); - } - set_tx_mod_mode(0); - - //power-up adc - switch(_iface->get_rev()){ - case usrp2_iface::USRP2_REV3: - case usrp2_iface::USRP2_REV4: - _iface->poke32(U2_REG_MISC_CTRL_ADC, U2_FLAG_MISC_CTRL_ADC_ON); - break; - - case usrp2_iface::USRP_N200: - case usrp2_iface::USRP_N210: - _ads62p44_regs.reset = 1; - this->send_ads62p44_reg(0x00); //issue a reset to the ADC - //everything else should be pretty much default, i think - //_ads62p44_regs.decimation = DECIMATION_DECIMATE_1; - _ads62p44_regs.power_down = ads62p44_regs_t::POWER_DOWN_NORMAL; - this->send_ads62p44_reg(0x14); - this->set_rx_analog_gain(1); - break; - - case usrp2_iface::USRP_N200_R4: - case usrp2_iface::USRP_N210_R4: - _ads62p44_regs.reset = 1; - this->send_ads62p44_reg(0x00); //issue a reset to the ADC - //everything else should be pretty much default, i think - //_ads62p44_regs.decimation = DECIMATION_DECIMATE_1; - _ads62p44_regs.override = 1; - this->send_ads62p44_reg(0x14); - _ads62p44_regs.power_down = ads62p44_regs_t::POWER_DOWN_NORMAL; - _ads62p44_regs.output_interface = ads62p44_regs_t::OUTPUT_INTERFACE_LVDS; - _ads62p44_regs.lvds_current = ads62p44_regs_t::LVDS_CURRENT_2_5MA; - _ads62p44_regs.lvds_data_term = ads62p44_regs_t::LVDS_DATA_TERM_100; - this->send_ads62p44_reg(0x11); - this->send_ads62p44_reg(0x12); - this->send_ads62p44_reg(0x14); - this->set_rx_analog_gain(1); - break; - - case usrp2_iface::USRP_NXXX: break; - } - } - - ~usrp2_codec_ctrl_impl(void){UHD_SAFE_CALL( - //power-down dac - _ad9777_regs.power_down_mode = 1; - this->send_ad9777_reg(0); - - //power-down adc - switch(_iface->get_rev()){ - case usrp2_iface::USRP2_REV3: - case usrp2_iface::USRP2_REV4: - _iface->poke32(U2_REG_MISC_CTRL_ADC, U2_FLAG_MISC_CTRL_ADC_OFF); - break; - - case usrp2_iface::USRP_N200: - case usrp2_iface::USRP_N210: - case usrp2_iface::USRP_N200_R4: - case usrp2_iface::USRP_N210_R4: - //send a global power-down to the ADC here... it will get lifted on reset - _ads62p44_regs.power_down = ads62p44_regs_t::POWER_DOWN_GLOBAL_PD; - this->send_ads62p44_reg(0x14); - break; - - case usrp2_iface::USRP_NXXX: break; - } - )} - - void set_tx_mod_mode(int mod_mode){ - //set the sign of the frequency shift - _ad9777_regs.modulation_form = (mod_mode > 0)? - ad9777_regs_t::MODULATION_FORM_E_PLUS_JWT: - ad9777_regs_t::MODULATION_FORM_E_MINUS_JWT - ; - - //set the frequency shift - switch(std::abs(mod_mode)){ - case 0: - case 1: _ad9777_regs.modulation_mode = ad9777_regs_t::MODULATION_MODE_NONE; break; - case 2: _ad9777_regs.modulation_mode = ad9777_regs_t::MODULATION_MODE_FS_2; break; - case 4: _ad9777_regs.modulation_mode = ad9777_regs_t::MODULATION_MODE_FS_4; break; - case 8: _ad9777_regs.modulation_mode = ad9777_regs_t::MODULATION_MODE_FS_8; break; - default: throw uhd::value_error("unknown modulation mode for ad9777"); - } - - this->send_ad9777_reg(0x01); //set the register - } - - void set_rx_digital_gain(double gain) { //fine digital gain - switch(_iface->get_rev()){ - case usrp2_iface::USRP_N200: - case usrp2_iface::USRP_N210: - case usrp2_iface::USRP_N200_R4: - case usrp2_iface::USRP_N210_R4: - _ads62p44_regs.fine_gain = int(gain/0.5); - this->send_ads62p44_reg(0x17); - break; - - default: UHD_THROW_INVALID_CODE_PATH(); - } - } - - void set_rx_digital_fine_gain(double gain) { //gain correction - switch(_iface->get_rev()){ - case usrp2_iface::USRP_N200: - case usrp2_iface::USRP_N210: - case usrp2_iface::USRP_N200_R4: - case usrp2_iface::USRP_N210_R4: - _ads62p44_regs.gain_correction = int(gain / 0.05); - this->send_ads62p44_reg(0x1A); - break; - - default: UHD_THROW_INVALID_CODE_PATH(); - } - } - - void set_rx_analog_gain(bool /*gain*/) { //turns on/off analog 3.5dB preamp - switch(_iface->get_rev()){ - case usrp2_iface::USRP_N200: - case usrp2_iface::USRP_N210: - case usrp2_iface::USRP_N200_R4: - case usrp2_iface::USRP_N210_R4: - _ads62p44_regs.coarse_gain = ads62p44_regs_t::COARSE_GAIN_3_5DB;//gain ? ads62p44_regs_t::COARSE_GAIN_3_5DB : ads62p44_regs_t::COARSE_GAIN_0DB; - this->send_ads62p44_reg(0x14); - break; - - default: UHD_THROW_INVALID_CODE_PATH(); - } - } - -private: - ad9777_regs_t _ad9777_regs; - ads62p44_regs_t _ads62p44_regs; - usrp2_iface::sptr _iface; - - void send_ad9777_reg(boost::uint8_t addr){ - boost::uint16_t reg = _ad9777_regs.get_write_reg(addr); - UHD_LOGV(always) << "send_ad9777_reg: " << std::hex << reg << std::endl; - _iface->write_spi( - SPI_SS_AD9777, spi_config_t::EDGE_RISE, - reg, 16 - ); - } - - void send_ads62p44_reg(boost::uint8_t addr) { - boost::uint16_t reg = _ads62p44_regs.get_write_reg(addr); - _iface->write_spi( - SPI_SS_ADS62P44, spi_config_t::EDGE_FALL, - reg, 16 - ); - } -}; - -/*********************************************************************** - * Public make function for the usrp2 codec control - **********************************************************************/ -usrp2_codec_ctrl::sptr usrp2_codec_ctrl::make(usrp2_iface::sptr iface){ - return sptr(new usrp2_codec_ctrl_impl(iface)); -} diff --git a/host/lib/usrp2/codec_ctrl.hpp b/host/lib/usrp2/codec_ctrl.hpp deleted file mode 100644 index ca300e2b1..000000000 --- a/host/lib/usrp2/codec_ctrl.hpp +++ /dev/null @@ -1,68 +0,0 @@ -// -// Copyright 2010-2011 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_CODEC_CTRL_HPP -#define INCLUDED_CODEC_CTRL_HPP - -#include "usrp2_iface.hpp" -#include <boost/shared_ptr.hpp> -#include <boost/utility.hpp> - -class usrp2_codec_ctrl : boost::noncopyable{ -public: - typedef boost::shared_ptr<usrp2_codec_ctrl> sptr; - - /*! - * Make a codec control for the DAC and ADC. - * \param _iface a pointer to the usrp2 interface object - * \return a new codec control object - */ - static sptr make(usrp2_iface::sptr iface); - - /*! - * Set the modulation mode for the DAC. - * Possible modes are 0, +/-1, +/-2, +/-4, +/-8 - * which correspond to shifts of fs/mod_mode. - * A mode of 0 or +/-1 means no modulation. - * \param mod_mode the modulation mode - */ - virtual void set_tx_mod_mode(int mod_mode) = 0; - - /*! - * Set the analog preamplifier on the USRP2+ ADC (ADS62P44). - * \param gain enable or disable the 3.5dB preamp - */ - - virtual void set_rx_analog_gain(bool gain) = 0; - - /*! - * Set the digital gain on the USRP2+ ADC (ADS62P44). - * \param gain from 0-6dB - */ - - virtual void set_rx_digital_gain(double gain) = 0; - - /*! - * Set the digital gain correction on the USRP2+ ADC (ADS62P44). - * \param gain from 0-0.5dB - */ - - virtual void set_rx_digital_fine_gain(double gain) = 0; - -}; - -#endif /* INCLUDED_CODEC_CTRL_HPP */ diff --git a/host/lib/usrp2/dboard_iface.cpp b/host/lib/usrp2/dboard_iface.cpp deleted file mode 100644 index 4ce49b409..000000000 --- a/host/lib/usrp2/dboard_iface.cpp +++ /dev/null @@ -1,350 +0,0 @@ -// -// Copyright 2010-2011 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_ctrl.hpp" -#include "usrp2_regs.hpp" //wishbone address constants -#include <uhd/usrp/dboard_iface.hpp> -#include <uhd/types/dict.hpp> -#include <uhd/exception.hpp> -#include <uhd/utils/algorithm.hpp> -#include <boost/assign/list_of.hpp> -#include <boost/asio.hpp> //htonl and ntohl -#include <boost/math/special_functions/round.hpp> -#include "ad7922_regs.hpp" //aux adc -#include "ad5623_regs.hpp" //aux dac - -using namespace uhd; -using namespace uhd::usrp; -using namespace boost::assign; - -class usrp2_dboard_iface : public dboard_iface{ -public: - usrp2_dboard_iface(usrp2_iface::sptr iface, usrp2_clock_ctrl::sptr clock_ctrl); - ~usrp2_dboard_iface(void); - - special_props_t get_special_props(void){ - special_props_t props; - props.soft_clock_divider = false; - props.mangle_i2c_addrs = false; - return props; - } - - void write_aux_dac(unit_t, aux_dac_t, double); - double read_aux_adc(unit_t, aux_adc_t); - - void _set_pin_ctrl(unit_t, boost::uint16_t); - void _set_atr_reg(unit_t, atr_reg_t, boost::uint16_t); - void _set_gpio_ddr(unit_t, boost::uint16_t); - void _set_gpio_out(unit_t, boost::uint16_t); - void set_gpio_debug(unit_t, int); - boost::uint16_t read_gpio(unit_t); - - void write_i2c(boost::uint8_t, const byte_vector_t &); - byte_vector_t read_i2c(boost::uint8_t, size_t); - - void set_clock_rate(unit_t, double); - double get_clock_rate(unit_t); - std::vector<double> get_clock_rates(unit_t); - void set_clock_enabled(unit_t, bool); - double get_codec_rate(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; - usrp2_clock_ctrl::sptr _clock_ctrl; - boost::uint32_t _ddr_shadow; - boost::uint32_t _gpio_shadow; - - uhd::dict<unit_t, ad5623_regs_t> _dac_regs; - uhd::dict<unit_t, double> _clock_rates; - void _write_aux_dac(unit_t); -}; - -/*********************************************************************** - * Make Function - **********************************************************************/ -dboard_iface::sptr make_usrp2_dboard_iface( - usrp2_iface::sptr iface, - usrp2_clock_ctrl::sptr clock_ctrl -){ - return dboard_iface::sptr(new usrp2_dboard_iface(iface, clock_ctrl)); -} - -/*********************************************************************** - * Structors - **********************************************************************/ -usrp2_dboard_iface::usrp2_dboard_iface( - usrp2_iface::sptr iface, - usrp2_clock_ctrl::sptr clock_ctrl -){ - _iface = iface; - _clock_ctrl = clock_ctrl; - _ddr_shadow = 0; - _gpio_shadow = 0; - - //reset the aux dacs - _dac_regs[UNIT_RX] = ad5623_regs_t(); - _dac_regs[UNIT_TX] = ad5623_regs_t(); - BOOST_FOREACH(unit_t unit, _dac_regs.keys()){ - _dac_regs[unit].data = 1; - _dac_regs[unit].addr = ad5623_regs_t::ADDR_ALL; - _dac_regs[unit].cmd = ad5623_regs_t::CMD_RESET; - this->_write_aux_dac(unit); - } - - //init the clock rate shadows with max rate clock - this->set_clock_rate(UNIT_RX, sorted(this->get_clock_rates(UNIT_RX)).back()); - this->set_clock_rate(UNIT_TX, sorted(this->get_clock_rates(UNIT_TX)).back()); -} - -usrp2_dboard_iface::~usrp2_dboard_iface(void){ - /* NOP */ -} - -/*********************************************************************** - * Clocks - **********************************************************************/ -void usrp2_dboard_iface::set_clock_rate(unit_t unit, double rate){ - _clock_rates[unit] = rate; //set to shadow - switch(unit){ - case UNIT_RX: _clock_ctrl->set_rate_rx_dboard_clock(rate); return; - case UNIT_TX: _clock_ctrl->set_rate_tx_dboard_clock(rate); return; - } -} - -double usrp2_dboard_iface::get_clock_rate(unit_t unit){ - return _clock_rates[unit]; //get from shadow -} - -std::vector<double> usrp2_dboard_iface::get_clock_rates(unit_t unit){ - switch(unit){ - case UNIT_RX: return _clock_ctrl->get_rates_rx_dboard_clock(); - case UNIT_TX: return _clock_ctrl->get_rates_tx_dboard_clock(); - default: UHD_THROW_INVALID_CODE_PATH(); - } -} - -void usrp2_dboard_iface::set_clock_enabled(unit_t unit, bool enb){ - switch(unit){ - case UNIT_RX: _clock_ctrl->enable_rx_dboard_clock(enb); return; - case UNIT_TX: _clock_ctrl->enable_tx_dboard_clock(enb); return; - } -} - -double usrp2_dboard_iface::get_codec_rate(unit_t){ - return _clock_ctrl->get_master_clock_rate(); -} -/*********************************************************************** - * GPIO - **********************************************************************/ -static const uhd::dict<dboard_iface::unit_t, int> unit_to_shift = map_list_of - (dboard_iface::UNIT_RX, 0) - (dboard_iface::UNIT_TX, 16) -; - -void usrp2_dboard_iface::_set_pin_ctrl(unit_t unit, boost::uint16_t value){ - //calculate the new selection mux setting - boost::uint32_t new_sels = 0x0; - for(size_t i = 0; i < 16; i++){ - bool is_bit_set = (value & (0x1 << i)) != 0; - new_sels |= ((is_bit_set)? U2_FLAG_GPIO_SEL_ATR : U2_FLAG_GPIO_SEL_GPIO) << (i*2); - } - - //write the selection mux value to register - switch(unit){ - case UNIT_RX: _iface->poke32(U2_REG_GPIO_RX_SEL, new_sels); return; - case UNIT_TX: _iface->poke32(U2_REG_GPIO_TX_SEL, new_sels); return; - } -} - -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(U2_REG_GPIO_DDR, _ddr_shadow); -} - -void usrp2_dboard_iface::_set_gpio_out(unit_t unit, boost::uint16_t value){ - _gpio_shadow = \ - (_gpio_shadow & ~(0xffff << unit_to_shift[unit])) | - (boost::uint32_t(value) << unit_to_shift[unit]); - _iface->poke32(U2_REG_GPIO_IO, _gpio_shadow); -} - -boost::uint16_t usrp2_dboard_iface::read_gpio(unit_t unit){ - return boost::uint16_t(_iface->peek32(U2_REG_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 = map_list_of - (UNIT_RX, map_list_of - (ATR_REG_IDLE, U2_REG_ATR_IDLE_RXSIDE) - (ATR_REG_TX_ONLY, U2_REG_ATR_INTX_RXSIDE) - (ATR_REG_RX_ONLY, U2_REG_ATR_INRX_RXSIDE) - (ATR_REG_FULL_DUPLEX, U2_REG_ATR_FULL_RXSIDE) - ) - (UNIT_TX, map_list_of - (ATR_REG_IDLE, U2_REG_ATR_IDLE_TXSIDE) - (ATR_REG_TX_ONLY, U2_REG_ATR_INTX_TXSIDE) - (ATR_REG_RX_ONLY, U2_REG_ATR_INRX_TXSIDE) - (ATR_REG_FULL_DUPLEX, U2_REG_ATR_FULL_TXSIDE) - ) - ; - _iface->poke16(unit_to_atr_to_addr[unit][atr], value); -} - -void usrp2_dboard_iface::set_gpio_debug(unit_t unit, int which){ - this->set_gpio_ddr(unit, 0xffff); //all outputs - - //calculate the new selection mux setting - boost::uint32_t new_sels = 0x0; - int sel = (which == 0)? - U2_FLAG_GPIO_SEL_DEBUG_0: - U2_FLAG_GPIO_SEL_DEBUG_1; - for(size_t i = 0; i < 16; i++){ - new_sels |= sel << (i*2); - } - - //write the selection mux value to register - switch(unit){ - case UNIT_RX: _iface->poke32(U2_REG_GPIO_RX_SEL, new_sels); return; - case UNIT_TX: _iface->poke32(U2_REG_GPIO_TX_SEL, new_sels); return; - } -} - -/*********************************************************************** - * SPI - **********************************************************************/ -static const uhd::dict<dboard_iface::unit_t, int> unit_to_spi_dev = map_list_of - (dboard_iface::UNIT_TX, SPI_SS_TX_DB) - (dboard_iface::UNIT_RX, SPI_SS_RX_DB) -; - -void usrp2_dboard_iface::write_spi( - unit_t unit, - const spi_config_t &config, - boost::uint32_t data, - size_t num_bits -){ - _iface->write_spi(unit_to_spi_dev[unit], config, data, num_bits); -} - -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->read_spi(unit_to_spi_dev[unit], config, data, num_bits); -} - -/*********************************************************************** - * I2C - **********************************************************************/ -void usrp2_dboard_iface::write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){ - return _iface->write_i2c(addr, bytes); -} - -byte_vector_t usrp2_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_bytes){ - return _iface->read_i2c(addr, num_bytes); -} - -/*********************************************************************** - * Aux DAX/ADC - **********************************************************************/ -void usrp2_dboard_iface::_write_aux_dac(unit_t unit){ - static const uhd::dict<unit_t, int> unit_to_spi_dac = map_list_of - (UNIT_RX, SPI_SS_RX_DAC) - (UNIT_TX, SPI_SS_TX_DAC) - ; - _iface->write_spi( - unit_to_spi_dac[unit], spi_config_t::EDGE_FALL, - _dac_regs[unit].get_reg(), 24 - ); -} - -void usrp2_dboard_iface::write_aux_dac(unit_t unit, aux_dac_t which, double value){ - _dac_regs[unit].data = boost::math::iround(4095*value/3.3); - _dac_regs[unit].cmd = ad5623_regs_t::CMD_WR_UP_DAC_CHAN_N; - - typedef uhd::dict<aux_dac_t, ad5623_regs_t::addr_t> aux_dac_to_addr; - static const uhd::dict<unit_t, aux_dac_to_addr> unit_to_which_to_addr = map_list_of - (UNIT_RX, map_list_of - (AUX_DAC_A, ad5623_regs_t::ADDR_DAC_B) - (AUX_DAC_B, ad5623_regs_t::ADDR_DAC_A) - (AUX_DAC_C, ad5623_regs_t::ADDR_DAC_A) - (AUX_DAC_D, ad5623_regs_t::ADDR_DAC_B) - ) - (UNIT_TX, map_list_of - (AUX_DAC_A, ad5623_regs_t::ADDR_DAC_A) - (AUX_DAC_B, ad5623_regs_t::ADDR_DAC_B) - (AUX_DAC_C, ad5623_regs_t::ADDR_DAC_B) - (AUX_DAC_D, ad5623_regs_t::ADDR_DAC_A) - ) - ; - _dac_regs[unit].addr = unit_to_which_to_addr[unit][which]; - this->_write_aux_dac(unit); -} - -double usrp2_dboard_iface::read_aux_adc(unit_t unit, aux_adc_t which){ - static const uhd::dict<unit_t, int> unit_to_spi_adc = map_list_of - (UNIT_RX, SPI_SS_RX_ADC) - (UNIT_TX, SPI_SS_TX_ADC) - ; - - //setup spi config args - spi_config_t config; - config.mosi_edge = spi_config_t::EDGE_FALL; - config.miso_edge = spi_config_t::EDGE_RISE; - - //setup the spi registers - ad7922_regs_t ad7922_regs; - switch(which){ - case AUX_ADC_A: ad7922_regs.mod = 0; break; - case AUX_ADC_B: ad7922_regs.mod = 1; break; - } ad7922_regs.chn = ad7922_regs.mod; //normal mode: mod == chn - - //write and read spi - _iface->write_spi( - unit_to_spi_adc[unit], config, - ad7922_regs.get_reg(), 16 - ); - ad7922_regs.set_reg(boost::uint16_t(_iface->read_spi( - unit_to_spi_adc[unit], config, - ad7922_regs.get_reg(), 16 - ))); - - //convert to voltage and return - return 3.3*ad7922_regs.result/4095; -} diff --git a/host/lib/usrp2/fw_common.h b/host/lib/usrp2/fw_common.h deleted file mode 100644 index 21abc6aed..000000000 --- a/host/lib/usrp2/fw_common.h +++ /dev/null @@ -1,154 +0,0 @@ -// -// Copyright 2010-2011 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_FW_COMMON_H -#define INCLUDED_USRP2_FW_COMMON_H - -#include <stdint.h> - -/*! - * Structs and constants for usrp2 communication. - * This header is shared by the firmware and host code. - * Therefore, this header may only contain valid C code. - */ -#ifdef __cplusplus -extern "C" { -#endif - -//fpga and firmware compatibility numbers -#define USRP2_FPGA_COMPAT_NUM 7 -#define USRP2_FW_COMPAT_NUM 10 - -//used to differentiate control packets over data port -#define USRP2_INVALID_VRT_HEADER 0 - -// udp ports for the usrp2 communication -// Dynamic and/or private ports: 49152-65535 -#define USRP2_UDP_CTRL_PORT 49152 -//#define USRP2_UDP_UPDATE_PORT 49154 -#define USRP2_UDP_DSP0_PORT 49156 -#define USRP2_UDP_ERR0_PORT 49157 -#define USRP2_UDP_DSP1_PORT 49158 - -//////////////////////////////////////////////////////////////////////// -// I2C addresses -//////////////////////////////////////////////////////////////////////// -#define USRP2_I2C_DEV_EEPROM 0x50 // 24LC02[45]: 7-bits 1010xxx -#define USRP2_I2C_ADDR_MBOARD (USRP2_I2C_DEV_EEPROM | 0x0) -#define USRP2_I2C_ADDR_TX_DB (USRP2_I2C_DEV_EEPROM | 0x4) -#define USRP2_I2C_ADDR_RX_DB (USRP2_I2C_DEV_EEPROM | 0x5) - -//////////////////////////////////////////////////////////////////////// -// EEPROM Layout -//////////////////////////////////////////////////////////////////////// -#define USRP2_EE_MBOARD_REV 0x00 //2 bytes, little-endian (historic, don't blame me) -#define USRP2_EE_MBOARD_MAC_ADDR 0x02 //6 bytes -#define USRP2_EE_MBOARD_IP_ADDR 0x0C //uint32, big-endian -#define USRP2_EE_MBOARD_BOOTLOADER_FLAGS 0xF7 - -typedef enum{ - USRP2_CTRL_ID_HUH_WHAT = ' ', - //USRP2_CTRL_ID_FOR_SURE, //TODO error condition enums - //USRP2_CTRL_ID_SUX_MAN, - - USRP2_CTRL_ID_WAZZUP_BRO = 'a', - USRP2_CTRL_ID_WAZZUP_DUDE = 'A', - - USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO = 's', - USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE = 'S', - - USRP2_CTRL_ID_DO_AN_I2C_READ_FOR_ME_BRO = 'i', - USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE = 'I', - - USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO = 'h', - USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE = 'H', - - USRP2_CTRL_ID_GET_THIS_REGISTER_FOR_ME_BRO = 'r', - USRP2_CTRL_ID_OMG_GOT_REGISTER_SO_BAD_DUDE = 'R', - - USRP2_CTRL_ID_HEY_WRITE_THIS_UART_FOR_ME_BRO = 'u', - USRP2_CTRL_ID_MAN_I_TOTALLY_WROTE_THAT_UART_DUDE = 'U', - - USRP2_CTRL_ID_SO_LIKE_CAN_YOU_READ_THIS_UART_BRO = 'v', - USRP2_CTRL_ID_I_HELLA_READ_THAT_UART_DUDE = 'V', - - USRP2_CTRL_ID_HOLLER_AT_ME_BRO = 'l', - USRP2_CTRL_ID_HOLLER_BACK_DUDE = 'L', - - USRP2_CTRL_ID_PEACE_OUT = '~' - -} usrp2_ctrl_id_t; - -typedef enum{ - USRP2_DIR_RX = 'r', - USRP2_DIR_TX = 't' -} usrp2_dir_which_t; - -typedef enum{ - USRP2_CLK_EDGE_RISE = 'r', - USRP2_CLK_EDGE_FALL = 'f' -} usrp2_clk_edge_t; - -typedef enum{ - USRP2_REG_ACTION_FPGA_PEEK32 = 1, - USRP2_REG_ACTION_FPGA_PEEK16 = 2, - USRP2_REG_ACTION_FPGA_POKE32 = 3, - USRP2_REG_ACTION_FPGA_POKE16 = 4, - USRP2_REG_ACTION_FW_PEEK32 = 5, - USRP2_REG_ACTION_FW_POKE32 = 6 -} usrp2_reg_action_t; - -typedef struct{ - uint32_t proto_ver; - uint32_t id; - uint32_t seq; - union{ - uint32_t ip_addr; - struct { - uint32_t dev; - uint32_t data; - uint8_t miso_edge; - uint8_t mosi_edge; - uint8_t num_bits; - uint8_t readback; - } spi_args; - struct { - uint8_t addr; - uint8_t bytes; - uint8_t data[20]; - } i2c_args; - struct { - uint32_t addr; - uint32_t data; - uint8_t action; - } reg_args; - struct { - uint8_t dev; - uint8_t bytes; - uint8_t data[20]; - } uart_args; - struct { - uint32_t len; - } echo_args; - } data; -} usrp2_ctrl_data_t; - -#ifdef __cplusplus -} -#endif - -#endif /* INCLUDED_USRP2_FW_COMMON_H */ diff --git a/host/lib/usrp2/io_impl.cpp b/host/lib/usrp2/io_impl.cpp deleted file mode 100644 index 64c099ff6..000000000 --- a/host/lib/usrp2/io_impl.cpp +++ /dev/null @@ -1,422 +0,0 @@ -// -// Copyright 2010-2011 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 "../../transport/super_recv_packet_handler.hpp" -#include "../../transport/super_send_packet_handler.hpp" -#include "usrp2_impl.hpp" -#include "usrp2_regs.hpp" -#include <uhd/utils/log.hpp> -#include <uhd/utils/msg.hpp> -#include <uhd/exception.hpp> -#include <uhd/utils/byteswap.hpp> -#include <uhd/utils/thread_priority.hpp> -#include <uhd/transport/bounded_buffer.hpp> -#include <boost/format.hpp> -#include <boost/bind.hpp> -#include <boost/thread/mutex.hpp> -#include <boost/thread/thread.hpp> -#include <boost/thread/barrier.hpp> -#include <iostream> - -using namespace uhd; -using namespace uhd::usrp; -using namespace uhd::transport; -namespace asio = boost::asio; -namespace pt = boost::posix_time; - -/*********************************************************************** - * helpers - **********************************************************************/ -static UHD_INLINE pt::time_duration to_time_dur(double timeout){ - return pt::microseconds(long(timeout*1e6)); -} - -static UHD_INLINE double from_time_dur(const pt::time_duration &time_dur){ - return 1e-6*time_dur.total_microseconds(); -} - -/*********************************************************************** - * constants - **********************************************************************/ -static const int underflow_flags = 0 - | async_metadata_t::EVENT_CODE_UNDERFLOW - | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET -; - -static const size_t vrt_send_header_offset_words32 = 1; - -/*********************************************************************** - * flow control monitor for a single tx channel - * - the pirate thread calls update - * - the get send buffer calls check - **********************************************************************/ -class flow_control_monitor{ -public: - typedef boost::uint32_t seq_type; - typedef boost::shared_ptr<flow_control_monitor> sptr; - - /*! - * Make a new flow control monitor. - * \param max_seqs_out num seqs before throttling - */ - flow_control_monitor(seq_type max_seqs_out){ - _last_seq_out = 0; - _last_seq_ack = 0; - _max_seqs_out = max_seqs_out; - _ready_fcn = boost::bind(&flow_control_monitor::ready, this); - } - - /*! - * Gets the current sequence number to go out. - * Increments the sequence for the next call - * \return the sequence to be sent to the dsp - */ - UHD_INLINE seq_type get_curr_seq_out(void){ - return _last_seq_out++; - } - - /*! - * Check the flow control condition. - * \param timeout the timeout in seconds - * \return false on timeout - */ - UHD_INLINE bool check_fc_condition(double timeout){ - boost::mutex::scoped_lock lock(_fc_mutex); - if (this->ready()) return true; - boost::this_thread::disable_interruption di; //disable because the wait can throw - return _fc_cond.timed_wait(lock, to_time_dur(timeout), _ready_fcn); - } - - /*! - * Update the flow control condition. - * \param seq the last sequence number to be ACK'd - */ - UHD_INLINE void update_fc_condition(seq_type seq){ - boost::mutex::scoped_lock lock(_fc_mutex); - _last_seq_ack = seq; - lock.unlock(); - _fc_cond.notify_one(); - } - -private: - bool ready(void){ - return seq_type(_last_seq_out -_last_seq_ack) < _max_seqs_out; - } - - boost::mutex _fc_mutex; - boost::condition _fc_cond; - seq_type _last_seq_out, _last_seq_ack, _max_seqs_out; - boost::function<bool(void)> _ready_fcn; -}; - -/*********************************************************************** - * io impl details (internal to this file) - * - pirate crew - * - alignment buffer - * - thread loop - * - vrt packet handler states - **********************************************************************/ -struct usrp2_impl::io_impl{ - - io_impl(void): - async_msg_fifo(100/*messages deep*/) - { - /* NOP */ - } - - ~io_impl(void){ - recv_pirate_crew.interrupt_all(); - recv_pirate_crew.join_all(); - } - - managed_send_buffer::sptr get_send_buff(size_t chan, double timeout){ - flow_control_monitor &fc_mon = *fc_mons[chan]; - - //wait on flow control w/ timeout - if (not fc_mon.check_fc_condition(timeout)) return managed_send_buffer::sptr(); - - //get a buffer from the transport w/ timeout - managed_send_buffer::sptr buff = tx_xports[chan]->get_send_buff(timeout); - - //write the flow control word into the buffer - if (buff.get()) buff->cast<boost::uint32_t *>()[0] = uhd::htonx(fc_mon.get_curr_seq_out()); - - return buff; - } - - //tx dsp: xports and flow control monitors - std::vector<zero_copy_if::sptr> tx_xports; - std::vector<flow_control_monitor::sptr> fc_mons; - - //state management for the vrt packet handler code - sph::recv_packet_handler recv_handler; - sph::send_packet_handler send_handler; - - //methods and variables for the pirate crew - void recv_pirate_loop(boost::barrier &, zero_copy_if::sptr, size_t); - boost::thread_group recv_pirate_crew; - bounded_buffer<async_metadata_t> async_msg_fifo; - double tick_rate; -}; - -/*********************************************************************** - * Receive Pirate Loop - * - while raiding, loot for message packet - * - update flow control condition count - * - put async message packets into queue - **********************************************************************/ -void usrp2_impl::io_impl::recv_pirate_loop( - boost::barrier &spawn_barrier, - zero_copy_if::sptr err_xport, - size_t index -){ - spawn_barrier.wait(); - set_thread_priority_safe(); - - //store a reference to the flow control monitor (offset by max dsps) - flow_control_monitor &fc_mon = *(this->fc_mons[index]); - - while (not boost::this_thread::interruption_requested()){ - managed_recv_buffer::sptr buff = err_xport->get_recv_buff(); - if (not buff.get()) continue; //ignore timeout/error buffers - - try{ - //extract the vrt header packet info - vrt::if_packet_info_t if_packet_info; - if_packet_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t); - const boost::uint32_t *vrt_hdr = buff->cast<const boost::uint32_t *>(); - vrt::if_hdr_unpack_be(vrt_hdr, if_packet_info); - - //handle a tx async report message - if (if_packet_info.sid == USRP2_TX_ASYNC_SID and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){ - - //fill in the async metadata - async_metadata_t metadata; - metadata.channel = index; - metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf; - metadata.time_spec = time_spec_t( - time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), tick_rate - ); - metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info)); - - //catch the flow control packets and react - if (metadata.event_code == 0){ - boost::uint32_t fc_word32 = (vrt_hdr + if_packet_info.num_header_words32)[1]; - fc_mon.update_fc_condition(uhd::ntohx(fc_word32)); - continue; - } - - //print the famous U, and push the metadata into the message queue - if (metadata.event_code & underflow_flags) UHD_MSG(fastpath) << "U"; - //else UHD_MSG(often) << "metadata.event_code " << metadata.event_code << std::endl; - async_msg_fifo.push_with_pop_on_full(metadata); - } - else{ - //TODO unknown received packet, may want to print error... - } - }catch(const std::exception &e){ - UHD_MSG(error) << "Error (usrp2 recv pirate loop): " << e.what() << std::endl; - } - } -} - -/*********************************************************************** - * Helper Functions - **********************************************************************/ -void usrp2_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_BIG_ENDIAN; - - //setup tx otw type - _tx_otw_type.width = 16; - _tx_otw_type.shift = 0; - _tx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; - - //create new io impl - _io_impl = UHD_PIMPL_MAKE(io_impl, ()); - - //init first so we dont have an access race - BOOST_FOREACH(const std::string &mb, _mbc.keys()){ - //init the tx xport and flow control monitor - _io_impl->tx_xports.push_back(_mbc[mb].dsp_xports.at(0)); - _io_impl->fc_mons.push_back(flow_control_monitor::sptr(new flow_control_monitor( - USRP2_SRAM_BYTES/_mbc[mb].dsp_xports.at(0)->get_send_frame_size() - ))); - } - - //create a new pirate thread for each zc if (yarr!!) - boost::barrier spawn_barrier(_mbc.size()+1); - size_t index = 0; - BOOST_FOREACH(const std::string &mb, _mbc.keys()){ - //spawn a new pirate to plunder the recv booty - _io_impl->recv_pirate_crew.create_thread(boost::bind( - &usrp2_impl::io_impl::recv_pirate_loop, - _io_impl.get(), boost::ref(spawn_barrier), - _mbc[mb].err_xports.at(0), index++ - )); - } - spawn_barrier.wait(); - - //init some handler stuff - _io_impl->recv_handler.set_vrt_unpacker(&vrt::if_hdr_unpack_be); - _io_impl->recv_handler.set_converter(_rx_otw_type); - _io_impl->send_handler.set_vrt_packer(&vrt::if_hdr_pack_be, vrt_send_header_offset_words32); - _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 usrp2_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); -} - -void usrp2_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); -} - -void usrp2_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 usrp2_impl::update_rx_subdev_spec(const std::string &which_mb, const subdev_spec_t &spec){ - boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock(); - property_tree::path_type root = "/mboards/" + which_mb + "/dboards"; - - //sanity checking - if (spec.size() == 0) throw uhd::value_error("rx subdev spec cant be empty"); - if (spec.size() > _mbc[which_mb].rx_dsps.size()) throw uhd::value_error("rx subdev spec too long"); - - //setup mux for this spec - for (size_t i = 0; i < spec.size(); i++){ - //ASSUME that we dont swap the rx fe mux... - const std::string conn = _tree->access<std::string>(root / spec[i].db_name / "rx_frontends" / spec[i].sd_name / "connection").get(); - _mbc[which_mb].rx_dsps[i]->set_mux(conn); - } - - //compute the new occupancy and resize - _mbc[which_mb].rx_chan_occ = spec.size(); - size_t nchan = 0; - BOOST_FOREACH(const std::string &mb, _mbc.keys()) nchan += _mbc[mb].rx_chan_occ; - _io_impl->recv_handler.resize(nchan); - - //bind new callbacks for the handler - size_t chan = 0; - BOOST_FOREACH(const std::string &mb, _mbc.keys()){ - for (size_t dsp = 0; dsp < _mbc[mb].rx_chan_occ; dsp++){ - _mbc[mb].rx_dsps[dsp]->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(chan++, boost::bind( - &zero_copy_if::get_recv_buff, _mbc[mb].dsp_xports[dsp], _1 - )); - } - } -} - -void usrp2_impl::update_tx_subdev_spec(const std::string &which_mb, const subdev_spec_t &spec){ - boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock(); - property_tree::path_type root = "/mboards/" + which_mb + "/dboards"; - - //sanity checking - if (spec.size() != 1) throw uhd::value_error("tx subdev spec has to be size 1"); - - //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(); - _mbc[which_mb].tx_fe->set_mux(conn); - - //compute the new occupancy and resize - _mbc[which_mb].tx_chan_occ = spec.size(); - size_t nchan = 0; - BOOST_FOREACH(const std::string &mb, _mbc.keys()) nchan += _mbc[mb].tx_chan_occ; - _io_impl->send_handler.resize(nchan); - - //bind new callbacks for the handler - size_t chan = 0, i = 0; - BOOST_FOREACH(const std::string &mb, _mbc.keys()){ - for (size_t dsp = 0; dsp < _mbc[mb].tx_chan_occ; dsp++){ - _io_impl->send_handler.set_xport_chan_get_buff(chan++, boost::bind( - &usrp2_impl::io_impl::get_send_buff, _io_impl.get(), i++, _1 - )); - } - } -} - -/*********************************************************************** - * Async Data - **********************************************************************/ -bool usrp2_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); -} - -/*********************************************************************** - * Send Data - **********************************************************************/ -size_t usrp2_impl::get_max_send_samps_per_packet(void) const{ - static const size_t hdr_size = 0 - + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) - + vrt_send_header_offset_words32*sizeof(boost::uint32_t) - - sizeof(vrt::if_packet_info_t().cid) //no class id ever used - ; - const size_t bpp = _mbc[_mbc.keys().front()].dsp_xports[0]->get_send_frame_size() - hdr_size; - return bpp/_tx_otw_type.get_sample_size(); -} - -size_t usrp2_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 - ); -} - -/*********************************************************************** - * Receive Data - **********************************************************************/ -size_t usrp2_impl::get_max_recv_samps_per_packet(void) const{ - 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 - ; - const size_t bpp = _mbc[_mbc.keys().front()].dsp_xports[0]->get_recv_frame_size() - hdr_size; - return bpp/_rx_otw_type.get_sample_size(); -} - -size_t usrp2_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 - ); -} diff --git a/host/lib/usrp2/usrp2_clk_regs.hpp b/host/lib/usrp2/usrp2_clk_regs.hpp deleted file mode 100644 index 8b185eac0..000000000 --- a/host/lib/usrp2/usrp2_clk_regs.hpp +++ /dev/null @@ -1,87 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_USRP2_CLK_REGS_HPP -#define INCLUDED_USRP2_CLK_REGS_HPP - -#include "usrp2_iface.hpp" - -class usrp2_clk_regs_t { -public: - usrp2_clk_regs_t(void) { ; } - usrp2_clk_regs_t(usrp2_iface::rev_type rev) { - test = 0; - fpga = 1; - dac = 3; - - switch(rev) { - case usrp2_iface::USRP2_REV3: - exp = 2; - adc = 4; - serdes = 2; - tx_db = 6; - break; - case usrp2_iface::USRP2_REV4: - exp = 5; - adc = 4; - serdes = 2; - tx_db = 6; - break; - case usrp2_iface::USRP_N200: - case usrp2_iface::USRP_N210: - case usrp2_iface::USRP_N200_R4: - case usrp2_iface::USRP_N210_R4: - exp = 6; - adc = 2; - serdes = 4; - tx_db = 5; - break; - case usrp2_iface::USRP_NXXX: - //dont throw, it may be unitialized - break; - } - - rx_db = 7; - } - - static int output(int clknum) { return 0x3C + clknum; } - static int div_lo(int clknum) { return 0x48 + 2 * clknum; } - static int div_hi(int clknum) { return 0x49 + 2 * clknum; } - - const static int acounter = 0x04; - const static int bcounter_msb = 0x05; - const static int bcounter_lsb = 0x06; - const static int pll_1 = 0x07; - const static int pll_2 = 0x08; - const static int pll_3 = 0x09; - const static int pll_4 = 0x0A; - const static int ref_counter_msb = 0x0B; - const static int ref_counter_lsb = 0x0C; - const static int pll_5 = 0x0D; - const static int update = 0x5A; - - int test; - int fpga; - int adc; - int dac; - int serdes; - int exp; - int tx_db; - int rx_db; -}; - -#endif //INCLUDED_USRP2_CLK_REGS_HPP diff --git a/host/lib/usrp2/usrp2_iface.cpp b/host/lib/usrp2/usrp2_iface.cpp deleted file mode 100644 index 0db9e5d58..000000000 --- a/host/lib/usrp2/usrp2_iface.cpp +++ /dev/null @@ -1,412 +0,0 @@ -// -// Copyright 2010-2011 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_regs.hpp" -#include "fw_common.h" -#include "usrp2_iface.hpp" -#include <uhd/exception.hpp> -#include <uhd/utils/msg.hpp> -#include <uhd/types/dict.hpp> -#include <boost/thread.hpp> -#include <boost/foreach.hpp> -#include <boost/asio.hpp> //used for htonl and ntohl -#include <boost/assign/list_of.hpp> -#include <boost/format.hpp> -#include <boost/tokenizer.hpp> -#include <boost/thread/thread.hpp> -#include <boost/thread/barrier.hpp> -#include <boost/functional/hash.hpp> -#include <algorithm> -#include <iostream> - -using namespace uhd; -using namespace uhd::usrp; -using namespace uhd::transport; - -static const double CTRL_RECV_TIMEOUT = 1.0; - -static const boost::uint32_t MIN_PROTO_COMPAT_SPI = 7; -static const boost::uint32_t MIN_PROTO_COMPAT_I2C = 7; -// The register compat number must reflect the protocol compatibility -// and the compatibility of the register mapping (more likely to change). -static const boost::uint32_t MIN_PROTO_COMPAT_REG = USRP2_FW_COMPAT_NUM; -static const boost::uint32_t MIN_PROTO_COMPAT_UART = 7; - -// Map for virtual firmware regs (not very big so we can keep it here for now) -#define U2_FW_REG_LOCK_TIME 0 -#define U2_FW_REG_LOCK_GPID 1 - -//Define get_gpid() to get a globally unique identifier for this process. -//The gpid is implemented as a hash of the pid and a unique machine identifier. -#ifdef UHD_PLATFORM_WIN32 -#include <Windows.h> -static inline size_t get_gpid(void){ - //extract volume serial number - char szVolName[MAX_PATH+1], szFileSysName[MAX_PATH+1]; - DWORD dwSerialNumber, dwMaxComponentLen, dwFileSysFlags; - GetVolumeInformation("C:\\", szVolName, MAX_PATH, - &dwSerialNumber, &dwMaxComponentLen, - &dwFileSysFlags, szFileSysName, sizeof(szFileSysName)); - - size_t hash = 0; - boost::hash_combine(hash, GetCurrentProcessId()); - boost::hash_combine(hash, dwSerialNumber); - return hash; -} -#else -#include <unistd.h> -static inline size_t get_gpid(void){ - size_t hash = 0; - boost::hash_combine(hash, getpid()); - boost::hash_combine(hash, gethostid()); - return hash; -} -#endif - -class usrp2_iface_impl : public usrp2_iface{ -public: -/*********************************************************************** - * Structors - **********************************************************************/ - usrp2_iface_impl(udp_simple::sptr ctrl_transport): - _ctrl_transport(ctrl_transport), - _ctrl_seq_num(0), - _protocol_compat(0) //initialized below... - { - //Obtain the firmware's compat number. - //Save the response compat number for communication. - //TODO can choose to reject certain older compat numbers - usrp2_ctrl_data_t ctrl_data; - ctrl_data.id = htonl(USRP2_CTRL_ID_WAZZUP_BRO); - ctrl_data = ctrl_send_and_recv(ctrl_data, 0, ~0); - if (ntohl(ctrl_data.id) != USRP2_CTRL_ID_WAZZUP_DUDE) - throw uhd::runtime_error("firmware not responding"); - _protocol_compat = ntohl(ctrl_data.proto_ver); - - mb_eeprom = mboard_eeprom_t(*this, mboard_eeprom_t::MAP_N100); - } - - ~usrp2_iface_impl(void){ - this->lock_device(false); - } - -/*********************************************************************** - * Device locking - **********************************************************************/ - - void lock_device(bool lock){ - if (lock){ - boost::barrier spawn_barrier(2); - _lock_thread_group.create_thread(boost::bind(&usrp2_iface_impl::lock_loop, this, boost::ref(spawn_barrier))); - spawn_barrier.wait(); - } - else{ - _lock_thread_group.interrupt_all(); - _lock_thread_group.join_all(); - } - } - - bool is_device_locked(void){ - boost::uint32_t lock_secs = this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_PEEK32>(U2_FW_REG_LOCK_TIME); - boost::uint32_t lock_gpid = this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_PEEK32>(U2_FW_REG_LOCK_GPID); - boost::uint32_t curr_secs = this->peek32(U2_REG_TIME64_SECS_RB_IMM); - - //if the difference is larger, assume not locked anymore - if (curr_secs - lock_secs >= 3) return false; - - //otherwise only lock if the device hash is different that ours - return lock_gpid != boost::uint32_t(get_gpid()); - } - - void lock_loop(boost::barrier &spawn_barrier){ - spawn_barrier.wait(); - - try{ - this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_GPID, boost::uint32_t(get_gpid())); - while(true){ - //re-lock in loop - boost::uint32_t curr_secs = this->peek32(U2_REG_TIME64_SECS_RB_IMM); - this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_TIME, curr_secs); - //sleep for a bit - boost::this_thread::sleep(boost::posix_time::milliseconds(1500)); - } - } - catch(const boost::thread_interrupted &){ - this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_TIME, 0); //unlock on exit - } - catch(const std::exception &e){ - UHD_MSG(error) - << "An unexpected exception was caught in the locker loop." << std::endl - << "The device will automatically unlock from this process." << std::endl - << e.what() << std::endl - ; - } - } - -/*********************************************************************** - * Peek and Poke - **********************************************************************/ - void poke32(wb_addr_type addr, boost::uint32_t data){ - this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FPGA_POKE32>(addr, data); - } - - boost::uint32_t peek32(wb_addr_type addr){ - return this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FPGA_PEEK32>(addr); - } - - void poke16(wb_addr_type addr, boost::uint16_t data){ - this->get_reg<boost::uint16_t, USRP2_REG_ACTION_FPGA_POKE16>(addr, data); - } - - boost::uint16_t peek16(wb_addr_type addr){ - return this->get_reg<boost::uint16_t, USRP2_REG_ACTION_FPGA_PEEK16>(addr); - } - - template <class T, usrp2_reg_action_t action> - T get_reg(wb_addr_type addr, T data = 0){ - //setup the out data - usrp2_ctrl_data_t out_data = usrp2_ctrl_data_t(); - out_data.id = htonl(USRP2_CTRL_ID_GET_THIS_REGISTER_FOR_ME_BRO); - out_data.data.reg_args.addr = htonl(addr); - out_data.data.reg_args.data = htonl(boost::uint32_t(data)); - out_data.data.reg_args.action = action; - - //send and recv - usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data, MIN_PROTO_COMPAT_REG); - UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_OMG_GOT_REGISTER_SO_BAD_DUDE); - return T(ntohl(in_data.data.reg_args.data)); - } - -/*********************************************************************** - * 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 = usrp2_ctrl_data_t(); - out_data.id = htonl(USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO); - out_data.data.spi_args.dev = htonl(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, MIN_PROTO_COMPAT_SPI); - UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE); - - return ntohl(in_data.data.spi_args.data); - } - -/*********************************************************************** - * I2C - **********************************************************************/ - void write_i2c(boost::uint8_t addr, const byte_vector_t &buf){ - //setup the out data - usrp2_ctrl_data_t out_data = usrp2_ctrl_data_t(); - out_data.id = htonl(USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO); - out_data.data.i2c_args.addr = addr; - out_data.data.i2c_args.bytes = buf.size(); - - //limitation of i2c transaction size - UHD_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 = this->ctrl_send_and_recv(out_data, MIN_PROTO_COMPAT_I2C); - UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE); - } - - byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes){ - //setup the out data - usrp2_ctrl_data_t out_data = usrp2_ctrl_data_t(); - out_data.id = htonl(USRP2_CTRL_ID_DO_AN_I2C_READ_FOR_ME_BRO); - out_data.data.i2c_args.addr = addr; - out_data.data.i2c_args.bytes = num_bytes; - - //limitation of i2c transaction size - UHD_ASSERT_THROW(num_bytes <= sizeof(out_data.data.i2c_args.data)); - - //send and recv - usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data, MIN_PROTO_COMPAT_I2C); - UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE); - UHD_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; - } - -/*********************************************************************** - * UART - **********************************************************************/ - void write_uart(boost::uint8_t dev, const std::string &buf){ - //first tokenize the string into 20-byte substrings - boost::offset_separator f(20, 20, true, true); - boost::tokenizer<boost::offset_separator> tok(buf, f); - std::vector<std::string> queue(tok.begin(), tok.end()); - - BOOST_FOREACH(std::string item, queue) { - //setup the out data - usrp2_ctrl_data_t out_data = usrp2_ctrl_data_t(); - out_data.id = htonl(USRP2_CTRL_ID_HEY_WRITE_THIS_UART_FOR_ME_BRO); - out_data.data.uart_args.dev = dev; - out_data.data.uart_args.bytes = item.size(); - - //limitation of uart transaction size - UHD_ASSERT_THROW(item.size() <= sizeof(out_data.data.uart_args.data)); - - //copy in the data - std::copy(item.begin(), item.end(), out_data.data.uart_args.data); - - //send and recv - usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data, MIN_PROTO_COMPAT_UART); - UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_MAN_I_TOTALLY_WROTE_THAT_UART_DUDE); - } - } - - std::string read_uart(boost::uint8_t dev){ - int readlen = 20; - std::string result; - while(readlen == 20) { //while we keep receiving full packets - //setup the out data - usrp2_ctrl_data_t out_data = usrp2_ctrl_data_t(); - out_data.id = htonl(USRP2_CTRL_ID_SO_LIKE_CAN_YOU_READ_THIS_UART_BRO); - out_data.data.uart_args.dev = dev; - out_data.data.uart_args.bytes = 20; - - //limitation of uart transaction size - //UHD_ASSERT_THROW(num_bytes <= sizeof(out_data.data.uart_args.data)); - - //send and recv - usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data, MIN_PROTO_COMPAT_UART); - UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_I_HELLA_READ_THAT_UART_DUDE); - readlen = in_data.data.uart_args.bytes; - - //copy out the data - result += std::string((const char *)in_data.data.uart_args.data, (size_t)readlen); - } - return result; - } - - gps_send_fn_t get_gps_write_fn(void) { - return boost::bind(&usrp2_iface_impl::write_uart, this, 2, _1); //2 is the GPS UART port on USRP2 - } - - gps_recv_fn_t get_gps_read_fn(void) { - return boost::bind(&usrp2_iface_impl::read_uart, this, 2); //2 is the GPS UART port on USRP2 - } - -/*********************************************************************** - * Send/Recv over control - **********************************************************************/ - usrp2_ctrl_data_t ctrl_send_and_recv( - const usrp2_ctrl_data_t &out_data, - boost::uint32_t lo = USRP2_FW_COMPAT_NUM, - boost::uint32_t hi = USRP2_FW_COMPAT_NUM - ){ - boost::mutex::scoped_lock lock(_ctrl_mutex); - - //fill in the seq number and send - usrp2_ctrl_data_t out_copy = out_data; - out_copy.proto_ver = htonl(_protocol_compat); - 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 - boost::uint8_t usrp2_ctrl_data_in_mem[udp_simple::mtu]; //allocate max bytes for recv - const usrp2_ctrl_data_t *ctrl_data_in = reinterpret_cast<const usrp2_ctrl_data_t *>(usrp2_ctrl_data_in_mem); - while(true){ - size_t len = _ctrl_transport->recv(boost::asio::buffer(usrp2_ctrl_data_in_mem), CTRL_RECV_TIMEOUT); - boost::uint32_t compat = ntohl(ctrl_data_in->proto_ver); - if(len >= sizeof(boost::uint32_t) and (hi < compat or lo > compat)){ - throw uhd::runtime_error(str(boost::format( - "\nPlease update the firmware and FPGA images for your device.\n" - "See the application notes for USRP2/N-Series for instructions.\n" - "Expected protocol compatibility number %s, but got %d:\n" - "The firmware build is not compatible with the host code build." - ) % ((lo == hi)? (boost::format("%d") % hi) : (boost::format("[%d to %d]") % lo % hi)) % compat)); - } - if (len >= sizeof(usrp2_ctrl_data_t) and ntohl(ctrl_data_in->seq) == _ctrl_seq_num){ - return *ctrl_data_in; - } - if (len == 0) break; //timeout - //didnt get seq or bad packet, continue looking... - } - throw uhd::runtime_error("no control response"); - } - - rev_type get_rev(void){ - switch (boost::lexical_cast<boost::uint16_t>(mb_eeprom["rev"])){ - case 0x0300: - case 0x0301: return USRP2_REV3; - case 0x0400: return USRP2_REV4; - case 0x0A00: return USRP_N200; - case 0x0A01: return USRP_N210; - case 0x0A10: return USRP_N200_R4; - case 0x0A11: return USRP_N210_R4; - } - return USRP_NXXX; //unknown type - } - - const std::string get_cname(void){ - switch(this->get_rev()){ - case USRP2_REV3: return "USRP2-REV3"; - case USRP2_REV4: return "USRP2-REV4"; - case USRP_N200: return "USRP-N200"; - case USRP_N210: return "USRP-N210"; - case USRP_N200_R4: return "USRP-N200-REV4"; - case USRP_N210_R4: return "USRP-N210-REV4"; - case USRP_NXXX: return "USRP-N???"; - } - UHD_THROW_INVALID_CODE_PATH(); - } - -private: - //this lovely lady makes it all possible - udp_simple::sptr _ctrl_transport; - - //used in send/recv - boost::mutex _ctrl_mutex; - boost::uint32_t _ctrl_seq_num; - boost::uint32_t _protocol_compat; - - //lock thread stuff - boost::thread_group _lock_thread_group; -}; - -/*********************************************************************** - * Public make function for usrp2 interface - **********************************************************************/ -usrp2_iface::sptr usrp2_iface::make(udp_simple::sptr ctrl_transport){ - return usrp2_iface::sptr(new usrp2_iface_impl(ctrl_transport)); -} - diff --git a/host/lib/usrp2/usrp2_iface.hpp b/host/lib/usrp2/usrp2_iface.hpp deleted file mode 100644 index f36febce4..000000000 --- a/host/lib/usrp2/usrp2_iface.hpp +++ /dev/null @@ -1,80 +0,0 @@ -// -// Copyright 2010-2011 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/types/serial.hpp> -#include <uhd/usrp/mboard_eeprom.hpp> -#include <boost/shared_ptr.hpp> -#include <boost/utility.hpp> -#include <boost/function.hpp> -#include "usrp2_regs.hpp" -#include "wb_iface.hpp" -#include <string> - -//TODO: kill this crap when you have the top level GPS include file -typedef boost::function<void(std::string)> gps_send_fn_t; -typedef boost::function<std::string(void)> gps_recv_fn_t; - -/*! - * The usrp2 interface class: - * Provides a set of functions to implementation layer. - * Including spi, peek, poke, control... - */ -class usrp2_iface : public wb_iface, public uhd::spi_iface, public uhd::i2c_iface, public uhd::uart_iface{ -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); - - virtual gps_recv_fn_t get_gps_read_fn(void) = 0; - virtual gps_send_fn_t get_gps_write_fn(void) = 0; - - //! The list of possible revision types - enum rev_type { - USRP2_REV3 = 3, - USRP2_REV4 = 4, - USRP_N200 = 200, - USRP_N200_R4 = 201, - USRP_N210 = 210, - USRP_N210_R4 = 211, - USRP_NXXX = 0 - }; - - //! Get the revision type for this device - virtual rev_type get_rev(void) = 0; - - //! Get the canonical name for this device - virtual const std::string get_cname(void) = 0; - - //! Lock the device to this iface - virtual void lock_device(bool lock) = 0; - - //! Is this device locked? - virtual bool is_device_locked(void) = 0; - - //motherboard eeprom map structure - uhd::usrp::mboard_eeprom_t mb_eeprom; -}; - -#endif /* INCLUDED_USRP2_IFACE_HPP */ diff --git a/host/lib/usrp2/usrp2_impl.cpp b/host/lib/usrp2/usrp2_impl.cpp deleted file mode 100644 index e00924ebd..000000000 --- a/host/lib/usrp2/usrp2_impl.cpp +++ /dev/null @@ -1,673 +0,0 @@ -// -// Copyright 2010-2011 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 "fw_common.h" -#include <uhd/utils/log.hpp> -#include <uhd/utils/msg.hpp> -#include <uhd/exception.hpp> -#include <uhd/transport/if_addrs.hpp> -#include <uhd/transport/udp_zero_copy.hpp> -#include <uhd/types/ranges.hpp> -#include <uhd/exception.hpp> -#include <uhd/utils/static.hpp> -#include <uhd/utils/byteswap.hpp> -#include <uhd/utils/safe_call.hpp> -#include <boost/format.hpp> -#include <boost/foreach.hpp> -#include <boost/lexical_cast.hpp> -#include <boost/bind.hpp> -#include <boost/assign/list_of.hpp> -#include <boost/asio/ip/address_v4.hpp> -#include <boost/asio.hpp> //used for htonl and ntohl - -using namespace uhd; -using namespace uhd::usrp; -using namespace uhd::transport; -namespace asio = boost::asio; - -/*********************************************************************** - * Discovery over the udp transport - **********************************************************************/ -static device_addrs_t usrp2_find(const device_addr_t &hint_){ - //handle the multi-device discovery - device_addrs_t hints = separate_device_addr(hint_); - if (hints.size() > 1){ - device_addrs_t found_devices; - BOOST_FOREACH(const device_addr_t &hint_i, hints){ - device_addrs_t found_devices_i = usrp2_find(hint_i); - if (found_devices_i.size() != 1) throw uhd::value_error(str(boost::format( - "Could not resolve device hint \"%s\" to a single device." - ) % hint_i.to_string())); - found_devices.push_back(found_devices_i[0]); - } - return device_addrs_t(1, combine_device_addrs(found_devices)); - } - - //initialize the hint for a single device case - UHD_ASSERT_THROW(hints.size() <= 1); - hints.resize(1); //in case it was empty - device_addr_t hint = hints[0]; - device_addrs_t usrp2_addrs; - - //return an empty list of addresses when type is set to non-usrp2 - if (hint.has_key("type") and hint["type"] != "usrp2") return usrp2_addrs; - - //if no address was specified, send a broadcast on each interface - if (not hint.has_key("addr")){ - BOOST_FOREACH(const if_addrs_t &if_addrs, get_if_addrs()){ - //avoid the loopback device - if (if_addrs.inet == asio::ip::address_v4::loopback().to_string()) continue; - - //create a new hint with this broadcast address - device_addr_t new_hint = hint; - new_hint["addr"] = if_addrs.bcast; - - //call discover with the new hint and append results - device_addrs_t new_usrp2_addrs = usrp2_find(new_hint); - usrp2_addrs.insert(usrp2_addrs.begin(), - new_usrp2_addrs.begin(), new_usrp2_addrs.end() - ); - } - return usrp2_addrs; - } - - //create a udp transport to communicate - 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 - ); - - //send a hello control packet - usrp2_ctrl_data_t ctrl_data_out = usrp2_ctrl_data_t(); - ctrl_data_out.proto_ver = uhd::htonx<boost::uint32_t>(USRP2_FW_COMPAT_NUM); - ctrl_data_out.id = uhd::htonx<boost::uint32_t>(USRP2_CTRL_ID_WAZZUP_BRO); - udp_transport->send(boost::asio::buffer(&ctrl_data_out, sizeof(ctrl_data_out))); - - //loop and recieve until the timeout - boost::uint8_t usrp2_ctrl_data_in_mem[udp_simple::mtu]; //allocate max bytes for recv - const usrp2_ctrl_data_t *ctrl_data_in = reinterpret_cast<const usrp2_ctrl_data_t *>(usrp2_ctrl_data_in_mem); - while(true){ - size_t len = udp_transport->recv(asio::buffer(usrp2_ctrl_data_in_mem)); - if (len > offsetof(usrp2_ctrl_data_t, data) and ntohl(ctrl_data_in->id) == USRP2_CTRL_ID_WAZZUP_DUDE){ - - //make a boost asio ipv4 with the raw addr in host byte order - boost::asio::ip::address_v4 ip_addr(ntohl(ctrl_data_in->data.ip_addr)); - device_addr_t new_addr; - new_addr["type"] = "usrp2"; - new_addr["addr"] = ip_addr.to_string(); - - //Attempt to read the name from the EEPROM and perform filtering. - //This operation can throw due to compatibility mismatch. - try{ - usrp2_iface::sptr iface = usrp2_iface::make(udp_simple::make_connected( - new_addr["addr"], BOOST_STRINGIZE(USRP2_UDP_CTRL_PORT) - )); - if (iface->is_device_locked()) continue; //ignore locked devices - mboard_eeprom_t mb_eeprom = iface->mb_eeprom; - new_addr["name"] = mb_eeprom["name"]; - new_addr["serial"] = mb_eeprom["serial"]; - } - catch(const std::exception &){ - //set these values as empty string so the device may still be found - //and the filter's below can still operate on the discovered device - new_addr["name"] = ""; - new_addr["serial"] = ""; - } - - //filter the discovered device below by matching optional keys - if ( - (not hint.has_key("name") or hint["name"] == new_addr["name"]) and - (not hint.has_key("serial") or hint["serial"] == new_addr["serial"]) - ){ - usrp2_addrs.push_back(new_addr); - } - - //dont break here, it will exit the while loop - //just continue on to the next loop iteration - } - if (len == 0) break; //timeout - } - - return usrp2_addrs; -} - -/*********************************************************************** - * Make - **********************************************************************/ -static device::sptr usrp2_make(const device_addr_t &device_addr){ - return device::sptr(new usrp2_impl(device_addr)); -} - -UHD_STATIC_BLOCK(register_usrp2_device){ - device::register_device(&usrp2_find, &usrp2_make); -} - -/*********************************************************************** - * MTU Discovery - **********************************************************************/ -struct mtu_result_t{ - size_t recv_mtu, send_mtu; -}; - -static mtu_result_t determine_mtu(const std::string &addr, const mtu_result_t &user_mtu){ - udp_simple::sptr udp_sock = udp_simple::make_connected( - addr, BOOST_STRINGIZE(USRP2_UDP_CTRL_PORT) - ); - - //The FPGA offers 4K buffers, and the user may manually request this. - //However, multiple simultaneous receives (2DSP slave + 2DSP master), - //require that buffering to be used internally, and this is a safe setting. - std::vector<boost::uint8_t> buffer(std::max(user_mtu.recv_mtu, user_mtu.send_mtu)); - usrp2_ctrl_data_t *ctrl_data = reinterpret_cast<usrp2_ctrl_data_t *>(&buffer.front()); - static const double echo_timeout = 0.020; //20 ms - - //test holler - check if its supported in this fw version - ctrl_data->id = htonl(USRP2_CTRL_ID_HOLLER_AT_ME_BRO); - ctrl_data->proto_ver = htonl(USRP2_FW_COMPAT_NUM); - ctrl_data->data.echo_args.len = htonl(sizeof(usrp2_ctrl_data_t)); - udp_sock->send(boost::asio::buffer(buffer, sizeof(usrp2_ctrl_data_t))); - udp_sock->recv(boost::asio::buffer(buffer), echo_timeout); - if (ntohl(ctrl_data->id) != USRP2_CTRL_ID_HOLLER_BACK_DUDE) - throw uhd::not_implemented_error("holler protocol not implemented"); - - size_t min_recv_mtu = sizeof(usrp2_ctrl_data_t), max_recv_mtu = user_mtu.recv_mtu; - size_t min_send_mtu = sizeof(usrp2_ctrl_data_t), max_send_mtu = user_mtu.send_mtu; - - while (min_recv_mtu < max_recv_mtu){ - - size_t test_mtu = (max_recv_mtu/2 + min_recv_mtu/2 + 3) & ~3; - - ctrl_data->id = htonl(USRP2_CTRL_ID_HOLLER_AT_ME_BRO); - ctrl_data->proto_ver = htonl(USRP2_FW_COMPAT_NUM); - ctrl_data->data.echo_args.len = htonl(test_mtu); - udp_sock->send(boost::asio::buffer(buffer, sizeof(usrp2_ctrl_data_t))); - - size_t len = udp_sock->recv(boost::asio::buffer(buffer), echo_timeout); - - if (len >= test_mtu) min_recv_mtu = test_mtu; - else max_recv_mtu = test_mtu - 4; - - } - - while (min_send_mtu < max_send_mtu){ - - size_t test_mtu = (max_send_mtu/2 + min_send_mtu/2 + 3) & ~3; - - ctrl_data->id = htonl(USRP2_CTRL_ID_HOLLER_AT_ME_BRO); - ctrl_data->proto_ver = htonl(USRP2_FW_COMPAT_NUM); - ctrl_data->data.echo_args.len = htonl(sizeof(usrp2_ctrl_data_t)); - udp_sock->send(boost::asio::buffer(buffer, test_mtu)); - - size_t len = udp_sock->recv(boost::asio::buffer(buffer), echo_timeout); - if (len >= sizeof(usrp2_ctrl_data_t)) len = ntohl(ctrl_data->data.echo_args.len); - - if (len >= test_mtu) min_send_mtu = test_mtu; - else max_send_mtu = test_mtu - 4; - } - - mtu_result_t mtu; - mtu.recv_mtu = min_recv_mtu; - mtu.send_mtu = min_send_mtu; - return mtu; -} - -/*********************************************************************** - * Helpers - **********************************************************************/ -static void init_xport(zero_copy_if::sptr xport){ - //Send a small data packet so the usrp2 knows the udp source port. - //This setup must happen before further initialization occurs - //or the async update packets will cause ICMP destination unreachable. - static const boost::uint32_t data[2] = { - uhd::htonx(boost::uint32_t(0 /* don't care seq num */)), - uhd::htonx(boost::uint32_t(USRP2_INVALID_VRT_HEADER)) - }; - - transport::managed_send_buffer::sptr send_buff = xport->get_send_buff(); - std::memcpy(send_buff->cast<void*>(), &data, sizeof(data)); - send_buff->commit(sizeof(data)); -} - -/*********************************************************************** - * Structors - **********************************************************************/ -usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){ - UHD_MSG(status) << "Opening a USRP2/N-Series device..." << std::endl; - device_addr_t device_addr = _device_addr; - - //setup the dsp transport hints (default to a large recv buff) - if (not device_addr.has_key("recv_buff_size")){ - #if defined(UHD_PLATFORM_MACOS) || defined(UHD_PLATFORM_BSD) - //limit buffer resize on macos or it will error - device_addr["recv_buff_size"] = "1e6"; - #elif defined(UHD_PLATFORM_LINUX) || defined(UHD_PLATFORM_WIN32) - //set to half-a-second of buffering at max rate - device_addr["recv_buff_size"] = "50e6"; - #endif - } - - device_addrs_t device_args = separate_device_addr(device_addr); - - //extract the user's requested MTU size or default - mtu_result_t user_mtu; - user_mtu.recv_mtu = size_t(device_addr.cast<double>("recv_frame_size", udp_simple::mtu)); - user_mtu.send_mtu = size_t(device_addr.cast<double>("send_frame_size", udp_simple::mtu)); - - try{ - //calculate the minimum send and recv mtu of all devices - mtu_result_t mtu = determine_mtu(device_args[0]["addr"], user_mtu); - for (size_t i = 1; i < device_args.size(); i++){ - mtu_result_t mtu_i = determine_mtu(device_args[i]["addr"], user_mtu); - mtu.recv_mtu = std::min(mtu.recv_mtu, mtu_i.recv_mtu); - mtu.send_mtu = std::min(mtu.send_mtu, mtu_i.send_mtu); - } - - device_addr["recv_frame_size"] = boost::lexical_cast<std::string>(mtu.recv_mtu); - device_addr["send_frame_size"] = boost::lexical_cast<std::string>(mtu.send_mtu); - - UHD_MSG(status) << boost::format("Current recv frame size: %d bytes") % mtu.recv_mtu << std::endl; - UHD_MSG(status) << boost::format("Current send frame size: %d bytes") % mtu.send_mtu << std::endl; - } - catch(const uhd::not_implemented_error &){ - //just ignore this error, makes older fw work... - } - - device_args = separate_device_addr(device_addr); //update args for new frame sizes - - //////////////////////////////////////////////////////////////////// - // create controller objects and initialize the properties tree - //////////////////////////////////////////////////////////////////// - _tree = property_tree::make(); - _tree->create<std::string>("/name").set("USRP2 / N-Series Device"); - - for (size_t mbi = 0; mbi < device_args.size(); mbi++){ - const device_addr_t device_args_i = device_args[mbi]; - const std::string mb = boost::lexical_cast<std::string>(mbi); - const std::string addr = device_args_i["addr"]; - property_tree::path_type mb_path = "/mboards/" + mb; - - //////////////////////////////////////////////////////////////// - // construct transports for dsp and async errors - //////////////////////////////////////////////////////////////// - UHD_LOG << "Making transport for DSP0..." << std::endl; - _mbc[mb].dsp_xports.push_back(udp_zero_copy::make( - addr, BOOST_STRINGIZE(USRP2_UDP_DSP0_PORT), device_args_i - )); - init_xport(_mbc[mb].dsp_xports.back()); - - UHD_LOG << "Making transport for DSP1..." << std::endl; - _mbc[mb].dsp_xports.push_back(udp_zero_copy::make( - addr, BOOST_STRINGIZE(USRP2_UDP_DSP1_PORT), device_args_i - )); - init_xport(_mbc[mb].dsp_xports.back()); - - UHD_LOG << "Making transport for ERR0..." << std::endl; - _mbc[mb].err_xports.push_back(udp_zero_copy::make( - addr, BOOST_STRINGIZE(USRP2_UDP_ERR0_PORT), device_addr_t() - )); - init_xport(_mbc[mb].err_xports.back()); - - //////////////////////////////////////////////////////////////// - // create the iface that controls i2c, spi, uart, and wb - //////////////////////////////////////////////////////////////// - _mbc[mb].iface = usrp2_iface::make(udp_simple::make_connected( - addr, BOOST_STRINGIZE(USRP2_UDP_CTRL_PORT) - )); - _tree->create<std::string>(mb_path / "name").set(_mbc[mb].iface->get_cname()); - - //////////////////////////////////////////////////////////////// - // setup the mboard eeprom - //////////////////////////////////////////////////////////////// - _tree->create<mboard_eeprom_t>(mb_path / "eeprom") - .set(_mbc[mb].iface->mb_eeprom) - .subscribe(boost::bind(&usrp2_impl::set_mb_eeprom, this, mb, _1)); - - //////////////////////////////////////////////////////////////// - // create clock control objects - //////////////////////////////////////////////////////////////// - _mbc[mb].clock = usrp2_clock_ctrl::make(_mbc[mb].iface); - _tree->create<double>(mb_path / "tick_rate") - .publish(boost::bind(&usrp2_clock_ctrl::get_master_clock_rate, _mbc[mb].clock)) - .subscribe(boost::bind(&usrp2_impl::update_tick_rate, this, _1)); - - //////////////////////////////////////////////////////////////// - // create codec control objects - //////////////////////////////////////////////////////////////// - property_tree::path_type rx_codec_path = mb_path / "rx_codecs/A"; - property_tree::path_type tx_codec_path = mb_path / "tx_codecs/A"; - _tree->create<int>(rx_codec_path / "gains"); //phony property so this dir exists - _tree->create<int>(tx_codec_path / "gains"); //phony property so this dir exists - _mbc[mb].codec = usrp2_codec_ctrl::make(_mbc[mb].iface); - switch(_mbc[mb].iface->get_rev()){ - case usrp2_iface::USRP_N200: - case usrp2_iface::USRP_N210: - case usrp2_iface::USRP_N200_R4: - case usrp2_iface::USRP_N210_R4:{ - _tree->create<std::string>(rx_codec_path / "name").set("ads62p44"); - _tree->create<meta_range_t>(rx_codec_path / "gains/digital/range").set(meta_range_t(0, 6.0, 0.5)); - _tree->create<double>(rx_codec_path / "gains/digital/value") - .subscribe(boost::bind(&usrp2_codec_ctrl::set_rx_digital_gain, _mbc[mb].codec, _1)).set(0); - _tree->create<meta_range_t>(rx_codec_path / "gains/fine/range").set(meta_range_t(0, 0.5, 0.05)); - _tree->create<double>(rx_codec_path / "gains/fine/value") - .subscribe(boost::bind(&usrp2_codec_ctrl::set_rx_digital_fine_gain, _mbc[mb].codec, _1)).set(0); - }break; - - case usrp2_iface::USRP2_REV3: - case usrp2_iface::USRP2_REV4: - _tree->create<std::string>(rx_codec_path / "name").set("ltc2284"); - break; - - case usrp2_iface::USRP_NXXX: - _tree->create<std::string>(rx_codec_path / "name").set("??????"); - break; - } - _tree->create<std::string>(tx_codec_path / "name").set("ad9777"); - - //////////////////////////////////////////////////////////////// - // create gpsdo control objects - //////////////////////////////////////////////////////////////// - if (_mbc[mb].iface->mb_eeprom["gpsdo"] == "internal"){ - _mbc[mb].gps = gps_ctrl::make( - _mbc[mb].iface->get_gps_write_fn(), - _mbc[mb].iface->get_gps_read_fn() - ); - BOOST_FOREACH(const std::string &name, _mbc[mb].gps->get_sensors()){ - _tree->create<sensor_value_t>(mb_path / "sensors" / name) - .publish(boost::bind(&gps_ctrl::get_sensor, _mbc[mb].gps, name)); - } - } - - //////////////////////////////////////////////////////////////// - // and do the misc mboard sensors - //////////////////////////////////////////////////////////////// - _tree->create<sensor_value_t>(mb_path / "sensors/mimo_locked") - .publish(boost::bind(&usrp2_impl::get_mimo_locked, this, mb)); - _tree->create<sensor_value_t>(mb_path / "sensors/ref_locked") - .publish(boost::bind(&usrp2_impl::get_ref_locked, this, mb)); - - //////////////////////////////////////////////////////////////// - // create frontend control objects - //////////////////////////////////////////////////////////////// - _mbc[mb].rx_fe = rx_frontend_core_200::make( - _mbc[mb].iface, U2_REG_SR_ADDR(SR_RX_FRONT) - ); - _mbc[mb].tx_fe = tx_frontend_core_200::make( - _mbc[mb].iface, U2_REG_SR_ADDR(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(&usrp2_impl::update_rx_subdev_spec, this, mb, _1)); - _tree->create<subdev_spec_t>(mb_path / "tx_subdev_spec") - .subscribe(boost::bind(&usrp2_impl::update_tx_subdev_spec, this, mb, _1)); - - //////////////////////////////////////////////////////////////// - // create rx dsp control objects - //////////////////////////////////////////////////////////////// - _mbc[mb].rx_dsps.push_back(rx_dsp_core_200::make( - _mbc[mb].iface, U2_REG_SR_ADDR(SR_RX_DSP0), U2_REG_SR_ADDR(SR_RX_CTRL0), USRP2_RX_SID_BASE + 0, true - )); - _mbc[mb].rx_dsps.push_back(rx_dsp_core_200::make( - _mbc[mb].iface, U2_REG_SR_ADDR(SR_RX_DSP1), U2_REG_SR_ADDR(SR_RX_CTRL1), USRP2_RX_SID_BASE + 1, true - )); - for (size_t dspno = 0; dspno < _mbc[mb].rx_dsps.size(); dspno++){ - _tree->access<double>(mb_path / "tick_rate") - .subscribe(boost::bind(&rx_dsp_core_200::set_tick_rate, _mbc[mb].rx_dsps[dspno], _1)); - //This is a hack/fix for the lingering packet problem. - //The dsp core starts streaming briefly... now we flush - _mbc[mb].dsp_xports[dspno]->get_recv_buff(0.01).get(); //recv with timeout for lingering - _mbc[mb].dsp_xports[dspno]->get_recv_buff(0.01).get(); //recv with timeout for expected - property_tree::path_type rx_dsp_path = mb_path / str(boost::format("rx_dsps/%u") % dspno); - _tree->create<double>(rx_dsp_path / "rate/value") - .coerce(boost::bind(&rx_dsp_core_200::set_host_rate, _mbc[mb].rx_dsps[dspno], _1)) - .subscribe(boost::bind(&usrp2_impl::update_rx_samp_rate, this, _1)); - _tree->create<double>(rx_dsp_path / "freq/value") - .coerce(boost::bind(&rx_dsp_core_200::set_freq, _mbc[mb].rx_dsps[dspno], _1)); - _tree->create<meta_range_t>(rx_dsp_path / "freq/range") - .publish(boost::bind(&rx_dsp_core_200::get_freq_range, _mbc[mb].rx_dsps[dspno])); - _tree->create<stream_cmd_t>(rx_dsp_path / "stream_cmd") - .subscribe(boost::bind(&rx_dsp_core_200::issue_stream_command, _mbc[mb].rx_dsps[dspno], _1)); - } - - //////////////////////////////////////////////////////////////// - // create tx dsp control objects - //////////////////////////////////////////////////////////////// - _mbc[mb].tx_dsp = tx_dsp_core_200::make( - _mbc[mb].iface, U2_REG_SR_ADDR(SR_TX_DSP), U2_REG_SR_ADDR(SR_TX_CTRL), USRP2_TX_ASYNC_SID - ); - _tree->access<double>(mb_path / "tick_rate") - .subscribe(boost::bind(&tx_dsp_core_200::set_tick_rate, _mbc[mb].tx_dsp, _1)); - _tree->create<double>(mb_path / "tx_dsps/0/rate/value") - .coerce(boost::bind(&tx_dsp_core_200::set_host_rate, _mbc[mb].tx_dsp, _1)) - .subscribe(boost::bind(&usrp2_impl::update_tx_samp_rate, this, _1)); - _tree->create<double>(mb_path / "tx_dsps/0/freq/value") - .coerce(boost::bind(&usrp2_impl::set_tx_dsp_freq, this, mb, _1)); - _tree->create<meta_range_t>(mb_path / "tx_dsps/0/freq/range") - .publish(boost::bind(&usrp2_impl::get_tx_dsp_freq_range, this, mb)); - - //setup dsp flow control - const double ups_per_sec = device_args_i.cast<double>("ups_per_sec", 20); - const size_t send_frame_size = _mbc[mb].dsp_xports.front()->get_send_frame_size(); - const double ups_per_fifo = device_args_i.cast<double>("ups_per_fifo", 8.0); - _mbc[mb].tx_dsp->set_updates( - (ups_per_sec > 0.0)? size_t(100e6/*approx tick rate*//ups_per_sec) : 0, - (ups_per_fifo > 0.0)? size_t(USRP2_SRAM_BYTES/ups_per_fifo/send_frame_size) : 0 - ); - - //////////////////////////////////////////////////////////////// - // create time control objects - //////////////////////////////////////////////////////////////// - time64_core_200::readback_bases_type time64_rb_bases; - time64_rb_bases.rb_secs_imm = U2_REG_TIME64_SECS_RB_IMM; - time64_rb_bases.rb_ticks_imm = U2_REG_TIME64_TICKS_RB_IMM; - time64_rb_bases.rb_secs_pps = U2_REG_TIME64_SECS_RB_PPS; - time64_rb_bases.rb_ticks_pps = U2_REG_TIME64_TICKS_RB_PPS; - _mbc[mb].time64 = time64_core_200::make( - _mbc[mb].iface, U2_REG_SR_ADDR(SR_TIME64), time64_rb_bases, mimo_clock_sync_delay_cycles - ); - _tree->access<double>(mb_path / "tick_rate") - .subscribe(boost::bind(&time64_core_200::set_tick_rate, _mbc[mb].time64, _1)); - _tree->create<time_spec_t>(mb_path / "time/now") - .publish(boost::bind(&time64_core_200::get_time_now, _mbc[mb].time64)) - .subscribe(boost::bind(&time64_core_200::set_time_now, _mbc[mb].time64, _1)); - _tree->create<time_spec_t>(mb_path / "time/pps") - .publish(boost::bind(&time64_core_200::get_time_last_pps, _mbc[mb].time64)) - .subscribe(boost::bind(&time64_core_200::set_time_next_pps, _mbc[mb].time64, _1)); - //setup time source props - _tree->create<std::string>(mb_path / "time_source/value") - .subscribe(boost::bind(&time64_core_200::set_time_source, _mbc[mb].time64, _1)); - _tree->create<std::vector<std::string> >(mb_path / "time_source/options") - .publish(boost::bind(&time64_core_200::get_time_sources, _mbc[mb].time64)); - //setup reference source props - _tree->create<std::string>(mb_path / "ref_source/value") - .subscribe(boost::bind(&usrp2_impl::update_ref_source, this, mb, _1)); - static const std::vector<std::string> ref_sources = boost::assign::list_of("internal")("sma")("mimo"); - _tree->create<std::vector<std::string> >(mb_path / "ref_source/options").set(ref_sources); - - //////////////////////////////////////////////////////////////// - // create dboard control objects - //////////////////////////////////////////////////////////////// - - //read the dboard eeprom to extract the dboard ids - dboard_eeprom_t rx_db_eeprom, tx_db_eeprom, gdb_eeprom; - rx_db_eeprom.load(*_mbc[mb].iface, USRP2_I2C_ADDR_RX_DB); - tx_db_eeprom.load(*_mbc[mb].iface, USRP2_I2C_ADDR_TX_DB); - gdb_eeprom.load(*_mbc[mb].iface, USRP2_I2C_ADDR_TX_DB ^ 5); - - //create the properties and register subscribers - _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/rx_eeprom") - .set(rx_db_eeprom) - .subscribe(boost::bind(&usrp2_impl::set_db_eeprom, this, mb, "rx", _1)); - _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/tx_eeprom") - .set(tx_db_eeprom) - .subscribe(boost::bind(&usrp2_impl::set_db_eeprom, this, mb, "tx", _1)); - _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/gdb_eeprom") - .set(gdb_eeprom) - .subscribe(boost::bind(&usrp2_impl::set_db_eeprom, this, mb, "gdb", _1)); - - //create a new dboard interface and manager - _mbc[mb].dboard_iface = make_usrp2_dboard_iface(_mbc[mb].iface, _mbc[mb].clock); - _tree->create<dboard_iface::sptr>(mb_path / "dboards/A/iface").set(_mbc[mb].dboard_iface); - _mbc[mb].dboard_manager = dboard_manager::make( - rx_db_eeprom.id, - ((gdb_eeprom.id == dboard_id_t::none())? tx_db_eeprom : gdb_eeprom).id, - _mbc[mb].dboard_iface - ); - BOOST_FOREACH(const std::string &name, _mbc[mb].dboard_manager->get_rx_subdev_names()){ - dboard_manager::populate_prop_tree_from_subdev( - _tree, mb_path / "dboards/A/rx_frontends" / name, - _mbc[mb].dboard_manager->get_rx_subdev(name) - ); - } - BOOST_FOREACH(const std::string &name, _mbc[mb].dboard_manager->get_tx_subdev_names()){ - dboard_manager::populate_prop_tree_from_subdev( - _tree, mb_path / "dboards/A/tx_frontends" / name, - _mbc[mb].dboard_manager->get_tx_subdev(name) - ); - } - } - - //initialize io handling - this->io_init(); - - //do some post-init tasks - BOOST_FOREACH(const std::string &mb, _mbc.keys()){ - property_tree::path_type root = "/mboards/" + mb; - _tree->access<double>(root / "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(root / "rx_dsps")){ - _tree->access<double>(root / "rx_dsps" / name / "rate" / "value").set(1e6); - } - BOOST_FOREACH(const std::string &name, _tree->list(root / "tx_dsps")){ - _tree->access<double>(root / "tx_dsps" / name / "rate" / "value").set(1e6); - } - - _tree->access<subdev_spec_t>(root / "rx_subdev_spec").set(subdev_spec_t("A:"+_mbc[mb].dboard_manager->get_rx_subdev_names()[0])); - _tree->access<subdev_spec_t>(root / "tx_subdev_spec").set(subdev_spec_t("A:"+_mbc[mb].dboard_manager->get_tx_subdev_names()[0])); - _tree->access<std::string>(root / "ref_source/value").set("internal"); - _tree->access<std::string>(root / "time_source/value").set("none"); - - //GPS installed: use external ref, time, and init time spec - if (_mbc[mb].gps.get() != NULL){ - _tree->access<std::string>(root / "time_source/value").set("sma"); - _tree->access<std::string>(root / "ref_source/value").set("sma"); - _mbc[mb].time64->set_time_next_pps(time_spec_t(time_t(_mbc[mb].gps->get_sensor("gps_time").to_int()+1))); - } - } - -} - -usrp2_impl::~usrp2_impl(void){UHD_SAFE_CALL( - BOOST_FOREACH(const std::string &mb, _mbc.keys()){ - _mbc[mb].tx_dsp->set_updates(0, 0); - } -)} - -void usrp2_impl::set_mb_eeprom(const std::string &mb, const uhd::usrp::mboard_eeprom_t &mb_eeprom){ - mb_eeprom.commit(*(_mbc[mb].iface), mboard_eeprom_t::MAP_N100); -} - -void usrp2_impl::set_db_eeprom(const std::string &mb, const std::string &type, const uhd::usrp::dboard_eeprom_t &db_eeprom){ - if (type == "rx") db_eeprom.store(*_mbc[mb].iface, USRP2_I2C_ADDR_RX_DB); - if (type == "tx") db_eeprom.store(*_mbc[mb].iface, USRP2_I2C_ADDR_TX_DB); - if (type == "gdb") db_eeprom.store(*_mbc[mb].iface, USRP2_I2C_ADDR_TX_DB ^ 5); -} - -sensor_value_t usrp2_impl::get_mimo_locked(const std::string &mb){ - const bool lock = (_mbc[mb].iface->peek32(U2_REG_IRQ_RB) & (1<<10)) != 0; - return sensor_value_t("MIMO", lock, "locked", "unlocked"); -} - -sensor_value_t usrp2_impl::get_ref_locked(const std::string &mb){ - const bool lock = (_mbc[mb].iface->peek32(U2_REG_IRQ_RB) & (1<<11)) != 0; - return sensor_value_t("Ref", lock, "locked", "unlocked"); -} - -#include <boost/math/special_functions/round.hpp> -#include <boost/math/special_functions/sign.hpp> - -double usrp2_impl::set_tx_dsp_freq(const std::string &mb, const double freq_){ - double new_freq = freq_; - const double tick_rate = _tree->access<double>("/mboards/"+mb+"/tick_rate").get(); - - //calculate the DAC shift (multiples of rate) - const int sign = boost::math::sign(new_freq); - const int zone = std::min(boost::math::iround(new_freq/tick_rate), 2); - const double dac_shift = sign*zone*tick_rate; - new_freq -= dac_shift; //update FPGA DSP target freq - - //set the DAC shift (modulation mode) - if (zone == 0) _mbc[mb].codec->set_tx_mod_mode(0); //no shift - else _mbc[mb].codec->set_tx_mod_mode(sign*4/zone); //DAC interp = 4 - - return _mbc[mb].tx_dsp->set_freq(new_freq) + dac_shift; //actual freq -} - -meta_range_t usrp2_impl::get_tx_dsp_freq_range(const std::string &mb){ - const double tick_rate = _tree->access<double>("/mboards/"+mb+"/tick_rate").get(); - const meta_range_t dsp_range = _mbc[mb].tx_dsp->get_freq_range(); - return meta_range_t(dsp_range.start() - tick_rate*2, dsp_range.stop() + tick_rate*2, dsp_range.step()); -} - -void usrp2_impl::update_ref_source(const std::string &mb, const std::string &source){ - //clock source ref 10mhz - switch(_mbc[mb].iface->get_rev()){ - case usrp2_iface::USRP_N200: - case usrp2_iface::USRP_N210: - case usrp2_iface::USRP_N200_R4: - case usrp2_iface::USRP_N210_R4: - if (source == "internal") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x12); - else if (source == "sma") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C); - else if (source == "mimo") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x15); - else throw uhd::value_error("unhandled clock configuration reference source: " + source); - _mbc[mb].clock->enable_external_ref(true); //USRP2P has an internal 10MHz TCXO - break; - - case usrp2_iface::USRP2_REV3: - case usrp2_iface::USRP2_REV4: - if (source == "internal") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x10); - else if (source == "sma") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C); - else if (source == "mimo") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x15); - else throw uhd::value_error("unhandled clock configuration reference source: " + source); - _mbc[mb].clock->enable_external_ref(source != "internal"); - break; - - case usrp2_iface::USRP_NXXX: break; - } - - //always drive the clock over serdes if not locking to it - _mbc[mb].clock->enable_mimo_clock_out(source != "mimo"); - - //set the mimo clock delay over the serdes - if (source != "mimo"){ - switch(_mbc[mb].iface->get_rev()){ - case usrp2_iface::USRP_N200: - case usrp2_iface::USRP_N210: - case usrp2_iface::USRP_N200_R4: - case usrp2_iface::USRP_N210_R4: - _mbc[mb].clock->set_mimo_clock_delay(mimo_clock_delay_usrp_n2xx); - break; - - case usrp2_iface::USRP2_REV4: - _mbc[mb].clock->set_mimo_clock_delay(mimo_clock_delay_usrp2_rev4); - break; - - default: break; //not handled - } - } -} diff --git a/host/lib/usrp2/usrp2_impl.hpp b/host/lib/usrp2/usrp2_impl.hpp deleted file mode 100644 index ad203079b..000000000 --- a/host/lib/usrp2/usrp2_impl.hpp +++ /dev/null @@ -1,134 +0,0 @@ -// -// Copyright 2010-2011 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_IMPL_HPP -#define INCLUDED_USRP2_IMPL_HPP - -#include "usrp2_iface.hpp" -#include "clock_ctrl.hpp" -#include "codec_ctrl.hpp" -#include "rx_frontend_core_200.hpp" -#include "tx_frontend_core_200.hpp" -#include "rx_dsp_core_200.hpp" -#include "tx_dsp_core_200.hpp" -#include "time64_core_200.hpp" -#include <uhd/property_tree.hpp> -#include <uhd/usrp/gps_ctrl.hpp> -#include <uhd/device.hpp> -#include <uhd/utils/pimpl.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 <uhd/usrp/dboard_eeprom.hpp> -#include <boost/shared_ptr.hpp> -#include <boost/function.hpp> -#include <uhd/transport/vrt_if_packet.hpp> -#include <uhd/transport/udp_simple.hpp> -#include <uhd/transport/udp_zero_copy.hpp> -#include <uhd/usrp/dboard_manager.hpp> -#include <uhd/usrp/subdev_spec.hpp> - -static const double mimo_clock_delay_usrp2_rev4 = 4.18e-9; -static const double mimo_clock_delay_usrp_n2xx = 3.55e-9; -static const size_t mimo_clock_sync_delay_cycles = 137; -static const size_t USRP2_SRAM_BYTES = size_t(1 << 20); -static const boost::uint32_t USRP2_TX_ASYNC_SID = 2; -static const boost::uint32_t USRP2_RX_SID_BASE = 3; - -/*! - * Make a usrp2 dboard interface. - * \param iface the usrp2 interface object - * \param clk_ctrl the clock control object - * \return a sptr to a new dboard interface - */ -uhd::usrp::dboard_iface::sptr make_usrp2_dboard_iface( - usrp2_iface::sptr iface, - usrp2_clock_ctrl::sptr clk_ctrl -); - -/*! - * USRP2 implementation guts: - * The implementation details are encapsulated here. - * Handles device properties and streaming... - */ -class usrp2_impl : public uhd::device{ -public: - usrp2_impl(const uhd::device_addr_t &); - ~usrp2_impl(void); - - //the io interface - size_t send( - const send_buffs_type &, size_t, - const uhd::tx_metadata_t &, const uhd::io_type_t &, - uhd::device::send_mode_t, double - ); - size_t recv( - const recv_buffs_type &, size_t, - uhd::rx_metadata_t &, const uhd::io_type_t &, - uhd::device::recv_mode_t, double - ); - size_t get_max_send_samps_per_packet(void) const; - size_t get_max_recv_samps_per_packet(void) const; - bool recv_async_msg(uhd::async_metadata_t &, double); - -private: - uhd::property_tree::sptr _tree; - struct mb_container_type{ - usrp2_iface::sptr iface; - usrp2_clock_ctrl::sptr clock; - usrp2_codec_ctrl::sptr codec; - gps_ctrl::sptr gps; - rx_frontend_core_200::sptr rx_fe; - tx_frontend_core_200::sptr tx_fe; - std::vector<rx_dsp_core_200::sptr> rx_dsps; - tx_dsp_core_200::sptr tx_dsp; - time64_core_200::sptr time64; - std::vector<uhd::transport::zero_copy_if::sptr> dsp_xports; - std::vector<uhd::transport::zero_copy_if::sptr> err_xports; - uhd::usrp::dboard_manager::sptr dboard_manager; - uhd::usrp::dboard_iface::sptr dboard_iface; - size_t rx_chan_occ, tx_chan_occ; - }; - uhd::dict<std::string, mb_container_type> _mbc; - - void set_mb_eeprom(const std::string &, const uhd::usrp::mboard_eeprom_t &); - void set_db_eeprom(const std::string &, const std::string &, const uhd::usrp::dboard_eeprom_t &); - - uhd::sensor_value_t get_mimo_locked(const std::string &); - uhd::sensor_value_t get_ref_locked(const std::string &); - - //device properties interface - void get(const wax::obj &, wax::obj &val){ - val = _tree; //entry point into property tree - } - - //io impl methods and members - uhd::otw_type_t _rx_otw_type, _tx_otw_type; - UHD_PIMPL_DECL(io_impl) _io_impl; - void io_init(void); - 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_subdev_spec(const std::string &, const uhd::usrp::subdev_spec_t &); - void update_tx_subdev_spec(const std::string &, const uhd::usrp::subdev_spec_t &); - double set_tx_dsp_freq(const std::string &, const double); - uhd::meta_range_t get_tx_dsp_freq_range(const std::string &); - void update_ref_source(const std::string &, const std::string &); -}; - -#endif /* INCLUDED_USRP2_IMPL_HPP */ diff --git a/host/lib/usrp2/usrp2_regs.hpp b/host/lib/usrp2/usrp2_regs.hpp deleted file mode 100644 index 19c1b45f1..000000000 --- a/host/lib/usrp2/usrp2_regs.hpp +++ /dev/null @@ -1,221 +0,0 @@ -// -// Copyright 2010-2011 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_REGS_HPP -#define INCLUDED_USRP2_REGS_HPP - -//////////////////////////////////////////////////////////////////////// -// Define slave bases -//////////////////////////////////////////////////////////////////////// -#define ROUTER_RAM_BASE 0x4000 -#define SPI_BASE 0x5000 -#define I2C_BASE 0x5400 -#define GPIO_BASE 0x5800 -#define READBACK_BASE 0x5C00 -#define ETH_BASE 0x6000 -#define SETTING_REGS_BASE 0x7000 -#define PIC_BASE 0x8000 -#define UART_BASE 0x8800 -#define ATR_BASE 0x8C00 - -//////////////////////////////////////////////////////////////////////// -// Setting register offsets -//////////////////////////////////////////////////////////////////////// -#define SR_MISC 0 // 7 regs -#define SR_SIMTIMER 8 // 2 -#define SR_TIME64 10 // 6 -#define SR_BUF_POOL 16 // 4 - -#define SR_RX_FRONT 24 // 5 -#define SR_RX_CTRL0 32 // 9 -#define SR_RX_DSP0 48 // 7 -#define SR_RX_CTRL1 80 // 9 -#define SR_RX_DSP1 96 // 7 - -#define SR_TX_FRONT 128 // ? -#define SR_TX_CTRL 144 // 6 -#define SR_TX_DSP 160 // 5 - -#define SR_UDP_SM 192 // 64 - -#define U2_REG_SR_ADDR(sr) (SETTING_REGS_BASE + (4 * (sr))) - -///////////////////////////////////////////////// -// SPI Slave Constants -//////////////////////////////////////////////// -// Masks for controlling different peripherals -#define SPI_SS_AD9510 1 -#define SPI_SS_AD9777 2 -#define SPI_SS_RX_DAC 4 -#define SPI_SS_RX_ADC 8 -#define SPI_SS_RX_DB 16 -#define SPI_SS_TX_DAC 32 -#define SPI_SS_TX_ADC 64 -#define SPI_SS_TX_DB 128 -#define SPI_SS_ADS62P44 256 //for usrp2p - -///////////////////////////////////////////////// -// Misc Control -//////////////////////////////////////////////// -#define U2_REG_MISC_CTRL_CLOCK U2_REG_SR_ADDR(0) -#define U2_REG_MISC_CTRL_SERDES U2_REG_SR_ADDR(1) -#define U2_REG_MISC_CTRL_ADC U2_REG_SR_ADDR(2) -#define U2_REG_MISC_CTRL_LEDS U2_REG_SR_ADDR(3) -#define U2_REG_MISC_CTRL_PHY U2_REG_SR_ADDR(4) -#define U2_REG_MISC_CTRL_DBG_MUX U2_REG_SR_ADDR(5) -#define U2_REG_MISC_CTRL_RAM_PAGE U2_REG_SR_ADDR(6) -#define U2_REG_MISC_CTRL_FLUSH_ICACHE U2_REG_SR_ADDR(7) -#define U2_REG_MISC_CTRL_LED_SRC U2_REG_SR_ADDR(8) - -#define U2_FLAG_MISC_CTRL_SERDES_ENABLE 8 -#define U2_FLAG_MISC_CTRL_SERDES_PRBSEN 4 -#define U2_FLAG_MISC_CTRL_SERDES_LOOPEN 2 -#define U2_FLAG_MISC_CTRL_SERDES_RXEN 1 - -#define U2_FLAG_MISC_CTRL_ADC_ON 0x0F -#define U2_FLAG_MISC_CTRL_ADC_OFF 0x00 - -///////////////////////////////////////////////// -// VITA49 64 bit time (write only) -//////////////////////////////////////////////// -#define U2_REG_TIME64_SECS U2_REG_SR_ADDR(SR_TIME64 + 0) -#define U2_REG_TIME64_TICKS U2_REG_SR_ADDR(SR_TIME64 + 1) -#define U2_REG_TIME64_FLAGS U2_REG_SR_ADDR(SR_TIME64 + 2) -#define U2_REG_TIME64_IMM U2_REG_SR_ADDR(SR_TIME64 + 3) -#define U2_REG_TIME64_TPS U2_REG_SR_ADDR(SR_TIME64 + 4) -#define U2_REG_TIME64_MIMO_SYNC U2_REG_SR_ADDR(SR_TIME64 + 5) - -//pps flags (see above) -#define U2_FLAG_TIME64_PPS_NEGEDGE (0 << 0) -#define U2_FLAG_TIME64_PPS_POSEDGE (1 << 0) -#define U2_FLAG_TIME64_PPS_SMA (0 << 1) -#define U2_FLAG_TIME64_PPS_MIMO (1 << 1) - -#define U2_FLAG_TIME64_LATCH_NOW 1 -#define U2_FLAG_TIME64_LATCH_NEXT_PPS 0 - -///////////////////////////////////////////////// -// Readback regs -//////////////////////////////////////////////// -#define U2_REG_STATUS READBACK_BASE + 4*8 -#define U2_REG_TIME64_SECS_RB_IMM READBACK_BASE + 4*10 -#define U2_REG_TIME64_TICKS_RB_IMM READBACK_BASE + 4*11 -#define U2_REG_COMPAT_NUM_RB READBACK_BASE + 4*12 -#define U2_REG_IRQ_RB READBACK_BASE + 4*13 -#define U2_REG_TIME64_SECS_RB_PPS READBACK_BASE + 4*14 -#define U2_REG_TIME64_TICKS_RB_PPS READBACK_BASE + 4*15 - -///////////////////////////////////////////////// -// RX FE -//////////////////////////////////////////////// -#define U2_REG_RX_FE_SWAP_IQ U2_REG_SR_ADDR(SR_RX_FRONT + 0) //lower bit -#define U2_REG_RX_FE_MAG_CORRECTION U2_REG_SR_ADDR(SR_RX_FRONT + 1) //18 bits -#define U2_REG_RX_FE_PHASE_CORRECTION U2_REG_SR_ADDR(SR_RX_FRONT + 2) //18 bits -#define U2_REG_RX_FE_OFFSET_I U2_REG_SR_ADDR(SR_RX_FRONT + 3) //18 bits -#define U2_REG_RX_FE_OFFSET_Q U2_REG_SR_ADDR(SR_RX_FRONT + 4) //18 bits - -///////////////////////////////////////////////// -// TX FE -//////////////////////////////////////////////// -#define U2_REG_TX_FE_DC_OFFSET_I U2_REG_SR_ADDR(SR_TX_FRONT + 0) //24 bits -#define U2_REG_TX_FE_DC_OFFSET_Q U2_REG_SR_ADDR(SR_TX_FRONT + 1) //24 bits -#define U2_REG_TX_FE_MAC_CORRECTION U2_REG_SR_ADDR(SR_TX_FRONT + 2) //18 bits -#define U2_REG_TX_FE_PHASE_CORRECTION U2_REG_SR_ADDR(SR_TX_FRONT + 3) //18 bits -#define U2_REG_TX_FE_MUX U2_REG_SR_ADDR(SR_TX_FRONT + 4) //8 bits (std output = 0x10, reversed = 0x01) - -///////////////////////////////////////////////// -// DSP TX Regs -//////////////////////////////////////////////// -#define U2_REG_DSP_TX_FREQ U2_REG_SR_ADDR(SR_TX_DSP + 0) -#define U2_REG_DSP_TX_SCALE_IQ U2_REG_SR_ADDR(SR_TX_DSP + 1) -#define U2_REG_DSP_TX_INTERP_RATE U2_REG_SR_ADDR(SR_TX_DSP + 2) - -///////////////////////////////////////////////// -// DSP RX Regs -//////////////////////////////////////////////// -#define U2_REG_DSP_RX_HELPER(which, offset) ((which == 0)? \ - (U2_REG_SR_ADDR(SR_RX_DSP0 + offset)) : \ - (U2_REG_SR_ADDR(SR_RX_DSP1 + offset))) - -#define U2_REG_DSP_RX_FREQ(which) U2_REG_DSP_RX_HELPER(which, 0) -#define U2_REG_DSP_RX_DECIM(which) U2_REG_DSP_RX_HELPER(which, 2) -#define U2_REG_DSP_RX_MUX(which) U2_REG_DSP_RX_HELPER(which, 3) - -#define U2_FLAG_DSP_RX_MUX_SWAP_IQ (1 << 0) -#define U2_FLAG_DSP_RX_MUX_REAL_MODE (1 << 1) - -//////////////////////////////////////////////// -// GPIO -//////////////////////////////////////////////// -#define U2_REG_GPIO_IO GPIO_BASE + 0 -#define U2_REG_GPIO_DDR GPIO_BASE + 4 -#define U2_REG_GPIO_TX_SEL GPIO_BASE + 8 -#define U2_REG_GPIO_RX_SEL GPIO_BASE + 12 - -// each 2-bit sel field is layed out this way -#define U2_FLAG_GPIO_SEL_GPIO 0 // if pin is an output, set by GPIO register -#define U2_FLAG_GPIO_SEL_ATR 1 // if pin is an output, set by ATR logic -#define U2_FLAG_GPIO_SEL_DEBUG_0 2 // if pin is an output, debug lines from FPGA fabric -#define U2_FLAG_GPIO_SEL_DEBUG_1 3 // if pin is an output, debug lines from FPGA fabric - -/////////////////////////////////////////////////// -// ATR Controller -//////////////////////////////////////////////// -#define U2_REG_ATR_IDLE_TXSIDE ATR_BASE + 0 -#define U2_REG_ATR_IDLE_RXSIDE ATR_BASE + 2 -#define U2_REG_ATR_INTX_TXSIDE ATR_BASE + 4 -#define U2_REG_ATR_INTX_RXSIDE ATR_BASE + 6 -#define U2_REG_ATR_INRX_TXSIDE ATR_BASE + 8 -#define U2_REG_ATR_INRX_RXSIDE ATR_BASE + 10 -#define U2_REG_ATR_FULL_TXSIDE ATR_BASE + 12 -#define U2_REG_ATR_FULL_RXSIDE ATR_BASE + 14 - -/////////////////////////////////////////////////// -// RX CTRL regs -/////////////////////////////////////////////////// -#define U2_REG_RX_CTRL_HELPER(which, offset) ((which == 0)? \ - (U2_REG_SR_ADDR(SR_RX_CTRL0 + offset)) : \ - (U2_REG_SR_ADDR(SR_RX_CTRL1 + offset))) - -#define U2_REG_RX_CTRL_STREAM_CMD(which) U2_REG_RX_CTRL_HELPER(which, 0) -#define U2_REG_RX_CTRL_TIME_SECS(which) U2_REG_RX_CTRL_HELPER(which, 1) -#define U2_REG_RX_CTRL_TIME_TICKS(which) U2_REG_RX_CTRL_HELPER(which, 2) -#define U2_REG_RX_CTRL_CLEAR(which) U2_REG_RX_CTRL_HELPER(which, 3) -#define U2_REG_RX_CTRL_VRT_HDR(which) U2_REG_RX_CTRL_HELPER(which, 4) -#define U2_REG_RX_CTRL_VRT_SID(which) U2_REG_RX_CTRL_HELPER(which, 5) -#define U2_REG_RX_CTRL_VRT_TLR(which) U2_REG_RX_CTRL_HELPER(which, 6) -#define U2_REG_RX_CTRL_NSAMPS_PP(which) U2_REG_RX_CTRL_HELPER(which, 7) -#define U2_REG_RX_CTRL_NCHANNELS(which) U2_REG_RX_CTRL_HELPER(which, 8) - -/////////////////////////////////////////////////// -// TX CTRL regs -/////////////////////////////////////////////////// -#define U2_REG_TX_CTRL_NUM_CHAN U2_REG_SR_ADDR(SR_TX_CTRL + 0) -#define U2_REG_TX_CTRL_CLEAR_STATE U2_REG_SR_ADDR(SR_TX_CTRL + 1) -#define U2_REG_TX_CTRL_REPORT_SID U2_REG_SR_ADDR(SR_TX_CTRL + 2) -#define U2_REG_TX_CTRL_POLICY U2_REG_SR_ADDR(SR_TX_CTRL + 3) -#define U2_REG_TX_CTRL_CYCLES_PER_UP U2_REG_SR_ADDR(SR_TX_CTRL + 4) -#define U2_REG_TX_CTRL_PACKETS_PER_UP U2_REG_SR_ADDR(SR_TX_CTRL + 5) - -#define U2_FLAG_TX_CTRL_POLICY_WAIT (0x1 << 0) -#define U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET (0x1 << 1) -#define U2_FLAG_TX_CTRL_POLICY_NEXT_BURST (0x1 << 2) - -//enable flag for registers: cycles and packets per update packet -#define U2_FLAG_TX_CTRL_UP_ENB (1ul << 31) - -#endif /* INCLUDED_USRP2_REGS_HPP */ |