From 9b4c8c7c9c9e9645b0ee27a6d6ad06bbfbf1ae66 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 27 Jun 2011 16:07:13 -0700 Subject: usrp2: setup many more control objects and xports --- host/lib/usrp2/usrp2_impl.cpp | 176 ++++++++++++++++++++++++++++++++++++++---- host/lib/usrp2/usrp2_impl.hpp | 13 +++- 2 files changed, 173 insertions(+), 16 deletions(-) (limited to 'host/lib/usrp2') diff --git a/host/lib/usrp2/usrp2_impl.cpp b/host/lib/usrp2/usrp2_impl.cpp index 9e08093dd..1ffcae626 100644 --- a/host/lib/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp2/usrp2_impl.cpp @@ -22,18 +22,18 @@ #include #include #include +#include #include #include #include #include -#include +#include #include #include #include #include #include #include //used for htonl and ntohl -#include using namespace uhd; using namespace uhd::usrp; @@ -109,6 +109,23 @@ static mtu_result_t determine_mtu(const std::string &addr, const mtu_result_t &u return mtu; } +/*********************************************************************** + * Helpers + **********************************************************************/ +static void init_xport(zero_copy_if::sptr xport){ + //Send a small data packet so the usrp2 knows the udp source port. + //This setup must happen before further initialization occurs + //or the async update packets will cause ICMP destination unreachable. + static const boost::uint32_t data[2] = { + uhd::htonx(boost::uint32_t(0 /* don't care seq num */)), + uhd::htonx(boost::uint32_t(USRP2_INVALID_VRT_HEADER)) + }; + + transport::managed_send_buffer::sptr send_buff = xport->get_send_buff(); + std::memcpy(send_buff->cast(), &data, sizeof(data)); + send_buff->commit(sizeof(data)); +} + /*********************************************************************** * Structors **********************************************************************/ @@ -162,30 +179,102 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){ _mboard_stuff.resize(device_args.size()); for (size_t mb = 0; mb < _mboard_stuff.size(); mb++){ - property_tree::path_type mb_path = str(boost::format("/mboard%u") % mb); - //create the iface that controls i2c, spi, uart, and wb + const std::string addr = device_args[mb]["addr"]; + property_tree::path_type mb_path = str(boost::format("/mboards/%u") % mb); + + //////////////////////////////////////////////////////////////// + // construct transports for dsp and async errors + //////////////////////////////////////////////////////////////// + UHD_LOG << "Making transport for DSP0..." << std::endl; + _mboard_stuff[mb].dsp_xports.push_back(udp_zero_copy::make( + addr, BOOST_STRINGIZE(USRP2_UDP_DSP0_PORT), device_args[mb] + )); + init_xport(_mboard_stuff[mb].dsp_xports.back()); + + UHD_LOG << "Making transport for DSP1..." << std::endl; + _mboard_stuff[mb].dsp_xports.push_back(udp_zero_copy::make( + addr, BOOST_STRINGIZE(USRP2_UDP_DSP1_PORT), device_args[mb] + )); + init_xport(_mboard_stuff[mb].dsp_xports.back()); + + UHD_LOG << "Making transport for ERR0..." << std::endl; + _mboard_stuff[mb].err_xports.push_back(udp_zero_copy::make( + addr, BOOST_STRINGIZE(USRP2_UDP_ERR0_PORT), device_addr_t() + )); + init_xport(_mboard_stuff[mb].err_xports.back()); + + //////////////////////////////////////////////////////////////// + // create the iface that controls i2c, spi, uart, and wb + //////////////////////////////////////////////////////////////// _mboard_stuff[mb].iface = usrp2_iface::make(udp_simple::make_connected( - device_args[mb]["addr"], BOOST_STRINGIZE(USRP2_UDP_CTRL_PORT) + addr, BOOST_STRINGIZE(USRP2_UDP_CTRL_PORT) )); + _tree->create(mb_path / "name", property(_mboard_stuff[mb].iface->get_cname())); - //setup the mboard eeprom - //TODO perform eeprom read here (not in iface) - //TODO move the iface REV checks out of here + //////////////////////////////////////////////////////////////// + // setup the mboard eeprom + //////////////////////////////////////////////////////////////// property mb_eeprom_prop; mb_eeprom_prop.set(_mboard_stuff[mb].iface->mb_eeprom); mb_eeprom_prop.subscribe(boost::bind(&usrp2_impl::set_mb_eeprom, this, mb, _1)); _tree->create(mb_path / "eeprom", mb_eeprom_prop); - //create clock control objects + //////////////////////////////////////////////////////////////// + // create clock control objects + //////////////////////////////////////////////////////////////// _mboard_stuff[mb].clock = usrp2_clock_ctrl::make(_mboard_stuff[mb].iface); - property tick_rate_prop(_mboard_stuff[mb].clock->get_master_clock_rate()); + const double tick_rate = _mboard_stuff[mb].clock->get_master_clock_rate(); + property tick_rate_prop(tick_rate); _tree->create(mb_path / "tick_rate", tick_rate_prop); - //create codec control objects + //////////////////////////////////////////////////////////////// + // create codec control objects + //////////////////////////////////////////////////////////////// + property_tree::path_type rx_codec_path = mb_path / "rx_codecs/0"; + property_tree::path_type tx_codec_path = mb_path / "tx_codecs/0"; _mboard_stuff[mb].codec = usrp2_codec_ctrl::make(_mboard_stuff[mb].iface); + switch(_mboard_stuff[mb].iface->get_rev()){ + case usrp2_iface::USRP_N200: + case usrp2_iface::USRP_N210: + case usrp2_iface::USRP_N200_R4: + case usrp2_iface::USRP_N210_R4:{ + _tree->create(rx_codec_path / "name", property("ads62p44")); + _tree->create(rx_codec_path / "gains/0/name", property("digital")); + _tree->create(rx_codec_path / "gains/0/range", property(meta_range_t(0, 6.0, 0.5))); + property dig_gain_prop, fine_gain_prop; + dig_gain_prop.subscribe(boost::bind(&usrp2_codec_ctrl::set_rx_digital_gain, _mboard_stuff[mb].codec, _1)); + _tree->create(rx_codec_path / "gains/0/value", dig_gain_prop); + _tree->create(rx_codec_path / "gains/1/name", property("digital-fine")); + _tree->create(rx_codec_path / "gains/1/range", property(meta_range_t(0, 0.5, 0.05))); + fine_gain_prop.subscribe(boost::bind(&usrp2_codec_ctrl::set_rx_digital_fine_gain, _mboard_stuff[mb].codec, _1)); + _tree->create(rx_codec_path / "gains/0/value", fine_gain_prop); + }break; + + case usrp2_iface::USRP2_REV3: + case usrp2_iface::USRP2_REV4: + _tree->create(rx_codec_path / "name", property("ltc2284")); + break; + + case usrp2_iface::USRP_NXXX: + _tree->create(rx_codec_path / "name", property("??????")); + break; + } + _tree->create(tx_codec_path / "name", property("ad9777")); - //create frontend control objects + //////////////////////////////////////////////////////////////// + // create gpsdo control objects + //////////////////////////////////////////////////////////////// + //TODO + //TODO register sensors + + //TODO other sensors + + //TODO clock source, time source + + //////////////////////////////////////////////////////////////// + // create frontend control objects + //////////////////////////////////////////////////////////////// _mboard_stuff[mb].rx_fe = rx_frontend_core_200::make( _mboard_stuff[mb].iface, U2_REG_SR_ADDR(SR_RX_FRONT) ); @@ -193,14 +282,73 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){ _mboard_stuff[mb].iface, U2_REG_SR_ADDR(SR_TX_FRONT) ); - //create dsp control objects + //////////////////////////////////////////////////////////////// + // create dsp control objects + //////////////////////////////////////////////////////////////// + _mboard_stuff[mb].rx_dsps.push_back(rx_dsp_core_200::make( + _mboard_stuff[mb].iface, U2_REG_SR_ADDR(SR_RX_DSP0), U2_REG_SR_ADDR(SR_RX_CTRL0), 3 + )); + _mboard_stuff[mb].rx_dsps.push_back(rx_dsp_core_200::make( + _mboard_stuff[mb].iface, U2_REG_SR_ADDR(SR_RX_DSP1), U2_REG_SR_ADDR(SR_RX_CTRL1), 4 + )); + for (size_t dspno = 0; dspno < _mboard_stuff[mb].rx_dsps.size(); dspno++){ + _mboard_stuff[mb].rx_dsps[dspno]->set_tick_rate(tick_rate); //does not change on usrp2 + property_tree::path_type rx_dsp_path = mb_path / str(boost::format("rx_dsps/%u") % dspno); + property host_rate_prop, freq_prop; + host_rate_prop.subscribe_master(boost::bind(&rx_dsp_core_200::set_host_rate, _mboard_stuff[mb].rx_dsps[dspno], _1)); + _tree->create(rx_dsp_path / "rate/value", host_rate_prop); + freq_prop.subscribe_master(boost::bind(&rx_dsp_core_200::set_freq, _mboard_stuff[mb].rx_dsps[dspno], _1)); + _tree->create(rx_dsp_path / "freq/value", freq_prop); + //TODO set nsamps per packet + } + _mboard_stuff[mb].tx_dsp = tx_dsp_core_200::make( + _mboard_stuff[mb].iface, U2_REG_SR_ADDR(SR_TX_DSP), U2_REG_SR_ADDR(SR_TX_CTRL), 2 + ); + _mboard_stuff[mb].tx_dsp->set_tick_rate(tick_rate); //does not change on usrp2 + property tx_dsp_host_rate_prop, tx_dsp_freq_prop; + tx_dsp_host_rate_prop.subscribe_master(boost::bind(&tx_dsp_core_200::set_host_rate, _mboard_stuff[mb].tx_dsp, _1)); + _tree->create(mb_path / "tx_dsps/0/rate/value", tx_dsp_host_rate_prop); + tx_dsp_freq_prop.subscribe_master(boost::bind(&tx_dsp_core_200::set_freq, _mboard_stuff[mb].tx_dsp, _1)); + _tree->create(mb_path / "tx_dsps/0/freq/value", tx_dsp_freq_prop); + //setup dsp flow control + const double ups_per_sec = device_args[mb].cast("ups_per_sec", 20); + const size_t send_frame_size = _mboard_stuff[mb].dsp_xports.front()->get_send_frame_size(); + const double ups_per_fifo = device_args[mb].cast("ups_per_fifo", 8.0); + _mboard_stuff[mb].tx_dsp->set_updates( + (ups_per_sec > 0.0)? size_t(tick_rate/ups_per_sec) : 0, + (ups_per_fifo > 0.0)? size_t(USRP2_SRAM_BYTES/ups_per_fifo/send_frame_size) : 0 + ); - //create time control objects + //////////////////////////////////////////////////////////////// + // create time control objects + //////////////////////////////////////////////////////////////// + time64_core_200::readback_bases_type time64_rb_bases; + time64_rb_bases.rb_secs_imm = U2_REG_TIME64_SECS_RB_IMM; + time64_rb_bases.rb_ticks_imm = U2_REG_TIME64_TICKS_RB_IMM; + time64_rb_bases.rb_secs_pps = U2_REG_TIME64_SECS_RB_PPS; + time64_rb_bases.rb_ticks_pps = U2_REG_TIME64_TICKS_RB_PPS; + _mboard_stuff[mb].time64 = time64_core_200::make( + _mboard_stuff[mb].iface, U2_REG_SR_ADDR(SR_TIME64), time64_rb_bases, mimo_clock_sync_delay_cycles + ); + _mboard_stuff[mb].time64->set_tick_rate(tick_rate); //does not change on usrp2 + property time_now_prop, time_pps_prop; + time_now_prop.publish(boost::bind(&time64_core_200::get_time_now, _mboard_stuff[mb].time64)); + time_now_prop.subscribe(boost::bind(&time64_core_200::set_time_now, _mboard_stuff[mb].time64, _1)); + _tree->create(mb_path / "time/now", time_now_prop); + time_pps_prop.publish(boost::bind(&time64_core_200::get_time_last_pps, _mboard_stuff[mb].time64)); + time_pps_prop.subscribe(boost::bind(&time64_core_200::set_time_next_pps, _mboard_stuff[mb].time64, _1)); + _tree->create(mb_path / "time/pps", time_pps_prop); } } +usrp2_impl::~usrp2_impl(void){UHD_SAFE_CALL( + for (size_t mb = 0; mb < _mboard_stuff.size(); mb++){ + _mboard_stuff[mb].tx_dsp->set_updates(0, 0); + } +)} + void usrp2_impl::set_mb_eeprom(const size_t which_mb, const uhd::usrp::mboard_eeprom_t &mb_eeprom){ mb_eeprom.commit(*(_mboard_stuff[which_mb].iface), mboard_eeprom_t::MAP_N100); } diff --git a/host/lib/usrp2/usrp2_impl.hpp b/host/lib/usrp2/usrp2_impl.hpp index c3a859851..19f1d8b0f 100644 --- a/host/lib/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp2/usrp2_impl.hpp @@ -25,6 +25,7 @@ #include "tx_frontend_core_200.hpp" #include "rx_dsp_core_200.hpp" #include "tx_dsp_core_200.hpp" +#include "time64_core_200.hpp" #include #include #include @@ -42,6 +43,11 @@ #include #include +static const double mimo_clock_delay_usrp2_rev4 = 4.18e-9; +static const double mimo_clock_delay_usrp_n2xx = 3.55e-9; +static const size_t mimo_clock_sync_delay_cycles = 137; +static const size_t USRP2_SRAM_BYTES = size_t(1 << 20); + /*! * Make a usrp2 dboard interface. * \param iface the usrp2 interface object @@ -61,6 +67,7 @@ uhd::usrp::dboard_iface::sptr make_usrp2_dboard_iface( class usrp2_impl{ public: usrp2_impl(const uhd::device_addr_t &_device_addr); + ~usrp2_impl(void); uhd::property_tree::sptr _tree; private: struct mboard_stuff_type{ @@ -69,9 +76,11 @@ private: usrp2_codec_ctrl::sptr codec; rx_frontend_core_200::sptr rx_fe; tx_frontend_core_200::sptr tx_fe; - rx_dsp_core_200::sptr rx_dsp; + std::vector rx_dsps; tx_dsp_core_200::sptr tx_dsp; - //TODO time core + time64_core_200::sptr time64; + std::vector dsp_xports; + std::vector err_xports; }; std::vector _mboard_stuff; -- cgit v1.2.3