diff options
Diffstat (limited to 'host/lib/transport')
-rwxr-xr-x | host/lib/transport/gen_vrt_if_packet.py | 48 | ||||
-rw-r--r-- | host/lib/transport/udp_zero_copy_asio.cpp | 22 | ||||
-rw-r--r-- | host/lib/transport/vrt_packet_handler.hpp | 50 |
3 files changed, 70 insertions, 50 deletions
diff --git a/host/lib/transport/gen_vrt_if_packet.py b/host/lib/transport/gen_vrt_if_packet.py index 9b5bfca02..07ce391ee 100755 --- a/host/lib/transport/gen_vrt_if_packet.py +++ b/host/lib/transport/gen_vrt_if_packet.py @@ -61,13 +61,6 @@ using namespace uhd::transport; #set $tsf_p = 0b01000 #set $tlr_p = 0b10000 -static UHD_INLINE void pack_uint64_$(suffix)(boost::uint64_t num, boost::uint32_t *mem){ - //*(reinterpret_cast<boost::uint64_t *>(mem)) = $(XE_MACRO)(num); - //second word is lower 32 bits due to fpga implementation - mem[1] = $(XE_MACRO)(boost::uint32_t(num >> 0)); - mem[0] = $(XE_MACRO)(boost::uint32_t(num >> 32)); -} - void vrt::if_hdr_pack_$(suffix)( boost::uint32_t *packet_buff, if_packet_info_t &if_packet_info @@ -94,8 +87,10 @@ void vrt::if_hdr_pack_$(suffix)( #end if ########## Class ID ########## #if $pred & $cid_p - pack_uint64_$(suffix)(if_packet_info.cid, packet_buff+$num_header_words); - #set $num_header_words += 2 + packet_buff[$num_header_words] = 0; //not implemented + #set $num_header_words += 1 + packet_buff[$num_header_words] = 0; //not implemented + #set $num_header_words += 1 #set $flags |= (0x1 << 27); #end if ########## Integer Time ########## @@ -106,8 +101,10 @@ void vrt::if_hdr_pack_$(suffix)( #end if ########## Fractional Time ########## #if $pred & $tsf_p - pack_uint64_$(suffix)(if_packet_info.tsf, packet_buff+$num_header_words); - #set $num_header_words += 2 + packet_buff[$num_header_words] = $(XE_MACRO)(boost::uint32_t(if_packet_info.tsf >> 32)); + #set $num_header_words += 1 + packet_buff[$num_header_words] = $(XE_MACRO)(boost::uint32_t(if_packet_info.tsf >> 0)); + #set $num_header_words += 1 #set $flags |= (0x1 << 20); #end if ########## Trailer ########## @@ -116,7 +113,6 @@ void vrt::if_hdr_pack_$(suffix)( #set $flags |= (0x1 << 26); #set $num_trailer_words = 1; #else - //packet_buff[$num_header_words+if_packet_info.num_payload_words32] = 0; #set $num_trailer_words = 0; #end if ########## Variables ########## @@ -139,13 +135,6 @@ void vrt::if_hdr_pack_$(suffix)( )); } -static UHD_INLINE void unpack_uint64_$(suffix)(boost::uint64_t &num, const boost::uint32_t *mem){ - //num = $(XE_MACRO)(*reinterpret_cast<const boost::uint64_t *>(mem)); - //second word is lower 32 bits due to fpga implementation - num = boost::uint64_t($(XE_MACRO)(mem[1])) << 0; - num |= boost::uint64_t($(XE_MACRO)(mem[0])) << 32; -} - void vrt::if_hdr_unpack_$(suffix)( const boost::uint32_t *packet_buff, if_packet_info_t &if_packet_info @@ -153,13 +142,16 @@ void vrt::if_hdr_unpack_$(suffix)( //extract vrt header boost::uint32_t vrt_hdr_word = $(XE_MACRO)(packet_buff[0]); size_t packet_words32 = vrt_hdr_word & 0xffff; - if_packet_info.packet_count = (vrt_hdr_word >> 16) & 0xf; - //failure cases + //failure case if (if_packet_info.num_packet_words32 < packet_words32) throw std::runtime_error("bad vrt header or packet fragment"); - if (vrt_hdr_word & (0x7 << 29)) - throw std::runtime_error("bad vrt header or unsupported packet type"); + + //extract fields from the header + if_packet_info.packet_type = if_packet_info_t::packet_type_t(vrt_hdr_word >> 29); + if_packet_info.packet_count = (vrt_hdr_word >> 16) & 0xf; + if_packet_info.sob = bool(vrt_hdr_word & $hex(0x1 << 25)); + if_packet_info.eob = bool(vrt_hdr_word & $hex(0x1 << 24)); boost::uint8_t pred = 0; if(vrt_hdr_word & $hex(0x1 << 28)) pred |= $hex($sid_p); @@ -184,7 +176,7 @@ void vrt::if_hdr_unpack_$(suffix)( ########## Class ID ########## #if $pred & $cid_p if_packet_info.has_cid = true; - unpack_uint64_$(suffix)(if_packet_info.cid, packet_buff+$num_header_words); + if_packet_info.cid = 0; //not implemented #set $num_header_words += 2 #else if_packet_info.has_cid = false; @@ -200,15 +192,17 @@ void vrt::if_hdr_unpack_$(suffix)( ########## Fractional Time ########## #if $pred & $tsf_p if_packet_info.has_tsf = true; - unpack_uint64_$(suffix)(if_packet_info.tsf, packet_buff+$num_header_words); - #set $num_header_words += 2 + if_packet_info.tsf = boost::uint64_t($(XE_MACRO)(packet_buff[$num_header_words])) << 32; + #set $num_header_words += 1 + if_packet_info.tsf |= boost::uint64_t($(XE_MACRO)(packet_buff[$num_header_words])) << 0; + #set $num_header_words += 1 #else if_packet_info.has_tsf = false; #end if ########## Trailer ########## #if $pred & $tlr_p if_packet_info.has_tlr = true; - if_packet_info.tlr = $(XE_MACRO)(packet_buff[$num_header_words+packet_words32]); + if_packet_info.tlr = $(XE_MACRO)(packet_buff[packet_words32-1]); #set $num_trailer_words = 1; #else if_packet_info.has_tlr = false; diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index 7f9292d24..e3f3ef5bf 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -16,6 +16,7 @@ // #include <uhd/transport/udp_zero_copy.hpp> +#include <uhd/transport/udp_simple.hpp> //mtu #include <uhd/utils/assert.hpp> #include <boost/cstdint.hpp> #include <boost/asio.hpp> @@ -29,7 +30,6 @@ using namespace uhd::transport; **********************************************************************/ //enough buffering for half a second of samples at full rate on usrp2 static const size_t MIN_SOCK_BUFF_SIZE = size_t(sizeof(boost::uint32_t) * 25e6 * 0.5); -static const size_t MAX_DGRAM_SIZE = 1500; //assume max size on send and recv static const double RECV_TIMEOUT = 0.1; //100 ms /*********************************************************************** @@ -51,8 +51,8 @@ public: const std::string &addr, const std::string &port ): - phony_zero_copy_recv_if(MAX_DGRAM_SIZE), - phony_zero_copy_send_if(MAX_DGRAM_SIZE) + phony_zero_copy_recv_if(udp_simple::mtu), + phony_zero_copy_send_if(udp_simple::mtu) { //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl; @@ -93,11 +93,11 @@ public: //This way, the transport caller will have an idea about how much buffering to create. size_t get_num_recv_frames(void) const{ - return this->get_buff_size<boost::asio::socket_base::receive_buffer_size>()/MAX_DGRAM_SIZE; + return this->get_buff_size<boost::asio::socket_base::receive_buffer_size>()/udp_simple::mtu; } size_t get_num_send_frames(void) const{ - return this->get_buff_size<boost::asio::socket_base::send_buffer_size>()/MAX_DGRAM_SIZE; + return this->get_buff_size<boost::asio::socket_base::send_buffer_size>()/udp_simple::mtu; } private: @@ -155,17 +155,17 @@ template<typename Opt> static void resize_buff_helper( else std::cout << boost::format( "Current %s sock buff size: %d bytes" ) % name % actual_size << std::endl; + if (actual_size < target_size) std::cerr << boost::format( + "Warning:\n" + " The %s buffer is smaller than the requested size.\n" + " The minimum recommended buffer size is %d bytes.\n" + " See the USRP2 application notes on buffer resizing.\n" + ) % name % MIN_SOCK_BUFF_SIZE << std::endl; } //otherwise, ensure that the buffer is at least the minimum size else if (udp_trans->get_buff_size<Opt>() < MIN_SOCK_BUFF_SIZE){ resize_buff_helper<Opt>(udp_trans, MIN_SOCK_BUFF_SIZE, name); - if (udp_trans->get_buff_size<Opt>() < MIN_SOCK_BUFF_SIZE){ - std::cerr << boost::format( - "Warning: the %s buffer size is smaller than the recommended size of %d bytes.\n" - " See the USRP2 application notes on buffer resizing." - ) % name % MIN_SOCK_BUFF_SIZE << std::endl; - } } } diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 68edeb1e1..11d749a81 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -21,6 +21,7 @@ #include <uhd/config.hpp> #include <uhd/device.hpp> #include <uhd/utils/assert.hpp> +#include <uhd/utils/byteswap.hpp> #include <uhd/types/io_type.hpp> #include <uhd/types/otw_type.hpp> #include <uhd/types/metadata.hpp> @@ -39,6 +40,9 @@ namespace vrt_packet_handler{ **********************************************************************/ typedef std::vector<uhd::transport::managed_recv_buffer::sptr> managed_recv_buffs_t; typedef boost::function<bool(managed_recv_buffs_t &)> get_recv_buffs_t; + typedef boost::function<void(size_t /*which channel*/)> handle_overrun_t; + + void handle_overrun_nop(size_t){} struct recv_state{ //width of the receiver in channels @@ -53,7 +57,7 @@ namespace vrt_packet_handler{ size_t size_of_copy_buffs; size_t fragment_offset_in_samps; - recv_state(size_t width): + recv_state(size_t width = 1): width(width), next_packet_seq(width, 0), managed_buffs(width), @@ -75,20 +79,25 @@ namespace vrt_packet_handler{ uhd::rx_metadata_t &metadata, double tick_rate, vrt_unpacker_type vrt_unpacker, + const handle_overrun_t &handle_overrun, size_t vrt_header_offset_words32 ){ - size_t num_packet_words32 = state.managed_buffs[0]->size()/sizeof(boost::uint32_t); - if (num_packet_words32 <= vrt_header_offset_words32){ - state.size_of_copy_buffs = 0; - return; //must exit here after setting the buffer - } - //vrt unpack each managed buffer uhd::transport::vrt::if_packet_info_t if_packet_info; for (size_t i = 0; i < state.width; i++){ + + //extract packet words and check thats its enough to move on + size_t num_packet_words32 = state.managed_buffs[i]->size()/sizeof(boost::uint32_t); + if (num_packet_words32 <= vrt_header_offset_words32){ + state.size_of_copy_buffs = 0; + return; //must exit here after setting the buffer + } + + //unpack the vrt header into the info struct const boost::uint32_t *vrt_hdr = state.managed_buffs[i]->cast<const boost::uint32_t *>() + vrt_header_offset_words32; if_packet_info.num_packet_words32 = num_packet_words32 - vrt_header_offset_words32; vrt_unpacker(vrt_hdr, if_packet_info); + const boost::uint32_t *vrt_data = vrt_hdr + if_packet_info.num_header_words32; //handle the packet count / sequence number if (if_packet_info.packet_count != state.next_packet_seq[i]){ @@ -96,8 +105,19 @@ namespace vrt_packet_handler{ } state.next_packet_seq[i] = (if_packet_info.packet_count+1)%16; + //make sure that its a data packet (TODO handle non-data packets) + if (if_packet_info.packet_type != uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_DATA){ + std::cout << "vrt packet handler _recv1_helper got non data packet" << std::endl; + //extract the context word (we dont know the endianness so mirror the bytes) + boost::uint32_t word0 = vrt_data[0] | uhd::byteswap(vrt_data[0]); + if (word0 & 8) handle_overrun(i); + // 4: broken chain, 2: late command... + state.size_of_copy_buffs = 0; + return; //must exit here after setting the buffer + } + //setup the buffer to point to the data - state.copy_buffs[i] = reinterpret_cast<const boost::uint8_t *>(vrt_hdr + if_packet_info.num_header_words32); + state.copy_buffs[i] = reinterpret_cast<const boost::uint8_t *>(vrt_data); //store the minimum payload length into the copy buffer length size_t num_payload_bytes = if_packet_info.num_payload_words32*sizeof(boost::uint32_t); @@ -111,6 +131,9 @@ namespace vrt_packet_handler{ metadata.time_spec = uhd::time_spec_t( time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), tick_rate ); + metadata.start_of_burst = if_packet_info.sob; + static const int tlr_eob_flags = (1 << 20) | (1 << 8); //enable and indicator bits + metadata.end_of_burst = if_packet_info.has_tlr and (int(if_packet_info.tlr & tlr_eob_flags) == tlr_eob_flags); } /******************************************************************* @@ -129,7 +152,7 @@ namespace vrt_packet_handler{ double tick_rate, vrt_unpacker_type vrt_unpacker, const get_recv_buffs_t &get_recv_buffs, - //use these two params to handle a layer above vrt + const handle_overrun_t &handle_overrun, size_t vrt_header_offset_words32 ){ metadata.has_time_spec = false; //false unless set in the helper @@ -140,7 +163,9 @@ namespace vrt_packet_handler{ if (not get_recv_buffs(state.managed_buffs)) return 0; try{ _recv1_helper( - state, metadata, tick_rate, vrt_unpacker, vrt_header_offset_words32 + state, metadata, tick_rate, + vrt_unpacker, handle_overrun, + vrt_header_offset_words32 ); }catch(const std::exception &e){ std::cerr << "Error (recv): " << e.what() << std::endl; @@ -191,7 +216,7 @@ namespace vrt_packet_handler{ double tick_rate, vrt_unpacker_type vrt_unpacker, const get_recv_buffs_t &get_recv_buffs, - //use these two params to handle a layer above vrt + const handle_overrun_t &handle_overrun = &handle_overrun_nop, size_t vrt_header_offset_words32 = 0 ){ switch(recv_mode){ @@ -208,6 +233,7 @@ namespace vrt_packet_handler{ tick_rate, vrt_unpacker, get_recv_buffs, + handle_overrun, vrt_header_offset_words32 ); } @@ -227,6 +253,7 @@ namespace vrt_packet_handler{ tick_rate, vrt_unpacker, get_recv_buffs, + handle_overrun, vrt_header_offset_words32 ); if (num_samps == 0) break; //had a recv timeout or error, break loop @@ -315,7 +342,6 @@ namespace vrt_packet_handler{ vrt_packer_type vrt_packer, const get_send_buffs_t &get_send_buffs, size_t max_samples_per_packet, - //use these two params to handle a layer above vrt size_t vrt_header_offset_words32 = 0 ){ //translate the metadata to vrt if packet info |