diff options
| author | Josh Blum <josh@joshknows.com> | 2010-11-23 09:57:33 -0800 | 
|---|---|---|
| committer | Josh Blum <josh@joshknows.com> | 2010-11-23 09:57:33 -0800 | 
| commit | d35b7327710f08f96f2cfb93bcc28f14515ea9bb (patch) | |
| tree | 0cfe31630905570c776a45746fcb3e2011d3dabd /host/lib/usrp/usrp2 | |
| parent | 6741de7b4545bb33d22cc6508e121023dd1a7a8c (diff) | |
| parent | 768af46dc01d036999cb60ff16df4215d014c906 (diff) | |
| download | uhd-d35b7327710f08f96f2cfb93bcc28f14515ea9bb.tar.gz uhd-d35b7327710f08f96f2cfb93bcc28f14515ea9bb.tar.bz2 uhd-d35b7327710f08f96f2cfb93bcc28f14515ea9bb.zip | |
Merge branch 'flow_ctrl' into next
Diffstat (limited to 'host/lib/usrp/usrp2')
| -rw-r--r-- | host/lib/usrp/usrp2/fw_common.h | 4 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/io_impl.cpp | 144 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/mboard_impl.cpp | 39 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_iface.cpp | 14 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.cpp | 13 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.hpp | 13 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_regs.cpp | 2 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_regs.hpp | 18 | 
8 files changed, 182 insertions, 65 deletions
| diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 6c9596092..a9c39e650 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -33,8 +33,8 @@ extern "C" {  #endif  //fpga and firmware compatibility numbers -#define USRP2_FPGA_COMPAT_NUM 2 -#define USRP2_FW_COMPAT_NUM 6 +#define USRP2_FPGA_COMPAT_NUM 3 +#define USRP2_FW_COMPAT_NUM 7  //used to differentiate control packets over data port  #define USRP2_INVALID_VRT_HEADER 0 diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 4b498ff7f..f2101519d 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -18,11 +18,11 @@  #include "../../transport/vrt_packet_handler.hpp"  #include "usrp2_impl.hpp"  #include "usrp2_regs.hpp" +#include <uhd/utils/byteswap.hpp>  #include <uhd/utils/thread_priority.hpp>  #include <uhd/transport/convert_types.hpp>  #include <uhd/transport/alignment_buffer.hpp>  #include <boost/format.hpp> -#include <boost/asio.hpp> //htonl and ntohl  #include <boost/bind.hpp>  #include <boost/thread.hpp>  #include <iostream> @@ -32,7 +32,73 @@ using namespace uhd::usrp;  using namespace uhd::transport;  namespace asio = boost::asio; -static const int underflow_flags = async_metadata_t::EVENT_CODE_UNDERFLOW | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET; +/*********************************************************************** + * constants + **********************************************************************/ +static const int underflow_flags = 0 +    | async_metadata_t::EVENT_CODE_UNDERFLOW +    | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET +; + +static const size_t vrt_send_header_offset_words32 = 1; + +/*********************************************************************** + * flow control monitor for a single tx channel + *  - the pirate thread calls update + *  - the get send buffer calls check + **********************************************************************/ +class flow_control_monitor{ +public: +    typedef boost::uint32_t seq_type; +    typedef boost::shared_ptr<flow_control_monitor> sptr; + +    /*! +     * Make a new flow control monitor. +     * \param max_seqs_out num seqs before throttling +     */ +    flow_control_monitor(seq_type max_seqs_out){ +        _last_seq_out = 0; +        _last_seq_ack = 0; +        _max_seqs_out = max_seqs_out; +    } + +    /*! +     * Check the flow control condition. +     * \param seq the sequence to go out +     * \param timeout the timeout in seconds +     * \return false on timeout +     */ +    UHD_INLINE bool check_fc_condition(seq_type seq, double timeout){ +        boost::this_thread::disable_interruption di; //disable because the wait can throw +        boost::unique_lock<boost::mutex> lock(_fc_mutex); +        _last_seq_out = seq; +        return _fc_cond.timed_wait( +            lock, +            boost::posix_time::microseconds(long(timeout*1e6)), +            boost::bind(&flow_control_monitor::ready, this) +        ); +    } + +    /*! +     * Update the flow control condition. +     * \param seq the last sequence number to be ACK'd +     */ +    UHD_INLINE void update_fc_condition(seq_type seq){ +        boost::unique_lock<boost::mutex> lock(_fc_mutex); +        _last_seq_ack = seq; +        lock.unlock(); +        _fc_cond.notify_one(); +    } + +private: +    bool ready(void){ +        return seq_type(_last_seq_out -_last_seq_ack) < _max_seqs_out; +    } + +    boost::mutex _fc_mutex; +    boost::condition _fc_cond; +    seq_type _last_seq_out, _last_seq_ack, _max_seqs_out; +};  /***********************************************************************   * io impl details (internal to this file) @@ -44,12 +110,14 @@ static const int underflow_flags = async_metadata_t::EVENT_CODE_UNDERFLOW | asyn  struct usrp2_impl::io_impl{      typedef alignment_buffer<managed_recv_buffer::sptr, time_spec_t> alignment_buffer_type; -    io_impl(size_t num_frames, size_t width): +    io_impl(size_t num_recv_frames, size_t send_frame_size, size_t width):          packet_handler_recv_state(width), -        recv_pirate_booty(alignment_buffer_type::make(num_frames-3, width)), +        recv_pirate_booty(alignment_buffer_type::make(num_recv_frames-3, width)),          async_msg_fifo(bounded_buffer<async_metadata_t>::make(100/*messages deep*/))      { -        /* NOP */ +        for (size_t i = 0; i < width; i++) fc_mons.push_back( +            flow_control_monitor::sptr(new flow_control_monitor(usrp2_impl::sram_bytes/send_frame_size)) +        );      }      ~io_impl(void){ @@ -63,6 +131,29 @@ struct usrp2_impl::io_impl{          return recv_pirate_booty->pop_elems_with_timed_wait(buffs, timeout);      } +    bool get_send_buffs( +        const std::vector<zero_copy_if::sptr> &trans, +        vrt_packet_handler::managed_send_buffs_t &buffs, +        double timeout +    ){ +        UHD_ASSERT_THROW(trans.size() == buffs.size()); + +        //calculate the flow control word +        const boost::uint32_t fc_word32 = packet_handler_send_state.next_packet_seq; + +        //grab a managed buffer for each index +        for (size_t i = 0; i < buffs.size(); i++){ +            if (not fc_mons[i]->check_fc_condition(fc_word32, timeout)) return false; +            buffs[i] = trans[i]->get_send_buff(timeout); +            if (not buffs[i].get()) return false; +            buffs[i]->cast<boost::uint32_t *>()[0] = uhd::htonx(fc_word32); +        } +        return true; +    } + +    //flow control monitors +    std::vector<flow_control_monitor::sptr> fc_mons; +      //state management for the vrt packet handler code      vrt_packet_handler::recv_state packet_handler_recv_state;      vrt_packet_handler::send_state packet_handler_send_state; @@ -115,8 +206,16 @@ void usrp2_impl::io_impl::recv_pirate_loop(                  );                  metadata.event_code = vrt_packet_handler::get_context_code<async_metadata_t::event_code_t>(vrt_hdr, if_packet_info); +                //catch the flow control packets and react +                if (metadata.event_code == 0){ +                    boost::uint32_t fc_word32 = (vrt_hdr + if_packet_info.num_header_words32)[1]; +                    this->fc_mons[index]->update_fc_condition(uhd::ntohx(fc_word32)); +                    continue; +                } +                  //print the famous U, and push the metadata into the message queue                  if (metadata.event_code & underflow_flags) std::cerr << "U" << std::flush; +                //else std::cout << "metadata.event_code " << metadata.event_code << std::endl;                  async_msg_fifo->push_with_pop_on_full(metadata);                  continue;              } @@ -146,22 +245,13 @@ void usrp2_impl::io_impl::recv_pirate_loop(   * Helper Functions   **********************************************************************/  void usrp2_impl::io_init(void){ -    //send a small data packet so the usrp2 knows the udp source port -    BOOST_FOREACH(zero_copy_if::sptr data_transport, _data_transports){ -        managed_send_buffer::sptr send_buff = data_transport->get_send_buff(); -        static const boost::uint32_t data = htonl(USRP2_INVALID_VRT_HEADER); -        std::memcpy(send_buff->cast<void*>(), &data, sizeof(data)); -        send_buff->commit(sizeof(data)); -        //drain the recv buffers (may have junk) -        while (data_transport->get_recv_buff().get()){}; -    } -    //the number of recv frames is the number for the first transport      //the assumption is that all data transports should be identical -    size_t num_frames = _data_transports.front()->get_num_recv_frames(); +    const size_t num_recv_frames = _data_transports.front()->get_num_recv_frames(); +    const size_t send_frame_size = _data_transports.front()->get_send_frame_size();      //create new io impl -    _io_impl = UHD_PIMPL_MAKE(io_impl, (num_frames, _data_transports.size())); +    _io_impl = UHD_PIMPL_MAKE(io_impl, (num_recv_frames, send_frame_size, _data_transports.size()));      //create a new pirate thread for each zc if (yarr!!)      for (size_t i = 0; i < _data_transports.size(); i++){ @@ -193,23 +283,10 @@ bool usrp2_impl::recv_async_msg(  /***********************************************************************   * Send Data   **********************************************************************/ -static bool get_send_buffs( -    const std::vector<udp_zero_copy::sptr> &trans, -    vrt_packet_handler::managed_send_buffs_t &buffs, -    double timeout -){ -    UHD_ASSERT_THROW(trans.size() == buffs.size()); -    bool good = true; -    for (size_t i = 0; i < buffs.size(); i++){ -        buffs[i] = trans[i]->get_send_buff(timeout); -        good = good and (buffs[i].get() != NULL); -    } -    return good; -} -  size_t usrp2_impl::get_max_send_samps_per_packet(void) const{      static const size_t hdr_size = 0          + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) +        + vrt_send_header_offset_words32*sizeof(boost::uint32_t)          - sizeof(vrt::if_packet_info_t().cid) //no class id ever used      ;      const size_t bpp = _data_transports.front()->get_send_frame_size() - hdr_size; @@ -228,8 +305,9 @@ size_t usrp2_impl::send(          io_type, _tx_otw_type,                     //input and output types to convert          _mboards.front()->get_master_clock_freq(), //master clock tick rate          uhd::transport::vrt::if_hdr_pack_be, -        boost::bind(&get_send_buffs, _data_transports, _1, timeout), -        get_max_send_samps_per_packet() +        boost::bind(&usrp2_impl::io_impl::get_send_buffs, _io_impl.get(), _data_transports, _1, timeout), +        get_max_send_samps_per_packet(), +        vrt_send_header_offset_words32      );  } diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 3df89d327..92b1d0be9 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -21,6 +21,7 @@  #include <uhd/usrp/dsp_utils.hpp>  #include <uhd/usrp/mboard_props.hpp>  #include <uhd/utils/assert.hpp> +#include <uhd/utils/byteswap.hpp>  #include <uhd/utils/algorithm.hpp>  #include <boost/bind.hpp>  #include <iostream> @@ -36,12 +37,24 @@ using namespace boost::posix_time;  usrp2_mboard_impl::usrp2_mboard_impl(      size_t index,      transport::udp_simple::sptr ctrl_transport, -    size_t recv_frame_size +    transport::zero_copy_if::sptr data_transport, +    size_t recv_samps_per_packet, +    const device_addr_t &flow_control_hints  ):      _index(index), -    _recv_frame_size(recv_frame_size),      _iface(usrp2_iface::make(ctrl_transport))  { +    //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. +    transport::managed_send_buffer::sptr send_buff = data_transport->get_send_buff(); +    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)) +    }; +    std::memcpy(send_buff->cast<void*>(), &data, sizeof(data)); +    send_buff->commit(sizeof(data)); +      //contruct the interfaces to mboard perifs      _clock_ctrl = usrp2_clock_ctrl::make(_iface);      _codec_ctrl = usrp2_codec_ctrl::make(_iface); @@ -64,13 +77,14 @@ usrp2_mboard_impl::usrp2_mboard_impl(          _allowed_decim_and_interp_rates.push_back(i);      } +      //Issue a stop streaming command (in case it was left running).      //Since this command is issued before the networking is setup,      //most if not all junk packets will never make it to the socket.      this->issue_ddc_stream_cmd(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);      //setup the vrt rx registers -    _iface->poke32(_iface->regs.rx_ctrl_nsamps_per_pkt, _recv_frame_size); +    _iface->poke32(_iface->regs.rx_ctrl_nsamps_per_pkt, recv_samps_per_packet);      _iface->poke32(_iface->regs.rx_ctrl_nchannels, 1);      _iface->poke32(_iface->regs.rx_ctrl_clear_overrun, 1); //reset      _iface->poke32(_iface->regs.rx_ctrl_vrt_header, 0 @@ -89,6 +103,17 @@ usrp2_mboard_impl::usrp2_mboard_impl(      _iface->poke32(_iface->regs.tx_ctrl_report_sid, 1);  //sid 1 (different from rx)      _iface->poke32(_iface->regs.tx_ctrl_policy, U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET); +    //setting the cycles per update +    const double ups_per_sec = flow_control_hints.cast<double>("ups_per_sec", 100); +    const size_t cycles_per_up = size_t(_clock_ctrl->get_master_clock_rate()/ups_per_sec); +    _iface->poke32(_iface->regs.tx_ctrl_cycles_per_up, U2_FLAG_TX_CTRL_UP_ENB | cycles_per_up); +    _iface->poke32(_iface->regs.tx_ctrl_cycles_per_up, 0); //cycles per update is disabled + +    //setting the packets per update +    const double ups_per_fifo = flow_control_hints.cast<double>("ups_per_fifo", 8); +    const size_t packets_per_up = size_t(usrp2_impl::sram_bytes/ups_per_fifo/data_transport->get_send_frame_size()); +    _iface->poke32(_iface->regs.tx_ctrl_packets_per_up, U2_FLAG_TX_CTRL_UP_ENB | packets_per_up); +      //init the ddc      init_ddc_config(); @@ -110,7 +135,8 @@ usrp2_mboard_impl::usrp2_mboard_impl(  }  usrp2_mboard_impl::~usrp2_mboard_impl(void){ -    /* NOP */ +    _iface->poke32(_iface->regs.tx_ctrl_cycles_per_up, 0); +    _iface->poke32(_iface->regs.tx_ctrl_packets_per_up, 0);  }  /*********************************************************************** @@ -187,7 +213,6 @@ void usrp2_mboard_impl::set_time_spec(const time_spec_t &time_spec, bool now){  }  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);      } @@ -195,9 +220,7 @@ void usrp2_mboard_impl::handle_overflow(void){  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 -    )); +    _iface->poke32(_iface->regs.rx_ctrl_stream_cmd, dsp_type1::calc_stream_cmd_word(stream_cmd));      _iface->poke32(_iface->regs.rx_ctrl_time_secs,  boost::uint32_t(stream_cmd.time_spec.get_full_secs()));      _iface->poke32(_iface->regs.rx_ctrl_time_ticks, stream_cmd.time_spec.get_tick_count(get_master_clock_freq()));  } diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp index 2b32faffb..81bc80c88 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.cpp +++ b/host/lib/usrp/usrp2/usrp2_iface.cpp @@ -33,18 +33,6 @@ using namespace uhd;  using namespace uhd::usrp;  using namespace uhd::transport; -/*! - * FIXME: large timeout, ethernet pause frames... - * - * Use a large timeout to work-around the fact that - * flow-control may throttle outgoing control packets - * due to its use of ethernet pause frames. - * - * This will be fixed when host-based flow control is implemented, - * along with larger incoming send buffers using the on-board SRAM. - */ -static const double CONTROL_TIMEOUT = 3.0; //seconds -  class usrp2_iface_impl : public usrp2_iface{  public:  /*********************************************************************** @@ -256,7 +244,7 @@ public:          boost::uint8_t usrp2_ctrl_data_in_mem[udp_simple::mtu]; //allocate max bytes for recv          const usrp2_ctrl_data_t *ctrl_data_in = reinterpret_cast<const usrp2_ctrl_data_t *>(usrp2_ctrl_data_in_mem);          while(true){ -            size_t len = _ctrl_transport->recv(boost::asio::buffer(usrp2_ctrl_data_in_mem), CONTROL_TIMEOUT); +            size_t len = _ctrl_transport->recv(boost::asio::buffer(usrp2_ctrl_data_in_mem));              if(len >= sizeof(boost::uint32_t) and ntohl(ctrl_data_in->proto_ver) != USRP2_FW_COMPAT_NUM){                  throw std::runtime_error(str(boost::format(                      "Expected protocol compatibility number %d, but got %d:\n" diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 42fe9c018..610e2f404 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -17,7 +17,7 @@  #include "usrp2_impl.hpp"  #include <uhd/transport/if_addrs.hpp> -#include <uhd/transport/udp_simple.hpp> +#include <uhd/transport/udp_zero_copy.hpp>  #include <uhd/usrp/device_props.hpp>  #include <uhd/utils/assert.hpp>  #include <uhd/utils/static.hpp> @@ -144,7 +144,7 @@ static device::sptr usrp2_make(const device_addr_t &device_addr){      //create a ctrl and data transport for each address      std::vector<udp_simple::sptr> ctrl_transports; -    std::vector<udp_zero_copy::sptr> data_transports; +    std::vector<zero_copy_if::sptr> data_transports;      BOOST_FOREACH(const std::string &addr, std::split_string(device_addr["addr"])){          ctrl_transports.push_back(udp_simple::make_connected( @@ -157,7 +157,7 @@ static device::sptr usrp2_make(const device_addr_t &device_addr){      //create the usrp2 implementation guts      return device::sptr( -        new usrp2_impl(ctrl_transports, data_transports) +        new usrp2_impl(ctrl_transports, data_transports, device_addr)      );  } @@ -170,7 +170,8 @@ UHD_STATIC_BLOCK(register_usrp2_device){   **********************************************************************/  usrp2_impl::usrp2_impl(      std::vector<udp_simple::sptr> ctrl_transports, -    std::vector<udp_zero_copy::sptr> data_transports +    std::vector<zero_copy_if::sptr> data_transports, +    const device_addr_t &flow_control_hints  ):      _data_transports(data_transports)  { @@ -189,7 +190,9 @@ usrp2_impl::usrp2_impl(      //create a new mboard handler for each control transport      for(size_t i = 0; i < ctrl_transports.size(); i++){          _mboards.push_back(usrp2_mboard_impl::sptr(new usrp2_mboard_impl( -            i, ctrl_transports[i], this->get_max_recv_samps_per_packet() +            i, ctrl_transports[i], data_transports[i], +            this->get_max_recv_samps_per_packet(), +            flow_control_hints          )));          //use an empty name when there is only one mboard          std::string name = (ctrl_transports.size() > 1)? boost::lexical_cast<std::string>(i) : ""; diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 738c398d9..ede777323 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -85,7 +85,9 @@ public:      usrp2_mboard_impl(          size_t index,          uhd::transport::udp_simple::sptr, -        size_t recv_frame_size +        uhd::transport::zero_copy_if::sptr, +        size_t recv_samps_per_packet, +        const uhd::device_addr_t &flow_control_hints      );      ~usrp2_mboard_impl(void); @@ -97,7 +99,6 @@ public:  private:      size_t _index; -    const size_t _recv_frame_size;      bool _continuous_streaming;      //interfaces @@ -178,14 +179,18 @@ private:   */  class usrp2_impl : public uhd::device{  public: +    static const size_t sram_bytes = size_t(1 << 20); +      /*!       * Create a new usrp2 impl base.       * \param ctrl_transports the udp transports for control       * \param data_transports the udp transports for data +     * \param flow_control_hints optional flow control params       */      usrp2_impl(          std::vector<uhd::transport::udp_simple::sptr> ctrl_transports, -        std::vector<uhd::transport::udp_zero_copy::sptr> data_transports +        std::vector<uhd::transport::zero_copy_if::sptr> data_transports, +        const uhd::device_addr_t &flow_control_hints      );      ~usrp2_impl(void); @@ -215,7 +220,7 @@ private:      uhd::dict<std::string, usrp2_mboard_impl::sptr> _mboard_dict;      //io impl methods and members -    std::vector<uhd::transport::udp_zero_copy::sptr> _data_transports; +    std::vector<uhd::transport::zero_copy_if::sptr> _data_transports;      uhd::otw_type_t _rx_otw_type, _tx_otw_type;      UHD_PIMPL_DECL(io_impl) _io_impl;      void io_init(void); diff --git a/host/lib/usrp/usrp2/usrp2_regs.cpp b/host/lib/usrp/usrp2/usrp2_regs.cpp index b24082edb..dd0433816 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.cpp +++ b/host/lib/usrp/usrp2/usrp2_regs.cpp @@ -95,6 +95,8 @@ usrp2_regs_t usrp2_get_regs(bool use_n2xx_map) {    x.tx_ctrl_clear_state = sr_addr(misc_output_base, x.sr_tx_ctrl + 1);    x.tx_ctrl_report_sid = sr_addr(misc_output_base, x.sr_tx_ctrl + 2);    x.tx_ctrl_policy = sr_addr(misc_output_base, x.sr_tx_ctrl + 3); +  x.tx_ctrl_cycles_per_up = sr_addr(misc_output_base, x.sr_tx_ctrl + 4); +  x.tx_ctrl_packets_per_up = sr_addr(misc_output_base, x.sr_tx_ctrl + 5);    return x;  } diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp index 1081ff159..9936d634a 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.hpp +++ b/host/lib/usrp/usrp2/usrp2_regs.hpp @@ -97,6 +97,8 @@ typedef struct {      int tx_ctrl_clear_state;      int tx_ctrl_report_sid;      int tx_ctrl_policy; +    int tx_ctrl_cycles_per_up; +    int tx_ctrl_packets_per_up;  } usrp2_regs_t;  extern const usrp2_regs_t usrp2_regs; //the register definitions, set in usrp2_regs.cpp and usrp2p_regs.cpp @@ -254,7 +256,18 @@ usrp2_regs_t usrp2_get_regs(bool);  ///////////////////////////////////////////////////  // RX CTRL regs  /////////////////////////////////////////////////// +// The following 3 are logically a single command register. +// They are clocked into the underlying fifo when time_ticks is written. +//#define U2_REG_RX_CTRL_STREAM_CMD        _SR_ADDR(SR_RX_CTRL + 0) // {now, chain, num_samples(30) +//#define U2_REG_RX_CTRL_TIME_SECS         _SR_ADDR(SR_RX_CTRL + 1) +//#define U2_REG_RX_CTRL_TIME_TICKS        _SR_ADDR(SR_RX_CTRL + 2) +//#define U2_REG_RX_CTRL_CLEAR_STATE       _SR_ADDR(SR_RX_CTRL + 3) +//#define U2_REG_RX_CTRL_VRT_HEADER        _SR_ADDR(SR_RX_CTRL + 4) // word 0 of packet.  FPGA fills in packet counter +//#define U2_REG_RX_CTRL_VRT_STREAM_ID     _SR_ADDR(SR_RX_CTRL + 5) // word 1 of packet. +//#define U2_REG_RX_CTRL_VRT_TRAILER       _SR_ADDR(SR_RX_CTRL + 6) +//#define U2_REG_RX_CTRL_NSAMPS_PER_PKT    _SR_ADDR(SR_RX_CTRL + 7) +//#define U2_REG_RX_CTRL_NCHANNELS         _SR_ADDR(SR_RX_CTRL + 8) // 1 in basic case, up to 4 for vector sources  ///////////////////////////////////////////////////  // TX CTRL regs @@ -263,9 +276,14 @@ usrp2_regs_t usrp2_get_regs(bool);  //#define U2_REG_TX_CTRL_CLEAR_STATE       _SR_ADDR(SR_TX_CTRL + 1)  //#define U2_REG_TX_CTRL_REPORT_SID        _SR_ADDR(SR_TX_CTRL + 2)  //#define U2_REG_TX_CTRL_POLICY            _SR_ADDR(SR_TX_CTRL + 3) +//#define U2_REG_TX_CTRL_CYCLES_PER_UP     _SR_ADDR(SR_TX_CTRL + 4) +//#define U2_REG_TX_CTRL_PACKETS_PER_UP    _SR_ADDR(SR_TX_CTRL + 5)  #define U2_FLAG_TX_CTRL_POLICY_WAIT          (0x1 << 0)  #define U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET   (0x1 << 1)  #define U2_FLAG_TX_CTRL_POLICY_NEXT_BURST    (0x1 << 2) +//enable flag for registers: cycles and packets per update packet +#define U2_FLAG_TX_CTRL_UP_ENB              (1ul << 31) +  #endif /* INCLUDED_USRP2_REGS_HPP */ | 
