diff options
26 files changed, 561 insertions, 4778 deletions
| diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index a8f490f0a..60ddbce5b 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -72,7 +72,6 @@ INCLUDE_SUBDIRECTORY(types)  INCLUDE_SUBDIRECTORY(convert)  INCLUDE_SUBDIRECTORY(transport)  INCLUDE_SUBDIRECTORY(usrp) -INCLUDE_SUBDIRECTORY(usrp2)  INCLUDE_SUBDIRECTORY(utils)  ######################################################################## diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt index 21e44509c..2a9939d0b 100644 --- a/host/lib/usrp/CMakeLists.txt +++ b/host/lib/usrp/CMakeLists.txt @@ -34,6 +34,6 @@ INCLUDE_SUBDIRECTORY(cores)  INCLUDE_SUBDIRECTORY(dboard)  INCLUDE_SUBDIRECTORY(fx2)  #INCLUDE_SUBDIRECTORY(usrp1) -#INCLUDE_SUBDIRECTORY(usrp2) +INCLUDE_SUBDIRECTORY(usrp2)  #INCLUDE_SUBDIRECTORY(b100)  #INCLUDE_SUBDIRECTORY(e100) diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt index c3f138c24..d16976060 100644 --- a/host/lib/usrp/usrp2/CMakeLists.txt +++ b/host/lib/usrp/usrp2/CMakeLists.txt @@ -1,5 +1,5 @@  # -# Copyright 2010-2011 Ettus Research LLC +# 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 @@ -18,28 +18,11 @@  ########################################################################  # This file included, use CMake directory variables  ######################################################################## - -######################################################################## -# Conditionally configure the USRP2 support -######################################################################## -LIBUHD_REGISTER_COMPONENT("USRP2" ENABLE_USRP2 ON "ENABLE_LIBUHD" OFF) - -IF(ENABLE_USRP2) -    LIBUHD_APPEND_SOURCES( -        ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.cpp -        ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.hpp -        ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp -        ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.hpp -        ${CMAKE_CURRENT_SOURCE_DIR}/codec_impl.cpp -        ${CMAKE_CURRENT_SOURCE_DIR}/dboard_impl.cpp -        ${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp -        ${CMAKE_CURRENT_SOURCE_DIR}/dsp_impl.cpp -        ${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp -        ${CMAKE_CURRENT_SOURCE_DIR}/mboard_impl.cpp -        ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.cpp -        ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.hpp -        ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_impl.cpp -        ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_impl.hpp -        ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_regs.hpp -    ) -ENDIF(ENABLE_USRP2) +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/usrp/usrp2/codec_impl.cpp b/host/lib/usrp/usrp2/codec_impl.cpp deleted file mode 100644 index 26da42759..000000000 --- a/host/lib/usrp/usrp2/codec_impl.cpp +++ /dev/null @@ -1,181 +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 <uhd/utils/assert_has.hpp> -#include <uhd/exception.hpp> -#include <uhd/usrp/codec_props.hpp> -#include <uhd/types/dict.hpp> -#include <uhd/types/ranges.hpp> -#include <boost/bind.hpp> -#include <boost/assign/list_of.hpp> - -using namespace uhd; -using namespace uhd::usrp; -using namespace boost::assign; - -//this only applies to N2XX -static const uhd::dict<std::string, gain_range_t> codec_rx_gain_ranges = map_list_of -                                  ("digital", gain_range_t(0, 6.0, 0.5)) -                                  ("digital-fine", gain_range_t(0, 0.5, 0.05)); - - -/*********************************************************************** - * Helper Methods - **********************************************************************/ -void usrp2_mboard_impl::codec_init(void){ -    //make proxies -    _rx_codec_proxy = wax_obj_proxy::make( -        boost::bind(&usrp2_mboard_impl::rx_codec_get, this, _1, _2), -        boost::bind(&usrp2_mboard_impl::rx_codec_set, this, _1, _2) -    ); -    _tx_codec_proxy = wax_obj_proxy::make( -        boost::bind(&usrp2_mboard_impl::tx_codec_get, this, _1, _2), -        boost::bind(&usrp2_mboard_impl::tx_codec_set, this, _1, _2) -    ); -     -    //initialize gain names. keeps get_rx_gain() from getting a gain  -    //that hasn't been set yet. -    BOOST_FOREACH(std::string key, codec_rx_gain_ranges.keys()) { -        _codec_rx_gains[key] = codec_rx_gain_ranges[key].start(); -    } -} - -/*********************************************************************** - * RX Codec Properties - **********************************************************************/ -void usrp2_mboard_impl::rx_codec_get(const wax::obj &key_, wax::obj &val){ -    named_prop_t key = named_prop_t::extract(key_); - -    //handle the get request conditioned on the key -    switch(key.as<codec_prop_t>()){ -    case CODEC_PROP_NAME: -        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: -            val = _iface->get_cname() + " adc - ads62p44"; -            break; - -        case usrp2_iface::USRP2_REV3: -        case usrp2_iface::USRP2_REV4: -            val = _iface->get_cname() + " adc - ltc2284"; -            break; - -        case usrp2_iface::USRP_NXXX: -            val = _iface->get_cname() + " adc - ??????"; -            break; -        } -        return; - -    case CODEC_PROP_OTHERS: -        val = prop_names_t(); -        return; - -    case CODEC_PROP_GAIN_NAMES: -        switch(_iface->get_rev()){ -        case usrp2_iface::USRP_N200: -        case usrp2_iface::USRP_N210: -            val = prop_names_t(codec_rx_gain_ranges.keys()); -            return; - -        default: val = prop_names_t(); -        } -        return; - -    case CODEC_PROP_GAIN_I: -    case CODEC_PROP_GAIN_Q: -        assert_has(_codec_rx_gains.keys(), key.name, "codec rx gain name"); -        val = _codec_rx_gains[key.name]; -        return; - -    case CODEC_PROP_GAIN_RANGE: -      assert_has(codec_rx_gain_ranges.keys(), key.name, "codec rx gain range name"); -      val = codec_rx_gain_ranges[key.name]; -      return; - -    default: UHD_THROW_PROP_GET_ERROR(); -    } -} - -void usrp2_mboard_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val){ -    named_prop_t key = named_prop_t::extract(key_); - -    switch(key.as<codec_prop_t>()) { -    case CODEC_PROP_GAIN_I: -    case CODEC_PROP_GAIN_Q: -        this->rx_codec_set_gain(val.as<double>(), key.name); -        return; - -    default: UHD_THROW_PROP_SET_ERROR(); -  } -} - -/*********************************************************************** - * Helper function to set RX codec gain - ***********************************************************************/ - -void usrp2_mboard_impl::rx_codec_set_gain(double gain, const std::string &name){ -  assert_has(codec_rx_gain_ranges.keys(), name, "codec rx gain name"); - -  _codec_rx_gains[name] = gain; -/* -  if(name == "analog") { -    _codec_ctrl->set_rx_analog_gain(gain > 0); //just turn it on or off -    return; -  } -*/ -  if(name == "digital") { -    _codec_ctrl->set_rx_digital_gain(gain); -    return; -  } -  if(name == "digital-fine") { -    _codec_ctrl->set_rx_digital_fine_gain(gain); -    return; -  } -  UHD_THROW_PROP_SET_ERROR(); -} - - -/*********************************************************************** - * TX Codec Properties - **********************************************************************/ -void usrp2_mboard_impl::tx_codec_get(const wax::obj &key_, wax::obj &val){ -    named_prop_t key = named_prop_t::extract(key_); - -    //handle the get request conditioned on the key -    switch(key.as<codec_prop_t>()){ -    case CODEC_PROP_NAME: -        val = _iface->get_cname() + " dac - ad9777"; -        return; - -    case CODEC_PROP_OTHERS: -        val = prop_names_t(); -        return; - -    case CODEC_PROP_GAIN_NAMES: -        val = prop_names_t(); //no gain elements to be controlled -        return; - -    default: UHD_THROW_PROP_GET_ERROR(); -    } -} - -void usrp2_mboard_impl::tx_codec_set(const wax::obj &, const wax::obj &){ -    UHD_THROW_PROP_SET_ERROR(); -} diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp deleted file mode 100644 index 8c6379d66..000000000 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ /dev/null @@ -1,183 +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 "usrp2_regs.hpp" -#include "fw_common.h" -#include <uhd/usrp/misc_utils.hpp> -#include <uhd/usrp/dsp_utils.hpp> -#include <uhd/usrp/subdev_props.hpp> -#include <uhd/usrp/dboard_props.hpp> -#include <uhd/exception.hpp> -#include <boost/format.hpp> -#include <boost/bind.hpp> -#include <boost/asio.hpp> //htonl and ntohl -#include <iostream> - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * Helper Methods - **********************************************************************/ -void usrp2_mboard_impl::dboard_init(void){ -    //read the dboard eeprom to extract the dboard ids -    _rx_db_eeprom.load(*_iface, USRP2_I2C_ADDR_RX_DB); -    _tx_db_eeprom.load(*_iface, USRP2_I2C_ADDR_TX_DB); -    _gdb_eeprom.load(*_iface, USRP2_I2C_ADDR_TX_DB ^ 5); - -    //create a new dboard interface and manager -    _dboard_iface = make_usrp2_dboard_iface(_iface, _clock_ctrl); -    _dboard_manager = dboard_manager::make( -        _rx_db_eeprom.id, -        ((_gdb_eeprom.id == dboard_id_t::none())? _tx_db_eeprom : _gdb_eeprom).id, -        _dboard_iface -    ); - -    //load dboards -    _rx_dboard_proxy = wax_obj_proxy::make( -        boost::bind(&usrp2_mboard_impl::rx_dboard_get, this, _1, _2), -        boost::bind(&usrp2_mboard_impl::rx_dboard_set, this, _1, _2) -    ); -    _tx_dboard_proxy = wax_obj_proxy::make( -        boost::bind(&usrp2_mboard_impl::tx_dboard_get, this, _1, _2), -        boost::bind(&usrp2_mboard_impl::tx_dboard_set, this, _1, _2) -    ); -} - -/*********************************************************************** - * RX DBoard Properties - **********************************************************************/ -void usrp2_mboard_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ -    named_prop_t key = named_prop_t::extract(key_); - -    //handle the get request conditioned on the key -    switch(key.as<dboard_prop_t>()){ -    case DBOARD_PROP_NAME: -        val = _iface->get_cname() + " dboard (rx unit)"; -        return; - -    case DBOARD_PROP_SUBDEV: -        val = _dboard_manager->get_rx_subdev(key.name); -        return; - -    case DBOARD_PROP_SUBDEV_NAMES: -        val = _dboard_manager->get_rx_subdev_names(); -        return; - -    case DBOARD_PROP_DBOARD_EEPROM: -        val = _rx_db_eeprom; -        return; - -    case DBOARD_PROP_DBOARD_IFACE: -        val = _dboard_iface; -        return; - -    case DBOARD_PROP_CODEC: -        val = _rx_codec_proxy->get_link(); -        return; - -    case DBOARD_PROP_GAIN_GROUP: -        val = make_gain_group( -            _rx_db_eeprom.id, -            _dboard_manager->get_rx_subdev(key.name), -            _rx_codec_proxy->get_link(), -            GAIN_GROUP_POLICY_RX -        ); -        return; - -    default: UHD_THROW_PROP_GET_ERROR(); -    } -} - -void usrp2_mboard_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){ -    switch(key.as<dboard_prop_t>()){ - -    case DBOARD_PROP_DBOARD_EEPROM: -        _rx_db_eeprom = val.as<dboard_eeprom_t>(); -        _rx_db_eeprom.store(*_iface, USRP2_I2C_ADDR_RX_DB); -        return; - -    default: UHD_THROW_PROP_SET_ERROR(); -    } -} - -/*********************************************************************** - * TX DBoard Properties - **********************************************************************/ -void usrp2_mboard_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ -    named_prop_t key = named_prop_t::extract(key_); - -    //handle the get request conditioned on the key -    switch(key.as<dboard_prop_t>()){ -    case DBOARD_PROP_NAME: -        val = _iface->get_cname() + " dboard (tx unit)"; -        return; - -    case DBOARD_PROP_SUBDEV: -        val = _dboard_manager->get_tx_subdev(key.name); -        return; - -    case DBOARD_PROP_SUBDEV_NAMES: -        val = _dboard_manager->get_tx_subdev_names(); -        return; - -    case DBOARD_PROP_DBOARD_EEPROM: -        val = _tx_db_eeprom; -        return; - -    case DBOARD_PROP_GBOARD_EEPROM: -        val = _gdb_eeprom; -        return; - -    case DBOARD_PROP_DBOARD_IFACE: -        val = _dboard_iface; -        return; - -    case DBOARD_PROP_CODEC: -        val = _tx_codec_proxy->get_link(); -        return; - -    case DBOARD_PROP_GAIN_GROUP: -        val = make_gain_group( -            _tx_db_eeprom.id, -            _dboard_manager->get_tx_subdev(key.name), -            _tx_codec_proxy->get_link(), -            GAIN_GROUP_POLICY_TX -        ); -        return; - -    default: UHD_THROW_PROP_GET_ERROR(); -    } -} - -void usrp2_mboard_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){ -    switch(key.as<dboard_prop_t>()){ - -    case DBOARD_PROP_DBOARD_EEPROM: -        _tx_db_eeprom = val.as<dboard_eeprom_t>(); -        _tx_db_eeprom.store(*_iface, USRP2_I2C_ADDR_TX_DB); -        return; - -    case DBOARD_PROP_GBOARD_EEPROM: -        _gdb_eeprom = val.as<dboard_eeprom_t>(); -        _gdb_eeprom.store(*_iface, USRP2_I2C_ADDR_TX_DB ^ 5); -        return; - -    default: UHD_THROW_PROP_SET_ERROR(); -    } -} diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp deleted file mode 100644 index d9cde3f13..000000000 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ /dev/null @@ -1,256 +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 "usrp2_regs.hpp" -#include <uhd/usrp/dsp_utils.hpp> -#include <uhd/usrp/dsp_props.hpp> -#include <boost/bind.hpp> -#include <boost/math/special_functions/round.hpp> -#include <boost/math/special_functions/sign.hpp> -#include <algorithm> -#include <cmath> - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * DSP impl and methods - **********************************************************************/ -struct usrp2_mboard_impl::dsp_impl{ -    uhd::dict<size_t, size_t> ddc_decim; -    uhd::dict<size_t, double> ddc_freq; -    uhd::dict<size_t, size_t> duc_interp; -    uhd::dict<size_t, double> duc_freq; -    std::vector<size_t> decim_and_interp_rates; -    uhd::dict<size_t, bool> continuous_streaming; -}; - -void usrp2_mboard_impl::dsp_init(void){ -    //create new dsp impl -    _dsp_impl = UHD_PIMPL_MAKE(dsp_impl, ()); - -    //load the allowed decim/interp rates -    //range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4) -    for (size_t i = 4; i <= 128; i+=1){ -        _dsp_impl->decim_and_interp_rates.push_back(i); -    } -    for (size_t i = 130; i <= 256; i+=2){ -        _dsp_impl->decim_and_interp_rates.push_back(i); -    } -    for (size_t i = 260; i <= 512; i+=4){ -        _dsp_impl->decim_and_interp_rates.push_back(i); -    } - -    //bind and initialize the rx dsps -    for (size_t i = 0; i < NUM_RX_DSPS; i++){ -        _rx_dsp_proxies[str(boost::format("DSP%d")%i)] = wax_obj_proxy::make( -            boost::bind(&usrp2_mboard_impl::ddc_get, this, _1, _2, i), -            boost::bind(&usrp2_mboard_impl::ddc_set, this, _1, _2, i) -        ); - -        //initial config and update -        ddc_set(DSP_PROP_FREQ_SHIFT, double(0), i); -        ddc_set(DSP_PROP_HOST_RATE, double(get_master_clock_freq()/16), i); - -        //setup the rx control registers -        _iface->poke32(U2_REG_RX_CTRL_CLEAR(i), 1); //reset -        _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PP(i), _device.get_max_recv_samps_per_packet()); -        _iface->poke32(U2_REG_RX_CTRL_NCHANNELS(i), 1); -        _iface->poke32(U2_REG_RX_CTRL_VRT_HDR(i), 0 -            | (0x1 << 28) //if data with stream id -            | (0x1 << 26) //has trailer -            | (0x3 << 22) //integer time other -            | (0x1 << 20) //fractional time sample count -        ); -        _iface->poke32(U2_REG_RX_CTRL_VRT_SID(i), usrp2_impl::RECV_SID); -        _iface->poke32(U2_REG_RX_CTRL_VRT_TLR(i), 0); -        _iface->poke32(U2_REG_TIME64_TPS, size_t(get_master_clock_freq())); -    } - -    //bind and initialize the tx dsps -    for (size_t i = 0; i < NUM_TX_DSPS; i++){ -        _tx_dsp_proxies[str(boost::format("DSP%d")%i)] = wax_obj_proxy::make( -            boost::bind(&usrp2_mboard_impl::duc_get, this, _1, _2, i), -            boost::bind(&usrp2_mboard_impl::duc_set, this, _1, _2, i) -        ); - -        //initial config and update -        duc_set(DSP_PROP_FREQ_SHIFT, double(0), i); -        duc_set(DSP_PROP_HOST_RATE, double(get_master_clock_freq()/16), i); - -        //init the tx control registers -        _iface->poke32(U2_REG_TX_CTRL_CLEAR_STATE, 1); //reset -        _iface->poke32(U2_REG_TX_CTRL_NUM_CHAN, 0);    //1 channel -        _iface->poke32(U2_REG_TX_CTRL_REPORT_SID, usrp2_impl::ASYNC_SID); -        _iface->poke32(U2_REG_TX_CTRL_POLICY, U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET); -    } -} - -template <typename rate_type> -static rate_type pick_closest_rate(double exact_rate, const std::vector<rate_type> &rates){ -    unsigned closest_match = rates.front(); -    BOOST_FOREACH(rate_type possible_rate, rates){ -        if(std::abs(exact_rate - possible_rate) < std::abs(exact_rate - closest_match)) -            closest_match = possible_rate; -    } -    return closest_match; -} - -void usrp2_mboard_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd, size_t which_dsp){ -    _dsp_impl->continuous_streaming[which_dsp] = stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS; -    _iface->poke32(U2_REG_RX_CTRL_STREAM_CMD(which_dsp), dsp_type1::calc_stream_cmd_word(stream_cmd)); -    _iface->poke32(U2_REG_RX_CTRL_TIME_SECS(which_dsp),  boost::uint32_t(stream_cmd.time_spec.get_full_secs())); -    _iface->poke32(U2_REG_RX_CTRL_TIME_TICKS(which_dsp), stream_cmd.time_spec.get_tick_count(get_master_clock_freq())); -} - -/*********************************************************************** - * DDC Properties - **********************************************************************/ -void usrp2_mboard_impl::ddc_get(const wax::obj &key_, wax::obj &val, size_t which_dsp){ -    named_prop_t key = named_prop_t::extract(key_); - -    switch(key.as<dsp_prop_t>()){ -    case DSP_PROP_NAME: -        val = str(boost::format("%s ddc%d") % _iface->get_cname() % which_dsp); -        return; - -    case DSP_PROP_OTHERS: -        val = prop_names_t(); //empty -        return; - -    case DSP_PROP_FREQ_SHIFT: -        val = _dsp_impl->ddc_freq[which_dsp]; -        return; - -    case DSP_PROP_CODEC_RATE: -        val = get_master_clock_freq(); -        return; - -    case DSP_PROP_HOST_RATE: -        val = get_master_clock_freq()/_dsp_impl->ddc_decim[which_dsp]; -        return; - -    default: UHD_THROW_PROP_GET_ERROR(); -    } -} - -void usrp2_mboard_impl::ddc_set(const wax::obj &key_, const wax::obj &val, size_t which_dsp){ -    named_prop_t key = named_prop_t::extract(key_); - -    switch(key.as<dsp_prop_t>()){ - -    case DSP_PROP_STREAM_CMD: -        issue_ddc_stream_cmd(val.as<stream_cmd_t>(), which_dsp); -        return; - -    case DSP_PROP_FREQ_SHIFT:{ -            double new_freq = val.as<double>(); -            _iface->poke32(U2_REG_DSP_RX_FREQ(which_dsp), -                dsp_type1::calc_cordic_word_and_update(new_freq, get_master_clock_freq()) -            ); -            _dsp_impl->ddc_freq[which_dsp] = new_freq; //shadow -        } -        return; - -    case DSP_PROP_HOST_RATE:{ -            double extact_rate = get_master_clock_freq()/val.as<double>(); -            _dsp_impl->ddc_decim[which_dsp] = pick_closest_rate(extact_rate, _dsp_impl->decim_and_interp_rates); - -            //set the decimation -            _iface->poke32(U2_REG_DSP_RX_DECIM(which_dsp), dsp_type1::calc_cic_filter_word(_dsp_impl->ddc_decim[which_dsp])); -        } -        _device.update_xport_channel_mapping(); //rate changed -> update -        return; - -    default: UHD_THROW_PROP_SET_ERROR(); -    } -} - -/*********************************************************************** - * DUC Properties - **********************************************************************/ -void usrp2_mboard_impl::duc_get(const wax::obj &key_, wax::obj &val, size_t which_dsp){ -    named_prop_t key = named_prop_t::extract(key_); - -    switch(key.as<dsp_prop_t>()){ -    case DSP_PROP_NAME: -        val = str(boost::format("%s duc%d") % _iface->get_cname() % which_dsp); -        return; - -    case DSP_PROP_OTHERS: -        val = prop_names_t(); //empty -        return; - -    case DSP_PROP_FREQ_SHIFT: -        val = _dsp_impl->duc_freq[which_dsp]; -        return; - -    case DSP_PROP_CODEC_RATE: -        val = get_master_clock_freq(); -        return; - -    case DSP_PROP_HOST_RATE: -        val = get_master_clock_freq()/_dsp_impl->duc_interp[which_dsp]; -        return; - -    default: UHD_THROW_PROP_GET_ERROR(); -    } -} - -void usrp2_mboard_impl::duc_set(const wax::obj &key_, const wax::obj &val, size_t which_dsp){ -    named_prop_t key = named_prop_t::extract(key_); - -    switch(key.as<dsp_prop_t>()){ - -    case DSP_PROP_FREQ_SHIFT:{ -            const double codec_rate = get_master_clock_freq(); -            double new_freq = val.as<double>(); - -            //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/codec_rate), 2); -            const double dac_shift = sign*zone*codec_rate; -            new_freq -= dac_shift; //update FPGA DSP target freq - -            //set the DAC shift (modulation mode) -            if (zone == 0) _codec_ctrl->set_tx_mod_mode(0); //no shift -            else _codec_ctrl->set_tx_mod_mode(sign*4/zone); //DAC interp = 4 - -            _iface->poke32(U2_REG_DSP_TX_FREQ, -                dsp_type1::calc_cordic_word_and_update(new_freq, codec_rate) -            ); -            _dsp_impl->duc_freq[which_dsp] = new_freq + dac_shift; //shadow -        } -        return; - -    case DSP_PROP_HOST_RATE:{ -            double extact_rate = get_master_clock_freq()/val.as<double>(); -            _dsp_impl->duc_interp[which_dsp] = pick_closest_rate(extact_rate, _dsp_impl->decim_and_interp_rates); - -            //set the interpolation -            _iface->poke32(U2_REG_DSP_TX_INTERP_RATE, dsp_type1::calc_cic_filter_word(_dsp_impl->duc_interp[which_dsp])); - -            //set the scaling -            _iface->poke32(U2_REG_DSP_TX_SCALE_IQ, dsp_type1::calc_iq_scale_word(_dsp_impl->duc_interp[which_dsp])); -        } -        _device.update_xport_channel_mapping(); //rate changed -> update -        return; - -    default: UHD_THROW_PROP_SET_ERROR(); -    } -} diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index df452942c..64c099ff6 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -22,8 +22,6 @@  #include <uhd/utils/log.hpp>  #include <uhd/utils/msg.hpp>  #include <uhd/exception.hpp> -#include <uhd/usrp/mboard_props.hpp> -#include <uhd/usrp/dsp_props.hpp>  #include <uhd/utils/byteswap.hpp>  #include <uhd/utils/thread_priority.hpp>  #include <uhd/transport/bounded_buffer.hpp> @@ -134,15 +132,10 @@ private:   **********************************************************************/  struct usrp2_impl::io_impl{ -    io_impl(std::vector<zero_copy_if::sptr> &dsp_xports): -        dsp_xports(dsp_xports), //the assumption is that all data transports should be identical +    io_impl(void):          async_msg_fifo(100/*messages deep*/)      { -        for (size_t i = 0; i < dsp_xports.size(); i++){ -            fc_mons.push_back(flow_control_monitor::sptr(new flow_control_monitor( -                usrp2_impl::sram_bytes/dsp_xports.front()->get_send_frame_size() -            ))); -        } +        /* NOP */      }      ~io_impl(void){ @@ -151,14 +144,13 @@ struct usrp2_impl::io_impl{      }      managed_send_buffer::sptr get_send_buff(size_t chan, double timeout){ -        const size_t index = send_map[chan]; -        flow_control_monitor &fc_mon = *fc_mons[index]; +        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 = dsp_xports[index]->get_send_buff(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()); @@ -166,15 +158,8 @@ struct usrp2_impl::io_impl{          return buff;      } -    std::vector<zero_copy_if::sptr> &dsp_xports; - -    //mappings from channel index to dsp xport -    std::vector<size_t> send_map, recv_map; - -    //previous state for each buffer -    std::vector<vrt::if_packet_info_t> prev_infos; - -    //flow control monitors +    //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 @@ -182,9 +167,10 @@ struct usrp2_impl::io_impl{      sph::send_packet_handler send_handler;      //methods and variables for the pirate crew -    void recv_pirate_loop(boost::barrier &, usrp2_mboard_impl::sptr, zero_copy_if::sptr, size_t); +    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;  };  /*********************************************************************** @@ -195,7 +181,6 @@ struct usrp2_impl::io_impl{   **********************************************************************/  void usrp2_impl::io_impl::recv_pirate_loop(      boost::barrier &spawn_barrier, -    usrp2_mboard_impl::sptr mboard,      zero_copy_if::sptr err_xport,      size_t index  ){ @@ -203,7 +188,7 @@ void usrp2_impl::io_impl::recv_pirate_loop(      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*usrp2_mboard_impl::MAX_NUM_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(); @@ -217,14 +202,14 @@ void usrp2_impl::io_impl::recv_pirate_loop(              vrt::if_hdr_unpack_be(vrt_hdr, if_packet_info);              //handle a tx async report message -            if (if_packet_info.sid == usrp2_impl::ASYNC_SID and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){ +            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), mboard->get_master_clock_freq() +                    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)); @@ -254,80 +239,126 @@ void usrp2_impl::io_impl::recv_pirate_loop(   **********************************************************************/  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, (dsp_xports)); +    _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(_mboards.size()+1); -    for (size_t i = 0; i < _mboards.size(); i++){ +    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), -            _mboards.at(i), err_xports.at(i), i +            _mbc[mb].err_xports.at(0), index++          ));      }      spawn_barrier.wait(); -    //update mapping here since it didnt b4 when io init not called first -    update_xport_channel_mapping(); +    //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_xport_channel_mapping(void){ -    if (_io_impl.get() == NULL) return; //not inited yet +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); +} -    _io_impl->recv_map.clear(); -    _io_impl->send_map.clear(); +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); +} -    for (size_t i = 0; i < _mboards.size(); i++){ +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); +} -        subdev_spec_t rx_subdev_spec = _mboards[i]->get_link()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>(); -        for (size_t j = 0; j < rx_subdev_spec.size(); j++){ -            _io_impl->recv_map.push_back(i*usrp2_mboard_impl::MAX_NUM_DSPS+j); -            UHD_LOG << "recv_map.back() " << _io_impl->recv_map.back() << std::endl; -        } +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"; -        subdev_spec_t tx_subdev_spec = _mboards[i]->get_link()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>(); -        for (size_t j = 0; j < tx_subdev_spec.size(); j++){ -            _io_impl->send_map.push_back(i*usrp2_mboard_impl::MAX_NUM_DSPS+j); -            UHD_LOG << "send_map.back() " << _io_impl->send_map.back() << std::endl; -        } +    //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);      } -    //set all of the relevant properties on the handler -    boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock(); -    _io_impl->recv_handler.resize(_io_impl->recv_map.size()); -    _io_impl->recv_handler.set_vrt_unpacker(&vrt::if_hdr_unpack_be); -    _io_impl->recv_handler.set_tick_rate(_mboards.front()->get_master_clock_freq()); -    //TODO temporarily use the first dsp rate until we support non-homo rates -    const std::string rx_dsp_name = _mboards.at(0)->get_link()[MBOARD_PROP_RX_DSP_NAMES].as<prop_names_t>().at(0); -    const double rx_host_rate = _mboards.at(0)->get_link()[named_prop_t(MBOARD_PROP_RX_DSP, rx_dsp_name)][DSP_PROP_HOST_RATE].as<double>(); -    _io_impl->recv_handler.set_samp_rate(rx_host_rate); -    for (size_t chan = 0; chan < _io_impl->recv_handler.size(); chan++){ -        _io_impl->recv_handler.set_xport_chan_get_buff(chan, boost::bind( -            &uhd::transport::zero_copy_if::get_recv_buff, -            _io_impl->dsp_xports[_io_impl->recv_map[chan]], _1 -        )); +    //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 +            )); +        }      } -    _io_impl->recv_handler.set_converter(_rx_otw_type); +} -    //set all of the relevant properties on the handler +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(); -    _io_impl->send_handler.resize(_io_impl->send_map.size()); -    _io_impl->send_handler.set_vrt_packer(&vrt::if_hdr_pack_be, vrt_send_header_offset_words32); -    _io_impl->send_handler.set_tick_rate(_mboards.front()->get_master_clock_freq()); -    //TODO temporarily use the first dsp rate until we support non-homo rates -    const std::string tx_dsp_name = _mboards.at(0)->get_link()[MBOARD_PROP_TX_DSP_NAMES].as<prop_names_t>().at(0); -    const double tx_host_rate = _mboards.at(0)->get_link()[named_prop_t(MBOARD_PROP_TX_DSP, tx_dsp_name)][DSP_PROP_HOST_RATE].as<double>(); -    _io_impl->send_handler.set_samp_rate(tx_host_rate); -    for (size_t chan = 0; chan < _io_impl->send_handler.size(); chan++){ -        _io_impl->send_handler.set_xport_chan_get_buff(chan, boost::bind( -            &usrp2_impl::io_impl::get_send_buff, _io_impl.get(), chan, _1 -        )); +    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 +            )); +        }      } -    _io_impl->send_handler.set_converter(_tx_otw_type); -    _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet());  }  /*********************************************************************** @@ -349,7 +380,7 @@ size_t usrp2_impl::get_max_send_samps_per_packet(void) const{          + 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 = dsp_xports.front()->get_send_frame_size() - hdr_size; +    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();  } @@ -374,7 +405,7 @@ size_t usrp2_impl::get_max_recv_samps_per_packet(void) const{          + 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 = dsp_xports.front()->get_recv_frame_size() - hdr_size; +    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();  } diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp deleted file mode 100644 index 5583a4335..000000000 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ /dev/null @@ -1,522 +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 "usrp2_regs.hpp" -#include "fw_common.h" -#include <uhd/utils/log.hpp> -#include <uhd/utils/msg.hpp> -#include <uhd/utils/safe_call.hpp> -#include <uhd/exception.hpp> -#include <uhd/usrp/gps_ctrl.hpp> -#include <uhd/usrp/misc_utils.hpp> -#include <uhd/usrp/dsp_utils.hpp> -#include <uhd/usrp/mboard_props.hpp> -#include <uhd/utils/byteswap.hpp> -#include <uhd/utils/algorithm.hpp> -#include <uhd/types/sensors.hpp> -#include <boost/assign/list_of.hpp> -#include <boost/bind.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; - -using namespace uhd; -using namespace uhd::usrp; -using namespace uhd::transport; - -/*********************************************************************** - * 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_mboard_impl::usrp2_mboard_impl( -    const device_addr_t &device_addr, -    size_t index, usrp2_impl &device -): -    _index(index), _device(device), -    _iface(usrp2_iface::make(udp_simple::make_connected( -        device_addr["addr"], BOOST_STRINGIZE(USRP2_UDP_CTRL_PORT) -    ))) -{ - -    //check the fpga compatibility number -    const boost::uint32_t fpga_compat_num = _iface->peek32(U2_REG_COMPAT_NUM_RB); -    if (fpga_compat_num != USRP2_FPGA_COMPAT_NUM){ -        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 FPGA compatibility number %d, but got %d:\n" -            "The FPGA build is not compatible with the host code build." -        ) % int(USRP2_FPGA_COMPAT_NUM) % fpga_compat_num)); -    } - -    //lock the device/motherboard to this process -    _iface->lock_device(true); - -    //construct transports for dsp and async errors -    UHD_LOG << "Making transport for DSP0..." << std::endl; -    device.dsp_xports.push_back(udp_zero_copy::make( -        device_addr["addr"], BOOST_STRINGIZE(USRP2_UDP_DSP0_PORT), device_addr -    )); -    init_xport(device.dsp_xports.back()); - -    UHD_LOG << "Making transport for DSP1..." << std::endl; -    device.dsp_xports.push_back(udp_zero_copy::make( -        device_addr["addr"], BOOST_STRINGIZE(USRP2_UDP_DSP1_PORT), device_addr -    )); -    init_xport(device.dsp_xports.back()); - -    UHD_LOG << "Making transport for ERR0..." << std::endl; -    device.err_xports.push_back(udp_zero_copy::make( -        device_addr["addr"], BOOST_STRINGIZE(USRP2_UDP_ERR0_PORT), device_addr_t() -    )); -    init_xport(device.err_xports.back()); - -    //contruct the interfaces to mboard perifs -    _clock_ctrl = usrp2_clock_ctrl::make(_iface); -    _codec_ctrl = usrp2_codec_ctrl::make(_iface); -    if (_iface->mb_eeprom["gpsdo"] == "internal"){ -        _gps_ctrl = gps_ctrl::make( -            _iface->get_gps_write_fn(), -            _iface->get_gps_read_fn()); -    } - -    //init the dsp stuff (before setting update packets) -    dsp_init(); - -    //setting the cycles per update (disabled by default) -    const double ups_per_sec = device_addr.cast<double>("ups_per_sec", 20); -    if (ups_per_sec > 0.0){ -        const size_t cycles_per_up = size_t(_clock_ctrl->get_master_clock_rate()/ups_per_sec); -        _iface->poke32(U2_REG_TX_CTRL_CYCLES_PER_UP, U2_FLAG_TX_CTRL_UP_ENB | cycles_per_up); -    } - -    //setting the packets per update (enabled by default) -    size_t send_frame_size = device.dsp_xports[0]->get_send_frame_size(); -    const double ups_per_fifo = device_addr.cast<double>("ups_per_fifo", 8.0); -    if (ups_per_fifo > 0.0){ -        const size_t packets_per_up = size_t(usrp2_impl::sram_bytes/ups_per_fifo/send_frame_size); -        _iface->poke32(U2_REG_TX_CTRL_PACKETS_PER_UP, U2_FLAG_TX_CTRL_UP_ENB | packets_per_up); -    } - -    //initialize the clock configuration -    if (device_addr.has_key("mimo_mode")){ -        if (device_addr["mimo_mode"] == "master"){ -            _mimo_clocking_mode_is_master = true; -        } -        else if (device_addr["mimo_mode"] == "slave"){ -            _mimo_clocking_mode_is_master = false; -        } -        else throw uhd::value_error( -            "mimo_mode must be set to master or slave" -        ); -    } -    else { -        _mimo_clocking_mode_is_master = (_iface->peek32(U2_REG_STATUS) & (1 << 8)) != 0; -    } -    UHD_MSG(status) << boost::format("mboard%d is MIMO %s") % _index % -        (_mimo_clocking_mode_is_master?"master":"slave") << std::endl; - -    //init the clock config -    if(_iface->mb_eeprom["gpsdo"] == "internal" or -       _iface->mb_eeprom["gpsdo"] == "external") { -        _clock_config = clock_config_t::external(); -    } -    else { -        _clock_config = clock_config_t::internal(); -    } -    update_clock_config(); - -    //init the codec before the dboard -    codec_init(); - -    //init the tx and rx dboards (do last) -    dboard_init(); - -    //set default subdev specs -    (*this)[MBOARD_PROP_RX_SUBDEV_SPEC] = subdev_spec_t(); -    (*this)[MBOARD_PROP_TX_SUBDEV_SPEC] = subdev_spec_t(); - -    //------------------------------------------------------------------ -    //This is a hack/fix for the lingering packet problem. -    stream_cmd_t stream_cmd(stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE); -    for (size_t i = 0; i < NUM_RX_DSPS; i++){ -        size_t index = device.dsp_xports.size() - NUM_RX_DSPS + i; -        stream_cmd.num_samps = 1; -        this->issue_ddc_stream_cmd(stream_cmd, i); -        device.dsp_xports.at(index)->get_recv_buff(0.01).get(); //recv with timeout for lingering -        device.dsp_xports.at(index)->get_recv_buff(0.01).get(); //recv with timeout for expected -        _iface->poke32(U2_REG_RX_CTRL_CLEAR(i), 1); //resets sequence -    } -    //------------------------------------------------------------------ - -    //initialize VITA time to GPS time -    if( _gps_ctrl.get() -    and _gps_ctrl->gps_detected()) { -        UHD_MSG(status) << "Setting device time to GPS time...\n"; -        set_time_spec(time_spec_t(double(_gps_ctrl->get_sensor("gps_time").to_int()+1)), false); -    } -} - -usrp2_mboard_impl::~usrp2_mboard_impl(void){UHD_SAFE_CALL( -    _iface->poke32(U2_REG_TX_CTRL_CYCLES_PER_UP, 0); -    _iface->poke32(U2_REG_TX_CTRL_PACKETS_PER_UP, 0); -)} - -/*********************************************************************** - * Helper Methods - **********************************************************************/ -void usrp2_mboard_impl::update_clock_config(void){ -    boost::uint32_t pps_flags = 0; - -    //slave mode overrides clock config settings -    if (not _mimo_clocking_mode_is_master){ -        _clock_config.ref_source = clock_config_t::REF_MIMO; -        _clock_config.pps_source = clock_config_t::PPS_MIMO; -    } - -    //translate pps source enums -    switch(_clock_config.pps_source){ -    case clock_config_t::PPS_MIMO: -        _iface->poke32(U2_REG_TIME64_MIMO_SYNC, -            (1 << 8) | (mimo_clock_sync_delay_cycles & 0xff) -        ); -        break; - -    case clock_config_t::PPS_SMA: -        _iface->poke32(U2_REG_TIME64_MIMO_SYNC, 0); -        pps_flags |= U2_FLAG_TIME64_PPS_SMA; -        break; - -    default: throw uhd::value_error("unhandled clock configuration pps source"); -    } - -    //translate pps polarity enums -    switch(_clock_config.pps_polarity){ -    case clock_config_t::PPS_POS: pps_flags |= U2_FLAG_TIME64_PPS_POSEDGE; break; -    case clock_config_t::PPS_NEG: pps_flags |= U2_FLAG_TIME64_PPS_NEGEDGE; break; -    default: throw uhd::value_error("unhandled clock configuration pps polarity"); -    } - -    //set the pps flags -    _iface->poke32(U2_REG_TIME64_FLAGS, pps_flags); - -    //clock source ref 10mhz -    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: -        switch(_clock_config.ref_source){ -        case clock_config_t::REF_INT : _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x12); break; -        case clock_config_t::REF_SMA : _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C); break; -        case clock_config_t::REF_MIMO: _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x15); break; -        default: throw uhd::value_error("unhandled clock configuration reference source"); -        } -        _clock_ctrl->enable_external_ref(true); //USRP2P has an internal 10MHz TCXO -        break; - -    case usrp2_iface::USRP2_REV3: -    case usrp2_iface::USRP2_REV4: -        switch(_clock_config.ref_source){ -        case clock_config_t::REF_INT : _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x10); break; -        case clock_config_t::REF_SMA : _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C); break; -        case clock_config_t::REF_MIMO: _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x15); break; -        default: throw uhd::value_error("unhandled clock configuration reference source"); -        } -        _clock_ctrl->enable_external_ref(_clock_config.ref_source != clock_config_t::REF_INT); -        break; - -    case usrp2_iface::USRP_NXXX: break; -    } - -    //masters always drive the clock over serdes -    _clock_ctrl->enable_mimo_clock_out(_mimo_clocking_mode_is_master); - -    //set the mimo clock delay over the serdes -    if (_mimo_clocking_mode_is_master){ -        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: -            _clock_ctrl->set_mimo_clock_delay(mimo_clock_delay_usrp_n2xx); -            break; - -        case usrp2_iface::USRP2_REV4: -            _clock_ctrl->set_mimo_clock_delay(mimo_clock_delay_usrp2_rev4); -            break; - -        default: break; //not handled -        } -    } - -} - -void usrp2_mboard_impl::set_time_spec(const time_spec_t &time_spec, bool now){ -    //dont set the time for slave devices, they always take from mimo cable -    if (not _mimo_clocking_mode_is_master) return; - -    //set the ticks -    _iface->poke32(U2_REG_TIME64_TICKS, time_spec.get_tick_count(get_master_clock_freq())); - -    //set the flags register -    boost::uint32_t imm_flags = (now)? U2_FLAG_TIME64_LATCH_NOW : U2_FLAG_TIME64_LATCH_NEXT_PPS; -    _iface->poke32(U2_REG_TIME64_IMM, imm_flags); - -    //set the seconds (latches in all 3 registers) -    _iface->poke32(U2_REG_TIME64_SECS, boost::uint32_t(time_spec.get_full_secs())); -} - -/*********************************************************************** - * MBoard Get Properties - **********************************************************************/ -void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){ -    named_prop_t key = named_prop_t::extract(key_); -    static const std::string dboard_name = "A"; - -    //handle the get request conditioned on the key -    switch(key.as<mboard_prop_t>()){ -    case MBOARD_PROP_NAME: -        val = _iface->get_cname() + " mboard"; -        return; - -    case MBOARD_PROP_OTHERS: -        val = prop_names_t(); -        return; - -    case MBOARD_PROP_RX_DBOARD: -        UHD_ASSERT_THROW(key.name == dboard_name or key.name == "0"); //allow for old name to work -        val = _rx_dboard_proxy->get_link(); -        return; - -    case MBOARD_PROP_RX_DBOARD_NAMES: -        val = prop_names_t(1, dboard_name); -        return; - -    case MBOARD_PROP_TX_DBOARD: -        UHD_ASSERT_THROW(key.name == dboard_name or key.name == "0"); //allow for old name to work -        val = _tx_dboard_proxy->get_link(); -        return; - -    case MBOARD_PROP_TX_DBOARD_NAMES: -        val = prop_names_t(1, dboard_name); -        return; - -    case MBOARD_PROP_RX_DSP: -        val = _rx_dsp_proxies[key.name]->get_link(); -        return; - -    case MBOARD_PROP_RX_DSP_NAMES: -        val = _rx_dsp_proxies.keys(); -        return; - -    case MBOARD_PROP_TX_DSP: -        val = _tx_dsp_proxies[key.name]->get_link(); -        return; - -    case MBOARD_PROP_TX_DSP_NAMES: -        val = _tx_dsp_proxies.keys(); -        return; - -    case MBOARD_PROP_CLOCK_CONFIG: -        val = _clock_config; -        return; - -    case MBOARD_PROP_TIME_NOW: while(true){ -        uint32_t secs = _iface->peek32(U2_REG_TIME64_SECS_RB_IMM); -        uint32_t ticks = _iface->peek32(U2_REG_TIME64_TICKS_RB_IMM); -        if (secs != _iface->peek32(U2_REG_TIME64_SECS_RB_IMM)) continue; -        val = time_spec_t(secs, ticks, get_master_clock_freq()); -        return; -    } - -    case MBOARD_PROP_TIME_PPS: while(true){ -        uint32_t secs = _iface->peek32(U2_REG_TIME64_SECS_RB_PPS); -        uint32_t ticks = _iface->peek32(U2_REG_TIME64_TICKS_RB_PPS); -        if (secs != _iface->peek32(U2_REG_TIME64_SECS_RB_PPS)) continue; -        val = time_spec_t(secs, ticks, get_master_clock_freq()); -        return; -    } - -    case MBOARD_PROP_RX_SUBDEV_SPEC: -        val = _rx_subdev_spec; -        return; - -    case MBOARD_PROP_TX_SUBDEV_SPEC: -        val = _tx_subdev_spec; -        return; - -    case MBOARD_PROP_EEPROM_MAP: -        val = _iface->mb_eeprom; -        return; - -    case MBOARD_PROP_CLOCK_RATE: -        val = this->get_master_clock_freq(); -        return; - -    case SUBDEV_PROP_SENSOR_NAMES:{ -            prop_names_t names = boost::assign::list_of("mimo_locked")("ref_locked"); -            if (_gps_ctrl.get()) { -                std::vector<std::string> gs = _gps_ctrl->get_sensors(); -                names.insert(names.end(), gs.begin(), gs.end()); -            } -            val = names; -        } -        return; - -    case MBOARD_PROP_SENSOR: -        if(key.name == "mimo_locked") { -            val = sensor_value_t("MIMO", this->get_mimo_locked(), "locked", "unlocked"); -            return; -        } -        else if(key.name == "ref_locked") { -            val = sensor_value_t("Ref", this->get_ref_locked(), "locked", "unlocked"); -            return; -        } -        else if(uhd::has(_gps_ctrl->get_sensors(), key.name) and _gps_ctrl.get()) { -            val = _gps_ctrl->get_sensor(key.name); -        } -        else { -            UHD_THROW_PROP_GET_ERROR(); -        } -        break; - -    default: UHD_THROW_PROP_GET_ERROR(); -    } -} - -bool usrp2_mboard_impl::get_mimo_locked(void) { -  return bool((_iface->peek32(U2_REG_IRQ_RB) & (1<<10)) > 0); -} - -bool usrp2_mboard_impl::get_ref_locked(void) { -  return bool((_iface->peek32(U2_REG_IRQ_RB) & (1<<11)) > 0); -} - -/*********************************************************************** - * MBoard Set Properties - **********************************************************************/ -void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){ -    //handle the set request conditioned on the key -    switch(key.as<mboard_prop_t>()){ - -    case MBOARD_PROP_CLOCK_CONFIG: -        _clock_config = val.as<clock_config_t>(); -        update_clock_config(); -        return; - -    case MBOARD_PROP_TIME_NOW: -        set_time_spec(val.as<time_spec_t>(), true); -        return; - -    case MBOARD_PROP_TIME_PPS: -        set_time_spec(val.as<time_spec_t>(), false); -        return; - -    case MBOARD_PROP_RX_SUBDEV_SPEC:{ -        _rx_subdev_spec = val.as<subdev_spec_t>(); -        verify_rx_subdev_spec(_rx_subdev_spec, this->get_link()); -        //sanity check -        UHD_ASSERT_THROW(_rx_subdev_spec.size() <= NUM_RX_DSPS); - -        //determine frontend swap IQ from the first channel -        bool fe_swap_iq = false; -        switch(_dboard_manager->get_rx_subdev(_rx_subdev_spec.at(0).sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()){ -        case SUBDEV_CONN_COMPLEX_QI: -        case SUBDEV_CONN_REAL_Q: -            fe_swap_iq = true; -            break; -        default: fe_swap_iq = false; -        } -        _iface->poke32(U2_REG_RX_FE_SWAP_IQ, fe_swap_iq? 1 : 0); - -        //set the dsp mux for each channel -        for (size_t i = 0; i < _rx_subdev_spec.size(); i++){ -            bool iq_swap = false, real_mode = false; -            switch(_dboard_manager->get_rx_subdev(_rx_subdev_spec.at(i).sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()){ -            case SUBDEV_CONN_COMPLEX_IQ: -                iq_swap = fe_swap_iq; -                real_mode = false; -                break; -            case SUBDEV_CONN_COMPLEX_QI: -                iq_swap = not fe_swap_iq; -                real_mode = false; -                break; -            case SUBDEV_CONN_REAL_I: -                iq_swap = fe_swap_iq; -                real_mode = true; -                break; -            case SUBDEV_CONN_REAL_Q: -                iq_swap = not fe_swap_iq; -                real_mode = true; -                break; -            } -            _iface->poke32(U2_REG_DSP_RX_MUX(i), -                (iq_swap?   U2_FLAG_DSP_RX_MUX_SWAP_IQ   : 0) | -                (real_mode? U2_FLAG_DSP_RX_MUX_REAL_MODE : 0) -            ); -        } -        _device.update_xport_channel_mapping(); -    }return; - -    case MBOARD_PROP_TX_SUBDEV_SPEC: -        _tx_subdev_spec = val.as<subdev_spec_t>(); -        verify_tx_subdev_spec(_tx_subdev_spec, this->get_link()); -        //sanity check -        UHD_ASSERT_THROW(_tx_subdev_spec.size() <= NUM_TX_DSPS); -        //set the mux -        for (size_t i = 0; i < _rx_subdev_spec.size(); i++){ -            _iface->poke32(U2_REG_TX_FE_MUX, dsp_type1::calc_tx_mux_word( -                _dboard_manager->get_tx_subdev(_tx_subdev_spec[i].sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>() -            )); -        } -        _device.update_xport_channel_mapping(); -        return; - -    case MBOARD_PROP_EEPROM_MAP: -        // Step1: commit the map, writing only those values set. -        // Step2: readback the entire eeprom map into the iface. -        val.as<mboard_eeprom_t>().commit(*_iface, mboard_eeprom_t::MAP_N100); -        _iface->mb_eeprom = mboard_eeprom_t(*_iface, mboard_eeprom_t::MAP_N100); -        return; - -    case MBOARD_PROP_CLOCK_RATE: -        UHD_ASSERT_THROW(val.as<double>() == this->get_master_clock_freq()); -        _device.update_xport_channel_mapping(); -        return; - -    default: UHD_THROW_PROP_SET_ERROR(); -    } -} diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp index 6ba364b28..0db9e5d58 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.cpp +++ b/host/lib/usrp/usrp2/usrp2_iface.cpp @@ -160,24 +160,24 @@ public:  /***********************************************************************   * Peek and Poke   **********************************************************************/ -    void poke32(boost::uint32_t addr, boost::uint32_t data){ +    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(boost::uint32_t addr){ +    boost::uint32_t peek32(wb_addr_type addr){          return this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FPGA_PEEK32>(addr);      } -    void poke16(boost::uint32_t addr, boost::uint16_t data){ +    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(boost::uint32_t addr){ +    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(boost::uint32_t addr, T data = 0){ +    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); diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp index 16b640a70..f36febce4 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.hpp +++ b/host/lib/usrp/usrp2/usrp2_iface.hpp @@ -19,15 +19,14 @@  #define INCLUDED_USRP2_IFACE_HPP  #include <uhd/transport/udp_simple.hpp> -#include <uhd/usrp/mboard_iface.hpp> +#include <uhd/types/serial.hpp> +#include <uhd/usrp/mboard_eeprom.hpp>  #include <boost/shared_ptr.hpp>  #include <boost/utility.hpp> -#include <boost/cstdint.hpp>  #include <boost/function.hpp> -#include <utility> -#include <string>  #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; @@ -38,7 +37,7 @@ typedef boost::function<std::string(void)> gps_recv_fn_t;   * Provides a set of functions to implementation layer.   * Including spi, peek, poke, control...   */ -class usrp2_iface : public uhd::usrp::mboard_iface, boost::noncopyable{ +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;      /*! diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index aa584ac8b..e00924ebd 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -22,18 +22,18 @@  #include <uhd/exception.hpp>  #include <uhd/transport/if_addrs.hpp>  #include <uhd/transport/udp_zero_copy.hpp> -#include <uhd/usrp/device_props.hpp> +#include <uhd/types/ranges.hpp>  #include <uhd/exception.hpp>  #include <uhd/utils/static.hpp>  #include <uhd/utils/byteswap.hpp> -#include <boost/assign/list_of.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 -#include <vector>  using namespace uhd;  using namespace uhd::usrp; @@ -227,6 +227,23 @@ static mtu_result_t determine_mtu(const std::string &addr, const mtu_result_t &u  }  /*********************************************************************** + * 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){ @@ -272,67 +289,385 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){      device_args = separate_device_addr(device_addr); //update args for new frame sizes -    //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; +    //////////////////////////////////////////////////////////////////// +    // 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()); -    //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; +        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()); -    //!!!!! set the otw type here before continuing, its used below +        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 a new mboard handler for each control transport -    for(size_t i = 0; i < device_args.size(); i++){ -        device_addr_t dev_addr_i = device_args[i]; -        BOOST_FOREACH(const std::string &key, device_addr.keys()){ -            if (dev_addr_i.has_key(key)) continue; -            dev_addr_i[key] = device_addr[key]; +        //////////////////////////////////////////////////////////////// +        // 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)); +            }          } -        _mboards.push_back(usrp2_mboard_impl::sptr( -            new usrp2_mboard_impl(dev_addr_i, i, *this) + +        //////////////////////////////////////////////////////////////// +        // 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          )); -        //use an empty name when there is only one mboard -        std::string name = (device_args.size() > 1)? boost::lexical_cast<std::string>(i) : ""; -        _mboard_dict[name] = _mboards.back(); +        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) +            ); +        }      } -    //init the send and recv io -    io_init(); +    //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){ -    /* NOP */ +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);  } -/*********************************************************************** - * Device Properties - **********************************************************************/ -void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ -    named_prop_t key = named_prop_t::extract(key_); +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); +} -    //handle the get request conditioned on the key -    switch(key.as<device_prop_t>()){ -    case DEVICE_PROP_NAME: -        if (_mboards.size() > 1) val = std::string("USRP2/N Series multi-device"); -        else                     val = std::string("USRP2/N Series device"); -        return; +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"); +} -    case DEVICE_PROP_MBOARD: -        val = _mboard_dict[key.name]->get_link(); -        return; +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"); +} -    case DEVICE_PROP_MBOARD_NAMES: -        val = prop_names_t(_mboard_dict.keys()); -        return; +#include <boost/math/special_functions/round.hpp> +#include <boost/math/special_functions/sign.hpp> -    default: UHD_THROW_PROP_GET_ERROR(); -    } +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  } -void usrp2_impl::set(const wax::obj &, const wax::obj &){ -    UHD_THROW_PROP_SET_ERROR(); +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/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 4d19863b1..ad203079b 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -21,6 +21,12 @@  #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> @@ -37,6 +43,13 @@  #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 @@ -49,139 +62,13 @@ uhd::usrp::dboard_iface::sptr make_usrp2_dboard_iface(  );  /*! - * Simple wax obj proxy class: - * Provides a wax obj interface for a set and a get function. - * This allows us to create nested properties structures - * while maintaining flattened code within the implementation. - */ -class wax_obj_proxy : public wax::obj{ -public: -    typedef boost::function<void(const wax::obj &, wax::obj &)>       get_t; -    typedef boost::function<void(const wax::obj &, const wax::obj &)> set_t; -    typedef boost::shared_ptr<wax_obj_proxy> sptr; - -    static sptr make(const get_t &get, const set_t &set){ -        return sptr(new wax_obj_proxy(get, set)); -    } - -private: -    get_t _get; set_t _set; -    wax_obj_proxy(const get_t &get, const set_t &set): _get(get), _set(set){}; -    void get(const wax::obj &key, wax::obj &val){return _get(key, val);} -    void set(const wax::obj &key, const wax::obj &val){return _set(key, val);} -}; - -class usrp2_impl; - -/*! - * USRP2 mboard implementation guts: - * The implementation details are encapsulated here. - * Handles properties on the mboard, dboard, dsps... - */ -class usrp2_mboard_impl : public wax::obj{ -public: -    typedef boost::shared_ptr<usrp2_mboard_impl> sptr; - -    static const size_t NUM_RX_DSPS = 2; -    static const size_t NUM_TX_DSPS = 1; -    static const size_t MAX_NUM_DSPS = 2; - -    //structors -    usrp2_mboard_impl( -        const uhd::device_addr_t &device_addr, -        size_t index, usrp2_impl &device -    ); -    ~usrp2_mboard_impl(void); - -    inline double get_master_clock_freq(void){ -        return _clock_ctrl->get_master_clock_rate(); -    } - -    void handle_overflow(size_t); - -private: -    size_t _index; -    usrp2_impl &_device; -    bool _mimo_clocking_mode_is_master; - -    //interfaces -    usrp2_iface::sptr _iface; -    usrp2_clock_ctrl::sptr _clock_ctrl; -    usrp2_codec_ctrl::sptr _codec_ctrl; -    gps_ctrl::sptr _gps_ctrl; - -    //properties for this mboard -    void get(const wax::obj &, wax::obj &); -    void set(const wax::obj &, const wax::obj &); -    uhd::usrp::subdev_spec_t _rx_subdev_spec, _tx_subdev_spec; - -    //rx and tx dboard methods and objects -    uhd::usrp::dboard_manager::sptr _dboard_manager; -    uhd::usrp::dboard_iface::sptr _dboard_iface; -    void dboard_init(void); - -    //methods and shadows for clock configuration -    uhd::clock_config_t _clock_config; -    void update_clock_config(void); -    void set_time_spec(const uhd::time_spec_t &time_spec, bool now); - -    //properties interface for the codec -    void codec_init(void); -    void rx_codec_get(const wax::obj &, wax::obj &); -    void rx_codec_set(const wax::obj &, const wax::obj &); -    void tx_codec_get(const wax::obj &, wax::obj &); -    void tx_codec_set(const wax::obj &, const wax::obj &); -    wax_obj_proxy::sptr _rx_codec_proxy; -    wax_obj_proxy::sptr _tx_codec_proxy; - -    void rx_codec_set_gain(double, const std::string &); -    uhd::dict<std::string, double> _codec_rx_gains; - -    //properties interface for rx dboard -    void rx_dboard_get(const wax::obj &, wax::obj &); -    void rx_dboard_set(const wax::obj &, const wax::obj &); -    wax_obj_proxy::sptr _rx_dboard_proxy; -    uhd::usrp::dboard_eeprom_t _rx_db_eeprom; - -    //properties interface for tx dboard -    void tx_dboard_get(const wax::obj &, wax::obj &); -    void tx_dboard_set(const wax::obj &, const wax::obj &); -    wax_obj_proxy::sptr _tx_dboard_proxy; -    uhd::usrp::dboard_eeprom_t _tx_db_eeprom, _gdb_eeprom; - -    //methods and shadows for the dsps -    UHD_PIMPL_DECL(dsp_impl) _dsp_impl; -    void dsp_init(void); -    void issue_ddc_stream_cmd(const uhd::stream_cmd_t &, size_t); - -    //properties interface for ddc -    void ddc_get(const wax::obj &, wax::obj &, size_t); -    void ddc_set(const wax::obj &, const wax::obj &, size_t); -    uhd::dict<std::string, wax_obj_proxy::sptr> _rx_dsp_proxies; - -    //properties interface for duc -    void duc_get(const wax::obj &, wax::obj &, size_t); -    void duc_set(const wax::obj &, const wax::obj &, size_t); -    uhd::dict<std::string, wax_obj_proxy::sptr> _tx_dsp_proxies; -     -    //sensors methods for mboard -    bool get_mimo_locked(void); -    bool get_ref_locked(void); -}; - -/*!   * USRP2 implementation guts:   * The implementation details are encapsulated here.   * Handles device properties and streaming...   */  class usrp2_impl : public uhd::device{  public: -    static const size_t sram_bytes = size_t(1 << 20); -    static const boost::uint32_t RECV_SID = 1; -    static const boost::uint32_t ASYNC_SID = 2; -      usrp2_impl(const uhd::device_addr_t &); -      ~usrp2_impl(void);      //the io interface @@ -199,27 +86,49 @@ public:      size_t get_max_recv_samps_per_packet(void) const;      bool recv_async_msg(uhd::async_metadata_t &, double); -    void update_xport_channel_mapping(void); - -    //public frame sizes, set by mboard, used by io impl -    size_t recv_frame_size, send_frame_size; - -    std::vector<uhd::transport::zero_copy_if::sptr> dsp_xports; -    std::vector<uhd::transport::zero_copy_if::sptr> err_xports; -  private: -    //device properties interface -    void get(const wax::obj &, wax::obj &); -    void set(const wax::obj &, const wax::obj &); +    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 &); -    //pointers to mboards on this device (think mimo setup) -    std::vector<usrp2_mboard_impl::sptr> _mboards; -    uhd::dict<std::string, usrp2_mboard_impl::sptr> _mboard_dict; +    //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/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 */ | 
