diff options
-rw-r--r-- | host/lib/usrp/cores/rx_dsp_core_200.cpp | 11 | ||||
-rw-r--r-- | host/lib/usrp/cores/rx_dsp_core_200.hpp | 4 | ||||
-rw-r--r-- | host/lib/usrp/cores/tx_dsp_core_200.cpp | 5 | ||||
-rw-r--r-- | host/lib/usrp/cores/tx_dsp_core_200.hpp | 2 | ||||
-rw-r--r-- | host/lib/usrp2/usrp2_impl.cpp | 176 | ||||
-rw-r--r-- | host/lib/usrp2/usrp2_impl.hpp | 13 |
6 files changed, 190 insertions, 21 deletions
diff --git a/host/lib/usrp/cores/rx_dsp_core_200.cpp b/host/lib/usrp/cores/rx_dsp_core_200.cpp index e4d88b38f..5aa32c630 100644 --- a/host/lib/usrp/cores/rx_dsp_core_200.cpp +++ b/host/lib/usrp/cores/rx_dsp_core_200.cpp @@ -48,12 +48,11 @@ public: rx_dsp_core_200_impl( wb_iface::sptr iface, const size_t dsp_base, const size_t ctrl_base, - const boost::uint32_t sid, const size_t nsamps + const boost::uint32_t sid ): _iface(iface), _dsp_base(dsp_base), _ctrl_base(ctrl_base) { _iface->poke32(REG_RX_CTRL_CLEAR, 1); //reset - _iface->poke32(REG_RX_CTRL_NSAMPS_PP, nsamps); _iface->poke32(REG_RX_CTRL_NCHANNELS, 1); _iface->poke32(REG_RX_CTRL_VRT_HDR, 0 | (0x1 << 28) //if data with stream id @@ -65,6 +64,10 @@ public: _iface->poke32(REG_RX_CTRL_VRT_TLR, 0); } + void set_nsamps_per_packet(const size_t nsamps){ + _iface->poke32(REG_RX_CTRL_NSAMPS_PP, nsamps); + } + void issue_stream_command(const stream_cmd_t &stream_cmd){ UHD_ASSERT_THROW(stream_cmd.num_samps <= 0x3fffffff); _continuous_streaming = stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS; @@ -159,6 +162,6 @@ private: bool _continuous_streaming; }; -rx_dsp_core_200::sptr rx_dsp_core_200::make(wb_iface::sptr iface, const size_t dsp_base, const size_t ctrl_base, const boost::uint32_t sid, const size_t nsamps){ - return sptr(new rx_dsp_core_200_impl(iface, dsp_base, ctrl_base, sid, nsamps)); +rx_dsp_core_200::sptr rx_dsp_core_200::make(wb_iface::sptr iface, const size_t dsp_base, const size_t ctrl_base, const boost::uint32_t sid){ + return sptr(new rx_dsp_core_200_impl(iface, dsp_base, ctrl_base, sid)); } diff --git a/host/lib/usrp/cores/rx_dsp_core_200.hpp b/host/lib/usrp/cores/rx_dsp_core_200.hpp index a88c39a2f..6bc7c6102 100644 --- a/host/lib/usrp/cores/rx_dsp_core_200.hpp +++ b/host/lib/usrp/cores/rx_dsp_core_200.hpp @@ -32,9 +32,11 @@ public: static sptr make( wb_iface::sptr iface, const size_t dsp_base, const size_t ctrl_base, - const boost::uint32_t sid, const size_t nsamps + const boost::uint32_t sid ); + virtual void set_nsamps_per_packet(const size_t nsamps) = 0; + virtual void issue_stream_command(const uhd::stream_cmd_t &stream_cmd) = 0; virtual void set_mux(const std::string &mode) = 0; diff --git a/host/lib/usrp/cores/tx_dsp_core_200.cpp b/host/lib/usrp/cores/tx_dsp_core_200.cpp index c7e18a8a6..6ad88c380 100644 --- a/host/lib/usrp/cores/tx_dsp_core_200.cpp +++ b/host/lib/usrp/cores/tx_dsp_core_200.cpp @@ -112,6 +112,11 @@ public: return actual_freq; } + void set_updates(const size_t cycles_per_up, const size_t packets_per_up){ + _iface->poke32(REG_TX_CTRL_CYCLES_PER_UP, (cycles_per_up == 0)? 0 : (FLAG_TX_CTRL_UP_ENB | cycles_per_up)); + _iface->poke32(REG_TX_CTRL_PACKETS_PER_UP, (packets_per_up == 0)? 0 : (FLAG_TX_CTRL_UP_ENB | packets_per_up)); + } + private: wb_iface::sptr _iface; const size_t _dsp_base, _ctrl_base; diff --git a/host/lib/usrp/cores/tx_dsp_core_200.hpp b/host/lib/usrp/cores/tx_dsp_core_200.hpp index 479023caa..f218fe8c9 100644 --- a/host/lib/usrp/cores/tx_dsp_core_200.hpp +++ b/host/lib/usrp/cores/tx_dsp_core_200.hpp @@ -39,6 +39,8 @@ public: virtual double set_freq(const double freq) = 0; + virtual void set_updates(const size_t cycles_per_up, const size_t packets_per_up) = 0; + }; #endif /* INCLUDED_LIBUHD_USRP_TX_DSP_CORE_200_HPP */ 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 <uhd/exception.hpp> #include <uhd/transport/if_addrs.hpp> #include <uhd/transport/udp_zero_copy.hpp> +#include <uhd/types/ranges.hpp> #include <uhd/usrp/device_props.hpp> #include <uhd/exception.hpp> #include <uhd/utils/static.hpp> #include <uhd/utils/byteswap.hpp> -#include <boost/assign/list_of.hpp> +#include <uhd/utils/safe_call.hpp> #include <boost/format.hpp> #include <boost/foreach.hpp> #include <boost/lexical_cast.hpp> #include <boost/bind.hpp> #include <boost/asio/ip/address_v4.hpp> #include <boost/asio.hpp> //used for htonl and ntohl -#include <vector> using namespace uhd; using namespace uhd::usrp; @@ -110,6 +110,23 @@ static mtu_result_t determine_mtu(const std::string &addr, const mtu_result_t &u } /*********************************************************************** + * Helpers + **********************************************************************/ +static void init_xport(zero_copy_if::sptr xport){ + //Send a small data packet so the usrp2 knows the udp source port. + //This setup must happen before further initialization occurs + //or the async update packets will cause ICMP destination unreachable. + static const boost::uint32_t data[2] = { + uhd::htonx(boost::uint32_t(0 /* don't care seq num */)), + uhd::htonx(boost::uint32_t(USRP2_INVALID_VRT_HEADER)) + }; + + transport::managed_send_buffer::sptr send_buff = xport->get_send_buff(); + std::memcpy(send_buff->cast<void*>(), &data, sizeof(data)); + send_buff->commit(sizeof(data)); +} + +/*********************************************************************** * Structors **********************************************************************/ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){ @@ -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<std::string>(_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<usrp::mboard_eeprom_t> 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<double> tick_rate_prop(_mboard_stuff[mb].clock->get_master_clock_rate()); + const double tick_rate = _mboard_stuff[mb].clock->get_master_clock_rate(); + property<double> 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<std::string>("ads62p44")); + _tree->create(rx_codec_path / "gains/0/name", property<std::string>("digital")); + _tree->create(rx_codec_path / "gains/0/range", property<meta_range_t>(meta_range_t(0, 6.0, 0.5))); + property<double> 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<std::string>("digital-fine")); + _tree->create(rx_codec_path / "gains/1/range", property<meta_range_t>(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<std::string>("ltc2284")); + break; + + case usrp2_iface::USRP_NXXX: + _tree->create(rx_codec_path / "name", property<std::string>("??????")); + break; + } + _tree->create(tx_codec_path / "name", property<std::string>("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<double> 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<double> 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<double>("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<double>("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_spec_t> 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 <uhd/property_tree.hpp> #include <uhd/usrp/gps_ctrl.hpp> #include <uhd/device.hpp> @@ -42,6 +43,11 @@ #include <uhd/usrp/dboard_manager.hpp> #include <uhd/usrp/subdev_spec.hpp> +static const double mimo_clock_delay_usrp2_rev4 = 4.18e-9; +static const double mimo_clock_delay_usrp_n2xx = 3.55e-9; +static const size_t mimo_clock_sync_delay_cycles = 137; +static const size_t USRP2_SRAM_BYTES = size_t(1 << 20); + /*! * 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_dsp_core_200::sptr> rx_dsps; tx_dsp_core_200::sptr tx_dsp; - //TODO time core + time64_core_200::sptr time64; + std::vector<uhd::transport::zero_copy_if::sptr> dsp_xports; + std::vector<uhd::transport::zero_copy_if::sptr> err_xports; }; std::vector<mboard_stuff_type> _mboard_stuff; |