diff options
Diffstat (limited to 'host/lib')
-rw-r--r-- | host/lib/transport/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/lib/transport/udp_zero_copy_asio.cpp | 136 | ||||
-rw-r--r-- | host/lib/transport/vrt_packet_handler.hpp | 358 | ||||
-rw-r--r-- | host/lib/types.cpp | 119 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/clock_ctrl.cpp | 8 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/io_impl.cpp | 162 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/mboard_impl.cpp | 2 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.cpp | 8 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.hpp | 50 |
9 files changed, 572 insertions, 272 deletions
diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index a36f0fc03..ed8c35225 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -49,4 +49,5 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_SOURCE_DIR}/lib/transport/if_addrs.cpp ${CMAKE_SOURCE_DIR}/lib/transport/udp_simple.cpp ${CMAKE_SOURCE_DIR}/lib/transport/udp_zero_copy_asio.cpp + ${CMAKE_SOURCE_DIR}/lib/transport/vrt_packet_handler.hpp ) diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index ee44803f4..56ba391d3 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -16,9 +16,9 @@ // #include <uhd/transport/udp_zero_copy.hpp> +#include <uhd/utils/assert.hpp> #include <boost/cstdint.hpp> #include <boost/asio.hpp> -#include <boost/thread.hpp> #include <boost/format.hpp> #include <iostream> @@ -26,65 +26,56 @@ using namespace uhd::transport; /*********************************************************************** * Managed receive buffer implementation for udp zero-copy asio: - * Frees the memory held by the const buffer on done. **********************************************************************/ class managed_recv_buffer_impl : public managed_recv_buffer{ public: managed_recv_buffer_impl(const boost::asio::const_buffer &buff) : _buff(buff){ - _done = false; + /* NOP */ } ~managed_recv_buffer_impl(void){ - if (not _done) this->done(); + /* NOP */ } void done(void){ - _done = true; - delete [] boost::asio::buffer_cast<const boost::uint32_t *>(_buff); + /* NOP */ } private: - const boost::asio::const_buffer &get(void){ + const boost::asio::const_buffer &get(void) const{ return _buff; } const boost::asio::const_buffer _buff; - bool _done; }; /*********************************************************************** * Managed send buffer implementation for udp zero-copy asio: - * Sends and frees the memory held by the mutable buffer on done. **********************************************************************/ class managed_send_buffer_impl : public managed_send_buffer{ public: managed_send_buffer_impl( const boost::asio::mutable_buffer &buff, boost::asio::ip::udp::socket *socket - ) : _buff(buff){ - _done = false; - _socket = socket; + ) : _buff(buff), _socket(socket){ + /* NOP */ } ~managed_send_buffer_impl(void){ - if (not _done) this->done(0); + /* NOP */ } void done(size_t num_bytes){ - _done = true; - boost::uint32_t *mem = boost::asio::buffer_cast<boost::uint32_t *>(_buff); - _socket->send(boost::asio::buffer(mem, num_bytes)); - delete [] mem; + _socket->send(boost::asio::buffer(_buff, num_bytes)); } private: - const boost::asio::mutable_buffer &get(void){ + const boost::asio::mutable_buffer &get(void) const{ return _buff; } const boost::asio::mutable_buffer _buff; boost::asio::ip::udp::socket *_socket; - bool _done; }; /*********************************************************************** @@ -94,8 +85,12 @@ private: * However, it is not a true zero copy implementation as each * send and recv requires a copy operation to/from userspace. **********************************************************************/ +static const size_t max_buff_size = 2000; //assume max size on send and recv + class udp_zero_copy_impl : public udp_zero_copy{ public: + typedef boost::shared_ptr<udp_zero_copy_impl> sptr; + //structors udp_zero_copy_impl(const std::string &addr, const std::string &port); ~udp_zero_copy_impl(void); @@ -104,23 +99,27 @@ public: managed_recv_buffer::sptr get_recv_buff(void); managed_send_buffer::sptr get_send_buff(void); - //resize - size_t resize_recv_buff(size_t num_bytes){ - boost::asio::socket_base::receive_buffer_size option(num_bytes); - _socket->set_option(option); + //manage buffer + template <typename Opt> size_t get_buff_size(void){ + Opt option; _socket->get_option(option); return option.value(); } - size_t resize_send_buff(size_t num_bytes){ - boost::asio::socket_base::send_buffer_size option(num_bytes); + + template <typename Opt> size_t resize_buff(size_t num_bytes){ + Opt option(num_bytes); _socket->set_option(option); - _socket->get_option(option); - return option.value(); + return get_buff_size<Opt>(); } private: boost::asio::ip::udp::socket *_socket; boost::asio::io_service _io_service; + + //send and recv buffer memory (allocated once) + boost::uint8_t _send_mem[max_buff_size], _recv_mem[max_buff_size]; + + managed_send_buffer::sptr _send_buff; }; udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::string &port){ @@ -131,10 +130,25 @@ udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::strin boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port); boost::asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query); - // Create, open, and connect the socket + // create, open, and connect the socket _socket = new boost::asio::ip::udp::socket(_io_service); _socket->open(boost::asio::ip::udp::v4()); _socket->connect(receiver_endpoint); + + // create the managed send buff (just once) + _send_buff = managed_send_buffer::sptr(new managed_send_buffer_impl( + boost::asio::buffer(_send_mem, max_buff_size), _socket + )); + + // set recv timeout + timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 100*1000; //100 ms + UHD_ASSERT_THROW(setsockopt( + _socket->native(), + SOL_SOCKET, SO_RCVTIMEO, + (const char *)&tv, sizeof(timeval) + ) == 0); } udp_zero_copy_impl::~udp_zero_copy_impl(void){ @@ -142,61 +156,55 @@ udp_zero_copy_impl::~udp_zero_copy_impl(void){ } managed_recv_buffer::sptr udp_zero_copy_impl::get_recv_buff(void){ - //implement timeout through polling and sleeping - size_t available = 0; - boost::asio::deadline_timer timer(_socket->get_io_service()); - timer.expires_from_now(boost::posix_time::milliseconds(100)); - while (not ((available = _socket->available()) or timer.expires_from_now().is_negative())){ - boost::this_thread::sleep(boost::posix_time::milliseconds(1)); - } - - //receive only if data is available - boost::uint32_t *buff_mem = new boost::uint32_t[available/sizeof(boost::uint32_t)]; - if (available){ - available = _socket->receive(boost::asio::buffer(buff_mem, available)); - } + //call recv() with timeout option + size_t num_bytes = _socket->receive(boost::asio::buffer(_recv_mem, max_buff_size)); //create a new managed buffer to house the data return managed_recv_buffer::sptr( - new managed_recv_buffer_impl(boost::asio::buffer(buff_mem, available)) + new managed_recv_buffer_impl(boost::asio::buffer(_recv_mem, num_bytes)) ); } managed_send_buffer::sptr udp_zero_copy_impl::get_send_buff(void){ - boost::uint32_t *buff_mem = new boost::uint32_t[2000/sizeof(boost::uint32_t)]; - return managed_send_buffer::sptr( - new managed_send_buffer_impl(boost::asio::buffer(buff_mem, 2000), _socket) - ); + return _send_buff; } /*********************************************************************** * UDP zero copy make function **********************************************************************/ +template<typename Opt> static inline void resize_buff_helper( + udp_zero_copy_impl::sptr udp_trans, + size_t target_size, + const std::string &name +){ + static const size_t min_buff_size = size_t(100e3); + + //resize the buffer if size was provided + if (target_size > 0){ + size_t actual_size = udp_trans->resize_buff<Opt>(target_size); + if (target_size != actual_size) std::cout << boost::format( + "Target %s buffer size: %d\n" + "Actual %s byffer size: %d" + ) % name % target_size % name % actual_size << std::endl; + } + + //otherwise, ensure that the buffer is at least the minimum size + else if (udp_trans->get_buff_size<Opt>() < min_buff_size){ + resize_buff_helper<Opt>(udp_trans, min_buff_size, name); + } +} + udp_zero_copy::sptr udp_zero_copy::make( const std::string &addr, const std::string &port, size_t recv_buff_size, size_t send_buff_size ){ - boost::shared_ptr<udp_zero_copy_impl> udp_trans(new udp_zero_copy_impl(addr, port)); - - //resize the recv buffer if size was provided - if (recv_buff_size > 0){ - size_t actual_bytes = udp_trans->resize_recv_buff(recv_buff_size); - if (recv_buff_size != actual_bytes) std::cout << boost::format( - "Target recv buffer size: %d\n" - "Actual recv byffer size: %d" - ) % recv_buff_size % actual_bytes << std::endl; - } + udp_zero_copy_impl::sptr udp_trans(new udp_zero_copy_impl(addr, port)); - //resize the send buffer if size was provided - if (send_buff_size > 0){ - size_t actual_bytes = udp_trans->resize_send_buff(send_buff_size); - if (send_buff_size != actual_bytes) std::cout << boost::format( - "Target send buffer size: %d\n" - "Actual send byffer size: %d" - ) % send_buff_size % actual_bytes << std::endl; - } + //call the helper to resize send and recv buffers + resize_buff_helper<boost::asio::socket_base::receive_buffer_size>(udp_trans, recv_buff_size, "recv"); + resize_buff_helper<boost::asio::socket_base::send_buffer_size> (udp_trans, send_buff_size, "send"); return udp_trans; } diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp new file mode 100644 index 000000000..c857db1c4 --- /dev/null +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -0,0 +1,358 @@ +// +// 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/>. +// + +#ifndef INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP +#define INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP + +#include <uhd/config.hpp> +#include <uhd/device.hpp> +#include <uhd/types/io_type.hpp> +#include <uhd/types/otw_type.hpp> +#include <uhd/types/metadata.hpp> +#include <uhd/transport/vrt.hpp> +#include <uhd/transport/convert_types.hpp> +#include <uhd/transport/zero_copy.hpp> +#include <boost/asio/buffer.hpp> +#include <boost/function.hpp> +#include <iostream> + +namespace vrt_packet_handler{ + +/*********************************************************************** + * vrt packet handler for recv + **********************************************************************/ + struct recv_state{ + //init the expected seq number + size_t next_packet_seq; + + //state variables to handle fragments + uhd::transport::managed_recv_buffer::sptr managed_buff; + boost::asio::const_buffer copy_buff; + size_t fragment_offset_in_samps; + + recv_state(void){ + //first expected seq is zero + next_packet_seq = 0; + + //initially empty copy buffer + copy_buff = boost::asio::buffer("", 0); + } + }; + + typedef boost::function<void(uhd::transport::managed_recv_buffer::sptr)> recv_cb_t; + + static UHD_INLINE void recv_cb_nop(uhd::transport::managed_recv_buffer::sptr){ + /* NOP */ + } + + /******************************************************************* + * Unpack a received vrt header and set the copy buffer. + * - helper function for vrt_packet_handler::_recv1 + ******************************************************************/ + static UHD_INLINE void _recv1_helper( + recv_state &state, + uhd::rx_metadata_t &metadata, + double tick_rate, + size_t vrt_header_offset_words32 + ){ + size_t num_packet_words32 = state.managed_buff->size()/sizeof(boost::uint32_t); + if (num_packet_words32 <= vrt_header_offset_words32){ + state.copy_buff = boost::asio::buffer("", 0); + return; //must exit here after setting the buffer + } + const boost::uint32_t *vrt_hdr = state.managed_buff->cast<const boost::uint32_t *>() + vrt_header_offset_words32; + size_t num_header_words32_out, num_payload_words32_out, packet_count_out; + uhd::transport::vrt::unpack( + metadata, //output + vrt_hdr, //input + num_header_words32_out, //output + num_payload_words32_out, //output + num_packet_words32, //input + packet_count_out, //output + tick_rate + ); + + //handle the packet count / sequence number + if (packet_count_out != state.next_packet_seq){ + std::cerr << "S" << (packet_count_out - state.next_packet_seq)%16; + } + state.next_packet_seq = (packet_count_out+1)%16; + + //setup the buffer to point to the data + state.copy_buff = boost::asio::buffer( + vrt_hdr + num_header_words32_out, + num_payload_words32_out*sizeof(boost::uint32_t) + ); + } + + /******************************************************************* + * Recv data, unpack a vrt header, and copy-convert the data. + * - helper function for vrt_packet_handler::recv + ******************************************************************/ + static UHD_INLINE size_t _recv1( + recv_state &state, + void *recv_mem, + size_t total_samps, + uhd::rx_metadata_t &metadata, + const uhd::io_type_t &io_type, + const uhd::otw_type_t &otw_type, + double tick_rate, + uhd::transport::zero_copy_if::sptr zc_iface, + //use these two params to handle a layer above vrt + size_t vrt_header_offset_words32, + const recv_cb_t& recv_cb + ){ + //perform a receive if no rx data is waiting to be copied + if (boost::asio::buffer_size(state.copy_buff) == 0){ + state.fragment_offset_in_samps = 0; + state.managed_buff = zc_iface->get_recv_buff(); + recv_cb(state.managed_buff); //callback before vrt unpack + _recv1_helper( + state, metadata, tick_rate, vrt_header_offset_words32 + ); + } + + //extract the number of samples available to copy + size_t bytes_per_item = otw_type.get_sample_size(); + size_t bytes_available = boost::asio::buffer_size(state.copy_buff); + size_t num_samps = std::min(total_samps, bytes_available/bytes_per_item); + + //setup the fragment flags and offset + metadata.more_fragments = total_samps < num_samps; + metadata.fragment_offset = state.fragment_offset_in_samps; + state.fragment_offset_in_samps += num_samps; //set for next call + + //copy-convert the samples from the recv buffer + uhd::transport::convert_otw_type_to_io_type( + boost::asio::buffer_cast<const void*>(state.copy_buff), otw_type, + recv_mem, io_type, num_samps + ); + + //update the rx copy buffer to reflect the bytes copied + size_t bytes_copied = num_samps*bytes_per_item; + state.copy_buff = boost::asio::buffer( + boost::asio::buffer_cast<const boost::uint8_t*>(state.copy_buff) + bytes_copied, + bytes_available - bytes_copied + ); + + return num_samps; + } + + /******************************************************************* + * Recv vrt packets and copy convert the samples into the buffer. + ******************************************************************/ + static UHD_INLINE size_t recv( + recv_state &state, + const boost::asio::mutable_buffer &buff, + uhd::rx_metadata_t &metadata, + uhd::device::recv_mode_t recv_mode, + const uhd::io_type_t &io_type, + const uhd::otw_type_t &otw_type, + double tick_rate, + uhd::transport::zero_copy_if::sptr zc_iface, + //use these two params to handle a layer above vrt + size_t vrt_header_offset_words32 = 0, + const recv_cb_t& recv_cb = &recv_cb_nop + ){ + metadata = uhd::rx_metadata_t(); //init the metadata + const size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size; + + switch(recv_mode){ + + //////////////////////////////////////////////////////////////// + case uhd::device::RECV_MODE_ONE_PACKET:{ + //////////////////////////////////////////////////////////////// + return _recv1( + state, + boost::asio::buffer_cast<void *>(buff), + total_num_samps, + metadata, + io_type, otw_type, + tick_rate, + zc_iface, + vrt_header_offset_words32, + recv_cb + ); + } + + //////////////////////////////////////////////////////////////// + case uhd::device::RECV_MODE_FULL_BUFF:{ + //////////////////////////////////////////////////////////////// + size_t num_samps = 0; + uhd::rx_metadata_t tmp_md; + while(num_samps < total_num_samps){ + num_samps += _recv1( + state, + boost::asio::buffer_cast<boost::uint8_t *>(buff) + (num_samps*io_type.size), + total_num_samps - num_samps, + (num_samps == 0)? metadata : tmp_md, //only the first metadata gets kept + io_type, otw_type, + tick_rate, + zc_iface, + vrt_header_offset_words32, + recv_cb + ); + } + return total_num_samps; + } + }//switch(recv_mode) + } + +/*********************************************************************** + * vrt packet handler for send + **********************************************************************/ + struct send_state{ + //init the expected seq number + size_t next_packet_seq; + + send_state(void){ + next_packet_seq = 0; + } + }; + + typedef boost::function<void(uhd::transport::managed_send_buffer::sptr)> send_cb_t; + + static UHD_INLINE void send_cb_nop(uhd::transport::managed_send_buffer::sptr){ + /* NOP */ + } + + /******************************************************************* + * Pack a vrt header, copy-convert the data, and send it. + * - helper function for vrt_packet_handler::send + ******************************************************************/ + static UHD_INLINE void _send1( + send_state &state, + const void *send_mem, + size_t num_samps, + const uhd::tx_metadata_t &metadata, + const uhd::io_type_t &io_type, + const uhd::otw_type_t &otw_type, + double tick_rate, + uhd::transport::zero_copy_if::sptr zc_iface, + size_t vrt_header_offset_words32, + const send_cb_t& send_cb + ){ + //get a new managed send buffer + uhd::transport::managed_send_buffer::sptr send_buff = zc_iface->get_send_buff(); + boost::uint32_t *tx_mem = send_buff->cast<boost::uint32_t *>() + vrt_header_offset_words32; + + size_t num_header_words32, num_packet_words32; + size_t packet_count = state.next_packet_seq++; + + //pack metadata into a vrt header + uhd::transport::vrt::pack( + metadata, //input + tx_mem, //output + num_header_words32, //output + num_samps, //input + num_packet_words32, //output + packet_count, //input + tick_rate + ); + + //copy-convert the samples into the send buffer + uhd::transport::convert_io_type_to_otw_type( + send_mem, io_type, + tx_mem + num_header_words32, otw_type, + num_samps + ); + + send_cb(send_buff); //callback after memory filled + + //commit the samples to the zero-copy interface + send_buff->done(num_packet_words32*sizeof(boost::uint32_t)); + } + + /******************************************************************* + * Send vrt packets and copy convert the samples into the buffer. + ******************************************************************/ + static UHD_INLINE size_t send( + send_state &state, + const boost::asio::const_buffer &buff, + const uhd::tx_metadata_t &metadata, + uhd::device::send_mode_t send_mode, + const uhd::io_type_t &io_type, + const uhd::otw_type_t &otw_type, + double tick_rate, + uhd::transport::zero_copy_if::sptr zc_iface, + size_t max_samples_per_packet, + //use these two params to handle a layer above vrt + size_t vrt_header_offset_words32 = 0, + const send_cb_t& send_cb = &send_cb_nop + ){ + const size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size; + switch(send_mode){ + + //////////////////////////////////////////////////////////////// + case uhd::device::SEND_MODE_ONE_PACKET:{ + //////////////////////////////////////////////////////////////// + size_t num_samps = std::min(total_num_samps, max_samples_per_packet); + _send1( + state, + boost::asio::buffer_cast<const void *>(buff), + num_samps, + metadata, + io_type, otw_type, + tick_rate, + zc_iface, + vrt_header_offset_words32, + send_cb + ); + return num_samps; + } + + //////////////////////////////////////////////////////////////// + case uhd::device::SEND_MODE_FULL_BUFF:{ + //////////////////////////////////////////////////////////////// + //calculate constants for fragmentation + const size_t final_packet_samps = total_num_samps%max_samples_per_packet; + const size_t num_fragments = (total_num_samps+max_samples_per_packet-1)/max_samples_per_packet; + static const size_t first_fragment_index = 0; + const size_t final_fragment_index = num_fragments-1; + + //make a rw copy of the metadata to re-flag below + uhd::tx_metadata_t md(metadata); + + //loop through the following fragment indexes + for (size_t n = first_fragment_index; n <= final_fragment_index; n++){ + + //calculate new flags for the fragments + md.has_time_spec = md.has_time_spec and (n == first_fragment_index); + md.start_of_burst = md.start_of_burst and (n == first_fragment_index); + md.end_of_burst = md.end_of_burst and (n == final_fragment_index); + + //send the fragment with the helper function + _send1( + state, + boost::asio::buffer_cast<const boost::uint8_t *>(buff) + (n*max_samples_per_packet*io_type.size), + (n == final_fragment_index)?final_packet_samps:max_samples_per_packet, + md, + io_type, otw_type, + tick_rate, + zc_iface, + vrt_header_offset_words32, + send_cb + ); + } + return total_num_samps; + } + }//switch(send_mode) + } + +} //namespace vrt_packet_handler + +#endif /* INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP */ diff --git a/host/lib/types.cpp b/host/lib/types.cpp index 33eb550a1..daf3be7f7 100644 --- a/host/lib/types.cpp +++ b/host/lib/types.cpp @@ -42,73 +42,89 @@ using namespace uhd; /*********************************************************************** * ranges **********************************************************************/ -gain_range_t::gain_range_t(float min_, float max_, float step_){ - min = min_; - max = max_; - step = step_; +gain_range_t::gain_range_t(float min, float max, float step): + min(min), + max(max), + step(step) +{ + /* NOP */ } -freq_range_t::freq_range_t(double min_, double max_){ - min = min_; - max = max_; +freq_range_t::freq_range_t(double min, double max): + min(min), + max(max) +{ + /* NOP */ } /*********************************************************************** * tune result **********************************************************************/ -tune_result_t::tune_result_t(void){ - target_inter_freq = 0.0; - actual_inter_freq = 0.0; - target_dsp_freq = 0.0; - actual_dsp_freq = 0.0; - spectrum_inverted = false; +tune_result_t::tune_result_t(void): + target_inter_freq(0.0), + actual_inter_freq(0.0), + target_dsp_freq(0.0), + actual_dsp_freq(0.0), + spectrum_inverted(false) +{ + /* NOP */ } /*********************************************************************** * clock config **********************************************************************/ -clock_config_t::clock_config_t(void){ - ref_source = REF_INT, - pps_source = PPS_INT, - pps_polarity = PPS_NEG; +clock_config_t::clock_config_t(void): + ref_source(REF_INT), + pps_source(PPS_INT), + pps_polarity(PPS_NEG) +{ + /* NOP */ } /*********************************************************************** * stream command **********************************************************************/ -stream_cmd_t::stream_cmd_t(const stream_mode_t &stream_mode_){ - stream_mode = stream_mode_; - stream_now = true; - num_samps = 0; +stream_cmd_t::stream_cmd_t(const stream_mode_t &stream_mode): + stream_mode(stream_mode), + num_samps(0), + stream_now(true) +{ + /* NOP */ } /*********************************************************************** * metadata **********************************************************************/ -rx_metadata_t::rx_metadata_t(void){ - stream_id = 0; - has_stream_id = false; - time_spec = time_spec_t(); - has_time_spec = false; - more_fragments = false; - fragment_offset = 0; +rx_metadata_t::rx_metadata_t(void): + has_stream_id(false), + stream_id(0), + has_time_spec(false), + time_spec(time_spec_t()), + more_fragments(false), + fragment_offset(0) +{ + /* NOP */ } -tx_metadata_t::tx_metadata_t(void){ - stream_id = 0; - has_stream_id = false; - time_spec = time_spec_t(); - has_time_spec = false; - start_of_burst = false; - end_of_burst = false; +tx_metadata_t::tx_metadata_t(void): + has_stream_id(false), + stream_id(0), + has_time_spec(false), + time_spec(time_spec_t()), + start_of_burst(false), + end_of_burst(false) +{ + /* NOP */ } /*********************************************************************** * time spec **********************************************************************/ -time_spec_t::time_spec_t(boost::uint32_t secs_, double nsecs_){ - secs = secs_; - nsecs = nsecs_; +time_spec_t::time_spec_t(boost::uint32_t secs, double nsecs): + secs(secs), + nsecs(nsecs) +{ + /* NOP */ } boost::uint32_t time_spec_t::get_ticks(double tick_rate) const{ @@ -165,9 +181,8 @@ std::string device_addr_t::to_string(void) const{ /*********************************************************************** * mac addr **********************************************************************/ -mac_addr_t::mac_addr_t(const byte_vector_t &bytes){ - UHD_ASSERT_THROW(bytes.size() == 6); - _bytes = bytes; +mac_addr_t::mac_addr_t(const byte_vector_t &bytes) : _bytes(bytes){ + UHD_ASSERT_THROW(_bytes.size() == 6); } mac_addr_t mac_addr_t::from_bytes(const byte_vector_t &bytes){ @@ -220,10 +235,16 @@ std::string mac_addr_t::to_string(void) const{ /*********************************************************************** * otw type **********************************************************************/ -otw_type_t::otw_type_t(void){ - width = 0; - shift = 0; - byteorder = BO_NATIVE; +size_t otw_type_t::get_sample_size(void) const{ + return (this->width * 2) / 8; +} + +otw_type_t::otw_type_t(void): + width(0), + shift(0), + byteorder(BO_NATIVE) +{ + /* NOP */ } /*********************************************************************** @@ -251,9 +272,11 @@ io_type_t::io_type_t(size_t size) /*********************************************************************** * serial **********************************************************************/ -spi_config_t::spi_config_t(edge_t edge){ - mosi_edge = edge; - miso_edge = edge; +spi_config_t::spi_config_t(edge_t edge): + mosi_edge(edge), + miso_edge(edge) +{ + /* NOP */ } void i2c_iface::write_eeprom( diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp index db8d8a886..4c5207203 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.cpp +++ b/host/lib/usrp/usrp2/clock_ctrl.cpp @@ -79,7 +79,9 @@ public: _ad9510_regs.power_down_lvds_cmos_out7 = enb? 0 : 1; _ad9510_regs.lvds_cmos_select_out7 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT7_CMOS; _ad9510_regs.output_level_lvds_out7 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT7_1_75MA; + _ad9510_regs.bypass_divider_out7 = 1; this->write_reg(0x43); + this->write_reg(0x57); this->update_regs(); } @@ -88,7 +90,9 @@ public: _ad9510_regs.power_down_lvds_cmos_out6 = enb? 0 : 1; _ad9510_regs.lvds_cmos_select_out6 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT6_CMOS; _ad9510_regs.output_level_lvds_out6 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT6_1_75MA; + _ad9510_regs.bypass_divider_out6 = 1; this->write_reg(0x42); + this->write_reg(0x55); this->update_regs(); } @@ -130,7 +134,9 @@ private: ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_NORMAL : ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_SAFE_PD; _ad9510_regs.output_level_lvpecl_out3 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT3_810MV; + _ad9510_regs.bypass_divider_out3 = 1; this->write_reg(0x3F); + this->write_reg(0x4F); this->update_regs(); } @@ -139,7 +145,9 @@ private: _ad9510_regs.power_down_lvds_cmos_out4 = enb? 0 : 1; _ad9510_regs.lvds_cmos_select_out4 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT4_LVDS; _ad9510_regs.output_level_lvds_out4 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT4_1_75MA; + _ad9510_regs.bypass_divider_out4 = 1; this->write_reg(0x40); + this->write_reg(0x51); this->update_regs(); } diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 7c9d003ce..b6ab919e7 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -31,16 +31,15 @@ namespace asio = boost::asio; * Helper Functions **********************************************************************/ void usrp2_impl::io_init(void){ - //setup otw type - _otw_type.width = 16; - _otw_type.shift = 0; - _otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; + //setup rx otw type + _rx_otw_type.width = 16; + _rx_otw_type.shift = 0; + _rx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; - //initially empty copy buffer - _rx_copy_buff = asio::buffer("", 0); - - //init the expected rx seq number - _rx_stream_id_to_packet_seq[0] = 0; + //setup tx otw type + _tx_otw_type.width = 16; + _tx_otw_type.shift = 0; + _tx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; //send a small data packet so the usrp2 knows the udp source port managed_send_buffer::sptr send_buff = _data_transport->get_send_buff(); @@ -49,7 +48,8 @@ void usrp2_impl::io_init(void){ send_buff->done(sizeof(data)); //setup RX DSP regs - _iface->poke32(FR_RX_CTRL_NSAMPS_PER_PKT, _max_rx_samples_per_packet); + std::cout << "RX samples per packet: " << get_max_recv_samps_per_packet() << std::endl; + _iface->poke32(FR_RX_CTRL_NSAMPS_PER_PKT, get_max_recv_samps_per_packet()); _iface->poke32(FR_RX_CTRL_NCHANNELS, 1); _iface->poke32(FR_RX_CTRL_CLEAR_OVERRUN, 1); //reset _iface->poke32(FR_RX_CTRL_VRT_HEADER, 0 @@ -63,98 +63,22 @@ void usrp2_impl::io_init(void){ } /*********************************************************************** - * Receive Raw Data - **********************************************************************/ -void usrp2_impl::recv_raw(rx_metadata_t &metadata){ - //do a receive - _rx_smart_buff = _data_transport->get_recv_buff(); - - //unpack the vrt header - size_t num_packet_words32 = _rx_smart_buff->size()/sizeof(boost::uint32_t); - if (num_packet_words32 == 0){ - _rx_copy_buff = boost::asio::buffer("", 0); - return; //must exit here after setting the buffer - } - const boost::uint32_t *vrt_hdr = _rx_smart_buff->cast<const boost::uint32_t *>(); - size_t num_header_words32_out, num_payload_words32_out, packet_count_out; - try{ - vrt::unpack( - metadata, //output - vrt_hdr, //input - num_header_words32_out, //output - num_payload_words32_out, //output - num_packet_words32, //input - packet_count_out, //output - get_master_clock_freq() - ); - }catch(const std::exception &e){ - std::cerr << "bad vrt header: " << e.what() << std::endl; - _rx_copy_buff = boost::asio::buffer("", 0); - return; //must exit here after setting the buffer - } - - //handle the packet count / sequence number - size_t expected_packet_count = _rx_stream_id_to_packet_seq[metadata.stream_id]; - if (packet_count_out != expected_packet_count){ - std::cerr << "S" << (packet_count_out - expected_packet_count)%16; - } - _rx_stream_id_to_packet_seq[metadata.stream_id] = (packet_count_out+1)%16; - - //setup the rx buffer to point to the data - _rx_copy_buff = asio::buffer( - vrt_hdr + num_header_words32_out, - num_payload_words32_out*sizeof(boost::uint32_t) - ); -} - -/*********************************************************************** * Send Data **********************************************************************/ size_t usrp2_impl::send( const asio::const_buffer &buff, - const tx_metadata_t &metadata_, - const io_type_t &io_type + const tx_metadata_t &metadata, + const io_type_t &io_type, + send_mode_t send_mode ){ - tx_metadata_t metadata = metadata_; //rw copy to change later - - transport::managed_send_buffer::sptr send_buff = _data_transport->get_send_buff(); - boost::uint32_t *tx_mem = send_buff->cast<boost::uint32_t *>(); - size_t num_samps = std::min(std::min( - asio::buffer_size(buff)/io_type.size, - size_t(_max_tx_samples_per_packet)), - send_buff->size()/io_type.size + return vrt_packet_handler::send( + _packet_handler_send_state, //last state of the send handler + buff, metadata, send_mode, //buffer to empty and samples metadata + io_type, _tx_otw_type, //input and output types to convert + get_master_clock_freq(), //master clock tick rate + _data_transport, //zero copy interface + get_max_send_samps_per_packet() ); - - //kill the end of burst flag if this is a fragment - if (asio::buffer_size(buff)/io_type.size < num_samps) - metadata.end_of_burst = false; - - size_t num_header_words32, num_packet_words32; - size_t packet_count = _tx_stream_id_to_packet_seq[metadata.stream_id]++; - - //pack metadata into a vrt header - vrt::pack( - metadata, //input - tx_mem, //output - num_header_words32, //output - num_samps, //input - num_packet_words32, //output - packet_count, //input - get_master_clock_freq() - ); - - boost::uint32_t *items = tx_mem + num_header_words32; //offset for data - - //copy-convert the samples into the send buffer - convert_io_type_to_otw_type( - asio::buffer_cast<const void*>(buff), io_type, - (void*)items, _otw_type, - num_samps - ); - - //send and return number of samples - send_buff->done(num_packet_words32*sizeof(boost::uint32_t)); - return num_samps; } /*********************************************************************** @@ -163,44 +87,14 @@ size_t usrp2_impl::send( size_t usrp2_impl::recv( const asio::mutable_buffer &buff, rx_metadata_t &metadata, - const io_type_t &io_type + const io_type_t &io_type, + recv_mode_t recv_mode ){ - //perform a receive if no rx data is waiting to be copied - if (asio::buffer_size(_rx_copy_buff) == 0){ - _fragment_offset_in_samps = 0; - recv_raw(metadata); - } - //otherwise flag the metadata to show that is is a fragment - else{ - metadata = rx_metadata_t(); - } - - //extract the number of samples available to copy - //and a pointer into the usrp2 received items memory - size_t bytes_to_copy = asio::buffer_size(_rx_copy_buff); - if (bytes_to_copy == 0) return 0; //nothing to receive - size_t num_samps = std::min( - asio::buffer_size(buff)/io_type.size, - bytes_to_copy/sizeof(boost::uint32_t) + return vrt_packet_handler::recv( + _packet_handler_recv_state, //last state of the recv handler + buff, metadata, recv_mode, //buffer to fill and samples metadata + io_type, _rx_otw_type, //input and output types to convert + get_master_clock_freq(), //master clock tick rate + _data_transport //zero copy interface ); - const boost::uint32_t *items = asio::buffer_cast<const boost::uint32_t*>(_rx_copy_buff); - - //setup the fragment flags and offset - metadata.more_fragments = asio::buffer_size(buff)/io_type.size < num_samps; - metadata.fragment_offset = _fragment_offset_in_samps; - _fragment_offset_in_samps += num_samps; //set for next time - - //copy-convert the samples from the recv buffer - convert_otw_type_to_io_type( - (const void*)items, _otw_type, - asio::buffer_cast<void*>(buff), io_type, - num_samps - ); - - //update the rx copy buffer to reflect the bytes copied - _rx_copy_buff = asio::buffer( - items + num_samps, bytes_to_copy - num_samps*sizeof(boost::uint32_t) - ); - - return num_samps; } diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 9ae68d158..f17efd88e 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -111,7 +111,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ //issue the stream command _iface->poke32(FR_RX_CTRL_STREAM_CMD, FR_RX_CTRL_MAKE_CMD( - (inst_samps)? stream_cmd.num_samps : ((inst_chain)? _max_rx_samples_per_packet : 1), + (inst_samps)? stream_cmd.num_samps : ((inst_chain)? get_max_recv_samps_per_packet() : 1), (stream_cmd.stream_now)? 1 : 0, (inst_chain)? 1 : 0, (inst_reload)? 1 : 0 diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 2b7bdeea2..af3ec216a 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -210,14 +210,6 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ val = prop_names_t(1, ""); return; - case DEVICE_PROP_MAX_RX_SAMPLES: - val = size_t(_max_rx_samples_per_packet); - return; - - case DEVICE_PROP_MAX_TX_SAMPLES: - val = size_t(_max_tx_samples_per_packet); - return; - default: UHD_THROW_PROP_GET_ERROR(); } } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index c5b6af810..afea9683c 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -33,6 +33,7 @@ #include <uhd/transport/vrt.hpp> #include <uhd/transport/udp_zero_copy.hpp> #include <uhd/usrp/dboard_manager.hpp> +#include "../../transport/vrt_packet_handler.hpp" /*! * Make a usrp2 dboard interface. @@ -103,8 +104,24 @@ public: ~usrp2_impl(void); //the io interface - size_t send(const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const uhd::io_type_t &); - size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const uhd::io_type_t &); + size_t get_max_send_samps_per_packet(void) const{ + return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size(); + } + size_t send( + const boost::asio::const_buffer &, + const uhd::tx_metadata_t &, + const uhd::io_type_t &, + uhd::device::send_mode_t + ); + size_t get_max_recv_samps_per_packet(void) const{ + return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size(); + } + size_t recv( + const boost::asio::mutable_buffer &, + uhd::rx_metadata_t &, + const uhd::io_type_t &, + uhd::device::recv_mode_t + ); private: double get_master_clock_freq(void){ @@ -121,25 +138,24 @@ private: codec_ctrl::sptr _codec_ctrl; serdes_ctrl::sptr _serdes_ctrl; - //the raw io interface (samples are in the usrp2 native format) - void recv_raw(uhd::rx_metadata_t &); - uhd::dict<boost::uint32_t, size_t> _tx_stream_id_to_packet_seq; - uhd::dict<boost::uint32_t, size_t> _rx_stream_id_to_packet_seq; + /******************************************************************* + * Deal with the rx and tx packet sizes + ******************************************************************/ static const size_t _mtu = 1500; //FIXME we have no idea static const size_t _hdrs = (2 + 14 + 20 + 8); //size of headers (pad, eth, ip, udp) - static const size_t _max_rx_samples_per_packet = - (_mtu - _hdrs)/sizeof(boost::uint32_t) - - USRP2_HOST_RX_VRT_HEADER_WORDS32 - - USRP2_HOST_RX_VRT_TRAILER_WORDS32 + static const size_t _max_rx_bytes_per_packet = + _mtu - _hdrs - + USRP2_HOST_RX_VRT_HEADER_WORDS32*sizeof(boost::uint32_t) - + USRP2_HOST_RX_VRT_TRAILER_WORDS32*sizeof(boost::uint32_t) ; - static const size_t _max_tx_samples_per_packet = - (_mtu - _hdrs)/sizeof(boost::uint32_t) - - uhd::transport::vrt::max_header_words32 + static const size_t _max_tx_bytes_per_packet = + _mtu - _hdrs - + uhd::transport::vrt::max_header_words32*sizeof(boost::uint32_t) ; - uhd::transport::managed_recv_buffer::sptr _rx_smart_buff; - boost::asio::const_buffer _rx_copy_buff; - size_t _fragment_offset_in_samps; - uhd::otw_type_t _otw_type; + + vrt_packet_handler::recv_state _packet_handler_recv_state; + vrt_packet_handler::send_state _packet_handler_send_state; + uhd::otw_type_t _rx_otw_type, _tx_otw_type; void io_init(void); //udp transports for control and data |