diff options
Diffstat (limited to 'host/lib')
36 files changed, 1304 insertions, 261 deletions
| diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 81845de21..e4de7bcc7 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -16,6 +16,25 @@  #  ######################################################################## +# Check Python Modules +######################################################################## +PYTHON_CHECK_MODULE( +    "Python version 2.6 or greater" +    "platform" "platform.python_version() >= '2.6'" +    HAVE_PYTHON_PLAT_MIN_VERSION +) + +PYTHON_CHECK_MODULE( +    "Cheetah templates 2.0.0 or greater" +    "Cheetah" "Cheetah.Version >= '2.0.0'" +    HAVE_PYTHON_MODULE_CHEETAH +) + +IF(NOT HAVE_PYTHON_PLAT_MIN_VERSION OR NOT HAVE_PYTHON_MODULE_CHEETAH) +    MESSAGE(FATAL_ERROR "Error: python requirements not met for the build system.") +ENDIF(NOT HAVE_PYTHON_PLAT_MIN_VERSION OR NOT HAVE_PYTHON_MODULE_CHEETAH) + +########################################################################  # Helpful Macros  ########################################################################  MACRO(LIBUHD_APPEND_SOURCES) diff --git a/host/lib/ic_reg_maps/CMakeLists.txt b/host/lib/ic_reg_maps/CMakeLists.txt index 772166334..ac051b843 100644 --- a/host/lib/ic_reg_maps/CMakeLists.txt +++ b/host/lib/ic_reg_maps/CMakeLists.txt @@ -60,6 +60,16 @@ LIBUHD_PYTHON_GEN_SOURCE(  )  LIBUHD_PYTHON_GEN_SOURCE( +    ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_max2112_regs.py +    ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/max2112_regs.hpp +) + +LIBUHD_PYTHON_GEN_SOURCE( +    ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_max2112_regs.py +    ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/max2112_regs.hpp +) + +LIBUHD_PYTHON_GEN_SOURCE(      ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_ad9862_regs.py      ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/ad9862_regs.hpp  ) diff --git a/host/lib/ic_reg_maps/gen_max2112_regs.py b/host/lib/ic_reg_maps/gen_max2112_regs.py new file mode 100755 index 000000000..c2fc4e3e2 --- /dev/null +++ b/host/lib/ic_reg_maps/gen_max2112_regs.py @@ -0,0 +1,181 @@ +#!/usr/bin/env python +# +# 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/>. +# + +######################################################################## +# Template for raw text data describing write registers +# name addr[bit range inclusive] default optional enums +######################################################################## +WRITE_REGS_TMPL="""\ +######################################################################## +## Note: offsets given from perspective of data bits (excludes address) +######################################################################## +## +######################################################################## +## N-Divider MSB (0) Write +######################################################################## +frac                  0[7]          1       invalid, frac +n_divider_msb         0[0:6]        0 +######################################################################## +## N-Divider LSB (1) Write +######################################################################## +n_divider_lsb         1[0:7]        0x23 +~n_divider            n_divider_lsb, n_divider_msb +######################################################################## +## Charge Pump (2) Write +######################################################################## +cpmp                  2[6:7]        0 +cplin                 2[4:5]        1 +f_divider_mmsb        2[0:3]        0x2 +######################################################################## +## F-Divider MSB (3) Write +######################################################################## +f_divider_msb         3[0:7]        0xF6 +######################################################################## +## F-Divider LSB (4) Write +######################################################################## +f_divider_lsb         4[0:7]        0x84  +~f_divider            f_divider_lsb, f_divider_msb, f_divider_mmsb +######################################################################## +## XTAL-Divider R-Divider (5) Write +######################################################################## +#set $xtal_divider_names = ', '.join(map(lambda x: 'div' + str(x), range(1,9))) +xtal_divider          5[5:7]        0       $xtal_divider_names +r_divider             5[0:4]        1        +######################################################################## +## PLL (6) Write +######################################################################## +d24                   6[7]          1       div2, div4  ## div2 for LO <= 1125M, div4 > 1125M +cps                   6[6]          1       i_cp_from_icp, i_cp_from_vas +icp                   6[5]          0       i_cp_600ua, i_cp_1200ua +##reserved            6[0:4]        0 +######################################################################## +## VCO (7) Write +######################################################################## +vco                   7[3:7]        0x19 +vas                   7[2]          1       disabled, enabled +adl                   7[1]          1       disabled, enabled +ade                   7[0]          1       disabled, enabled +######################################################################## +## LPF (8) Write +######################################################################## +lp                    8[0:7]        0x4B    ## map(lambda x: "%0.2f"%((4e6 + (x - 12) * 290e3)/1e6), range(255)) in MHz +######################################################################## +## Control (9) Write +######################################################################## +stby                  9[7]          0       normal, disable_sig_and_synth +##reserved            9[6]          0 +pwdn                  9[5]          0       normal, invalid +##reserved            9[4]          0 +bbg                   9[0:3]        0       ## Baseband Gain in dB +######################################################################## +## Shutdown (0xA) Write +######################################################################## +##reserved            0xA[7]        0 +pll_shutdown          0xA[6]        0       normal, shutdown +div_shutdown          0xA[5]        0       normal, shutdown +vco_shutdown          0xA[4]        0       normal, shutdown +bb_shutdown           0xA[3]        0       normal, shutdown +rfmix_shutdown        0xA[2]        0       normal, shutdown +rfvga_shutdown        0xA[1]        0       normal, shutdown +fe_shutdown           0xA[0]        0       normal, shutdown +######################################################################## +## Test (0xB) Write +######################################################################## +cptst                 0xB[5:7]      0 +##reserved            0xB[4]        0 +turbo                 0xB[3]        1 +ld_mux                0xB[0:2]      0       refout=0, invalid +""" + +######################################################################## +# Template for raw text data describing read registers +# name addr[bit range inclusive] default optional enums +######################################################################## +READ_REGS_TMPL="""\ +######################################################################## +## Status Byte-1 (0xC) Read +######################################################################## +por                   0xC[7]        0       read, reset +vasa                  0xC[6]        0       vas_fail, vas_win +vase                  0xC[5]        0       active, inactive +ld                    0xC[4]        0       unlocked, locked +##reserved            0xC[0:3]      0 +######################################################################## +## Status Byte-2 (0xD) Read +######################################################################## +vcosbr                0xD[3:7]      0       ## vco band readback +adc                   0xD[0:2]      0       ool0, lock0, vaslock0, vaslock1, vaslock2, vaslock3, lock1, ool1 +""" + +######################################################################## +# Template for methods in the body of the struct +######################################################################## +BODY_TMPL="""\ +boost::uint8_t get_reg(boost::uint8_t addr){ +    boost::uint8_t reg = 0; +    switch(addr){ +    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) +    case $addr: +        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) +        reg |= (boost::uint8_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); +        #end for +        break; +    #end for +    } +    return boost::uint8_t(reg); +} + +void set_reg(boost::uint8_t addr, boost::uint8_t reg){ +    switch(addr){ +    #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) +    case $addr: +        #for $reg in filter(lambda r: r.get_addr() == addr, $regs) +        $reg.get_name() = $(reg.get_type())((reg >> $reg.get_shift()) & $reg.get_mask()); +        #end for +        break; +    #end for +    } +} +""" + +SPLIT_REGS_HELPER_TMPL="""\ +#for $divname in ['n','f'] +void set_$(divname)_divider(boost::uint32_t $divname){ +    #for $regname in sorted(map(lambda r: r.get_name(), filter(lambda r: r.get_name().find(divname + '_divider') == 0, $regs))) +    #end for +} +#end for +""" +    #$regname = boost::uint8_t($divname & $regs[regname].get_mask()); +    #$divname = boost::uint32_t($divname >> $regs[regname].get_shift()); + +if __name__ == '__main__': +    import common; common.generate( +        name='max2112_write_regs', +        regs_tmpl=WRITE_REGS_TMPL, +        body_tmpl=BODY_TMPL, +        file=__file__, +    ) + +    import common; common.generate( +        name='max2112_read_regs', +        regs_tmpl=READ_REGS_TMPL, +        body_tmpl=BODY_TMPL, +        file=__file__, +        append=True, +    ) diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index d84aeefdd..ed29864e9 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -336,7 +336,7 @@ template<typename Opt> static void resize_buff_helper(          else std::cout << boost::format(              "Current %s sock buff size: %d bytes"          ) % name % actual_size << std::endl; -        if (actual_size < target_size) uhd::print_warning(str(boost::format( +        if (actual_size < target_size) uhd::warning::post(str(boost::format(              "The %s buffer is smaller than the requested size.\n"              "The minimum recommended buffer size is %d bytes.\n"              "See the transport application notes on buffer resizing.\n%s" diff --git a/host/lib/types.cpp b/host/lib/types.cpp index 6aa82b012..e5e6a2512 100644 --- a/host/lib/types.cpp +++ b/host/lib/types.cpp @@ -17,6 +17,7 @@  #include <uhd/utils/assert.hpp>  #include <uhd/types/ranges.hpp> +#include <uhd/types/tune_request.hpp>  #include <uhd/types/tune_result.hpp>  #include <uhd/types/clock_config.hpp>  #include <uhd/types/stream_cmd.hpp> @@ -58,6 +59,26 @@ freq_range_t::freq_range_t(double min, double max):  }  /*********************************************************************** + * tune request + **********************************************************************/ +tune_request_t::tune_request_t(double target_freq): +    target_freq(target_freq), +    inter_freq_policy(POLICY_AUTO), +    dsp_freq_policy(POLICY_AUTO) +{ +    /* NOP */ +} + +tune_request_t::tune_request_t(double target_freq, double lo_off): +    target_freq(target_freq), +    inter_freq_policy(POLICY_MANUAL), +    inter_freq(target_freq + lo_off), +    dsp_freq_policy(POLICY_AUTO) +{ +    /* NOP */ +} + +/***********************************************************************   * tune result   **********************************************************************/  std::string tune_result_t::to_pp_string(void) const{ @@ -229,22 +250,19 @@ mac_addr_t mac_addr_t::from_bytes(const byte_vector_t &bytes){  mac_addr_t mac_addr_t::from_string(const std::string &mac_addr_str){ -    byte_vector_t bytes = boost::assign::list_of -        (0x00)(0x50)(0xC2)(0x85)(0x30)(0x00); // Matt's IAB +    byte_vector_t bytes;      try{ -        //only allow patterns of xx:xx or xx:xx:xx:xx:xx:xx -        //the IAB above will fill in for the shorter pattern -        if (mac_addr_str.size() != 5 and mac_addr_str.size() != 17) -            throw std::runtime_error("expected exactly 5 or 17 characters"); +        if (mac_addr_str.size() != 17){ +            throw std::runtime_error("expected exactly 17 characters"); +        }          //split the mac addr hex string at the colons -        size_t i = 0;          BOOST_FOREACH(const std::string &hex_str, std::split_string(mac_addr_str, ":")){              int hex_num;              std::istringstream iss(hex_str);              iss >> std::hex >> hex_num; -            bytes[i++] = boost::uint8_t(hex_num); +            bytes.push_back(boost::uint8_t(hex_num));          }      } diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt index eeb181e0b..3d832c356 100644 --- a/host/lib/usrp/CMakeLists.txt +++ b/host/lib/usrp/CMakeLists.txt @@ -23,6 +23,7 @@ LIBUHD_APPEND_SOURCES(      ${CMAKE_SOURCE_DIR}/lib/usrp/dboard_id.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/dboard_manager.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/dsp_utils.cpp +    ${CMAKE_SOURCE_DIR}/lib/usrp/mboard_eeprom.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/misc_utils.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/multi_usrp.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/single_usrp.cpp diff --git a/host/lib/usrp/dboard/CMakeLists.txt b/host/lib/usrp/dboard/CMakeLists.txt index 8d3d11530..79cd42d18 100644 --- a/host/lib/usrp/dboard/CMakeLists.txt +++ b/host/lib/usrp/dboard/CMakeLists.txt @@ -25,5 +25,6 @@ LIBUHD_APPEND_SOURCES(      ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_dbsrx.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_unknown.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_tvrx.cpp +    ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_dbsrx2.cpp  ) diff --git a/host/lib/usrp/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp index 41f6f8002..f03dd43d1 100644 --- a/host/lib/usrp/dboard/db_basic_and_lf.cpp +++ b/host/lib/usrp/dboard/db_basic_and_lf.cpp @@ -20,6 +20,7 @@  #include <uhd/types/ranges.hpp>  #include <uhd/utils/assert.hpp>  #include <uhd/utils/static.hpp> +#include <uhd/utils/warning.hpp>  #include <uhd/usrp/dboard_base.hpp>  #include <uhd/usrp/dboard_manager.hpp>  #include <boost/assign/list_of.hpp> @@ -30,6 +31,16 @@ using namespace uhd::usrp;  using namespace boost::assign;  /*********************************************************************** + * Constants + **********************************************************************/ +static const uhd::dict<std::string, double> subdev_bandwidth_scalar = map_list_of +    ("A", 1.0) +    ("B", 1.0) +    ("AB", 2.0) +    ("BA", 2.0) +; + +/***********************************************************************   * The basic and lf boards:   *   They share a common class because only the frequency bounds differ.   **********************************************************************/ @@ -68,11 +79,11 @@ static const uhd::dict<std::string, subdev_conn_t> sd_name_to_conn = map_list_of   * Register the basic and LF dboards   **********************************************************************/  static dboard_base::sptr make_basic_rx(dboard_base::ctor_args_t args){ -    return dboard_base::sptr(new basic_rx(args, 90e9)); +    return dboard_base::sptr(new basic_rx(args, 250e6));  }  static dboard_base::sptr make_basic_tx(dboard_base::ctor_args_t args){ -    return dboard_base::sptr(new basic_tx(args, 90e9)); +    return dboard_base::sptr(new basic_tx(args, 250e6));  }  static dboard_base::sptr make_lf_rx(dboard_base::ctor_args_t args){ @@ -161,6 +172,10 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){          val = true; //there is no LO, so it must be true!          return; +    case SUBDEV_PROP_BANDWIDTH: +        val = subdev_bandwidth_scalar[get_subdev_name()]*_max_freq; +        return; +      default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -185,6 +200,14 @@ void basic_rx::rx_set(const wax::obj &key_, const wax::obj &val){      case SUBDEV_PROP_ENABLED:          return; //always enabled +    case SUBDEV_PROP_BANDWIDTH: +        uhd::warning::post( +            str(boost::format("%s: No tunable bandwidth, fixed filtered to %0.2fMHz") +                % get_rx_id().to_pp_string() % _max_freq +            ) +        ); +        return; +      default: UHD_THROW_PROP_SET_ERROR();      }  } @@ -260,6 +283,10 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){          val = true; //there is no LO, so it must be true!          return; +    case SUBDEV_PROP_BANDWIDTH: +        val = subdev_bandwidth_scalar[get_subdev_name()]*_max_freq; +        return; +      default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -284,6 +311,14 @@ void basic_tx::tx_set(const wax::obj &key_, const wax::obj &val){      case SUBDEV_PROP_ENABLED:          return; //always enabled +    case SUBDEV_PROP_BANDWIDTH: +        uhd::warning::post( +            str(boost::format("%s: No tunable bandwidth, fixed filtered to %0.2fMHz") +                % get_tx_id().to_pp_string() % _max_freq +            ) +        ); +        return; +      default: UHD_THROW_PROP_SET_ERROR();      }  } diff --git a/host/lib/usrp/dboard/db_dbsrx.cpp b/host/lib/usrp/dboard/db_dbsrx.cpp index 0b8b4db83..85251bdf9 100644 --- a/host/lib/usrp/dboard/db_dbsrx.cpp +++ b/host/lib/usrp/dboard/db_dbsrx.cpp @@ -175,7 +175,7 @@ UHD_STATIC_BLOCK(reg_dbsrx_dboard){  dbsrx::dbsrx(ctor_args_t args) : rx_dboard_base(args){      //warn user about incorrect DBID on USRP1, requires R193 populated      if (this->get_iface()->get_special_props().soft_clock_divider and this->get_rx_id() == 0x000D) -        uhd::print_warning( +        uhd::warning::post(              str(boost::format(                  "DBSRX: incorrect dbid\n"                  "Expected dbid 0x0002 and R193\n" @@ -186,7 +186,7 @@ dbsrx::dbsrx(ctor_args_t args) : rx_dboard_base(args){      //warn user about incorrect DBID on non-USRP1, requires R194 populated      if (not this->get_iface()->get_special_props().soft_clock_divider and this->get_rx_id() == 0x0002) -        uhd::print_warning( +        uhd::warning::post(              str(boost::format(                  "DBSRX: incorrect dbid\n"                  "Expected dbid 0x000D and R194\n" @@ -236,8 +236,10 @@ void dbsrx::set_lo_freq(double target_freq){      bool update_filter_settings = false;      //choose refclock      std::vector<double> clock_rates = this->get_iface()->get_clock_rates(dboard_iface::UNIT_RX); +    const double max_clock_rate = std::sorted(clock_rates).back();      BOOST_FOREACH(ref_clock, std::reversed(std::sorted(clock_rates))){          if (ref_clock > 27.0e6) continue; +        if (size_t(max_clock_rate/ref_clock)%2 == 1) continue; //reject asymmetric clocks (odd divisors)          //choose m_divider such that filter tuning constraint is met          m = 31; @@ -340,7 +342,7 @@ void dbsrx::set_lo_freq(double target_freq){          //vtune is too low, try lower frequency vco          if (_max2118_read_regs.adc == 0){              if (_max2118_write_regs.osc_band == 0){ -                uhd::print_warning( +                uhd::warning::post(                      str(boost::format(                          "DBSRX: Tuning exceeded vco range, _max2118_write_regs.osc_band == %d\n"                           ) % int(_max2118_write_regs.osc_band)) @@ -354,7 +356,7 @@ void dbsrx::set_lo_freq(double target_freq){          //vtune is too high, try higher frequency vco          if (_max2118_read_regs.adc == 7){              if (_max2118_write_regs.osc_band == 7){ -                uhd::print_warning( +                uhd::warning::post(                      str(boost::format(                          "DBSRX: Tuning exceeded vco range, _max2118_write_regs.osc_band == %d\n"                           ) % int(_max2118_write_regs.osc_band)) @@ -561,7 +563,7 @@ void dbsrx::rx_get(const wax::obj &key_, wax::obj &val){          return;      case SUBDEV_PROP_BANDWIDTH: -        val = _bandwidth; +        val = 2*_bandwidth; //_bandwidth is low-pass, we want complex double-sided          return;      default: UHD_THROW_PROP_GET_ERROR(); @@ -586,7 +588,7 @@ void dbsrx::rx_set(const wax::obj &key_, const wax::obj &val){          return; //always enabled      case SUBDEV_PROP_BANDWIDTH: -        this->set_bandwidth(val.as<double>()); +        this->set_bandwidth(val.as<double>()/2.0); //complex double-sided, we want low-pass          return;      default: UHD_THROW_PROP_SET_ERROR(); diff --git a/host/lib/usrp/dboard/db_dbsrx2.cpp b/host/lib/usrp/dboard/db_dbsrx2.cpp new file mode 100644 index 000000000..5a65e6123 --- /dev/null +++ b/host/lib/usrp/dboard/db_dbsrx2.cpp @@ -0,0 +1,439 @@ +// +// 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/>. +// + +// No RX IO Pins Used + +#include "max2112_regs.hpp" +#include <uhd/utils/static.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/utils/algorithm.hpp> +#include <uhd/types/ranges.hpp> +#include <uhd/types/dict.hpp> +#include <uhd/usrp/subdev_props.hpp> +#include <uhd/usrp/dboard_base.hpp> +#include <uhd/usrp/dboard_manager.hpp> +#include <boost/assign/list_of.hpp> +#include <boost/format.hpp> +#include <boost/thread.hpp> +#include <boost/math/special_functions/round.hpp> +#include <utility> + +using namespace uhd; +using namespace uhd::usrp; +using namespace boost::assign; + +/*********************************************************************** + * The DBSRX2 constants + **********************************************************************/ +static const bool dbsrx2_debug = false; + +static const freq_range_t dbsrx2_freq_range(0.8e9, 2.4e9); + +static const int dbsrx2_ref_divider = 4; // Hitachi HMC426 divider (U7) + +static const prop_names_t dbsrx2_antennas = list_of("J3"); + +static const uhd::dict<std::string, gain_range_t> dbsrx2_gain_ranges = map_list_of +    ("GC1", gain_range_t(0, 73, float(0.05))) +    ("BBG", gain_range_t(0, 15, 1)) +; + +/*********************************************************************** + * The DBSRX2 dboard class + **********************************************************************/ +class dbsrx2 : public rx_dboard_base{ +public: +    dbsrx2(ctor_args_t args); +    ~dbsrx2(void); + +    void rx_get(const wax::obj &key, wax::obj &val); +    void rx_set(const wax::obj &key, const wax::obj &val); + +private: +    double _lo_freq; +    double _bandwidth; +    uhd::dict<std::string, float> _gains; +    max2112_write_regs_t _max2112_write_regs; +    max2112_read_regs_t _max2112_read_regs; +    boost::uint8_t _max2112_addr(){ //0x60 or 0x61 depending on which side +        return (this->get_iface()->get_special_props().mangle_i2c_addrs)? 0x60 : 0x61; +    } + +    void set_lo_freq(double target_freq); +    void set_gain(float gain, const std::string &name); +    void set_bandwidth(double bandwidth); + +    void send_reg(boost::uint8_t start_reg, boost::uint8_t stop_reg){ +        start_reg = boost::uint8_t(std::clip(int(start_reg), 0x0, 0xB)); +        stop_reg = boost::uint8_t(std::clip(int(stop_reg), 0x0, 0xB)); + +        for(boost::uint8_t start_addr=start_reg; start_addr <= stop_reg; start_addr += sizeof(boost::uint32_t) - 1){ +            int num_bytes = int(stop_reg - start_addr + 1) > int(sizeof(boost::uint32_t)) - 1 ? sizeof(boost::uint32_t) - 1 : stop_reg - start_addr + 1; + +            //create buffer for register data (+1 for start address) +            byte_vector_t regs_vector(num_bytes + 1); + +            //first byte is the address of first register +            regs_vector[0] = start_addr; + +            //get the register data +            for(int i=0; i<num_bytes; i++){ +                regs_vector[1+i] = _max2112_write_regs.get_reg(start_addr+i); +                if(dbsrx2_debug) std::cerr << boost::format( +                    "DBSRX2: send reg 0x%02x, value 0x%04x, start_addr = 0x%04x, num_bytes %d" +                ) % int(start_addr+i) % int(regs_vector[1+i]) % int(start_addr) % num_bytes << std::endl; +            } + +            //send the data +            this->get_iface()->write_i2c( +                _max2112_addr(), regs_vector +            ); +        } +    } + +    void read_reg(boost::uint8_t start_reg, boost::uint8_t stop_reg){ +        static const boost::uint8_t status_addr = 0xC; +        start_reg = boost::uint8_t(std::clip(int(start_reg), 0x0, 0xD)); +        stop_reg = boost::uint8_t(std::clip(int(stop_reg), 0x0, 0xD)); + +        for(boost::uint8_t start_addr=start_reg; start_addr <= stop_reg; start_addr += sizeof(boost::uint32_t)){ +            int num_bytes = int(stop_reg - start_addr + 1) > int(sizeof(boost::uint32_t)) ? sizeof(boost::uint32_t) : stop_reg - start_addr + 1; + +            //create address to start reading register data +            byte_vector_t address_vector(1); +            address_vector[0] = start_addr; + +            //send the address +            this->get_iface()->write_i2c( +                _max2112_addr(), address_vector +            ); + +            //create buffer for register data +            byte_vector_t regs_vector(num_bytes); + +            //read from i2c +            regs_vector = this->get_iface()->read_i2c( +                _max2112_addr(), num_bytes +            ); + +            for(boost::uint8_t i=0; i < num_bytes; i++){ +                if (i + start_addr >= status_addr){ +                    _max2112_read_regs.set_reg(i + start_addr, regs_vector[i]); +                    /* +                    if(dbsrx2_debug) std::cerr << boost::format( +                        "DBSRX2: set reg 0x%02x, value 0x%04x" +                    ) % int(i + start_addr) % int(_max2112_read_regs.get_reg(i + start_addr)) << std::endl; +                    */ +                } +                if(dbsrx2_debug) std::cerr << boost::format( +                    "DBSRX2: read reg 0x%02x, value 0x%04x, start_addr = 0x%04x, num_bytes %d" +                ) % int(start_addr+i) % int(regs_vector[i]) % int(start_addr) % num_bytes << std::endl; +            } +        } +    } + +    /*! +     * Is the LO locked? +     * \return true for locked +     */ +    bool get_locked(void){ +        read_reg(0xC, 0xD); + +        //mask and return lock detect +        bool locked = (_max2112_read_regs.ld & _max2112_read_regs.vasa & _max2112_read_regs.vase) != 0; + +        if(dbsrx2_debug) std::cerr << boost::format( +            "DBSRX2 locked: %d" +        ) % locked << std::endl; + +        return locked; +    } + +}; + +/*********************************************************************** + * Register the DBSRX2 dboard + **********************************************************************/ +// FIXME 0x67 is the default i2c address on USRP2 +//       need to handle which side for USRP1 with different address +static dboard_base::sptr make_dbsrx2(dboard_base::ctor_args_t args){ +    return dboard_base::sptr(new dbsrx2(args)); +} + +UHD_STATIC_BLOCK(reg_dbsrx2_dboard){ +    //register the factory function for the rx dbid +    dboard_manager::register_dboard(0x0012, &make_dbsrx2, "DBSRX2"); +} + +/*********************************************************************** + * Structors + **********************************************************************/ +dbsrx2::dbsrx2(ctor_args_t args) : rx_dboard_base(args){ +    //enable only the clocks we need +    this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true); + +    //set the gpio directions and atr controls (identically) +    this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, 0x0); // All unused in atr +    this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, 0x0); // All Inputs + +    //send initial register settings +    send_reg(0x0, 0xB); +    //for (boost::uint8_t addr=0; addr<=12; addr++) this->send_reg(addr, addr); + +    //set defaults for LO, gains +    set_lo_freq(dbsrx2_freq_range.min); +    BOOST_FOREACH(const std::string &name, dbsrx2_gain_ranges.keys()){ +        set_gain(dbsrx2_gain_ranges[name].min, name); +    } + +    set_bandwidth(40e6); // default bandwidth from datasheet +    get_locked(); + +    _max2112_write_regs.bbg = boost::math::iround(std::clip<float>(0, dbsrx2_gain_ranges["BBG"].min, dbsrx2_gain_ranges["BBG"].max)); +    send_reg(0x9, 0x9); +} + +dbsrx2::~dbsrx2(void){ +} + + +/*********************************************************************** + * Tuning + **********************************************************************/ +void dbsrx2::set_lo_freq(double target_freq){ +    //target_freq = std::clip(target_freq, dbsrx2_freq_range.min, dbsrx2_freq_range.max); + +    //variables used in the calculation below +    int scaler = target_freq > 1125e6 ? 2 : 4; +    double ref_freq = this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX); +    int R, intdiv, fracdiv, ext_div; +    double N; + +    //compute tuning variables +    ext_div = dbsrx2_ref_divider; // 12MHz < ref_freq/ext_divider < 30MHz + +    R = 1; //Divide by 1 is the only tested value + +    N = (target_freq*R*ext_div)/(ref_freq); //actual spec range is (19, 251) +    intdiv = int(std::floor(N)); //  if (intdiv < 19  or intdiv > 251) continue; +    fracdiv = boost::math::iround((N - intdiv)*double(1 << 20)); + +    //calculate the actual freq from the values above +    N = double(intdiv) + double(fracdiv)/double(1 << 20); +    _lo_freq = (N*ref_freq)/(R*ext_div); + +    //load new counters into registers +    _max2112_write_regs.set_n_divider(intdiv); +    _max2112_write_regs.set_f_divider(fracdiv); +    _max2112_write_regs.r_divider = R; +    _max2112_write_regs.d24 = scaler == 4 ? max2112_write_regs_t::D24_DIV4 : max2112_write_regs_t::D24_DIV2; + +    //debug output of calculated variables +    if (dbsrx2_debug) std::cerr +        << boost::format("DBSRX2 tune:\n") +        << boost::format("    R=%d, N=%f, scaler=%d, ext_div=%d\n") % R % N % scaler % ext_div +        << boost::format("    int=%d, frac=%d, d24=%d\n") % intdiv % fracdiv % int(_max2112_write_regs.d24) +        << boost::format("    Ref    Freq=%fMHz\n") % (ref_freq/1e6) +        << boost::format("    Target Freq=%fMHz\n") % (target_freq/1e6) +        << boost::format("    Actual Freq=%fMHz\n") % (_lo_freq/1e6) +        << std::endl; + +    //send the registers +    send_reg(0x0, 0x7); + +    //FIXME: probably unnecessary to call get_locked here +    //get_locked(); + +} + +/*********************************************************************** + * Gain Handling + **********************************************************************/ +/*! + * Convert a requested gain for the BBG vga into the integer register value. + * The gain passed into the function will be set to the actual value. + * \param gain the requested gain in dB + * \return 4 bit the register value + */ +static int gain_to_bbg_vga_reg(float &gain){ +    int reg = boost::math::iround(std::clip<float>(gain, dbsrx2_gain_ranges["BBG"].min, dbsrx2_gain_ranges["BBG"].max)); + +    gain = float(reg); + +    if (dbsrx2_debug) std::cerr  +        << boost::format("DBSRX2 BBG Gain:\n") +        << boost::format("    %f dB, bbg: %d") % gain % reg  +        << std::endl; + +    return reg; +} + +/*! + * Convert a requested gain for the GC1 rf vga into the dac_volts value. + * The gain passed into the function will be set to the actual value. + * \param gain the requested gain in dB + * \return dac voltage value + */ +static float gain_to_gc1_rfvga_dac(float &gain){ +    //clip the input +    gain = std::clip<float>(gain, dbsrx2_gain_ranges["GC1"].min, dbsrx2_gain_ranges["GC1"].max); + +    //voltage level constants +    static const float max_volts = float(0.5), min_volts = float(2.7); +    static const float slope = (max_volts-min_volts)/dbsrx2_gain_ranges["GC1"].max; + +    //calculate the voltage for the aux dac +    float dac_volts = gain*slope + min_volts; + +    if (dbsrx2_debug) std::cerr  +        << boost::format("DBSRX2 GC1 Gain:\n") +        << boost::format("    %f dB, dac_volts: %f V") % gain % dac_volts  +        << std::endl; + +    //the actual gain setting +    gain = (dac_volts - min_volts)/slope; + +    return dac_volts; +} + +void dbsrx2::set_gain(float gain, const std::string &name){ +    assert_has(dbsrx2_gain_ranges.keys(), name, "dbsrx2 gain name"); +    if (name == "BBG"){ +        _max2112_write_regs.bbg = gain_to_bbg_vga_reg(gain); +        send_reg(0x9, 0x9); +    } +    else if(name == "GC1"){ +        //write the new voltage to the aux dac +        this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_A, gain_to_gc1_rfvga_dac(gain)); +    } +    else UHD_THROW_INVALID_CODE_PATH(); +    _gains[name] = gain; +} + +/*********************************************************************** + * Bandwidth Handling + **********************************************************************/ +void dbsrx2::set_bandwidth(double bandwidth){ +    //clip the input +    bandwidth = std::clip<double>(bandwidth, 4e6, 40e6); + +    _max2112_write_regs.lp = int((bandwidth/1e6 - 4)/0.29 + 12); +    _bandwidth = double(4 + (_max2112_write_regs.lp - 12) * 0.29)*1e6; + +    if (dbsrx2_debug) std::cerr  +        << boost::format("DBSRX2 Bandwidth:\n") +        << boost::format("    %f MHz, lp: %f V") % (_bandwidth/1e6) % int(_max2112_write_regs.lp) +        << std::endl; + +    this->send_reg(0x8, 0x8); +} + +/*********************************************************************** + * RX Get and Set + **********************************************************************/ +void dbsrx2::rx_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<subdev_prop_t>()){ +    case SUBDEV_PROP_NAME: +        val = get_rx_id().to_pp_string(); +        return; + +    case SUBDEV_PROP_OTHERS: +        val = prop_names_t(); //empty +        return; + +    case SUBDEV_PROP_GAIN: +        assert_has(_gains.keys(), key.name, "dbsrx2 gain name"); +        val = _gains[key.name]; +        return; + +    case SUBDEV_PROP_GAIN_RANGE: +        assert_has(dbsrx2_gain_ranges.keys(), key.name, "dbsrx2 gain name"); +        val = dbsrx2_gain_ranges[key.name]; +        return; + +    case SUBDEV_PROP_GAIN_NAMES: +        val = prop_names_t(dbsrx2_gain_ranges.keys()); +        return; + +    case SUBDEV_PROP_FREQ: +        val = _lo_freq; +        return; + +    case SUBDEV_PROP_FREQ_RANGE: +        val = dbsrx2_freq_range; +        return; + +    case SUBDEV_PROP_ANTENNA: +        val = std::string("J3"); +        return; + +    case SUBDEV_PROP_ANTENNA_NAMES: +        val = dbsrx2_antennas; +        return; + +    case SUBDEV_PROP_CONNECTION: +        val = SUBDEV_CONN_COMPLEX_QI; +        return; + +    case SUBDEV_PROP_ENABLED: +        val = true; //always enabled +        return; + +    case SUBDEV_PROP_USE_LO_OFFSET: +        val = false; +        return; + +    case SUBDEV_PROP_LO_LOCKED: +        val = this->get_locked(); +        return; + +    case SUBDEV_PROP_BANDWIDTH: +        val = _bandwidth; +        return; + +    default: UHD_THROW_PROP_GET_ERROR(); +    } +} + +void dbsrx2::rx_set(const wax::obj &key_, const wax::obj &val){ +    named_prop_t key = named_prop_t::extract(key_); + +    //handle the get request conditioned on the key +    switch(key.as<subdev_prop_t>()){ + +    case SUBDEV_PROP_FREQ: +        this->set_lo_freq(val.as<double>()); +        return; + +    case SUBDEV_PROP_GAIN: +        this->set_gain(val.as<float>(), key.name); +        return; + +    case SUBDEV_PROP_ENABLED: +        return; //always enabled + +    case SUBDEV_PROP_BANDWIDTH: +        this->set_bandwidth(val.as<double>()); +        return; + +    default: UHD_THROW_PROP_SET_ERROR(); +    } +} + diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp index 3c24d90db..152198c3a 100644 --- a/host/lib/usrp/dboard/db_rfx.cpp +++ b/host/lib/usrp/dboard/db_rfx.cpp @@ -43,6 +43,7 @@  #include <uhd/utils/assert.hpp>  #include <uhd/utils/static.hpp>  #include <uhd/utils/algorithm.hpp> +#include <uhd/utils/warning.hpp>  #include <uhd/usrp/dboard_id.hpp>  #include <uhd/usrp/dboard_base.hpp>  #include <uhd/usrp/dboard_manager.hpp> @@ -456,6 +457,10 @@ void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){          val = this->get_locked(dboard_iface::UNIT_RX);          return; +    case SUBDEV_PROP_BANDWIDTH: +        val = 2*20.0e6; //20MHz low-pass, we want complex double-sided +        return; +      default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -481,6 +486,12 @@ void rfx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){      case SUBDEV_PROP_ENABLED:          return; //always enabled +    case SUBDEV_PROP_BANDWIDTH: +        uhd::warning::post( +            str(boost::format("RFX: No tunable bandwidth, fixed filtered to 40MHz")) +        ); +        return; +      default: UHD_THROW_PROP_SET_ERROR();      }  } @@ -543,6 +554,10 @@ void rfx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){          val = this->get_locked(dboard_iface::UNIT_TX);          return; +    case SUBDEV_PROP_BANDWIDTH: +        val = 2*20.0e6; //20MHz low-pass, we want complex double-sided +        return; +      default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -568,6 +583,12 @@ void rfx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){      case SUBDEV_PROP_ENABLED:          return; //always enabled +    case SUBDEV_PROP_BANDWIDTH: +        uhd::warning::post( +            str(boost::format("RFX: No tunable bandwidth, fixed filtered to 40MHz")) +        ); +        return; +      default: UHD_THROW_PROP_SET_ERROR();      }  } diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp index d39dc3bf8..2873e3d54 100644 --- a/host/lib/usrp/dboard/db_tvrx.cpp +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -459,6 +459,10 @@ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){          val = true;          return; +    case SUBDEV_PROP_BANDWIDTH: +        val = 6.0e6; +        return; +      default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -479,6 +483,12 @@ void tvrx::rx_set(const wax::obj &key_, const wax::obj &val){      case SUBDEV_PROP_ENABLED:          return; //always enabled +    case SUBDEV_PROP_BANDWIDTH: +        uhd::warning::post( +            str(boost::format("TVRX: No tunable bandwidth, fixed filtered to 6MHz")) +        ); +        return; +      default: UHD_THROW_PROP_SET_ERROR();      }  } diff --git a/host/lib/usrp/dboard/db_unknown.cpp b/host/lib/usrp/dboard/db_unknown.cpp index ec7ab440b..d0359d124 100644 --- a/host/lib/usrp/dboard/db_unknown.cpp +++ b/host/lib/usrp/dboard/db_unknown.cpp @@ -19,23 +19,52 @@  #include <uhd/types/ranges.hpp>  #include <uhd/utils/assert.hpp>  #include <uhd/utils/static.hpp> +#include <uhd/utils/warning.hpp>  #include <uhd/usrp/dboard_base.hpp>  #include <uhd/usrp/dboard_manager.hpp>  #include <boost/assign/list_of.hpp>  #include <boost/format.hpp> +#include <boost/foreach.hpp> +#include <boost/tuple/tuple.hpp> +#include <vector>  using namespace uhd;  using namespace uhd::usrp;  using namespace boost::assign;  /*********************************************************************** + * Utility functions + **********************************************************************/ +static void warn_if_old_rfx(const dboard_id_t &dboard_id, const std::string &xx){ +    typedef boost::tuple<std::string, dboard_id_t, dboard_id_t> old_ids_t; //name, rx_id, tx_id +    static const std::vector<old_ids_t> old_rfx_ids = list_of +        (old_ids_t("Flex 400 Classic",  0x0004, 0x0008)) +        (old_ids_t("Flex 900 Classic",  0x0005, 0x0009)) +        (old_ids_t("Flex 1200 Classic", 0x0006, 0x000a)) +        (old_ids_t("Flex 1800 Classic", 0x0030, 0x0031)) +        (old_ids_t("Flex 2400 Classic", 0x0007, 0x000b)) +    ; +    BOOST_FOREACH(const old_ids_t &old_id, old_rfx_ids){ +        std::string name; dboard_id_t rx_id, tx_id; +        boost::tie(name, rx_id, tx_id) = old_id; +        if ( +            (xx == "RX" and rx_id == dboard_id) or +            (xx == "TX" and tx_id == dboard_id) +        ) uhd::warning::post(str(boost::format( +            "Detected %s daughterboard %s\n" +            "This board requires modification to use.\n" +            "See the daughterboard application notes.\n" +        ) % xx % name)); +    } +} + +/***********************************************************************   * The unknown boards:   *   Like a basic board, but with only one subdev.   **********************************************************************/  class unknown_rx : public rx_dboard_base{  public:      unknown_rx(ctor_args_t args); -    ~unknown_rx(void);      void rx_get(const wax::obj &key, wax::obj &val);      void rx_set(const wax::obj &key, const wax::obj &val); @@ -44,7 +73,6 @@ public:  class unknown_tx : public tx_dboard_base{  public:      unknown_tx(ctor_args_t args); -    ~unknown_tx(void);      void tx_get(const wax::obj &key, wax::obj &val);      void tx_set(const wax::obj &key, const wax::obj &val); @@ -70,11 +98,7 @@ UHD_STATIC_BLOCK(reg_unknown_dboards){   * Unknown RX dboard   **********************************************************************/  unknown_rx::unknown_rx(ctor_args_t args) : rx_dboard_base(args){ -    /* NOP */ -} - -unknown_rx::~unknown_rx(void){ -    /* NOP */ +    warn_if_old_rfx(this->get_rx_id(), "RX");  }  void unknown_rx::rx_get(const wax::obj &key_, wax::obj &val){ @@ -134,6 +158,10 @@ void unknown_rx::rx_get(const wax::obj &key_, wax::obj &val){          val = true; //there is no LO, so it must be true!          return; +    case SUBDEV_PROP_BANDWIDTH: +        val = 0.0; +        return; +      default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -158,19 +186,21 @@ void unknown_rx::rx_set(const wax::obj &key_, const wax::obj &val){      case SUBDEV_PROP_ENABLED:          return; //always enabled +    case SUBDEV_PROP_BANDWIDTH: +        uhd::warning::post( +            str(boost::format("Unknown Daughterboard: No tunable bandwidth, fixed filtered to 0.0MHz")) +        ); +        return; +      default: UHD_THROW_PROP_SET_ERROR();      }  }  /*********************************************************************** - * Basic and LF TX dboard + * Unknown TX dboard   **********************************************************************/  unknown_tx::unknown_tx(ctor_args_t args) : tx_dboard_base(args){ -    /* NOP */ -} - -unknown_tx::~unknown_tx(void){ -    /* NOP */ +    warn_if_old_rfx(this->get_tx_id(), "TX");  }  void unknown_tx::tx_get(const wax::obj &key_, wax::obj &val){ @@ -230,6 +260,10 @@ void unknown_tx::tx_get(const wax::obj &key_, wax::obj &val){          val = true; //there is no LO, so it must be true!          return; +    case SUBDEV_PROP_BANDWIDTH: +        val = 0.0; +        return; +      default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -254,6 +288,12 @@ void unknown_tx::tx_set(const wax::obj &key_, const wax::obj &val){      case SUBDEV_PROP_ENABLED:          return; //always enabled +    case SUBDEV_PROP_BANDWIDTH: +        uhd::warning::post( +            str(boost::format("Unknown Daughterboard: No tunable bandwidth, fixed filtered to 0.0MHz")) +        ); +        return; +      default: UHD_THROW_PROP_SET_ERROR();      }  } diff --git a/host/lib/usrp/dboard/db_wbx.cpp b/host/lib/usrp/dboard/db_wbx.cpp index 907268aac..572f5de97 100644 --- a/host/lib/usrp/dboard/db_wbx.cpp +++ b/host/lib/usrp/dboard/db_wbx.cpp @@ -71,6 +71,7 @@  #include <uhd/utils/assert.hpp>  #include <uhd/utils/static.hpp>  #include <uhd/utils/algorithm.hpp> +#include <uhd/utils/warning.hpp>  #include <uhd/usrp/dboard_base.hpp>  #include <uhd/usrp/dboard_manager.hpp>  #include <boost/assign/list_of.hpp> @@ -525,6 +526,10 @@ void wbx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){          val = this->get_locked(dboard_iface::UNIT_RX);          return; +    case SUBDEV_PROP_BANDWIDTH: +        val = 2*20.0e6; //20MHz low-pass, we want complex double-sided +        return; +      default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -550,6 +555,12 @@ void wbx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){      case SUBDEV_PROP_ENABLED:          return; //always enabled +    case SUBDEV_PROP_BANDWIDTH: +        uhd::warning::post( +            str(boost::format("WBX: No tunable bandwidth, fixed filtered to 40MHz")) +        ); +        return; +      default: UHD_THROW_PROP_SET_ERROR();      }  } @@ -616,6 +627,10 @@ void wbx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){          val = this->get_locked(dboard_iface::UNIT_TX);          return; +    case SUBDEV_PROP_BANDWIDTH: +        val = 2*20.0e6; //20MHz low-pass, we want complex double-sided +        return; +      default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -641,6 +656,12 @@ void wbx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){      case SUBDEV_PROP_ENABLED:          return; //always enabled +    case SUBDEV_PROP_BANDWIDTH: +        uhd::warning::post( +            str(boost::format("WBX: No tunable bandwidth, fixed filtered to 40MHz")) +        ); +        return; +      default: UHD_THROW_PROP_SET_ERROR();      }  } diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp index fb1367113..be0e42b92 100644 --- a/host/lib/usrp/dboard/db_xcvr2450.cpp +++ b/host/lib/usrp/dboard/db_xcvr2450.cpp @@ -626,7 +626,7 @@ void xcvr2450::rx_get(const wax::obj &key_, wax::obj &val){          return;      case SUBDEV_PROP_BANDWIDTH: -        val = _rx_bandwidth; +        val = 2*_rx_bandwidth; //_tx_bandwidth is low-pass, we want complex double-sided          return;      default: UHD_THROW_PROP_GET_ERROR(); @@ -652,7 +652,7 @@ void xcvr2450::rx_set(const wax::obj &key_, const wax::obj &val){          return;      case SUBDEV_PROP_BANDWIDTH: -        this->set_rx_bandwidth(val.as<double>()); +        this->set_rx_bandwidth(val.as<double>()/2.0); //complex double-sided, we want low-pass          return;      case SUBDEV_PROP_ENABLED: @@ -725,7 +725,7 @@ void xcvr2450::tx_get(const wax::obj &key_, wax::obj &val){          return;      case SUBDEV_PROP_BANDWIDTH: -        val = _tx_bandwidth; +        val = 2*_tx_bandwidth; //_tx_bandwidth is low-pass, we want complex double-sided          return;      default: UHD_THROW_PROP_GET_ERROR(); @@ -747,7 +747,7 @@ void xcvr2450::tx_set(const wax::obj &key_, const wax::obj &val){          return;      case SUBDEV_PROP_BANDWIDTH: -        this->set_tx_bandwidth(val.as<double>()); +        this->set_tx_bandwidth(val.as<double>()/2.0); //complex double-sided, we want low-pass          return;      case SUBDEV_PROP_ANTENNA: diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp index d73a698ae..5a98bb8eb 100644 --- a/host/lib/usrp/dboard_manager.cpp +++ b/host/lib/usrp/dboard_manager.cpp @@ -189,7 +189,7 @@ static args_t get_dboard_args(      //verify that there is a registered constructor for this id      if (not get_id_to_args_map().has_key(dboard_id)){ -        uhd::print_warning(str(boost::format( +        uhd::warning::post(str(boost::format(              "Unknown dboard ID: %s.\n"          ) % dboard_id.to_pp_string()));          return get_dboard_args(unit, dboard_id, true); @@ -217,7 +217,7 @@ dboard_manager_impl::dboard_manager_impl(      //warn for invalid dboard id xcvr combinations      if (rx_dboard_is_xcvr != this_dboard_is_xcvr or tx_dboard_is_xcvr != this_dboard_is_xcvr){ -        uhd::print_warning(str(boost::format( +        uhd::warning::post(str(boost::format(              "Unknown transceiver board ID combination...\n"              "RX dboard ID: %s\n"              "TX dboard ID: %s\n" diff --git a/host/lib/usrp/mboard_eeprom.cpp b/host/lib/usrp/mboard_eeprom.cpp new file mode 100644 index 000000000..661030aa7 --- /dev/null +++ b/host/lib/usrp/mboard_eeprom.cpp @@ -0,0 +1,194 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include <uhd/usrp/mboard_eeprom.hpp> +#include <uhd/types/mac_addr.hpp> +#include <uhd/utils/algorithm.hpp> +#include <boost/asio/ip/address_v4.hpp> +#include <boost/assign/list_of.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/foreach.hpp> + +using namespace uhd; +using namespace uhd::usrp; + +/*********************************************************************** + * Constants + **********************************************************************/ +static const size_t SERIAL_LEN = 9; +static const size_t NAME_MAX_LEN = 32 - SERIAL_LEN; + +/*********************************************************************** + * Utility functions + **********************************************************************/ + +//! create a string from a byte vector, return empty if invalid ascii +static const std::string bytes_to_string(const byte_vector_t &bytes){ +    std::string out; +    BOOST_FOREACH(boost::uint8_t byte, bytes){ +        if (byte < 32 or byte > 127) return out; +        out += byte; +    } +    return out; +} + +//! create a byte vector from a string, null terminate unless max length +static const byte_vector_t string_to_bytes(const std::string &string, size_t max_length){ +    byte_vector_t bytes; +    for (size_t i = 0; i < std::min(string.size(), max_length); i++){ +        bytes.push_back(string[i]); +    } +    if (bytes.size() < max_length - 1) bytes.push_back('\0'); +    return bytes; +} + +/*********************************************************************** + * Implementation of N100 load/store + **********************************************************************/ +static const boost::uint8_t N100_EEPROM_ADDR = 0x50; + +static const uhd::dict<std::string, boost::uint8_t> USRP_N100_OFFSETS = boost::assign::map_list_of +    ("rev-lsb-msb", 0x00) +    ("mac-addr", 0x02) +    ("ip-addr", 0x08) +    //leave space here for other addresses (perhaps) +    ("serial", 0x18) +    ("name", 0x18 + SERIAL_LEN) +; + +static void load_n100(mboard_eeprom_t &mb_eeprom, i2c_iface &iface){ +    //extract the revision number +    byte_vector_t rev_lsb_msb = iface.read_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["rev-lsb-msb"], 2); +    boost::uint16_t rev = (boost::uint16_t(rev_lsb_msb.at(0)) << 0) | (boost::uint16_t(rev_lsb_msb.at(1)) << 8); +    mb_eeprom["rev"] = boost::lexical_cast<std::string>(rev); + +    //extract the addresses +    mb_eeprom["mac-addr"] = mac_addr_t::from_bytes(iface.read_eeprom( +        N100_EEPROM_ADDR, USRP_N100_OFFSETS["mac-addr"], 6 +    )).to_string(); + +    boost::asio::ip::address_v4::bytes_type ip_addr_bytes; +    std::copy(iface.read_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["ip-addr"], 4), ip_addr_bytes); +    mb_eeprom["ip-addr"] = boost::asio::ip::address_v4(ip_addr_bytes).to_string(); + +    //extract the serial +    mb_eeprom["serial"] = bytes_to_string(iface.read_eeprom( +        N100_EEPROM_ADDR, USRP_N100_OFFSETS["serial"], SERIAL_LEN +    )); + +    //extract the name +    mb_eeprom["name"] = bytes_to_string(iface.read_eeprom( +        N100_EEPROM_ADDR, USRP_N100_OFFSETS["name"], NAME_MAX_LEN +    )); + +    //empty serial correction: use the mac address +    if (mb_eeprom["serial"].empty()) mb_eeprom["serial"] = mb_eeprom["mac-addr"]; +} + +static void store_n100(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface){ +    //parse the revision number +    if (mb_eeprom.has_key("rev")){ +        boost::uint16_t rev = boost::lexical_cast<boost::uint16_t>(mb_eeprom["rev"]); +        byte_vector_t rev_lsb_msb = boost::assign::list_of +            (boost::uint8_t(rev >> 0)) +            (boost::uint8_t(rev >> 8)) +        ; +        iface.write_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["rev-lsb-msb"], rev_lsb_msb); +    } + +    //store the addresses +    if (mb_eeprom.has_key("mac-addr")) iface.write_eeprom( +        N100_EEPROM_ADDR, USRP_N100_OFFSETS["mac-addr"], +        mac_addr_t::from_string(mb_eeprom["mac-addr"]).to_bytes() +    ); + +    if (mb_eeprom.has_key("ip-addr")){ +        byte_vector_t ip_addr_bytes(4); +        std::copy(boost::asio::ip::address_v4::from_string(mb_eeprom["ip-addr"]).to_bytes(), ip_addr_bytes); +        iface.write_eeprom(N100_EEPROM_ADDR, USRP_N100_OFFSETS["ip-addr"], ip_addr_bytes); +    } + +    //store the serial +    if (mb_eeprom.has_key("serial")) iface.write_eeprom( +        N100_EEPROM_ADDR, USRP_N100_OFFSETS["serial"], +        string_to_bytes(mb_eeprom["serial"], SERIAL_LEN) +    ); + +    //store the name +    if (mb_eeprom.has_key("name")) iface.write_eeprom( +        N100_EEPROM_ADDR, USRP_N100_OFFSETS["name"], +        string_to_bytes(mb_eeprom["name"], NAME_MAX_LEN) +    ); +} + +/*********************************************************************** + * Implementation of B000 load/store + **********************************************************************/ +static const boost::uint8_t B000_EEPROM_ADDR = 0x50; +static const size_t B000X_SERIAL_LEN = 8; + +static const uhd::dict<std::string, boost::uint8_t> USRP_B000_OFFSETS = boost::assign::map_list_of +    ("serial", 0xf8) +    ("name", 0xf8 - NAME_MAX_LEN) +; + +static void load_b000(mboard_eeprom_t &mb_eeprom, i2c_iface &iface){ +    //extract the serial +    mb_eeprom["serial"] = bytes_to_string(iface.read_eeprom( +        B000_EEPROM_ADDR, USRP_B000_OFFSETS["serial"], B000X_SERIAL_LEN +    )); + +    //extract the name +    mb_eeprom["name"] = bytes_to_string(iface.read_eeprom( +        B000_EEPROM_ADDR, USRP_B000_OFFSETS["name"], NAME_MAX_LEN +    )); +} + +static void store_b000(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface){ +    //store the serial +    if (mb_eeprom.has_key("serial")) iface.write_eeprom( +        B000_EEPROM_ADDR, USRP_B000_OFFSETS["serial"], +        string_to_bytes(mb_eeprom["serial"], B000X_SERIAL_LEN) +    ); + +    //store the name +    if (mb_eeprom.has_key("name")) iface.write_eeprom( +        B000_EEPROM_ADDR, USRP_B000_OFFSETS["name"], +        string_to_bytes(mb_eeprom["name"], NAME_MAX_LEN) +    ); +} + +/*********************************************************************** + * Implementation of mboard eeprom + **********************************************************************/ +mboard_eeprom_t::mboard_eeprom_t(void){ +    /* NOP */ +} + +mboard_eeprom_t::mboard_eeprom_t(i2c_iface &iface, map_type map){ +    switch(map){ +    case MAP_N100: load_n100(*this, iface); break; +    case MAP_B000: load_b000(*this, iface); break; +    } +} + +void mboard_eeprom_t::commit(i2c_iface &iface, map_type map){ +    switch(map){ +    case MAP_N100: store_n100(*this, iface); break; +    case MAP_B000: store_b000(*this, iface); break; +    } +} diff --git a/host/lib/usrp/misc_utils.cpp b/host/lib/usrp/misc_utils.cpp index 7e49baa52..5856d706f 100644 --- a/host/lib/usrp/misc_utils.cpp +++ b/host/lib/usrp/misc_utils.cpp @@ -164,13 +164,13 @@ static void verify_xx_subdev_spec(          }          //sanity check that the dboard/subdevice names exist for this mboard -        BOOST_FOREACH(const subdev_spec_pair_t &pair, subdev_spec){ +        BOOST_FOREACH(subdev_spec_pair_t &pair, subdev_spec){              //empty db name means select dboard automatically              if (pair.db_name.empty()){                  if (dboard_names.size() != 1) throw std::runtime_error(                      "A daughterboard name must be provided for multi-slot motherboards: " + subdev_spec.to_string()                  ); -                pair.db_name == dboard_names.front(); +                pair.db_name = dboard_names.front();              }              uhd::assert_has(dboard_names, pair.db_name, xx_type + " dboard name");              wax::obj dboard = mboard[named_prop_t(dboard_prop, pair.db_name)]; @@ -181,7 +181,7 @@ static void verify_xx_subdev_spec(                  if (subdev_names.size() != 1) throw std::runtime_error(                      "A subdevice name must be provided for multi-subdev daughterboards: " + subdev_spec.to_string()                  ); -                pair.sd_name == subdev_names.front(); +                pair.sd_name = subdev_names.front();              }              uhd::assert_has(subdev_names, pair.sd_name, xx_type + " subdev name");          } diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp index 443b91594..876f1a3fc 100644 --- a/host/lib/usrp/multi_usrp.cpp +++ b/host/lib/usrp/multi_usrp.cpp @@ -145,7 +145,7 @@ public:              time_spec_t time_0 = _mboard(0)[MBOARD_PROP_TIME_NOW].as<time_spec_t>();              time_spec_t time_i = _mboard(m)[MBOARD_PROP_TIME_NOW].as<time_spec_t>();              if (time_i < time_0 or (time_i - time_0) > time_spec_t(0.01)){ //10 ms: greater than RTT but not too big -                uhd::print_warning(str(boost::format( +                uhd::warning::post(str(boost::format(                      "Detected time deviation between board %d and board 0.\n"                      "Board 0 time is %f seconds.\n"                      "Board %d time is %f seconds.\n" @@ -154,6 +154,15 @@ public:          }      } +    bool get_time_synchronized(void){ +        for (size_t m = 1; m < get_num_mboards(); m++){ +            time_spec_t time_0 = _mboard(0)[MBOARD_PROP_TIME_NOW].as<time_spec_t>(); +            time_spec_t time_i = _mboard(m)[MBOARD_PROP_TIME_NOW].as<time_spec_t>(); +            if (time_i < time_0 or (time_i - time_0) > time_spec_t(0.01)) return false; +        } +        return true; +    } +      void issue_stream_cmd(const stream_cmd_t &stream_cmd){          for (size_t m = 0; m < get_num_mboards(); m++){              _mboard(m)[MBOARD_PROP_STREAM_CMD] = stream_cmd; @@ -210,15 +219,9 @@ public:          return _rx_dsp(0)[DSP_PROP_HOST_RATE].as<double>();      } -    tune_result_t set_rx_freq(double target_freq, size_t chan){ -        tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan/rx_cpm()), chan%rx_cpm(), target_freq); -        do_tune_freq_warning_message(target_freq, get_rx_freq(chan), "RX"); -        return r; -    } - -    tune_result_t set_rx_freq(double target_freq, double lo_off, size_t chan){ -        tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan/rx_cpm()), chan%rx_cpm(), target_freq, lo_off); -        do_tune_freq_warning_message(target_freq, get_rx_freq(chan), "RX"); +    tune_result_t set_rx_freq(const tune_request_t &tune_request, size_t chan){ +        tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan/rx_cpm()), chan%rx_cpm(), tune_request); +        do_tune_freq_warning_message(tune_request.target_freq, get_rx_freq(chan), "RX");          return r;      } @@ -314,15 +317,9 @@ public:          return _tx_dsp(0)[DSP_PROP_HOST_RATE].as<double>();      } -    tune_result_t set_tx_freq(double target_freq, size_t chan){ -        tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan/tx_cpm()), chan%tx_cpm(), target_freq); -        do_tune_freq_warning_message(target_freq, get_tx_freq(chan), "TX"); -        return r; -    } - -    tune_result_t set_tx_freq(double target_freq, double lo_off, size_t chan){ -        tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan/tx_cpm()), chan%tx_cpm(), target_freq, lo_off); -        do_tune_freq_warning_message(target_freq, get_tx_freq(chan), "TX"); +    tune_result_t set_tx_freq(const tune_request_t &tune_request, size_t chan){ +        tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan/tx_cpm()), chan%tx_cpm(), tune_request); +        do_tune_freq_warning_message(tune_request.target_freq, get_tx_freq(chan), "TX");          return r;      } diff --git a/host/lib/usrp/single_usrp.cpp b/host/lib/usrp/single_usrp.cpp index 5e57849b8..a0456d1f0 100644 --- a/host/lib/usrp/single_usrp.cpp +++ b/host/lib/usrp/single_usrp.cpp @@ -146,15 +146,9 @@ public:          return _rx_dsp()[DSP_PROP_HOST_RATE].as<double>();      } -    tune_result_t set_rx_freq(double target_freq, size_t chan){ -        tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(), chan, target_freq); -        do_tune_freq_warning_message(target_freq, get_rx_freq(chan), "RX"); -        return r; -    } - -    tune_result_t set_rx_freq(double target_freq, double lo_off, size_t chan){ -        tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(), chan, target_freq, lo_off); -        do_tune_freq_warning_message(target_freq, get_rx_freq(chan), "RX"); +    tune_result_t set_rx_freq(const tune_request_t &tune_request, size_t chan){ +        tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(), chan, tune_request); +        do_tune_freq_warning_message(tune_request.target_freq, get_rx_freq(chan), "RX");          return r;      } @@ -238,15 +232,9 @@ public:          return _tx_dsp()[DSP_PROP_HOST_RATE].as<double>();      } -    tune_result_t set_tx_freq(double target_freq, size_t chan){ -        tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(), chan, target_freq); -        do_tune_freq_warning_message(target_freq, get_tx_freq(chan), "TX"); -        return r; -    } - -    tune_result_t set_tx_freq(double target_freq, double lo_off, size_t chan){ -        tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(), chan, target_freq, lo_off); -        do_tune_freq_warning_message(target_freq, get_tx_freq(chan), "TX"); +    tune_result_t set_tx_freq(const tune_request_t &tune_request, size_t chan){ +        tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(), chan, tune_request); +        do_tune_freq_warning_message(tune_request.target_freq, get_tx_freq(chan), "TX");          return r;      } diff --git a/host/lib/usrp/tune_helper.cpp b/host/lib/usrp/tune_helper.cpp index 7633c67f2..fa40a8a26 100644 --- a/host/lib/usrp/tune_helper.cpp +++ b/host/lib/usrp/tune_helper.cpp @@ -19,6 +19,7 @@  #include <uhd/usrp/subdev_props.hpp>  #include <uhd/usrp/dsp_props.hpp>  #include <uhd/usrp/dboard_iface.hpp> //unit_t +#include <uhd/utils/algorithm.hpp>  #include <boost/math/special_functions/sign.hpp>  #include <cmath> @@ -28,55 +29,99 @@ using namespace uhd::usrp;  /***********************************************************************   * Tune Helper Functions   **********************************************************************/ -static tune_result_t tune_xx_subdev_and_dxc( +static tune_result_t tune_xx_subdev_and_dsp(      dboard_iface::unit_t unit, -    wax::obj subdev, wax::obj dxc, size_t chan, -    double target_freq, double lo_offset +    wax::obj subdev, wax::obj dsp, size_t chan, +    const tune_request_t &tune_request  ){      wax::obj subdev_freq_proxy = subdev[SUBDEV_PROP_FREQ]; -    std::string freq_name = dxc[DSP_PROP_FREQ_SHIFT_NAMES].as<prop_names_t>().at(chan); -    wax::obj dxc_freq_proxy = dxc[named_prop_t(DSP_PROP_FREQ_SHIFT, freq_name)]; -    double dxc_sample_rate = dxc[DSP_PROP_CODEC_RATE].as<double>(); +    std::string freq_name = dsp[DSP_PROP_FREQ_SHIFT_NAMES].as<prop_names_t>().at(chan); +    wax::obj dsp_freq_proxy = dsp[named_prop_t(DSP_PROP_FREQ_SHIFT, freq_name)]; +    double dsp_sample_rate = dsp[DSP_PROP_CODEC_RATE].as<double>(); -    // Ask the d'board to tune as closely as it can to target_freq+lo_offset -    double target_inter_freq = target_freq + lo_offset; -    subdev_freq_proxy = target_inter_freq; -    double actual_inter_freq = subdev_freq_proxy.as<double>(); - -    //perform the correction correction for dxc rates outside of nyquist -    double delta_freq = std::fmod(target_freq - actual_inter_freq, dxc_sample_rate); -    bool outside_of_nyquist = std::abs(delta_freq) > dxc_sample_rate/2.0; -    double target_dxc_freq = (outside_of_nyquist)? -        boost::math::sign(delta_freq)*dxc_sample_rate - delta_freq : -delta_freq; +    //------------------------------------------------------------------ +    //-- calculate the LO offset, only used with automatic policy +    //------------------------------------------------------------------ +    double lo_offset = 0.0; +    if (subdev[SUBDEV_PROP_USE_LO_OFFSET].as<bool>()){ +        //If the local oscillator will be in the passband, use an offset. +        //But constrain the LO offset by the width of the filter bandwidth. +        double rate = dsp[DSP_PROP_HOST_RATE].as<double>(); +        double bw = subdev[SUBDEV_PROP_BANDWIDTH].as<double>(); +        if (bw > rate) lo_offset = std::min((bw - rate)/2, rate/2); +    } -    //invert the sign on the dxc freq given the following conditions -    if (unit == dboard_iface::UNIT_TX) target_dxc_freq *= -1.0; +    //------------------------------------------------------------------ +    //-- set the intermediate frequency depending upon the IF policy +    //------------------------------------------------------------------ +    double target_inter_freq = 0.0; +    switch (tune_request.inter_freq_policy){ +    case tune_request_t::POLICY_AUTO: +        target_inter_freq = tune_request.target_freq + lo_offset; +        subdev_freq_proxy = target_inter_freq; +        break; + +    case tune_request_t::POLICY_MANUAL: +        target_inter_freq = tune_request.inter_freq; +        subdev_freq_proxy = target_inter_freq; +        break; + +    case tune_request_t::POLICY_NONE: break; //does not set +    } +    double actual_inter_freq = subdev_freq_proxy.as<double>(); -    dxc_freq_proxy = target_dxc_freq; -    double actual_dxc_freq = dxc_freq_proxy.as<double>(); +    //------------------------------------------------------------------ +    //-- calculate the dsp freq, only used with automatic policy +    //------------------------------------------------------------------ +    double delta_freq = std::fmod(tune_request.target_freq - actual_inter_freq, dsp_sample_rate); +    bool outside_of_nyquist = std::abs(delta_freq) > dsp_sample_rate/2.0; +    double target_dsp_freq = (outside_of_nyquist)? +        boost::math::sign(delta_freq)*dsp_sample_rate - delta_freq : -delta_freq; + +    //invert the sign on the dsp freq given the following conditions +    if (unit == dboard_iface::UNIT_TX) target_dsp_freq *= -1.0; + +    //------------------------------------------------------------------ +    //-- set the dsp frequency depending upon the dsp frequency policy +    //------------------------------------------------------------------ +    switch (tune_request.dsp_freq_policy){ +    case tune_request_t::POLICY_AUTO: +        dsp_freq_proxy = target_dsp_freq; +        break; + +    case tune_request_t::POLICY_MANUAL: +        target_dsp_freq = tune_request.dsp_freq; +        dsp_freq_proxy = target_dsp_freq; +        break; + +    case tune_request_t::POLICY_NONE: break; //does not set +    } +    double actual_dsp_freq = dsp_freq_proxy.as<double>(); -    //load and return the tune result +    //------------------------------------------------------------------ +    //-- load and return the tune result +    //------------------------------------------------------------------      tune_result_t tune_result;      tune_result.target_inter_freq = target_inter_freq;      tune_result.actual_inter_freq = actual_inter_freq; -    tune_result.target_dsp_freq = target_dxc_freq; -    tune_result.actual_dsp_freq = actual_dxc_freq; +    tune_result.target_dsp_freq = target_dsp_freq; +    tune_result.actual_dsp_freq = actual_dsp_freq;      return tune_result;  } -static double derive_freq_from_xx_subdev_and_dxc( +static double derive_freq_from_xx_subdev_and_dsp(      dboard_iface::unit_t unit, -    wax::obj subdev, wax::obj dxc, size_t chan +    wax::obj subdev, wax::obj dsp, size_t chan  ){      //extract actual dsp and IF frequencies      double actual_inter_freq = subdev[SUBDEV_PROP_FREQ].as<double>(); -    std::string freq_name = dxc[DSP_PROP_FREQ_SHIFT_NAMES].as<prop_names_t>().at(chan); -    double actual_dxc_freq = dxc[named_prop_t(DSP_PROP_FREQ_SHIFT, freq_name)].as<double>(); +    std::string freq_name = dsp[DSP_PROP_FREQ_SHIFT_NAMES].as<prop_names_t>().at(chan); +    double actual_dsp_freq = dsp[named_prop_t(DSP_PROP_FREQ_SHIFT, freq_name)].as<double>(); -    //invert the sign on the dxc freq given the following conditions -    if (unit == dboard_iface::UNIT_TX) actual_dxc_freq *= -1.0; +    //invert the sign on the dsp freq given the following conditions +    if (unit == dboard_iface::UNIT_TX) actual_dsp_freq *= -1.0; -    return actual_inter_freq - actual_dxc_freq; +    return actual_inter_freq - actual_dsp_freq;  }  /*********************************************************************** @@ -84,27 +129,15 @@ static double derive_freq_from_xx_subdev_and_dxc(   **********************************************************************/  tune_result_t usrp::tune_rx_subdev_and_dsp(      wax::obj subdev, wax::obj ddc, size_t chan, -    double target_freq, double lo_offset -){ -    return tune_xx_subdev_and_dxc(dboard_iface::UNIT_RX, subdev, ddc, chan, target_freq, lo_offset); -} - -tune_result_t usrp::tune_rx_subdev_and_dsp( -    wax::obj subdev, wax::obj ddc, -    size_t chan, double target_freq +    const tune_request_t &tune_request  ){ -    double lo_offset = 0.0; -    //if the local oscillator will be in the passband, use an offset -    if (subdev[SUBDEV_PROP_USE_LO_OFFSET].as<bool>()){ -        lo_offset = 2.0*ddc[DSP_PROP_HOST_RATE].as<double>(); -    } -    return tune_rx_subdev_and_dsp(subdev, ddc, chan, target_freq, lo_offset); +    return tune_xx_subdev_and_dsp(dboard_iface::UNIT_RX, subdev, ddc, chan, tune_request);  }  double usrp::derive_freq_from_rx_subdev_and_dsp(      wax::obj subdev, wax::obj ddc, size_t chan  ){ -    return derive_freq_from_xx_subdev_and_dxc(dboard_iface::UNIT_RX, subdev, ddc, chan); +    return derive_freq_from_xx_subdev_and_dsp(dboard_iface::UNIT_RX, subdev, ddc, chan);  }  /*********************************************************************** @@ -112,25 +145,13 @@ double usrp::derive_freq_from_rx_subdev_and_dsp(   **********************************************************************/  tune_result_t usrp::tune_tx_subdev_and_dsp(      wax::obj subdev, wax::obj duc, size_t chan, -    double target_freq, double lo_offset +    const tune_request_t &tune_request  ){ -    return tune_xx_subdev_and_dxc(dboard_iface::UNIT_TX, subdev, duc, chan, target_freq, lo_offset); -} - -tune_result_t usrp::tune_tx_subdev_and_dsp( -    wax::obj subdev, wax::obj duc, -    size_t chan, double target_freq -){ -    double lo_offset = 0.0; -    //if the local oscillator will be in the passband, use an offset -    if (subdev[SUBDEV_PROP_USE_LO_OFFSET].as<bool>()){ -        lo_offset = 2.0*duc[DSP_PROP_HOST_RATE].as<double>(); -    } -    return tune_tx_subdev_and_dsp(subdev, duc, chan, target_freq, lo_offset); +    return tune_xx_subdev_and_dsp(dboard_iface::UNIT_TX, subdev, duc, chan, tune_request);  }  double usrp::derive_freq_from_tx_subdev_and_dsp(      wax::obj subdev, wax::obj duc, size_t chan  ){ -    return derive_freq_from_xx_subdev_and_dxc(dboard_iface::UNIT_TX, subdev, duc, chan); +    return derive_freq_from_xx_subdev_and_dsp(dboard_iface::UNIT_TX, subdev, duc, chan);  } diff --git a/host/lib/usrp/usrp1/CMakeLists.txt b/host/lib/usrp/usrp1/CMakeLists.txt index 67487f99e..022015231 100644 --- a/host/lib/usrp/usrp1/CMakeLists.txt +++ b/host/lib/usrp/usrp1/CMakeLists.txt @@ -40,7 +40,7 @@ ENDIF(ENABLE_USRP1 AND NOT HAVE_USB_SUPPORT)  IF(ENABLE_USRP1)      MESSAGE(STATUS "  Building USRP1 support.") -    INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/../firmware/fx2/include) +    INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/../firmware/fx2/common)      LIBUHD_APPEND_SOURCES(          ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/clock_ctrl.cpp diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index fe3774eb4..4df5ada0a 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -98,7 +98,7 @@ static boost::uint32_t calc_rx_mux(      //    for all quadrature sources: Z = 0      //    for mixed sources: warning + Z = 0      int Z = (num_quads > 0)? 0 : 1; -    if (num_quads != 0 and num_reals != 0) uhd::print_warning( +    if (num_quads != 0 and num_reals != 0) uhd::warning::post(          "Mixing real and quadrature rx subdevices is not supported.\n"          "The Q input to the real source(s) will be non-zero.\n"      ); @@ -262,24 +262,10 @@ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val)  {      named_prop_t key = named_prop_t::extract(key_); -    if(key_.type() == typeid(std::string)) { -      if(key.as<std::string>() == "serial") { -        uhd::byte_vector_t buf; -        buf.insert(buf.begin(), 248); -        boost::this_thread::sleep(boost::posix_time::milliseconds(100)); -        _iface->write_i2c(I2C_DEV_EEPROM, buf); -        boost::this_thread::sleep(boost::posix_time::milliseconds(100)); -        buf = _iface->read_i2c(I2C_DEV_EEPROM, 8); -        val = std::string(buf.begin(), buf.end()); -      } - -      return; -   	} -      //handle the get request conditioned on the key      switch(key.as<mboard_prop_t>()){      case MBOARD_PROP_NAME: -        val = std::string("usrp1 mboard - " + (*_mboard_proxy)[std::string("serial")].as<std::string>()); +        val = std::string("usrp1 mboard - " + _iface->mb_eeprom["serial"]);          return;      case MBOARD_PROP_OTHERS: @@ -336,6 +322,10 @@ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val)          val = _tx_subdev_spec;          return; +    case MBOARD_PROP_EEPROM_MAP: +        val = _iface->mb_eeprom; +        return; +      default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -351,14 +341,6 @@ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val)          std::cout << "USRP1 EEPROM image: " << usrp1_eeprom_image << std::endl;          _ctrl_transport->usrp_load_eeprom(val.as<std::string>());        } - -      if(key.as<std::string>() == "serial") { -        std::string sernum = val.as<std::string>(); -        uhd::byte_vector_t buf(sernum.begin(), sernum.end()); -        buf.insert(buf.begin(), 248); -        _iface->write_i2c(I2C_DEV_EEPROM, buf); -      } -        return;     	} @@ -395,6 +377,13 @@ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val)          _iface->poke32(FR_TX_MUX, calc_tx_mux(_tx_subdev_spec, _mboard_proxy->get_link()));          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_B000); +        _iface->mb_eeprom = mboard_eeprom_t(*_iface, mboard_eeprom_t::MAP_B000); +        return; +      default: UHD_THROW_PROP_SET_ERROR();      }  } diff --git a/host/lib/usrp/usrp1/usrp1_iface.cpp b/host/lib/usrp/usrp1/usrp1_iface.cpp index 64ced2905..63fcd5777 100644 --- a/host/lib/usrp/usrp1/usrp1_iface.cpp +++ b/host/lib/usrp/usrp1/usrp1_iface.cpp @@ -25,6 +25,7 @@  #include <iomanip>  using namespace uhd; +using namespace uhd::usrp;  using namespace uhd::transport;  static const bool iface_debug = false; @@ -36,7 +37,8 @@ public:       ******************************************************************/      usrp1_iface_impl(usrp_ctrl::sptr ctrl_transport)      { -        _ctrl_transport = ctrl_transport;  +        _ctrl_transport = ctrl_transport; +        mb_eeprom = mboard_eeprom_t(*this, mboard_eeprom_t::MAP_B000);      }      ~usrp1_iface_impl(void) diff --git a/host/lib/usrp/usrp1/usrp1_iface.hpp b/host/lib/usrp/usrp1/usrp1_iface.hpp index 3f608584a..34a2330b5 100644 --- a/host/lib/usrp/usrp1/usrp1_iface.hpp +++ b/host/lib/usrp/usrp1/usrp1_iface.hpp @@ -18,6 +18,7 @@  #ifndef INCLUDED_USRP1_IFACE_HPP  #define INCLUDED_USRP1_IFACE_HPP +#include <uhd/usrp/mboard_eeprom.hpp>  #include <uhd/types/serial.hpp>  #include <boost/shared_ptr.hpp>  #include <boost/utility.hpp> @@ -81,6 +82,8 @@ public:                                     boost::uint16_t index,                                     unsigned char* buff,                                     boost::uint16_t length) = 0; + +    uhd::usrp::mboard_eeprom_t mb_eeprom;  };  #endif /* INCLUDED_USRP1_IFACE_HPP */ diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index 276ca86f6..6016b0979 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -56,15 +56,17 @@ static device_addrs_t usrp1_find(const device_addr_t &hint)      //return an empty list of addresses when type is set to non-usrp1      if (hint.has_key("type") and hint["type"] != "usrp1") return usrp1_addrs; +    //Return an empty list of addresses when an address is specified, +    //since an address is intended for a different, non-USB, device. +    if (hint.has_key("addr")) return usrp1_addrs; +      //extract the firmware path for the USRP1      std::string usrp1_fw_image;      try{ -        usrp1_fw_image = find_image_path( -            hint.has_key("fw")? hint["fw"] : "usrp1_fw.ihx" -        ); +        usrp1_fw_image = find_image_path(hint.get("fw", "usrp1_fw.ihx"));      }      catch(...){ -        uhd::print_warning( +        uhd::warning::post(              "Could not locate USRP1 firmware.\n"              "Please install the images package.\n"          ); @@ -91,11 +93,16 @@ static device_addrs_t usrp1_find(const device_addr_t &hint)      pid = USRP1_PRODUCT_ID;      BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid, pid)) { +        usrp1_iface::sptr iface = usrp1_iface::make(usrp_ctrl::make(usb_control::make(handle)));          device_addr_t new_addr;          new_addr["type"] = "usrp1"; +        new_addr["name"] = iface->mb_eeprom["name"];          new_addr["serial"] = handle->get_serial(); -        //this is a found usrp1 when a hint serial is not specified or it matches -        if (not hint.has_key("serial") or hint["serial"] == new_addr["serial"]){ +        //this is a found usrp1 when the hint serial and name match or blank +        if ( +            (not hint.has_key("name")   or hint["name"]   == new_addr["name"]) and +            (not hint.has_key("serial") or hint["serial"] == new_addr["serial"]) +        ){              usrp1_addrs.push_back(new_addr);          }      } @@ -110,7 +117,7 @@ static device::sptr usrp1_make(const device_addr_t &device_addr){      //extract the FPGA path for the USRP1      std::string usrp1_fpga_image = find_image_path( -        device_addr.has_key("fpga")? device_addr["fpga"] : "usrp1_fpga.rbf" +        device_addr.get("fpga", "usrp1_fpga.rbf")      );      //std::cout << "USRP1 FPGA image: " << usrp1_fpga_image << std::endl; diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp index 04bbd6ba3..8eaafe680 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.cpp +++ b/host/lib/usrp/usrp2/clock_ctrl.cpp @@ -22,6 +22,7 @@  #include "usrp2_clk_regs.hpp"  #include <uhd/utils/assert.hpp>  #include <boost/cstdint.hpp> +#include <boost/lexical_cast.hpp>  #include <iostream>  using namespace uhd; diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index bbe9c273f..83b70bddc 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -236,6 +236,11 @@ size_t usrp2_impl::get_max_recv_samps_per_packet(void) const{      return bpp/_rx_otw_type.get_sample_size();  } +static void handle_overflow(std::vector<usrp2_mboard_impl::sptr> &mboards, size_t chan){ +    std::cerr << "O" << std::flush; +    mboards.at(chan/mboards.size())->handle_overflow(); +} +  size_t usrp2_impl::recv(      const std::vector<void *> &buffs, size_t num_samps,      rx_metadata_t &metadata, const io_type_t &io_type, @@ -248,6 +253,7 @@ size_t usrp2_impl::recv(          io_type, _rx_otw_type,                     //input and output types to convert          _mboards.front()->get_master_clock_freq(), //master clock tick rate          uhd::transport::vrt::if_hdr_unpack_be, -        boost::bind(&usrp2_impl::io_impl::get_recv_buffs, _io_impl.get(), _1, timeout) +        boost::bind(&usrp2_impl::io_impl::get_recv_buffs, _io_impl.get(), _1, timeout), +        boost::bind(&handle_overflow, _mboards, _1)      );  } diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 9ccf90bbb..eb5b79b20 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -23,11 +23,7 @@  #include "mboard_rev.hpp"  #include <uhd/utils/assert.hpp>  #include <uhd/utils/algorithm.hpp> -#include <uhd/types/mac_addr.hpp> -#include <uhd/types/dict.hpp>  #include <boost/bind.hpp> -#include <boost/assign/list_of.hpp> -#include <boost/asio/ip/address_v4.hpp>  #include <iostream>  #include <boost/date_time/posix_time/posix_time.hpp> @@ -44,11 +40,9 @@ usrp2_mboard_impl::usrp2_mboard_impl(      size_t recv_frame_size  ):      _index(index), -    _recv_frame_size(recv_frame_size) +    _recv_frame_size(recv_frame_size), +    _iface(usrp2_iface::make(ctrl_transport))  { -    //make a new interface for usrp2 stuff -    _iface = usrp2_iface::make(ctrl_transport); -          //contruct the interfaces to mboard perifs      _clock_ctrl = usrp2_clock_ctrl::make(_iface);      _codec_ctrl = usrp2_codec_ctrl::make(_iface); @@ -188,7 +182,15 @@ void usrp2_mboard_impl::set_time_spec(const time_spec_t &time_spec, bool now){      _iface->poke32(_iface->regs.time64_secs, boost::uint32_t(time_spec.get_full_secs()));  } +void usrp2_mboard_impl::handle_overflow(void){ +    _iface->poke32(_iface->regs.rx_ctrl_clear_overrun, 1); +    if (_continuous_streaming){ //re-issue the stream command if already continuous +        this->issue_ddc_stream_cmd(stream_cmd_t::STREAM_MODE_START_CONTINUOUS); +    } +} +  void usrp2_mboard_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ +    _continuous_streaming = stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS;      _iface->poke32(_iface->regs.rx_ctrl_stream_cmd, dsp_type1::calc_stream_cmd_word(          stream_cmd, _recv_frame_size      )); @@ -203,42 +205,14 @@ static const std::string dboard_name = "0";  void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){      named_prop_t key = named_prop_t::extract(key_); - -    //handle the other props -    if (key_.type() == typeid(std::string)){ -        if (key.as<std::string>() == "mac-addr"){ -            byte_vector_t bytes = _iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, 6); -            val = mac_addr_t::from_bytes(bytes).to_string(); -            return; -        } - -        if (key.as<std::string>() == "ip-addr"){ -            boost::asio::ip::address_v4::bytes_type bytes; -            std::copy(_iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, 4), bytes); -            val = boost::asio::ip::address_v4(bytes).to_string(); -            return; -        } -         -        if (key.as<std::string>() == "hw-rev"){ -            //extract the mboard rev number -            val = _iface->get_hw_rev().to_string(); -            return; -        } -    } -      //handle the get request conditioned on the key      switch(key.as<mboard_prop_t>()){      case MBOARD_PROP_NAME: -        val = str(boost::format("usrp2 mboard%d - rev %s") % _index % _iface->get_hw_rev().to_string()); +        val = str(boost::format("usrp2 mboard%d - rev %s") % _index % _iface->mb_eeprom["rev"]);          return; -    case MBOARD_PROP_OTHERS:{ -            prop_names_t others = boost::assign::list_of -                ("mac-addr") -                ("ip-addr") -            ; -            val = others; -        } +    case MBOARD_PROP_OTHERS: +        val = prop_names_t();          return;      case MBOARD_PROP_RX_DBOARD: @@ -299,6 +273,10 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){          val = _tx_subdev_spec;          return; +    case MBOARD_PROP_EEPROM_MAP: +        val = _iface->mb_eeprom; +        return; +      default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -307,32 +285,6 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){   * MBoard Set Properties   **********************************************************************/  void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){ -    //handle the other props -    if (key.type() == typeid(std::string)){ -        if (key.as<std::string>() == "mac-addr"){ -            byte_vector_t bytes = mac_addr_t::from_string(val.as<std::string>()).to_bytes(); -            _iface->write_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, bytes); -            return; -        } - -        if (key.as<std::string>() == "ip-addr"){ -            byte_vector_t bytes(4); -            std::copy(boost::asio::ip::address_v4::from_string(val.as<std::string>()).to_bytes(), bytes); -            _iface->write_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, bytes); -            return; -        } -         -        if (key.as<std::string>() == "hw-rev"){ -            mboard_rev_t rev = mboard_rev_t::from_string(val.as<std::string>()); -            byte_vector_t rev_bytes(2); -            rev_bytes[1] = rev.to_uint16() >> 8; -            rev_bytes[0] = rev.to_uint16() & 0xff; -            _iface->write_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV, rev_bytes); -            _iface->set_hw_rev(rev); //so the iface knows what rev it is -            return; -        } -    } -      //handle the set request conditioned on the key      switch(key.as<mboard_prop_t>()){ @@ -375,6 +327,13 @@ void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){          ));          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; +      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 d5ac14155..52adb5373 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.cpp +++ b/host/lib/usrp/usrp2/usrp2_iface.cpp @@ -30,6 +30,7 @@  #include <algorithm>  using namespace uhd; +using namespace uhd::usrp;  using namespace uhd::transport;  /*! @@ -65,6 +66,7 @@ public:              ) % int(USRP2_FPGA_COMPAT_NUM) % fpga_compat_num));          } +        mb_eeprom = mboard_eeprom_t(*this, mboard_eeprom_t::MAP_N100);      }      ~usrp2_iface_impl(void){ diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp index fee3b23af..88bff5913 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.hpp +++ b/host/lib/usrp/usrp2/usrp2_iface.hpp @@ -20,6 +20,7 @@  #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/cstdint.hpp> @@ -128,6 +129,8 @@ public:       * Hardware revision as returned by the device.       */      mboard_rev_t hw_rev; +    //motherboard eeprom map structure +    uhd::usrp::mboard_eeprom_t mb_eeprom;  };  #endif /* INCLUDED_USRP2_IFACE_HPP */ diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index a680708ad..5f549c4fd 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -21,6 +21,7 @@  #include <uhd/usrp/device_props.hpp>  #include <uhd/utils/assert.hpp>  #include <uhd/utils/static.hpp> +#include <uhd/utils/warning.hpp>  #include <uhd/utils/algorithm.hpp>  #include <boost/assign/list_of.hpp>  #include <boost/format.hpp> @@ -61,7 +62,7 @@ static uhd::device_addrs_t usrp2_find(const device_addr_t &hint){              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; +            device_addr_t new_hint = hint;              new_hint["addr"] = if_addrs.bcast;              //call discover with the new hint and append results @@ -101,19 +102,37 @@ static uhd::device_addrs_t usrp2_find(const device_addr_t &hint){      while(true){          size_t len = udp_transport->recv(asio::buffer(usrp2_ctrl_data_in_mem), DISCOVERY_TIMEOUT_MS);          //std::cout << len << "\n"; -        if (len > offsetof(usrp2_ctrl_data_t, data)){ -            //handle the received data -            switch(ntohl(ctrl_data_in->id)){ -            case 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(); -                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 > 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 COMPAT mismatch. That is OK. +            //We will allow the device to be found and the COMPAT mismatch +            //will be thrown as an exception in the factory function. +            try{ +                mboard_eeprom_t mb_eeprom = usrp2_iface::make( +                    udp_simple::make_connected(new_addr["addr"], num2str(USRP2_UDP_CTRL_PORT)) +                )->mb_eeprom; +                new_addr["name"] = mb_eeprom["name"]; +                new_addr["serial"] = mb_eeprom["serial"]; +                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); +                }              } +            catch(const std::exception &e){ +                uhd::warning::post( +                    std::string("Ignoring discovered device\n") +                    + e.what() +                ); +            } +            //dont break here, it will exit the while loop +            //just continue on to the next loop iteration          }          if (len == 0) break; //timeout      } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 1ebd90ca4..738c398d9 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -33,7 +33,7 @@  #include <boost/shared_ptr.hpp>  #include <boost/function.hpp>  #include <uhd/transport/vrt_if_packet.hpp> -#include <uhd/transport/udp_simple.hpp> //mtu +#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> @@ -93,14 +93,12 @@ public:          return _clock_ctrl->get_master_clock_rate();      } +    void handle_overflow(void); +  private:      size_t _index;      const size_t _recv_frame_size; - -    //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; +    bool _continuous_streaming;      //interfaces      usrp2_iface::sptr _iface; @@ -109,6 +107,11 @@ private:      usrp2_serdes_ctrl::sptr _serdes_ctrl;      usrp2_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; diff --git a/host/lib/usrp/wrapper_utils.hpp b/host/lib/usrp/wrapper_utils.hpp index aee230fc0..6f9fdbfca 100644 --- a/host/lib/usrp/wrapper_utils.hpp +++ b/host/lib/usrp/wrapper_utils.hpp @@ -40,7 +40,7 @@ static inline void do_samp_rate_warning_message(  ){      static const double max_allowed_error = 1.0; //Sps      if (std::abs(target_rate - actual_rate) > max_allowed_error){ -        uhd::print_warning(str(boost::format( +        uhd::warning::post(str(boost::format(              "The hardware does not support the requested %s sample rate:\n"              "Target sample rate: %f MSps\n"              "Actual sample rate: %f MSps\n" @@ -55,7 +55,7 @@ static inline void do_tune_freq_warning_message(  ){      static const double max_allowed_error = 1.0; //Hz      if (std::abs(target_freq - actual_freq) > max_allowed_error){ -        uhd::print_warning(str(boost::format( +        uhd::warning::post(str(boost::format(              "The hardware does not support the requested %s frequency:\n"              "Target frequency: %f MHz\n"              "Actual frequency: %f MHz\n" diff --git a/host/lib/utils/thread_priority.cpp b/host/lib/utils/thread_priority.cpp index f09d1b1d6..40b74f655 100644 --- a/host/lib/utils/thread_priority.cpp +++ b/host/lib/utils/thread_priority.cpp @@ -26,7 +26,7 @@ bool uhd::set_thread_priority_safe(float priority, bool realtime){          set_thread_priority(priority, realtime);          return true;      }catch(const std::exception &e){ -        uhd::print_warning(str(boost::format( +        uhd::warning::post(str(boost::format(              "%s\n"              "Failed to set thread priority %d (%s):\n"              "Performance may be negatively affected.\n" diff --git a/host/lib/utils/warning.cpp b/host/lib/utils/warning.cpp index 8a7d35a23..05be7ae4d 100644 --- a/host/lib/utils/warning.cpp +++ b/host/lib/utils/warning.cpp @@ -17,16 +17,67 @@  #include <uhd/utils/warning.hpp>  #include <uhd/utils/algorithm.hpp> +#include <uhd/utils/static.hpp> +#include <uhd/types/dict.hpp>  #include <boost/foreach.hpp> +#include <sstream> +#include <stdexcept>  #include <iostream>  #include <vector>  using namespace uhd; -void uhd::print_warning(const std::string &msg){ -    //print the warning message -    std::cerr << std::endl << "Warning:" << std::endl; +/*********************************************************************** + * Registry implementation + **********************************************************************/ +//create the registry for the handlers +typedef uhd::dict<std::string, warning::handler_t> registry_t; +UHD_SINGLETON_FCN(registry_t, get_registry) + +//the default warning handler +static void stderr_warning(const std::string &msg){ +    std::cerr << msg; +} + +//register a default handler +UHD_STATIC_BLOCK(warning_register_default){ +    warning::register_handler("default", &stderr_warning); +} + +/*********************************************************************** + * Post + format + **********************************************************************/ +void warning::post(const std::string &msg){ +    std::stringstream ss; + +    //format the warning message +    ss << std::endl << "Warning:" << std::endl;      BOOST_FOREACH(const std::string &line, std::split_string(msg, "\n")){ -        std::cerr << "    " << line << std::endl; +        ss << "    " << line << std::endl; +    } + +    //post the formatted message +    BOOST_FOREACH(const std::string &name, get_registry().keys()){ +        get_registry()[name](ss.str());      }  } + +/*********************************************************************** + * Registry accessor functions + **********************************************************************/ +void warning::register_handler( +    const std::string &name, const handler_t &handler +){ +    get_registry()[name] = handler; +} + +warning::handler_t warning::unregister_handler(const std::string &name){ +    if (not get_registry().has_key(name)) throw std::runtime_error( +        "The warning registry does not have a handler registered to " + name +    ); +    return get_registry().pop(name); +} + +const std::vector<std::string> warning::registry_names(void){ +    return get_registry().keys(); +} | 
