diff options
Diffstat (limited to 'host/lib/usrp')
29 files changed, 1011 insertions, 247 deletions
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" |