From abf2bc77f1880e34e206bd299fa0170f1bf9fe1d Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 13 May 2010 18:23:19 -0700 Subject: memcpy data when in custom io type --- host/lib/transport/convert_types.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'host/lib/transport') diff --git a/host/lib/transport/convert_types.cpp b/host/lib/transport/convert_types.cpp index 8c3d6b17a..510d39454 100644 --- a/host/lib/transport/convert_types.cpp +++ b/host/lib/transport/convert_types.cpp @@ -115,10 +115,13 @@ void transport::convert_io_type_to_otw_type( switch(io_type.tid){ case io_type_t::COMPLEX_FLOAT32: host_floats_to_usrp2_items((boost::uint32_t *)otw_buff, (const fc32_t*)io_buff, num_samps); - break; + return; case io_type_t::COMPLEX_INT16: host_items_to_usrp2_items((boost::uint32_t *)otw_buff, (const boost::uint32_t*)io_buff, num_samps); - break; + return; + case io_type_t::CUSTOM_TYPE: + std::memcpy(otw_buff, io_buff, num_samps*io_type.size); + return; default: throw std::runtime_error(str(boost::format("convert_types: cannot handle type \"%c\"") % io_type.tid)); } @@ -135,10 +138,13 @@ void transport::convert_otw_type_to_io_type( switch(io_type.tid){ case io_type_t::COMPLEX_FLOAT32: usrp2_items_to_host_floats((fc32_t*)io_buff, (const boost::uint32_t *)otw_buff, num_samps); - break; + return; case io_type_t::COMPLEX_INT16: usrp2_items_to_host_items((boost::uint32_t*)io_buff, (const boost::uint32_t *)otw_buff, num_samps); - break; + return; + case io_type_t::CUSTOM_TYPE: + std::memcpy(io_buff, otw_buff, num_samps*io_type.size); + return; default: throw std::runtime_error(str(boost::format("convert_types: cannot handle type \"%c\"") % io_type.tid)); } -- cgit v1.2.3 From 7823e08855f1fe48fbc014c37f822a9f22de19ef Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 17 May 2010 10:12:16 -0700 Subject: simplification of udp asio socket stuff --- host/include/uhd/transport/zero_copy.hpp | 12 ++--- host/lib/transport/udp_zero_copy_asio.cpp | 75 +++++++++++++++---------------- 2 files changed, 43 insertions(+), 44 deletions(-) (limited to 'host/lib/transport') diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp index 4fc1df9de..fdc5b141c 100644 --- a/host/include/uhd/transport/zero_copy.hpp +++ b/host/include/uhd/transport/zero_copy.hpp @@ -45,7 +45,7 @@ public: * Get the size of the underlying buffer. * \return the number of bytes */ - size_t size(void){ + size_t size(void) const{ return boost::asio::buffer_size(this->get()); } @@ -53,7 +53,7 @@ public: * Get a pointer to the underlying buffer. * \return a pointer into memory */ - template T cast(void){ + template T cast(void) const{ return boost::asio::buffer_cast(this->get()); } @@ -63,7 +63,7 @@ private: * The buffer has a reference to memory and a size. * \return a boost asio const buffer */ - virtual const boost::asio::const_buffer &get(void) = 0; + virtual const boost::asio::const_buffer &get(void) const = 0; }; /*! @@ -87,7 +87,7 @@ public: * Get the size of the underlying buffer. * \return the number of bytes */ - size_t size(void){ + size_t size(void) const{ return boost::asio::buffer_size(this->get()); } @@ -95,7 +95,7 @@ public: * Get a pointer to the underlying buffer. * \return a pointer into memory */ - template T cast(void){ + template T cast(void) const{ return boost::asio::buffer_cast(this->get()); } @@ -105,7 +105,7 @@ private: * The buffer has a reference to memory and a size. * \return a boost asio mutable buffer */ - virtual const boost::asio::mutable_buffer &get(void) = 0; + virtual const boost::asio::mutable_buffer &get(void) const = 0; }; /*! diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index ee44803f4..c26b39867 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -16,9 +16,9 @@ // #include +#include #include #include -#include #include #include @@ -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(_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(_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,6 +85,8 @@ 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: //structors @@ -121,6 +114,11 @@ public: 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 +129,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, + (timeval *)&tv, sizeof(timeval) + ) == 0); } udp_zero_copy_impl::~udp_zero_copy_impl(void){ @@ -142,31 +155,17 @@ 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; } /*********************************************************************** -- cgit v1.2.3 From 7facfba666046f305086f754c9cebe1406ea54ad Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 17 May 2010 10:22:14 -0700 Subject: windows fix for setsockopt --- host/lib/transport/udp_zero_copy_asio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'host/lib/transport') diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index c26b39867..e97bbf31c 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -146,7 +146,7 @@ udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::strin UHD_ASSERT_THROW(setsockopt( _socket->native(), SOL_SOCKET, SO_RCVTIMEO, - (timeval *)&tv, sizeof(timeval) + (const char *)&tv, sizeof(timeval) ) == 0); } -- cgit v1.2.3 From a6f7b02ae69eb4b0755f2805922eeb06d977c1ee Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 17 May 2010 11:01:42 -0700 Subject: automatic resize for small udp buffers --- host/lib/transport/udp_zero_copy_asio.cpp | 61 ++++++++++++++++++------------- 1 file changed, 35 insertions(+), 26 deletions(-) (limited to 'host/lib/transport') diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index e97bbf31c..56ba391d3 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -89,6 +89,8 @@ 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 sptr; + //structors udp_zero_copy_impl(const std::string &addr, const std::string &port); ~udp_zero_copy_impl(void); @@ -97,18 +99,17 @@ 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 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 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(); } private: @@ -171,31 +172,39 @@ managed_send_buffer::sptr udp_zero_copy_impl::get_send_buff(void){ /*********************************************************************** * UDP zero copy make function **********************************************************************/ +template 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(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() < min_buff_size){ + resize_buff_helper(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_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(udp_trans, recv_buff_size, "recv"); + resize_buff_helper (udp_trans, send_buff_size, "send"); return udp_trans; } -- cgit v1.2.3 From d9cc352ed14dbab04523f53e21f855b05c30eb3f Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 17 May 2010 13:22:26 -0700 Subject: work on generic packet handler (got rx working) --- host/lib/transport/vrt_packet_handler.hpp | 161 ++++++++++++++++++++++++++++++ host/lib/usrp/usrp2/io_impl.cpp | 95 ++---------------- host/lib/usrp/usrp2/usrp2_impl.hpp | 8 +- 3 files changed, 169 insertions(+), 95 deletions(-) create mode 100644 host/lib/transport/vrt_packet_handler.hpp (limited to 'host/lib/transport') diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp new file mode 100644 index 000000000..a6161ef55 --- /dev/null +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -0,0 +1,161 @@ +// +// 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 . +// + +#ifndef INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP +#define INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 recv_cb_t; + + static inline void recv_cb_nop(uhd::transport::managed_recv_buffer::sptr){ + /* NOP */ + } + + static inline size_t recv( + recv_state &state, + const boost::asio::mutable_buffer &buff, + 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, + size_t vrt_header_offset_words32 = 0, + const recv_cb_t& recv_cb = &recv_cb_nop + ){ + //////////////////////////////////////////////////////////////// + // Perform the recv + //////////////////////////////////////////////////////////////// + { + //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); + } + //otherwise flag the metadata to show that is is a fragment + else{ + metadata = uhd::rx_metadata_t(); + goto vrt_recv_copy_convert; + } + } + + //////////////////////////////////////////////////////////////// + // Unpack the vrt header + //////////////////////////////////////////////////////////////// + { + 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); + goto vrt_recv_copy_convert; //must exit here after setting the buffer + } + const boost::uint32_t *vrt_hdr = state.managed_buff->cast() + 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) + ); + } + + //////////////////////////////////////////////////////////////// + // Perform copy-convert into buffer + //////////////////////////////////////////////////////////////// + vrt_recv_copy_convert:{ + size_t bytes_per_item = (otw_type.width * 2) / 8; + + //extract the number of samples available to copy + //and a pointer into the usrp2 received items memory + size_t bytes_available = boost::asio::buffer_size(state.copy_buff); + size_t num_samps = std::min( + boost::asio::buffer_size(buff)/io_type.size, + bytes_available/bytes_per_item + ); + + //setup the fragment flags and offset + metadata.more_fragments = boost::asio::buffer_size(buff)/io_type.size < num_samps; + metadata.fragment_offset = state.fragment_offset_in_samps; + state.fragment_offset_in_samps += num_samps; //set for next time + + //copy-convert the samples from the recv buffer + uhd::transport::convert_otw_type_to_io_type( + boost::asio::buffer_cast(state.copy_buff), otw_type, + boost::asio::buffer_cast(buff), 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(state.copy_buff) + bytes_copied, + bytes_available - bytes_copied + ); + + return num_samps; + } + } + +} //namespace vrt_packet_handler + +#endif /* INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP */ diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index de0c76eb1..389460fe8 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -41,13 +41,6 @@ void usrp2_impl::io_init(void){ _tx_otw_type.shift = 0; _tx_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; - //send a small data packet so the usrp2 knows the udp source port managed_send_buffer::sptr send_buff = _data_transport->get_send_buff(); boost::uint32_t data = htonl(USRP2_INVALID_VRT_HEADER); @@ -69,51 +62,6 @@ void usrp2_impl::io_init(void){ _iface->poke32(FR_RX_CTRL_VRT_TRAILER, 0); } -/*********************************************************************** - * 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(); - 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 **********************************************************************/ @@ -172,42 +120,11 @@ size_t usrp2_impl::recv( rx_metadata_t &metadata, const io_type_t &io_type ){ - //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) - ); - const boost::uint32_t *items = asio::buffer_cast(_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, _rx_otw_type, - asio::buffer_cast(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 vrt_packet_handler::recv( + _packet_handler_recv_state, //last state of the recv handler + buff, metadata, //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 ); - - return num_samps; } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index e2d37e512..6958fc8ea 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -33,6 +33,7 @@ #include #include #include +#include "../../transport/vrt_packet_handler.hpp" /*! * Make a usrp2 dboard interface. @@ -121,10 +122,7 @@ 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 _tx_stream_id_to_packet_seq; - uhd::dict _rx_stream_id_to_packet_seq; /******************************************************************* * Deal with the rx and tx packet sizes @@ -147,9 +145,7 @@ private: return _max_tx_bytes_per_packet/(_tx_otw_type.width*2/8); } - uhd::transport::managed_recv_buffer::sptr _rx_smart_buff; - boost::asio::const_buffer _rx_copy_buff; - size_t _fragment_offset_in_samps; + vrt_packet_handler::recv_state _packet_handler_recv_state; uhd::otw_type_t _rx_otw_type, _tx_otw_type; void io_init(void); -- cgit v1.2.3 From 101afd526de722b6d30381340a7ca8148aa9a6d7 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 17 May 2010 18:47:33 -0700 Subject: Created inline send vrt packer function that also handles fragmentation. --- host/include/uhd/device.hpp | 11 +- host/include/uhd/types/otw_type.hpp | 6 + host/lib/transport/vrt_packet_handler.hpp | 280 ++++++++++++++++++++++-------- host/lib/types.cpp | 4 + host/lib/usrp/usrp2/io_impl.cpp | 48 +---- host/lib/usrp/usrp2/usrp2_impl.hpp | 7 +- 6 files changed, 232 insertions(+), 124 deletions(-) (limited to 'host/lib/transport') diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index ae75e6dc8..ecbe8c95c 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -80,12 +80,11 @@ public: * Send a buffer containing IF data with its metadata. * * Send handles fragmentation as follows: - * If the buffer has more samples than the maximum supported, - * the send method will send the maximum number of samples - * as supported by the transport and return the number sent. - * In this case, the end of burst flag will be forced to false. - * It is up to the caller to call send again on the un-sent - * portions of the buffer, until the buffer is exhausted. + * If the buffer has more samples than the maximum per packet, + * the send method will fragment the samples across several packets. + * Send will respect the burst flags when fragmenting to ensure + * that start of burst can only be set on the first fragment and + * that end of burst can only be set on the final fragment. * * This is a blocking call and will not return until the number * of samples returned have been read out of the buffer. diff --git a/host/include/uhd/types/otw_type.hpp b/host/include/uhd/types/otw_type.hpp index f10664584..8e3e65d78 100644 --- a/host/include/uhd/types/otw_type.hpp +++ b/host/include/uhd/types/otw_type.hpp @@ -55,6 +55,12 @@ namespace uhd{ BO_NOT_APPLICABLE = '|' } byteorder; + /*! + * Get the sample size of this otw type. + * \return the size of a sample in bytes + */ + size_t get_sample_size(void) const; + otw_type_t(void); }; diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index a6161ef55..cd0c89b05 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -57,6 +57,49 @@ namespace vrt_packet_handler{ /* NOP */ } + /******************************************************************* + * Unpack a received vrt header and set the copy buffer. + * - helper function for vrt_packet_handler::recv + ******************************************************************/ + static inline void _recv_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() + 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 vrt packets and copy convert the samples into the buffer. + ******************************************************************/ static inline size_t recv( recv_state &state, const boost::asio::mutable_buffer &buff, @@ -65,95 +108,184 @@ namespace vrt_packet_handler{ 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 ){ - //////////////////////////////////////////////////////////////// - // Perform the recv - //////////////////////////////////////////////////////////////// - { - //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); - } - //otherwise flag the metadata to show that is is a fragment - else{ - metadata = uhd::rx_metadata_t(); - goto vrt_recv_copy_convert; - } - } + metadata = uhd::rx_metadata_t(); //init the metadata - //////////////////////////////////////////////////////////////// - // Unpack the vrt header - //////////////////////////////////////////////////////////////// - { - 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); - goto vrt_recv_copy_convert; //must exit here after setting the buffer - } - const boost::uint32_t *vrt_hdr = state.managed_buff->cast() + 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 + //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 + _recv_helper( + state, metadata, tick_rate, vrt_header_offset_words32 ); + } - //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; + //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( + boost::asio::buffer_size(buff)/io_type.size, + bytes_available/bytes_per_item + ); - //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) - ); + //setup the fragment flags and offset + metadata.more_fragments = boost::asio::buffer_size(buff)/io_type.size < 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(state.copy_buff), otw_type, + boost::asio::buffer_cast(buff), 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(state.copy_buff) + bytes_copied, + bytes_available - bytes_copied + ); + + return num_samps; + } + +/*********************************************************************** + * 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; } + }; - //////////////////////////////////////////////////////////////// - // Perform copy-convert into buffer - //////////////////////////////////////////////////////////////// - vrt_recv_copy_convert:{ - size_t bytes_per_item = (otw_type.width * 2) / 8; - - //extract the number of samples available to copy - //and a pointer into the usrp2 received items memory - size_t bytes_available = boost::asio::buffer_size(state.copy_buff); - size_t num_samps = std::min( - boost::asio::buffer_size(buff)/io_type.size, - bytes_available/bytes_per_item - ); + typedef boost::function send_cb_t; - //setup the fragment flags and offset - metadata.more_fragments = boost::asio::buffer_size(buff)/io_type.size < num_samps; - metadata.fragment_offset = state.fragment_offset_in_samps; - state.fragment_offset_in_samps += num_samps; //set for next time + static inline void send_cb_nop(uhd::transport::managed_send_buffer::sptr){ + /* NOP */ + } - //copy-convert the samples from the recv buffer - uhd::transport::convert_otw_type_to_io_type( - boost::asio::buffer_cast(state.copy_buff), otw_type, - boost::asio::buffer_cast(buff), io_type, - num_samps - ); + /******************************************************************* + * Pack a vrt header, copy-convert the data, and send it. + * - helper function for vrt_packet_handler::send + ******************************************************************/ + static inline void _send_helper( + 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() + vrt_header_offset_words32; + + size_t num_header_words32, num_packet_words32; + size_t packet_count = state.next_packet_seq++; - //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(state.copy_buff) + bytes_copied, - bytes_available - bytes_copied + //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 inline size_t send( + send_state &state, + const boost::asio::const_buffer &buff, + 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 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 + ){ + + size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size; + + //special case: no fragmentation needed + if (total_num_samps <= max_samples_per_packet){ + _send_helper( + state, + boost::asio::buffer_cast(buff), + total_num_samps, + metadata, + io_type, otw_type, + tick_rate, + zc_iface, + vrt_header_offset_words32, + send_cb ); + return total_num_samps; + } - return num_samps; + //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 + _send_helper( + state, + boost::asio::buffer_cast(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; } } //namespace vrt_packet_handler diff --git a/host/lib/types.cpp b/host/lib/types.cpp index 33eb550a1..87a2ad4ab 100644 --- a/host/lib/types.cpp +++ b/host/lib/types.cpp @@ -220,6 +220,10 @@ std::string mac_addr_t::to_string(void) const{ /*********************************************************************** * otw type **********************************************************************/ +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; diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 389460fe8..b26dbb8bd 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -67,49 +67,17 @@ void usrp2_impl::io_init(void){ **********************************************************************/ size_t usrp2_impl::send( const asio::const_buffer &buff, - const tx_metadata_t &metadata_, + const tx_metadata_t &metadata, const io_type_t &io_type ){ - 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(); - size_t num_samps = std::min(std::min( - asio::buffer_size(buff)/io_type.size, - size_t(max_tx_samps_per_packet())), - send_buff->size()/io_type.size - ); - - //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(buff), io_type, - (void*)items, _tx_otw_type, - num_samps + return vrt_packet_handler::send( + _packet_handler_send_state, //last state of the send handler + buff, metadata, //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 + max_tx_samps_per_packet() ); - - //send and return number of samples - send_buff->done(num_packet_words32*sizeof(boost::uint32_t)); - return num_samps; } /*********************************************************************** diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 6958fc8ea..f98aa1938 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -122,8 +122,6 @@ private: codec_ctrl::sptr _codec_ctrl; serdes_ctrl::sptr _serdes_ctrl; - uhd::dict _tx_stream_id_to_packet_seq; - /******************************************************************* * Deal with the rx and tx packet sizes ******************************************************************/ @@ -139,13 +137,14 @@ private: uhd::transport::vrt::max_header_words32*sizeof(boost::uint32_t) ; size_t max_rx_samps_per_packet(void){ - return _max_rx_bytes_per_packet/(_rx_otw_type.width*2/8); + return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size(); } size_t max_tx_samps_per_packet(void){ - return _max_tx_bytes_per_packet/(_tx_otw_type.width*2/8); + return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size(); } 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); -- cgit v1.2.3 From 18f3f257145c4dcd981182221779550a7474488a Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 17 May 2010 22:24:14 -0700 Subject: Created config macro to force inline. --- host/CMakeLists.txt | 1 + host/include/uhd/config.hpp | 9 +++++++++ host/lib/transport/CMakeLists.txt | 1 + host/lib/transport/vrt_packet_handler.hpp | 13 +++++++------ 4 files changed, 18 insertions(+), 6 deletions(-) (limited to 'host/lib/transport') diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index f2725e4b3..0b2d3f012 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -62,6 +62,7 @@ IF(UNIX) UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-ansi HAVE_ANSI) #only export symbols that are declared to be part of the uhd api: UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN) + UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-O3 HAVE_O3) #have some optimizations ENDIF(UNIX) IF(WIN32) diff --git a/host/include/uhd/config.hpp b/host/include/uhd/config.hpp index 32eafc89b..fea95145c 100644 --- a/host/include/uhd/config.hpp +++ b/host/include/uhd/config.hpp @@ -76,4 +76,13 @@ #define UHD_LOCAL #endif // UHD_DLL +// Define force inline macro +#ifdef BOOST_MSVC + #define UHD_INLINE __forceinline +#elif defined(__GNUG__) && __GNUG__ >= 4 + #define UHD_INLINE inline __attribute__((always_inline)) +#else + #define UHD_INLINE inline +#endif + #endif /* INCLUDED_UHD_CONFIG_HPP */ 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/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index cd0c89b05..f6353ef99 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -18,6 +18,7 @@ #ifndef INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP #define INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP +#include #include #include #include @@ -53,7 +54,7 @@ namespace vrt_packet_handler{ typedef boost::function recv_cb_t; - static inline void recv_cb_nop(uhd::transport::managed_recv_buffer::sptr){ + static UHD_INLINE void recv_cb_nop(uhd::transport::managed_recv_buffer::sptr){ /* NOP */ } @@ -61,7 +62,7 @@ namespace vrt_packet_handler{ * Unpack a received vrt header and set the copy buffer. * - helper function for vrt_packet_handler::recv ******************************************************************/ - static inline void _recv_helper( + static UHD_INLINE void _recv_helper( recv_state &state, uhd::rx_metadata_t &metadata, double tick_rate, @@ -100,7 +101,7 @@ namespace vrt_packet_handler{ /******************************************************************* * Recv vrt packets and copy convert the samples into the buffer. ******************************************************************/ - static inline size_t recv( + static UHD_INLINE size_t recv( recv_state &state, const boost::asio::mutable_buffer &buff, uhd::rx_metadata_t &metadata, @@ -168,7 +169,7 @@ namespace vrt_packet_handler{ typedef boost::function send_cb_t; - static inline void send_cb_nop(uhd::transport::managed_send_buffer::sptr){ + static UHD_INLINE void send_cb_nop(uhd::transport::managed_send_buffer::sptr){ /* NOP */ } @@ -176,7 +177,7 @@ namespace vrt_packet_handler{ * Pack a vrt header, copy-convert the data, and send it. * - helper function for vrt_packet_handler::send ******************************************************************/ - static inline void _send_helper( + static UHD_INLINE void _send_helper( send_state &state, const void *send_mem, size_t num_samps, @@ -222,7 +223,7 @@ namespace vrt_packet_handler{ /******************************************************************* * Send vrt packets and copy convert the samples into the buffer. ******************************************************************/ - static inline size_t send( + static UHD_INLINE size_t send( send_state &state, const boost::asio::const_buffer &buff, const uhd::tx_metadata_t &metadata, -- cgit v1.2.3 From eaa1508dcf6ff32496838f593ba4eb9eb1aee2ff Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 18 May 2010 12:34:04 -0700 Subject: Added send and recv modes to the device class and packet handler implementation. --- host/include/uhd/device.hpp | 33 +++++- host/lib/transport/vrt_packet_handler.hpp | 178 ++++++++++++++++++++---------- host/lib/usrp/usrp2/io_impl.cpp | 10 +- host/lib/usrp/usrp2/usrp2_impl.hpp | 14 ++- 4 files changed, 170 insertions(+), 65 deletions(-) (limited to 'host/lib/transport') diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index ecbe8c95c..a76b34ee2 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -76,6 +76,16 @@ public: */ static sptr make(const device_addr_t &hint, size_t which = 0); + /*! + * Send modes for the device send routine. + */ + enum send_mode_t{ + //! Tells the send routine to send the entire buffer + SEND_MODE_FULL_BUFF = 0, + //! Tells the send routine to return after one packet + SEND_MODE_ONE_PACKET = 1 + }; + /*! * Send a buffer containing IF data with its metadata. * @@ -85,6 +95,7 @@ public: * Send will respect the burst flags when fragmenting to ensure * that start of burst can only be set on the first fragment and * that end of burst can only be set on the final fragment. + * Fragmentation only applies in the full buffer send mode. * * This is a blocking call and will not return until the number * of samples returned have been read out of the buffer. @@ -92,14 +103,26 @@ public: * \param buff a buffer pointing to some read-only memory * \param metadata data describing the buffer's contents * \param io_type the type of data loaded in the buffer + * \param send_mode tells send how to unload the buffer * \return the number of samples sent */ virtual size_t send( const boost::asio::const_buffer &buff, const tx_metadata_t &metadata, - const io_type_t &io_type + const io_type_t &io_type, + send_mode_t send_mode = SEND_MODE_ONE_PACKET ) = 0; + /*! + * Recv modes for the device recv routine. + */ + enum recv_mode_t{ + //! Tells the recv routine to recv the entire buffer + RECV_MODE_FULL_BUFF = 0, + //! Tells the recv routine to return after one packet + RECV_MODE_ONE_PACKET = 1 + }; + /*! * Receive a buffer containing IF data and its metadata. * @@ -122,15 +145,21 @@ public: * immediately when no packets are available to the transport layer, * and that the timeout duration is reasonably tuned for performance. * + * When using the full buffer recv mode, the metadata only applies + * to the first packet received and written into the recv buffer. + * Use the one packet recv mode to get per packet metadata. + * * \param buff the buffer to fill with IF data * \param metadata data to fill describing the buffer * \param io_type the type of data to fill into the buffer + * \param recv_mode tells recv how to load the buffer * \return the number of samples received */ virtual size_t recv( const boost::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 = RECV_MODE_ONE_PACKET ) = 0; }; diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index f6353ef99..c857db1c4 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -19,6 +19,7 @@ #define INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP #include +#include #include #include #include @@ -60,9 +61,9 @@ namespace vrt_packet_handler{ /******************************************************************* * Unpack a received vrt header and set the copy buffer. - * - helper function for vrt_packet_handler::recv + * - helper function for vrt_packet_handler::_recv1 ******************************************************************/ - static UHD_INLINE void _recv_helper( + static UHD_INLINE void _recv1_helper( recv_state &state, uhd::rx_metadata_t &metadata, double tick_rate, @@ -99,28 +100,28 @@ namespace vrt_packet_handler{ } /******************************************************************* - * Recv vrt packets and copy convert the samples into the buffer. + * Recv data, unpack a vrt header, and copy-convert the data. + * - helper function for vrt_packet_handler::recv ******************************************************************/ - static UHD_INLINE size_t recv( + static UHD_INLINE size_t _recv1( recv_state &state, - const boost::asio::mutable_buffer &buff, + 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 = 0, - const recv_cb_t& recv_cb = &recv_cb_nop + size_t vrt_header_offset_words32, + const recv_cb_t& recv_cb ){ - metadata = uhd::rx_metadata_t(); //init the metadata - //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 - _recv_helper( + _recv1_helper( state, metadata, tick_rate, vrt_header_offset_words32 ); } @@ -128,21 +129,17 @@ namespace vrt_packet_handler{ //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( - boost::asio::buffer_size(buff)/io_type.size, - bytes_available/bytes_per_item - ); + size_t num_samps = std::min(total_samps, bytes_available/bytes_per_item); //setup the fragment flags and offset - metadata.more_fragments = boost::asio::buffer_size(buff)/io_type.size < num_samps; + 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(state.copy_buff), otw_type, - boost::asio::buffer_cast(buff), io_type, - num_samps + recv_mem, io_type, num_samps ); //update the rx copy buffer to reflect the bytes copied @@ -155,6 +152,66 @@ namespace vrt_packet_handler{ 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(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(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 **********************************************************************/ @@ -177,7 +234,7 @@ namespace vrt_packet_handler{ * Pack a vrt header, copy-convert the data, and send it. * - helper function for vrt_packet_handler::send ******************************************************************/ - static UHD_INLINE void _send_helper( + static UHD_INLINE void _send1( send_state &state, const void *send_mem, size_t num_samps, @@ -227,6 +284,7 @@ namespace vrt_packet_handler{ 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, @@ -236,15 +294,17 @@ namespace vrt_packet_handler{ size_t vrt_header_offset_words32 = 0, const send_cb_t& send_cb = &send_cb_nop ){ - - size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size; - - //special case: no fragmentation needed - if (total_num_samps <= max_samples_per_packet){ - _send_helper( + 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(buff), - total_num_samps, + num_samps, metadata, io_type, otw_type, tick_rate, @@ -252,41 +312,45 @@ namespace vrt_packet_handler{ vrt_header_offset_words32, send_cb ); - return total_num_samps; + return num_samps; } - //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 - _send_helper( - state, - boost::asio::buffer_cast(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 - ); + //////////////////////////////////////////////////////////////// + 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(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; } - - return total_num_samps; + }//switch(send_mode) } } //namespace vrt_packet_handler diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index b26dbb8bd..485cc2bd9 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -68,11 +68,12 @@ void usrp2_impl::io_init(void){ size_t usrp2_impl::send( const asio::const_buffer &buff, const tx_metadata_t &metadata, - const io_type_t &io_type + const io_type_t &io_type, + send_mode_t send_mode ){ return vrt_packet_handler::send( _packet_handler_send_state, //last state of the send handler - buff, metadata, //buffer to empty and samples metadata + 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 @@ -86,11 +87,12 @@ 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 ){ return vrt_packet_handler::recv( _packet_handler_recv_state, //last state of the recv handler - buff, metadata, //buffer to fill and samples metadata + 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 diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index f98aa1938..ad674f594 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -104,8 +104,18 @@ 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 send( + const boost::asio::const_buffer &, + const uhd::tx_metadata_t &, + const uhd::io_type_t &, + uhd::device::send_mode_t + ); + 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){ -- cgit v1.2.3 From bea1c582491d71bf90e240be345a32ba77028460 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 18 May 2010 18:03:27 -0700 Subject: tweaks to remove warning is msvc --- host/examples/tx_timed_samples.cpp | 2 +- host/lib/transport/vrt_packet_handler.hpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'host/lib/transport') diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp index 6dee69cd5..e9e0c785e 100644 --- a/host/examples/tx_timed_samples.cpp +++ b/host/examples/tx_timed_samples.cpp @@ -41,7 +41,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ ("nsamps", po::value(&total_num_samps)->default_value(1000), "total number of samples to transmit") ("txrate", po::value(&tx_rate)->default_value(100e6/16), "rate of outgoing samples") ("freq", po::value(&freq)->default_value(0), "rf center frequency in Hz") - ("ampl", po::value(&l)->default_value(0.3), "amplitude of each sample") + ("ampl", po::value(&l)->default_value(float(0.3)), "amplitude of each sample") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index c857db1c4..5b73c82bf 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include namespace vrt_packet_handler{ @@ -209,6 +210,8 @@ namespace vrt_packet_handler{ } return total_num_samps; } + + default: throw std::runtime_error("unknown recv mode"); }//switch(recv_mode) } @@ -350,6 +353,8 @@ namespace vrt_packet_handler{ } return total_num_samps; } + + default: throw std::runtime_error("unknown send mode"); }//switch(send_mode) } -- cgit v1.2.3 From fd28cd7056867ec1ab81f7fb408c382e110ddaa1 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 19 May 2010 11:56:50 -0700 Subject: break recv loop on timeout --- host/lib/transport/vrt_packet_handler.hpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'host/lib/transport') diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 5b73c82bf..ab1b7e16c 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -193,22 +193,24 @@ namespace vrt_packet_handler{ //////////////////////////////////////////////////////////////// case uhd::device::RECV_MODE_FULL_BUFF:{ //////////////////////////////////////////////////////////////// - size_t num_samps = 0; + size_t accum_num_samps = 0; uhd::rx_metadata_t tmp_md; - while(num_samps < total_num_samps){ - num_samps += _recv1( + while(accum_num_samps < total_num_samps){ + size_t num_samps = _recv1( state, boost::asio::buffer_cast(buff) + (num_samps*io_type.size), total_num_samps - num_samps, - (num_samps == 0)? metadata : tmp_md, //only the first metadata gets kept + (accum_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 ); + if (num_samps == 0) break; //had a recv timeout or error, break loop + accum_num_samps += num_samps; } - return total_num_samps; + return accum_num_samps; } default: throw std::runtime_error("unknown recv mode"); -- cgit v1.2.3 From b46c5abe79dcd70cd21f7dce56f29e962237d6c9 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 19 May 2010 15:09:31 -0700 Subject: Fixed some bugs in the send and recv full buffer modes. Dealing with samples counts, metadata flags, etc.. --- host/lib/transport/convert_types.cpp | 9 +++++---- host/lib/transport/vrt_packet_handler.hpp | 14 +++++++------- 2 files changed, 12 insertions(+), 11 deletions(-) (limited to 'host/lib/transport') diff --git a/host/lib/transport/convert_types.cpp b/host/lib/transport/convert_types.cpp index 510d39454..43503025a 100644 --- a/host/lib/transport/convert_types.cpp +++ b/host/lib/transport/convert_types.cpp @@ -15,6 +15,7 @@ // along with this program. If not, see . // +#include #include #include #include //endianness conversion @@ -49,7 +50,7 @@ static const bool is_big_endian = true; static const bool is_big_endian = false; #endif -static inline void host_floats_to_usrp2_items( +static UHD_INLINE void host_floats_to_usrp2_items( boost::uint32_t *usrp2_items, const fc32_t *host_floats, size_t num_samps @@ -62,7 +63,7 @@ static inline void host_floats_to_usrp2_items( unrolled_loop(host_floats_to_usrp2_items_i, num_samps); } -static inline void usrp2_items_to_host_floats( +static UHD_INLINE void usrp2_items_to_host_floats( fc32_t *host_floats, const boost::uint32_t *usrp2_items, size_t num_samps @@ -76,7 +77,7 @@ static inline void usrp2_items_to_host_floats( unrolled_loop(usrp2_items_to_host_floats_i, num_samps); } -static inline void host_items_to_usrp2_items( +static UHD_INLINE void host_items_to_usrp2_items( boost::uint32_t *usrp2_items, const boost::uint32_t *host_items, size_t num_samps @@ -90,7 +91,7 @@ static inline void host_items_to_usrp2_items( } } -static inline void usrp2_items_to_host_items( +static UHD_INLINE void usrp2_items_to_host_items( boost::uint32_t *host_items, const boost::uint32_t *usrp2_items, size_t num_samps diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index ab1b7e16c..2a7f995a1 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -198,8 +198,8 @@ namespace vrt_packet_handler{ while(accum_num_samps < total_num_samps){ size_t num_samps = _recv1( state, - boost::asio::buffer_cast(buff) + (num_samps*io_type.size), - total_num_samps - num_samps, + boost::asio::buffer_cast(buff) + (accum_num_samps*io_type.size), + total_num_samps - accum_num_samps, (accum_num_samps == 0)? metadata : tmp_md, //only the first metadata gets kept io_type, otw_type, tick_rate, @@ -300,6 +300,7 @@ namespace vrt_packet_handler{ const send_cb_t& send_cb = &send_cb_nop ){ const size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size; + if (total_num_samps <= max_samples_per_packet) send_mode = uhd::device::SEND_MODE_ONE_PACKET; switch(send_mode){ //////////////////////////////////////////////////////////////// @@ -324,7 +325,6 @@ namespace vrt_packet_handler{ 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; @@ -336,15 +336,15 @@ namespace vrt_packet_handler{ 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); + md.has_time_spec = metadata.has_time_spec and (n == first_fragment_index); + md.start_of_burst = metadata.start_of_burst and (n == first_fragment_index); + md.end_of_burst = metadata.end_of_burst and (n == final_fragment_index); //send the fragment with the helper function _send1( state, boost::asio::buffer_cast(buff) + (n*max_samples_per_packet*io_type.size), - (n == final_fragment_index)?final_packet_samps:max_samples_per_packet, + (n == final_fragment_index)?(total_num_samps%max_samples_per_packet):max_samples_per_packet, md, io_type, otw_type, tick_rate, -- cgit v1.2.3 From 76ce1d824a41beacdb5bd603549c9b0e3f64d98f Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 21 May 2010 17:30:05 -0700 Subject: mac os x card burner support and documentation notes --- host/docs/build.rst | 31 ++++++++++++++++++++++++++----- host/docs/usrp2.rst | 2 +- host/lib/transport/gen_vrt.py | 2 +- host/utils/usrp2_card_burner.py | 21 +++++++++++++++++++++ 4 files changed, 49 insertions(+), 7 deletions(-) (limited to 'host/lib/transport') diff --git a/host/docs/build.rst b/host/docs/build.rst index d28682764..f5a8dac8d 100644 --- a/host/docs/build.rst +++ b/host/docs/build.rst @@ -8,9 +8,14 @@ UHD - Build Guide Build Dependencies ------------------------------------------------------------------------ -**Unix Notes:** +**Linux Notes:** The dependencies can be acquired through the package manager. +**Mac OS X Notes:** +Install the "Xcode Developer Tools" to get the build tools (gcc and make). +Use MacPorts to get the Boost and Cheetah dependencies. +Other dependencies can be downloaded as dmg installers from the web. + **Windows Notes:** The dependencies can be acquired through installable exe files. Usually, the windows installer can be found on the project's website. @@ -27,12 +32,13 @@ or install msysgit from http://code.google.com/p/msysgit/downloads/list ^^^^^^^^^^^^^^^^ C++ ^^^^^^^^^^^^^^^^ -On unix, this is GCC 4.0 and above. On windows, this is MSVC 2008. +On Unix, this is GCC 4.0 and above. On Windows, this is MSVC 2008. Other compilers have not been tested yet or confirmed working. ^^^^^^^^^^^^^^^^ CMake ^^^^^^^^^^^^^^^^ +* **Purpose:** generates project build files * **Version:** at least 2.8 * **Required for:** build time * **Download URL:** http://www.cmake.org/cmake/resources/software.html @@ -40,6 +46,7 @@ CMake ^^^^^^^^^^^^^^^^ Boost ^^^^^^^^^^^^^^^^ +* **Purpose:** C++ library * **Version:** at least 3.6 unix, at least 4.0 windows * **Required for:** build time + run time * **Download URL:** http://www.boost.org/users/download/ @@ -48,13 +55,15 @@ Boost ^^^^^^^^^^^^^^^^ Python ^^^^^^^^^^^^^^^^ +* **Purpose:** used by Cheetah and utility scripts * **Version:** at least 2.6 -* **Required for:** build time +* **Required for:** build time + run time utility scripts * **Download URL:** http://www.python.org/download/ ^^^^^^^^^^^^^^^^ Cheetah ^^^^^^^^^^^^^^^^ +* **Purpose:** source code generation * **Version:** at least 2.0 * **Required for:** build time * **Download URL:** http://www.cheetahtemplate.org/download.html @@ -63,9 +72,17 @@ Cheetah ^^^^^^^^^^^^^^^^ Doxygen ^^^^^^^^^^^^^^^^ +* **Purpose:** generates html api documentation * **Required for:** build time (optional) * **Download URL:** http://www.stack.nl/~dimitri/doxygen/download.html#latestsrc +^^^^^^^^^^^^^^^^ +Docutils +^^^^^^^^^^^^^^^^ +* **Purpose:** generates html user manual +* **Required for:** build time (optional) +* **Download URL:** http://docutils.sourceforge.net/ + ------------------------------------------------------------------------ Build Instructions (Unix) ------------------------------------------------------------------------ @@ -80,7 +97,7 @@ Generate Makefiles with cmake cd build cmake ../ -For a custom prefix, use: cmake -DCMAKE_INSTALL_PREFIX= ../ +For a custom prefix, use: cmake -DCMAKE_INSTALL_PREFIX= ../ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Build and install @@ -92,11 +109,15 @@ Build and install sudo make install ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Setup the library path +Setup the library path (Linux) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Make sure that libuhd.so is in your LD_LIBRARY_PATH or add it to /etc/ld.so.conf and make sure to run sudo ldconfig +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Setup the library path (Mac OS X) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Make sure that libuhd.dylib is in your DYLD_LIBRARY_PATH ------------------------------------------------------------------------ Build Instructions (Windows) diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst index c4a7aa64f..1bd95cefa 100644 --- a/host/docs/usrp2.rst +++ b/host/docs/usrp2.rst @@ -50,7 +50,7 @@ you could overwrite your hard drive. Make sure that --dev= specifies the SD card Use the *--list* option to get a list of possible raw devices. The list result will filter out disk partitions and devices too large to be the sd card. -The list option has not yet been implemented on macosx. +The list option has been implemented on Linux, Mac OS X, and Windows. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use the card burner tool (unix) diff --git a/host/lib/transport/gen_vrt.py b/host/lib/transport/gen_vrt.py index 9a57c83c3..c34ffb198 100755 --- a/host/lib/transport/gen_vrt.py +++ b/host/lib/transport/gen_vrt.py @@ -57,7 +57,7 @@ void vrt::pack( size_t packet_count, //input double tick_rate //input ){ - boost::uint32_t vrt_hdr_flags; + boost::uint32_t vrt_hdr_flags = 0; boost::uint8_t pred = 0; if (metadata.has_stream_id) pred |= $hex($sid_p); diff --git a/host/utils/usrp2_card_burner.py b/host/utils/usrp2_card_burner.py index 60aca9133..d47a4f5f4 100755 --- a/host/utils/usrp2_card_burner.py +++ b/host/utils/usrp2_card_burner.py @@ -22,6 +22,7 @@ import subprocess import urllib import optparse import os +import re ######################################################################## # constants @@ -106,6 +107,26 @@ def get_raw_device_hints(): return sorted(set(devs)) + #################################################################### + # Platform Mac OS X: parse diskutil list and info commands + #################################################################### + if platform.system() == 'Darwin': + devs = map(lambda d: d.split()[0], filter(lambda l: l.startswith('/dev'), command('diskutil', 'list').splitlines())) + def output_to_info(output): + return dict([map(str.strip, pair.lower().split(':')) for pair in filter(lambda l: ':' in l, output.splitlines())]) + def is_dev_valid(dev): + info = output_to_info(command('diskutil', 'info', dev)) + try: + if info.has_key('internal'): assert info['internal'] == 'no' + if info.has_key('ejectable'): assert info['ejectable'] == 'yes' + if info.has_key('total size'): + size_match = re.match('^.*\((\d+)\s*bytes\).*$', info['total size']) + if size_match: assert int(size_match.groups()[0]) <= MAX_SD_CARD_SIZE + return True + except: return False + + return sorted(set(filter(is_dev_valid, devs))) + #################################################################### # Platform Others: #################################################################### -- cgit v1.2.3 From 71169b8e030d984220eadde83c4b40481f97cf6b Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 24 May 2010 14:38:25 -0700 Subject: Added timeout error message to timed samples example. Added try catch to recv helper because vrt unpack can throw. --- host/examples/rx_timed_samples.cpp | 4 ++++ host/lib/transport/vrt_packet_handler.hpp | 11 ++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'host/lib/transport') diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp index d2306c7c4..64da260d5 100644 --- a/host/examples/rx_timed_samples.cpp +++ b/host/examples/rx_timed_samples.cpp @@ -86,6 +86,10 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ md, uhd::io_type_t::COMPLEX_FLOAT32, uhd::device::RECV_MODE_ONE_PACKET ); + if (num_rx_samps == 0 and num_acc_samps > 0){ + std::cout << "Got timeout before all samples received, possible packet loss, exiting loop..." << std::endl; + break; + } if (num_rx_samps == 0) continue; //wait for packets with contents std::cout << boost::format("Got packet: %u samples, %u secs, %u nsecs") diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 2a7f995a1..81420b39e 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -122,9 +122,14 @@ namespace vrt_packet_handler{ 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 - ); + try{ + _recv1_helper( + state, metadata, tick_rate, vrt_header_offset_words32 + ); + }catch(const std::exception &e){ + std::cerr << "Error (recv): " << e.what() << std::endl; + return 0; + } } //extract the number of samples available to copy -- cgit v1.2.3 From 4eff47a4b66eff61feffe6498b9ecebef94dc6b9 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 27 May 2010 14:10:50 -0700 Subject: Tweak with the udp and zero-copy transport. Eventually, the caller will hang onto a ring of managed buffers. --- host/include/uhd/transport/zero_copy.hpp | 5 ++-- host/lib/transport/udp_zero_copy_asio.cpp | 38 ++++++++++++++++--------------- host/lib/transport/vrt_packet_handler.hpp | 2 +- host/lib/usrp/usrp2/io_impl.cpp | 2 +- 4 files changed, 25 insertions(+), 22 deletions(-) (limited to 'host/lib/transport') diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp index fdc5b141c..52c6d4143 100644 --- a/host/include/uhd/transport/zero_copy.hpp +++ b/host/include/uhd/transport/zero_copy.hpp @@ -35,11 +35,12 @@ public: typedef boost::shared_ptr sptr; /*! + * Managed recv buffer destructor: * Signal to the transport that we are done with the buffer. * This should be called to release the buffer to the transport. * After calling, the referenced memory should be considered invalid. */ - virtual void done(void) = 0; + virtual ~managed_recv_buffer(void){}; /*! * Get the size of the underlying buffer. @@ -81,7 +82,7 @@ public: * After calling, the referenced memory should be considered invalid. * \param num_bytes the number of bytes written into the buffer */ - virtual void done(size_t num_bytes) = 0; + virtual void commit(size_t num_bytes) = 0; /*! * Get the size of the underlying buffer. diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index 56ba391d3..f8a222475 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -24,6 +24,13 @@ using namespace uhd::transport; +/*********************************************************************** + * Constants + **********************************************************************/ +static const size_t MIN_SOCK_BUFF_SIZE = size_t(100e3); +static const size_t MAX_DGRAM_SIZE = 2048; //assume max size on send and recv +static const double RECV_TIMEOUT = 0.1; // 100 ms + /*********************************************************************** * Managed receive buffer implementation for udp zero-copy asio: **********************************************************************/ @@ -34,11 +41,7 @@ public: } ~managed_recv_buffer_impl(void){ - /* NOP */ - } - - void done(void){ - /* NOP */ + delete [] this->cast(); } private: @@ -65,7 +68,7 @@ public: /* NOP */ } - void done(size_t num_bytes){ + void commit(size_t num_bytes){ _socket->send(boost::asio::buffer(_buff, num_bytes)); } @@ -85,8 +88,6 @@ 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 sptr; @@ -117,7 +118,7 @@ private: 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]; + boost::uint8_t _send_mem[MIN_SOCK_BUFF_SIZE]; managed_send_buffer::sptr _send_buff; }; @@ -137,13 +138,13 @@ udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::strin // 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 + boost::asio::buffer(_send_mem, MIN_SOCK_BUFF_SIZE), _socket )); // set recv timeout timeval tv; tv.tv_sec = 0; - tv.tv_usec = 100*1000; //100 ms + tv.tv_usec = size_t(RECV_TIMEOUT*1e6); UHD_ASSERT_THROW(setsockopt( _socket->native(), SOL_SOCKET, SO_RCVTIMEO, @@ -156,17 +157,20 @@ udp_zero_copy_impl::~udp_zero_copy_impl(void){ } managed_recv_buffer::sptr udp_zero_copy_impl::get_recv_buff(void){ + //allocate memory + boost::uint8_t *recv_mem = new boost::uint8_t[MAX_DGRAM_SIZE]; + //call recv() with timeout option - size_t num_bytes = _socket->receive(boost::asio::buffer(_recv_mem, max_buff_size)); + size_t num_bytes = _socket->receive(boost::asio::buffer(recv_mem, MIN_SOCK_BUFF_SIZE)); //create a new managed buffer to house the data return managed_recv_buffer::sptr( - new managed_recv_buffer_impl(boost::asio::buffer(_recv_mem, num_bytes)) + new managed_recv_buffer_impl(boost::asio::buffer(recv_mem, num_bytes)) ); } managed_send_buffer::sptr udp_zero_copy_impl::get_send_buff(void){ - return _send_buff; + return _send_buff; //FIXME there is only ever one send buff, we assume that the caller doesnt hang onto these } /*********************************************************************** @@ -177,8 +181,6 @@ template static inline void resize_buff_helper( 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(target_size); @@ -189,8 +191,8 @@ template static inline void resize_buff_helper( } //otherwise, ensure that the buffer is at least the minimum size - else if (udp_trans->get_buff_size() < min_buff_size){ - resize_buff_helper(udp_trans, min_buff_size, name); + else if (udp_trans->get_buff_size() < MIN_SOCK_BUFF_SIZE){ + resize_buff_helper(udp_trans, MIN_SOCK_BUFF_SIZE, name); } } diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 81420b39e..e64e3383d 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -284,7 +284,7 @@ namespace vrt_packet_handler{ 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_buff->commit(num_packet_words32*sizeof(boost::uint32_t)); } /******************************************************************* diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index b6ab919e7..79b18fb63 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -45,7 +45,7 @@ void usrp2_impl::io_init(void){ managed_send_buffer::sptr send_buff = _data_transport->get_send_buff(); boost::uint32_t data = htonl(USRP2_INVALID_VRT_HEADER); memcpy(send_buff->cast(), &data, sizeof(data)); - send_buff->done(sizeof(data)); + send_buff->commit(sizeof(data)); //setup RX DSP regs std::cout << "RX samples per packet: " << get_max_recv_samps_per_packet() << std::endl; -- cgit v1.2.3