diff options
| author | Josh Blum <josh@joshknows.com> | 2010-06-29 22:55:45 -0700 | 
|---|---|---|
| committer | Josh Blum <josh@joshknows.com> | 2010-07-05 13:45:11 -0700 | 
| commit | 08fad28f209a2f6c79d939ad54ca3a1d4e270b0b (patch) | |
| tree | 6561410b24bcf0f3e72d680c27143b3b2a015bd0 | |
| parent | 01e5f592d62e2193cc88081bd88765cae4708148 (diff) | |
| download | uhd-08fad28f209a2f6c79d939ad54ca3a1d4e270b0b.tar.gz uhd-08fad28f209a2f6c79d939ad54ca3a1d4e270b0b.tar.bz2 uhd-08fad28f209a2f6c79d939ad54ca3a1d4e270b0b.zip | |
uhd: work vectorizing the vrt packet handler, reworked vrt packet stuff, needs testing
| -rw-r--r-- | host/include/uhd/device.hpp | 51 | ||||
| -rw-r--r-- | host/include/uhd/transport/vrt.hpp | 110 | ||||
| -rw-r--r-- | host/include/uhd/types/metadata.hpp | 14 | ||||
| -rwxr-xr-x | host/lib/transport/gen_vrt.py | 117 | ||||
| -rw-r--r-- | host/lib/transport/vrt_packet_handler.hpp | 252 | ||||
| -rw-r--r-- | host/lib/types.cpp | 4 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/io_impl.cpp | 32 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.hpp | 9 | ||||
| -rw-r--r-- | host/test/vrt_test.cpp | 147 | 
9 files changed, 401 insertions, 335 deletions
| diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index d3e9015c4..f04a5b4fb 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -27,6 +27,7 @@  #include <boost/shared_ptr.hpp>  #include <boost/function.hpp>  #include <boost/asio/buffer.hpp> +#include <vector>  namespace uhd{ @@ -96,8 +97,22 @@ public:          RECV_MODE_ONE_PACKET = 1      }; +    //! wrapper call for single buffer recv //TODO put somewhere +    size_t send( +        const boost::asio::const_buffer &buff, +        const tx_metadata_t &metadata, +        const io_type_t &io_type, +        send_mode_t send_mode +    ){ +        return send( +            std::vector<const void *>(1, boost::asio::buffer_cast<const void *>(buff)), +            boost::asio::buffer_size(buff)/io_type.size, +            metadata, io_type, send_mode +        ); +    } +      /*! -     * Send a buffer containing IF data with its metadata. +     * Send buffers containing IF data described by the metadata.       *       * Send handles fragmentation as follows:       * If the buffer has more samples than the maximum per packet, @@ -108,23 +123,39 @@ public:       * 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. +     * of samples returned have been read out of each buffer.       * -     * \param buff a buffer pointing to some read-only memory +     * \param buffs a vector of read-only memory containing IF data +     * \param nsamps_per_buff the number of samples to send, per buffer       * \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 std::vector<const void *> &buffs, +        size_t nsamps_per_buff,          const tx_metadata_t &metadata,          const io_type_t &io_type,          send_mode_t send_mode      ) = 0; +    //! wrapper call for single buffer recv //TODO put somewhere +    size_t recv( +        const boost::asio::mutable_buffer &buff, +        rx_metadata_t &metadata, +        const io_type_t &io_type, +        recv_mode_t recv_mode +    ){ +        return recv( +            std::vector<void *>(1, boost::asio::buffer_cast<void *>(buff)), +            boost::asio::buffer_size(buff)/io_type.size, +            metadata, io_type, recv_mode +        ); +    } +      /*! -     * Receive a buffer containing IF data and its metadata. +     * Receive buffers containing IF data described by the metadata.       *       * Receive handles fragmentation as follows:       * If the buffer has insufficient space to hold all samples @@ -138,7 +169,7 @@ public:       * See the rx metadata fragment flags and offset fields for details.       *       * This is a blocking call and will not return until the number -     * of samples returned have been written into the buffer. +     * of samples returned have been written into each buffer.       * However, a call to receive may timeout and return zero samples.       * The timeout duration is decided by the underlying transport layer.       * The caller should assume that the call to receive will not return @@ -146,17 +177,19 @@ public:       * 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. +     * to the first packet received and written into the recv buffers.       * Use the one packet recv mode to get per packet metadata.       * -     * \param buff the buffer to fill with IF data +     * \param buffs a vector of writable memory to fill with IF data +     * \param nsamps_per_buff the size of each buffer in number of samples       * \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, +        const std::vector<void *> &buffs, +        size_t nsamps_per_buff,          rx_metadata_t &metadata,          const io_type_t &io_type,          recv_mode_t recv_mode diff --git a/host/include/uhd/transport/vrt.hpp b/host/include/uhd/transport/vrt.hpp index fb6efc99c..17da2d540 100644 --- a/host/include/uhd/transport/vrt.hpp +++ b/host/include/uhd/transport/vrt.hpp @@ -19,93 +19,77 @@  #define INCLUDED_UHD_TRANSPORT_VRT_HPP  #include <uhd/config.hpp> -#include <uhd/types/metadata.hpp> -#include <cstddef> +#include <boost/cstdint.hpp> +#include <cstddef> //size_t  namespace uhd{ namespace transport{  namespace vrt{ -    static const size_t max_header_words32 = 5; //hdr+sid+tsi+tsf (no class id supported) +    //! The maximum number of 32-bit words in a vrt if packet header +    static const size_t max_if_hdr_words32 = 7; //hdr+sid+cid+tsi+tsf + +    /*! +     * Definition for fields that can be packed into a vrt if header. +     * The size fields are used for input and output depending upon +     * the operation used (ie the pack or unpack function call). +     */ +    struct UHD_API if_packet_info_t{ +        //size fields +        size_t num_payload_words32; //required in pack, derived in unpack +        size_t num_header_words32;  //derived in pack, derived in unpack +        size_t num_packet_words32;  //derived in pack, required in unpack + +        //header fields +        size_t packet_count; +        bool sob, eob; + +        //optional fields +        bool has_sid; boost::uint32_t sid; +        bool has_cid; boost::uint64_t cid; +        bool has_tsi; boost::uint32_t tsi; +        bool has_tsf; boost::uint64_t tsf; +        bool has_tlr; boost::uint32_t tlr; +    };      /*!       * Pack a vrt header from metadata (big endian format). -     * \param metadata the tx metadata with flags and timestamps -     * \param header_buff memory to write the packed vrt header -     * \param num_header_words32 number of words in the vrt header -     * \param num_payload_words32 the length of the payload -     * \param num_packet_words32 the length of the packet -     * \param packet_count the packet count sequence number -     * \param tick_rate ticks per second used in time conversion +     * \param packet_buff memory to write the packed vrt header +     * \param if_packet_info the if packet info (read/write)       */ -    UHD_API void pack_be( -        const tx_metadata_t &metadata, //input -        boost::uint32_t *header_buff,  //output -        size_t &num_header_words32,    //output -        size_t num_payload_words32,    //input -        size_t &num_packet_words32,    //output -        size_t packet_count,           //input -        double tick_rate               //input +    UHD_API void if_hdr_pack_be( +        boost::uint32_t *packet_buff, +        if_packet_info_t &if_packet_info      );      /*!       * Unpack a vrt header to metadata (big endian format). -     * \param metadata the rx metadata with flags and timestamps -     * \param header_buff memory to read the packed vrt header -     * \param num_header_words32 number of words in the vrt header -     * \param num_payload_words32 the length of the payload -     * \param num_packet_words32 the length of the packet -     * \param packet_count the packet count sequence number -     * \param tick_rate ticks per second used in time conversion +     * \param packet_buff memory to read the packed vrt header +     * \param if_packet_info the if packet info (read/write)       */ -    UHD_API void unpack_be( -        rx_metadata_t &metadata,            //output -        const boost::uint32_t *header_buff, //input -        size_t &num_header_words32,         //output -        size_t &num_payload_words32,        //output -        size_t num_packet_words32,          //input -        size_t &packet_count,               //output -        double tick_rate                    //input +    UHD_API void if_hdr_unpack_be( +        const boost::uint32_t *packet_buff, +        if_packet_info_t &if_packet_info      );      /*!       * Pack a vrt header from metadata (little endian format). -     * \param metadata the tx metadata with flags and timestamps -     * \param header_buff memory to write the packed vrt header -     * \param num_header_words32 number of words in the vrt header -     * \param num_payload_words32 the length of the payload -     * \param num_packet_words32 the length of the packet -     * \param packet_count the packet count sequence number -     * \param tick_rate ticks per second used in time conversion +     * \param packet_buff memory to write the packed vrt header +     * \param if_packet_info the if packet info (read/write)       */ -    UHD_API void pack_le( -        const tx_metadata_t &metadata, //input -        boost::uint32_t *header_buff,  //output -        size_t &num_header_words32,    //output -        size_t num_payload_words32,    //input -        size_t &num_packet_words32,    //output -        size_t packet_count,           //input -        double tick_rate               //input +    UHD_API void if_hdr_pack_le( +        boost::uint32_t *packet_buff, +        if_packet_info_t &if_packet_info      );      /*!       * Unpack a vrt header to metadata (little endian format). -     * \param metadata the rx metadata with flags and timestamps -     * \param header_buff memory to read the packed vrt header -     * \param num_header_words32 number of words in the vrt header -     * \param num_payload_words32 the length of the payload -     * \param num_packet_words32 the length of the packet -     * \param packet_count the packet count sequence number -     * \param tick_rate ticks per second used in time conversion +     * \param packet_buff memory to read the packed vrt header +     * \param if_packet_info the if packet info (read/write)       */ -    UHD_API void unpack_le( -        rx_metadata_t &metadata,            //output -        const boost::uint32_t *header_buff, //input -        size_t &num_header_words32,         //output -        size_t &num_payload_words32,        //output -        size_t num_packet_words32,          //input -        size_t &packet_count,               //output -        double tick_rate                    //input +    UHD_API void if_hdr_unpack_le( +        const boost::uint32_t *packet_buff, +        if_packet_info_t &if_packet_info      );  } //namespace vrt diff --git a/host/include/uhd/types/metadata.hpp b/host/include/uhd/types/metadata.hpp index 55add71cc..f4c962ff7 100644 --- a/host/include/uhd/types/metadata.hpp +++ b/host/include/uhd/types/metadata.hpp @@ -31,13 +31,6 @@ namespace uhd{       */      struct UHD_API rx_metadata_t{          /*! -         * Stream IDs may be used to identify source DSP units. -         * --Not currently used in any known device implementation.-- -         */ -        bool has_stream_id; -        boost::uint32_t stream_id; - -        /*!           * Time specification:           * Set from timestamps on incoming data when provided.           */ @@ -84,13 +77,6 @@ namespace uhd{       */      struct UHD_API tx_metadata_t{          /*! -         * Stream IDs may be used to identify destination DSP units. -         * --Not currently used in any known device implementation.-- -         */ -        bool has_stream_id; -        boost::uint32_t stream_id; - -        /*!           * Time specification:           * Set has time spec to false to perform a send "now".           * Or, set to true, and fill in time spec for a send "at". diff --git a/host/lib/transport/gen_vrt.py b/host/lib/transport/gen_vrt.py index 8e0fce9ff..ad87b9972 100755 --- a/host/lib/transport/gen_vrt.py +++ b/host/lib/transport/gen_vrt.py @@ -61,20 +61,22 @@ using namespace uhd::transport;  #set $tsf_p = 0b01000  #set $tlr_p = 0b10000 -void vrt::pack_$(suffix)( -    const tx_metadata_t &metadata, //input -    boost::uint32_t *header_buff,  //output -    size_t &num_header_words32,    //output -    size_t num_payload_words32,    //input -    size_t &num_packet_words32,    //output -    size_t packet_count,           //input -    double tick_rate               //input +static UHD_INLINE void pack_uint64_$(suffix)(boost::uint64_t num, boost::uint32_t *mem){ +    *(reinterpret_cast<boost::uint64_t *>(mem)) = $(XE_MACRO)(num); +} + +void vrt::if_hdr_pack_$(suffix)( +    boost::uint32_t *packet_buff, +    if_packet_info_t &if_packet_info  ){      boost::uint32_t vrt_hdr_flags = 0;      boost::uint8_t pred = 0; -    if (metadata.has_stream_id) pred |= $hex($sid_p); -    if (metadata.has_time_spec) pred |= $hex($tsi_p | $tsf_p); +    if (if_packet_info.has_sid) pred |= $hex($sid_p); +    if (if_packet_info.has_cid) pred |= $hex($cid_p); +    if (if_packet_info.has_tsi) pred |= $hex($tsi_p); +    if (if_packet_info.has_tsf) pred |= $hex($tsf_p); +    if (if_packet_info.has_tlr) pred |= $hex($tlr_p);      switch(pred){      #for $pred in range(2**5) @@ -83,79 +85,71 @@ void vrt::pack_$(suffix)(          #set $flags = 0          ########## Stream ID ##########          #if $pred & $sid_p -            header_buff[$num_header_words] = $(XE_MACRO)(metadata.stream_id); +            packet_buff[$num_header_words] = $(XE_MACRO)(if_packet_info.sid);              #set $num_header_words += 1              #set $flags |= (0x1 << 28);          #end if          ########## Class ID ##########          #if $pred & $cid_p -            header_buff[$num_header_words] = 0; -            #set $num_header_words += 1 -            header_buff[$num_header_words] = 0; -            #set $num_header_words += 1 +            pack_uint64_$(suffix)(if_packet_info.cid, packet_buff+$num_header_words); +            #set $num_header_words += 2              #set $flags |= (0x1 << 27);          #end if          ########## Integer Time ##########          #if $pred & $tsi_p -            header_buff[$num_header_words] = $(XE_MACRO)(boost::uint32_t(metadata.time_spec.get_full_secs())); +            packet_buff[$num_header_words] = $(XE_MACRO)(if_packet_info.tsi);              #set $num_header_words += 1              #set $flags |= (0x3 << 22);          #end if          ########## Fractional Time ##########          #if $pred & $tsf_p -            header_buff[$num_header_words] = 0; -            #set $num_header_words += 1 -            header_buff[$num_header_words] = $(XE_MACRO)(boost::uint32_t(metadata.time_spec.get_tick_count(tick_rate))); -            #set $num_header_words += 1 +            pack_uint64_$(suffix)(if_packet_info.tsf, packet_buff+$num_header_words); +            #set $num_header_words += 2              #set $flags |= (0x1 << 20);          #end if          ########## Trailer ##########          #if $pred & $tlr_p +            packet_buff[$num_header_words+if_packet_info.num_payload_words32] = $(XE_MACRO)(if_packet_info.tlr);              #set $flags |= (0x1 << 26);              #set $num_trailer_words = 1;          #else              #set $num_trailer_words = 0;          #end if          ########## Variables ########## -            num_header_words32 = $num_header_words; -            num_packet_words32 = $($num_header_words + $num_trailer_words) + num_payload_words32; +            if_packet_info.num_header_words32 = $num_header_words; +            if_packet_info.num_packet_words32 = $($num_header_words + $num_trailer_words) + if_packet_info.num_payload_words32;              vrt_hdr_flags = $hex($flags);          break;      #end for      }      //set the burst flags -    if (metadata.start_of_burst) vrt_hdr_flags |= $hex(0x1 << 25); -    if (metadata.end_of_burst)   vrt_hdr_flags |= $hex(0x1 << 24); +    if (if_packet_info.sob) vrt_hdr_flags |= $hex(0x1 << 25); +    if (if_packet_info.eob) vrt_hdr_flags |= $hex(0x1 << 24);      //fill in complete header word -    header_buff[0] = $(XE_MACRO)(boost::uint32_t(0 +    packet_buff[0] = $(XE_MACRO)(boost::uint32_t(0          | vrt_hdr_flags -        | ((packet_count & 0xf) << 16) -        | (num_packet_words32 & 0xffff) +        | ((if_packet_info.packet_count & 0xf) << 16) +        | (if_packet_info.num_packet_words32 & 0xffff)      ));  } -void vrt::unpack_$(suffix)( -    rx_metadata_t &metadata,            //output -    const boost::uint32_t *header_buff, //input -    size_t &num_header_words32,         //output -    size_t &num_payload_words32,        //output -    size_t num_packet_words32,          //input -    size_t &packet_count,               //output -    double tick_rate                    //input -){ -    //clear the metadata -    metadata = rx_metadata_t(); -    boost::uint32_t secs = 0, ticks = 0; +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)); +} +void vrt::if_hdr_unpack_$(suffix)( +    const boost::uint32_t *packet_buff, +    if_packet_info_t &if_packet_info +){      //extract vrt header -    boost::uint32_t vrt_hdr_word = $(XE_MACRO)(header_buff[0]); +    boost::uint32_t vrt_hdr_word = $(XE_MACRO)(packet_buff[0]);      size_t packet_words32 = vrt_hdr_word & 0xffff; -    packet_count = (vrt_hdr_word >> 16) & 0xf; +    if_packet_info.packet_count = (vrt_hdr_word >> 16) & 0xf;      //failure cases -    if (packet_words32 == 0 or num_packet_words32 < packet_words32) +    if (packet_words32 == 0 or 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("unsupported vrt packet type"); @@ -174,41 +168,48 @@ void vrt::unpack_$(suffix)(          #set $num_header_words = 1          ########## Stream ID ##########          #if $pred & $sid_p -            metadata.has_stream_id = true; -            metadata.stream_id = $(XE_MACRO)(header_buff[$num_header_words]); +            if_packet_info.has_sid = true; +            if_packet_info.sid = $(XE_MACRO)(packet_buff[$num_header_words]);              #set $num_header_words += 1 +        #else +            if_packet_info.has_sid = false;          #end if          ########## Class ID ##########          #if $pred & $cid_p -            #set $num_header_words += 1 -            #set $num_header_words += 1 +            if_packet_info.has_cid = true; +            unpack_uint64_$(suffix)(if_packet_info.cid, packet_buff+$num_header_words); +            #set $num_header_words += 2 +        #else +            if_packet_info.has_cid = false;          #end if          ########## Integer Time ##########          #if $pred & $tsi_p -            #set $has_time_spec = True -            secs = $(XE_MACRO)(header_buff[$num_header_words]); +            if_packet_info.has_tsi = true; +            if_packet_info.tsi = $(XE_MACRO)(packet_buff[$num_header_words]);              #set $num_header_words += 1 +        #else +            if_packet_info.has_tsi = false;          #end if          ########## Fractional Time ##########          #if $pred & $tsf_p -            #set $has_time_spec = True -            #set $num_header_words += 1 -            ticks = $(XE_MACRO)(header_buff[$num_header_words]); -            #set $num_header_words += 1 -        #end if -        #if $has_time_spec -            metadata.has_time_spec = true; -            metadata.time_spec = time_spec_t(secs, ticks, tick_rate); +            if_packet_info.has_tsf = true; +            unpack_uint64_$(suffix)(if_packet_info.tsf, packet_buff+$num_header_words); +            #set $num_header_words += 2 +        #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]);              #set $num_trailer_words = 1;          #else +            if_packet_info.has_tlr = false;              #set $num_trailer_words = 0;          #end if          ########## Variables ########## -            num_header_words32 = $num_header_words; -            num_payload_words32 = packet_words32 - $($num_header_words + $num_trailer_words); +            if_packet_info.num_header_words32 = $num_header_words; +            if_packet_info.num_payload_words32 = packet_words32 - $($num_header_words + $num_trailer_words);          break;      #end for      } diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 8dfc7b3d0..01cccd81e 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -20,6 +20,7 @@  #include <uhd/config.hpp>  #include <uhd/device.hpp> +#include <uhd/utils/assert.hpp>  #include <uhd/types/io_type.hpp>  #include <uhd/types/otw_type.hpp>  #include <uhd/types/metadata.hpp> @@ -30,37 +31,43 @@  #include <boost/function.hpp>  #include <stdexcept>  #include <iostream> +#include <vector>  namespace vrt_packet_handler{  /***********************************************************************   * vrt packet handler for recv   **********************************************************************/ +    typedef std::vector<uhd::transport::managed_recv_buffer::sptr> managed_recv_buffs_t; +      struct recv_state{ +        //width of the receiver in channels +        size_t width; +          //init the expected seq number -        size_t next_packet_seq; +        std::vector<size_t> next_packet_seq;          //state variables to handle fragments -        uhd::transport::managed_recv_buffer::sptr managed_buff; -        boost::asio::const_buffer copy_buff; +        managed_recv_buffs_t managed_buffs; +        std::vector<const boost::uint8_t *> copy_buffs; +        size_t size_of_copy_buffs;          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); +        recv_state(size_t width): +            width(width), +            next_packet_seq(width, 0), +            managed_buffs(width), +            copy_buffs(width, NULL), +            size_of_copy_buffs(0), +            fragment_offset_in_samps(0) +        { +            /* NOP */          }      }; -    typedef boost::function<uhd::transport::managed_recv_buffer::sptr(void)> get_recv_buff_t; - -    typedef boost::function<void(uhd::transport::managed_recv_buffer::sptr)> recv_cb_t; +    typedef boost::function<bool(managed_recv_buffs_t &)> get_recv_buffs_t; -    static UHD_INLINE void recv_cb_nop(uhd::transport::managed_recv_buffer::sptr){ -        /* NOP */ -    } +    typedef boost::function<void(managed_recv_buffs_t &)> recv_cb_t;      /*******************************************************************       * Unpack a received vrt header and set the copy buffer. @@ -74,33 +81,41 @@ namespace vrt_packet_handler{          vrt_unpacker_type vrt_unpacker,          size_t vrt_header_offset_words32      ){ -        size_t num_packet_words32 = state.managed_buff->size()/sizeof(boost::uint32_t); +        size_t num_packet_words32 = state.managed_buffs[0]->size()/sizeof(boost::uint32_t);          if (num_packet_words32 <= vrt_header_offset_words32){ -            state.copy_buff = boost::asio::buffer("", 0); +            state.size_of_copy_buffs = 0;              return; //must exit here after setting the buffer          } -        const boost::uint32_t *vrt_hdr = state.managed_buff->cast<const boost::uint32_t *>() + vrt_header_offset_words32; -        size_t num_header_words32_out, num_payload_words32_out, packet_count_out; -        vrt_unpacker( -            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; +        //vrt unpack each managed buffer +        uhd::transport::vrt::if_packet_info_t if_packet_info; +        for (size_t i = 0; i < state.width; i++){ +            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_unpacker(vrt_hdr, if_packet_info); + +            //handle the packet count / sequence number +            if (if_packet_info.packet_count != state.next_packet_seq[i]){ +                std::cerr << "S" << (if_packet_info.packet_count - state.next_packet_seq[i])%16; +            } +            state.next_packet_seq[i] = (if_packet_info.packet_count+1)%16; + +            //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); + +            //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); +            if (i == 0 or state.size_of_copy_buffs > num_payload_bytes){ +                state.size_of_copy_buffs = num_payload_bytes; +            }          } -        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) +        //store the last vrt info into the metadata +        metadata.has_time_spec = if_packet_info.has_tsi or if_packet_info.has_tsf; +        metadata.time_spec = uhd::time_spec_t( +            time_t((if_packet_info.has_tsi)? if_packet_info.tsi : 0), +            size_t((if_packet_info.has_tsf)? if_packet_info.tsf : 0), +            tick_rate          );      } @@ -111,24 +126,22 @@ namespace vrt_packet_handler{      template<typename vrt_unpacker_type>      static UHD_INLINE size_t _recv1(          recv_state &state, -        void *recv_mem, +        const std::vector<void *> &buffs, +        size_t offset_bytes,          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,          vrt_unpacker_type vrt_unpacker, -        const get_recv_buff_t &get_recv_buff, +        const get_recv_buffs_t &get_recv_buffs,          //use these two params to handle a layer above vrt -        size_t vrt_header_offset_words32, -        const recv_cb_t &recv_cb +        size_t vrt_header_offset_words32      ){          //perform a receive if no rx data is waiting to be copied -        if (boost::asio::buffer_size(state.copy_buff) == 0){ +        if (state.size_of_copy_buffs == 0){              state.fragment_offset_in_samps = 0; -            state.managed_buff = get_recv_buff(); -            if (state.managed_buff.get() == NULL) return 0; -            recv_cb(state.managed_buff); //callback before vrt unpack +            if (not get_recv_buffs(state.managed_buffs)) return 0;              try{                  _recv1_helper(                      state, metadata, tick_rate, vrt_unpacker, vrt_header_offset_words32 @@ -141,26 +154,28 @@ 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 bytes_available = state.size_of_copy_buffs;          size_t num_samps = std::min(total_samps, bytes_available/bytes_per_item); +        size_t bytes_to_copy = num_samps*bytes_per_item;          //setup the fragment flags and offset          metadata.more_fragments = total_samps < num_samps;          metadata.fragment_offset = state.fragment_offset_in_samps;          state.fragment_offset_in_samps += num_samps; //set for next call -        //copy-convert the samples from the recv buffer -        uhd::transport::convert_otw_type_to_io_type( -            boost::asio::buffer_cast<const void*>(state.copy_buff), otw_type, -            recv_mem, io_type, num_samps -        ); +        for (size_t i = 0; i < state.width; i++){ +            //copy-convert the samples from the recv buffer +            uhd::transport::convert_otw_type_to_io_type( +                state.copy_buffs[i], otw_type, +                reinterpret_cast<boost::uint8_t *>(buffs[i]) + offset_bytes, +                io_type, num_samps +            ); -        //update the rx copy buffer to reflect the bytes copied -        size_t bytes_copied = num_samps*bytes_per_item; -        state.copy_buff = boost::asio::buffer( -            boost::asio::buffer_cast<const boost::uint8_t*>(state.copy_buff) + bytes_copied, -            bytes_available - bytes_copied -        ); +            //update the rx copy buffer to reflect the bytes copied +            state.copy_buffs[i] = reinterpret_cast<const boost::uint8_t *>(state.copy_buffs[i]) + bytes_to_copy; +        } +        //update the copy buffer's availability +        state.size_of_copy_buffs -= bytes_to_copy;          return num_samps;      } @@ -171,20 +186,19 @@ namespace vrt_packet_handler{      template<typename vrt_unpacker_type>      static UHD_INLINE size_t recv(          recv_state &state, -        const boost::asio::mutable_buffer &buff, +        const std::vector<void *> &buffs, +        const size_t total_num_samps,          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,          vrt_unpacker_type vrt_unpacker, -        const get_recv_buff_t &get_recv_buff, +        const get_recv_buffs_t &get_recv_buffs,          //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 = 0      ){          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){ @@ -193,15 +207,14 @@ namespace vrt_packet_handler{          ////////////////////////////////////////////////////////////////              return _recv1(                  state, -                boost::asio::buffer_cast<void *>(buff), +                buffs, 0,                  total_num_samps,                  metadata,                  io_type, otw_type,                  tick_rate,                  vrt_unpacker, -                get_recv_buff, -                vrt_header_offset_words32, -                recv_cb +                get_recv_buffs, +                vrt_header_offset_words32              );          } @@ -213,15 +226,14 @@ namespace vrt_packet_handler{              while(accum_num_samps < total_num_samps){                  size_t num_samps = _recv1(                      state, -                    boost::asio::buffer_cast<boost::uint8_t *>(buff) + (accum_num_samps*io_type.size), +                    buffs, 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,                      vrt_unpacker, -                    get_recv_buff, -                    vrt_header_offset_words32, -                    recv_cb +                    get_recv_buffs, +                    vrt_header_offset_words32                  );                  if (num_samps == 0) break; //had a recv timeout or error, break loop                  accum_num_samps += num_samps; @@ -236,6 +248,8 @@ namespace vrt_packet_handler{  /***********************************************************************   * vrt packet handler for send   **********************************************************************/ +    typedef std::vector<uhd::transport::managed_send_buffer::sptr> managed_send_buffs_t; +      struct send_state{          //init the expected seq number          size_t next_packet_seq; @@ -245,13 +259,9 @@ namespace vrt_packet_handler{          }      }; -    typedef boost::function<uhd::transport::managed_send_buffer::sptr(void)> get_send_buff_t; - -    typedef boost::function<void(uhd::transport::managed_send_buffer::sptr)> send_cb_t; +    typedef boost::function<bool(managed_send_buffs_t &)> get_send_buffs_t; -    static UHD_INLINE void send_cb_nop(uhd::transport::managed_send_buffer::sptr){ -        /* NOP */ -    } +    typedef boost::function<void(managed_send_buffs_t &)> send_cb_t;      /*******************************************************************       * Pack a vrt header, copy-convert the data, and send it. @@ -260,46 +270,51 @@ namespace vrt_packet_handler{      template<typename vrt_packer_type>      static UHD_INLINE void _send1(          send_state &state, -        const void *send_mem, +        const std::vector<const void *> &buffs, +        size_t offset_bytes,          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,          vrt_packer_type vrt_packer, -        const get_send_buff_t &get_send_buff, -        size_t vrt_header_offset_words32, -        const send_cb_t& send_cb +        const get_send_buffs_t &get_send_buffs, +        size_t vrt_header_offset_words32      ){ -        //get a new managed send buffer -        uhd::transport::managed_send_buffer::sptr send_buff = get_send_buff(); -        boost::uint32_t *tx_mem = send_buff->cast<boost::uint32_t *>() + vrt_header_offset_words32; - -        size_t num_header_words32, num_packet_words32; -        size_t packet_count = state.next_packet_seq++; - -        //pack metadata into a vrt header -        vrt_packer( -            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 +        //translate the metadata to vrt if packet info +        uhd::transport::vrt::if_packet_info_t if_packet_info; +        if_packet_info.has_sid = false; +        if_packet_info.has_cid = false; +        if_packet_info.has_tsi = metadata.has_time_spec; +        if_packet_info.tsi = boost::uint32_t(metadata.time_spec.get_full_secs()); +        if_packet_info.has_tsf = metadata.has_time_spec; +        if_packet_info.tsf = boost::uint64_t(metadata.time_spec.get_tick_count(tick_rate)); +        if_packet_info.has_tlr = false; +        if_packet_info.num_payload_words32 = (num_samps*io_type.size)/sizeof(boost::uint32_t); +        if_packet_info.packet_count = state.next_packet_seq++; + +        //get send buffers for each channel +        managed_send_buffs_t send_buffs(buffs.size()); +        UHD_ASSERT_THROW(get_send_buffs(send_buffs)); + +        for (size_t i = 0; i < buffs.size(); i++){ +            //calculate pointers with offsets to io and otw memory +            const boost::uint8_t *io_mem = reinterpret_cast<const boost::uint8_t *>(buffs[i]) + offset_bytes; +            boost::uint32_t *otw_mem = send_buffs[i]->cast<boost::uint32_t *>() + vrt_header_offset_words32; + +            //pack metadata into a vrt header +            vrt_packer(otw_mem, if_packet_info); + +            //copy-convert the samples into the send buffer +            uhd::transport::convert_io_type_to_otw_type( +                io_mem, io_type, +                otw_mem + if_packet_info.num_header_words32, otw_type, +                num_samps +            ); -        //commit the samples to the zero-copy interface -        send_buff->commit(num_packet_words32*sizeof(boost::uint32_t)); +            //commit the samples to the zero-copy interface +            send_buffs[i]->commit(if_packet_info.num_packet_words32*sizeof(boost::uint32_t)); +        }      }      /******************************************************************* @@ -308,20 +323,19 @@ namespace vrt_packet_handler{      template<typename vrt_packer_type>      static UHD_INLINE size_t send(          send_state &state, -        const boost::asio::const_buffer &buff, +        const std::vector<const void *> &buffs, +        const size_t total_num_samps,          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,          vrt_packer_type vrt_packer, -        const get_send_buff_t &get_send_buff, +        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, -        const send_cb_t& send_cb = &send_cb_nop +        size_t vrt_header_offset_words32 = 0      ){ -        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){ @@ -331,15 +345,14 @@ namespace vrt_packet_handler{              size_t num_samps = std::min(total_num_samps, max_samples_per_packet);              _send1(                  state, -                boost::asio::buffer_cast<const void *>(buff), +                buffs, 0,                  num_samps,                  metadata,                  io_type, otw_type,                  tick_rate,                  vrt_packer, -                get_send_buff, -                vrt_header_offset_words32, -                send_cb +                get_send_buffs, +                vrt_header_offset_words32              );              return num_samps;          } @@ -366,15 +379,14 @@ namespace vrt_packet_handler{                  //send the fragment with the helper function                  _send1(                      state, -                    boost::asio::buffer_cast<const boost::uint8_t *>(buff) + (n*max_samples_per_packet*io_type.size), +                    buffs, n*max_samples_per_packet*io_type.size,                      (n == final_fragment_index)?(total_num_samps%max_samples_per_packet):max_samples_per_packet,                      md,                      io_type, otw_type,                      tick_rate,                      vrt_packer, -                    get_send_buff, -                    vrt_header_offset_words32, -                    send_cb +                    get_send_buffs, +                    vrt_header_offset_words32                  );              }              return total_num_samps; diff --git a/host/lib/types.cpp b/host/lib/types.cpp index 6a9fcf5b5..9cf2a2220 100644 --- a/host/lib/types.cpp +++ b/host/lib/types.cpp @@ -96,8 +96,6 @@ stream_cmd_t::stream_cmd_t(const stream_mode_t &stream_mode):   * metadata   **********************************************************************/  rx_metadata_t::rx_metadata_t(void): -    has_stream_id(false), -    stream_id(0),      has_time_spec(false),      time_spec(time_spec_t()),      more_fragments(false), @@ -107,8 +105,6 @@ rx_metadata_t::rx_metadata_t(void):  }  tx_metadata_t::tx_metadata_t(void): -    has_stream_id(false), -    stream_id(0),      has_time_spec(false),      time_spec(time_spec_t()),      start_of_burst(false), diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index aa0f63321..e3a3a3b17 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -52,7 +52,7 @@ struct usrp2_impl::io_impl{      bounded_buffer<managed_recv_buffer::sptr>::sptr recv_pirate_booty;  }; -usrp2_impl::io_impl::io_impl(zero_copy_if::sptr zc_if){ +usrp2_impl::io_impl::io_impl(zero_copy_if::sptr zc_if): packet_handler_recv_state(1){      //create a large enough booty      size_t num_frames = zc_if->get_num_recv_frames();      std::cout << "Recv pirate num frames: " << num_frames << std::endl; @@ -130,19 +130,26 @@ void usrp2_impl::io_init(void){  /***********************************************************************   * Send Data   **********************************************************************/ +bool tmp_todo_fixme_remove_get_send_buffs(vrt_packet_handler::managed_send_buffs_t &buffs, const zero_copy_if::sptr &zc_if){ +    buffs[0] = zc_if->get_send_buff(); +    return buffs[0].get() != NULL; +} +  size_t usrp2_impl::send( -    const asio::const_buffer &buff, +    const std::vector<const void *> &buffs, +    size_t nsamps_per_buff,      const tx_metadata_t &metadata,      const io_type_t &io_type,      send_mode_t send_mode  ){      return vrt_packet_handler::send(          _io_impl->packet_handler_send_state, //last state of the send handler -        buff, metadata, send_mode,  //buffer to empty and samples metadata +        buffs, nsamps_per_buff,     //buffer to empty +        metadata, send_mode,        //samples metadata          io_type, _tx_otw_type,      //input and output types to convert          get_master_clock_freq(),    //master clock tick rate -        uhd::transport::vrt::pack_be, -        boost::bind(&zero_copy_if::get_send_buff, _data_transport), +        uhd::transport::vrt::if_hdr_pack_be, +        boost::bind(&tmp_todo_fixme_remove_get_send_buffs, _1, _data_transport),          get_max_send_samps_per_packet()      );  } @@ -150,18 +157,25 @@ size_t usrp2_impl::send(  /***********************************************************************   * Receive Data   **********************************************************************/ +bool tmp_todo_fixme_remove_get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs, boost::shared_ptr<usrp2_impl::io_impl> impl){ +    buffs[0] = impl->get_recv_buff(); +    return buffs[0].get() != NULL; +} +  size_t usrp2_impl::recv( -    const asio::mutable_buffer &buff, +    const std::vector<void *> &buffs, +    size_t nsamps_per_buff,      rx_metadata_t &metadata,      const io_type_t &io_type,      recv_mode_t recv_mode  ){      return vrt_packet_handler::recv(          _io_impl->packet_handler_recv_state, //last state of the recv handler -        buff, metadata, recv_mode,  //buffer to fill and samples metadata +        buffs, nsamps_per_buff,     //buffer to empty +        metadata, recv_mode,        //samples metadata          io_type, _rx_otw_type,      //input and output types to convert          get_master_clock_freq(),    //master clock tick rate -        uhd::transport::vrt::unpack_be, -        boost::bind(&usrp2_impl::io_impl::get_recv_buff, _io_impl) +        uhd::transport::vrt::if_hdr_unpack_be, +        boost::bind(&tmp_todo_fixme_remove_get_recv_buffs, _1, _io_impl)      );  } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 2126b9565..70735173e 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -108,7 +108,7 @@ public:          return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size();      }      size_t send( -        const boost::asio::const_buffer &, +        const std::vector<const void *> &, size_t,          const uhd::tx_metadata_t &,          const uhd::io_type_t &,          uhd::device::send_mode_t @@ -117,12 +117,14 @@ public:          return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size();      }      size_t recv( -        const boost::asio::mutable_buffer &, +        const std::vector<void *> &, size_t,          uhd::rx_metadata_t &,          const uhd::io_type_t &,          uhd::device::recv_mode_t      ); +    UHD_PIMPL_DECL(io_impl) _io_impl; +  private:      inline double get_master_clock_freq(void){          return _clock_ctrl->get_master_clock_rate(); @@ -148,11 +150,10 @@ private:      ;      static const size_t _max_tx_bytes_per_packet =          USRP2_UDP_BYTES - -        uhd::transport::vrt::max_header_words32*sizeof(boost::uint32_t) +        uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t)      ;      uhd::otw_type_t _rx_otw_type, _tx_otw_type; -    UHD_PIMPL_DECL(io_impl) _io_impl;      void io_init(void);      //udp transports for control and data diff --git a/host/test/vrt_test.cpp b/host/test/vrt_test.cpp index 3776e33aa..3f74a836e 100644 --- a/host/test/vrt_test.cpp +++ b/host/test/vrt_test.cpp @@ -17,84 +17,123 @@  #include <boost/test/unit_test.hpp>  #include <uhd/transport/vrt.hpp> +#include <cstdlib>  using namespace uhd::transport;  static void pack_and_unpack( -    const uhd::tx_metadata_t &metadata, -    size_t num_payload_words32, -    size_t packet_count +    vrt::if_packet_info_t &if_packet_info_in  ){ -    boost::uint32_t header_buff[vrt::max_header_words32]; -    size_t num_header_words32; -    size_t num_packet_words32; +    boost::uint32_t header_buff[vrt::max_if_hdr_words32];      //pack metadata into a vrt header -    vrt::pack_be( -        metadata,            //input -        header_buff,         //output -        num_header_words32,  //output -        num_payload_words32, //input -        num_packet_words32,  //output -        packet_count,        //input -        100e6 +    vrt::if_hdr_pack_be( +        header_buff, if_packet_info_in      ); -    uhd::rx_metadata_t metadata_out; -    size_t num_header_words32_out; -    size_t num_payload_words32_out; -    size_t packet_count_out; +    vrt::if_packet_info_t if_packet_info_out; +    if_packet_info_out.num_packet_words32 = if_packet_info_in.num_packet_words32;      //unpack the vrt header back into metadata -    vrt::unpack_be( -        metadata_out,            //output -        header_buff,             //input -        num_header_words32_out,  //output -        num_payload_words32_out, //output -        num_packet_words32,      //input -        packet_count_out,        //output -        100e6 +    vrt::if_hdr_unpack_be( +        header_buff, if_packet_info_out      );      //check the the unpacked metadata is the same -    BOOST_CHECK_EQUAL(packet_count, packet_count_out); -    BOOST_CHECK_EQUAL(num_header_words32, num_header_words32_out); -    BOOST_CHECK_EQUAL(num_payload_words32, num_payload_words32_out); -    BOOST_CHECK_EQUAL(metadata.has_stream_id, metadata_out.has_stream_id); -    if (metadata.has_stream_id and metadata_out.has_stream_id){ -        BOOST_CHECK_EQUAL(metadata.stream_id, metadata_out.stream_id); +    BOOST_CHECK_EQUAL(if_packet_info_in.packet_count, if_packet_info_out.packet_count); +    BOOST_CHECK_EQUAL(if_packet_info_in.num_header_words32, if_packet_info_out.num_header_words32); +    BOOST_CHECK_EQUAL(if_packet_info_in.num_payload_words32, if_packet_info_out.num_payload_words32); +    BOOST_CHECK_EQUAL(if_packet_info_in.has_sid, if_packet_info_out.has_sid); +    if (if_packet_info_in.has_sid and if_packet_info_out.has_sid){ +        BOOST_CHECK_EQUAL(if_packet_info_in.sid, if_packet_info_out.sid);      } -    BOOST_CHECK_EQUAL(metadata.has_time_spec, metadata_out.has_time_spec); -    if (metadata.has_time_spec and metadata_out.has_time_spec){ -        BOOST_CHECK_EQUAL(metadata.time_spec.get_full_secs(), metadata_out.time_spec.get_full_secs()); -        BOOST_CHECK_EQUAL(metadata.time_spec.get_frac_secs(), metadata_out.time_spec.get_frac_secs()); +    BOOST_CHECK_EQUAL(if_packet_info_in.has_cid, if_packet_info_out.has_cid); +    if (if_packet_info_in.has_cid and if_packet_info_out.has_cid){ +        BOOST_CHECK_EQUAL(if_packet_info_in.cid, if_packet_info_out.cid); +    } +    BOOST_CHECK_EQUAL(if_packet_info_in.has_tsi, if_packet_info_out.has_tsi); +    if (if_packet_info_in.has_tsi and if_packet_info_out.has_tsi){ +        BOOST_CHECK_EQUAL(if_packet_info_in.tsi, if_packet_info_out.tsi); +    } +    BOOST_CHECK_EQUAL(if_packet_info_in.has_tsf, if_packet_info_out.has_tsf); +    if (if_packet_info_in.has_tsf and if_packet_info_out.has_tsf){ +        BOOST_CHECK_EQUAL(if_packet_info_in.tsf, if_packet_info_out.tsf); +    } +    BOOST_CHECK_EQUAL(if_packet_info_in.has_tlr, if_packet_info_out.has_tlr); +    if (if_packet_info_in.has_tlr and if_packet_info_out.has_tlr){ +        BOOST_CHECK_EQUAL(if_packet_info_in.tlr, if_packet_info_out.tlr);      }  } +/*********************************************************************** + * Loopback test the vrt packer/unpacker with various packet info combos + * The trailer is not tested as it is not convenient to do so. + **********************************************************************/ +  BOOST_AUTO_TEST_CASE(test_with_none){ -    uhd::tx_metadata_t metadata; -    pack_and_unpack(metadata, 300, 1); +    vrt::if_packet_info_t if_packet_info; +    if_packet_info.packet_count = 0; +    if_packet_info.has_sid = false; +    if_packet_info.has_cid = false; +    if_packet_info.has_tsi = false; +    if_packet_info.has_tsf = false; +    if_packet_info.has_tlr = false; +    if_packet_info.num_payload_words32 = 0; +    pack_and_unpack(if_packet_info);  }  BOOST_AUTO_TEST_CASE(test_with_sid){ -    uhd::tx_metadata_t metadata; -    metadata.has_stream_id = true; -    metadata.stream_id = 6; -    pack_and_unpack(metadata, 400, 2); +    vrt::if_packet_info_t if_packet_info; +    if_packet_info.packet_count = 1; +    if_packet_info.has_sid = true; +    if_packet_info.has_cid = false; +    if_packet_info.has_tsi = false; +    if_packet_info.has_tsf = false; +    if_packet_info.has_tlr = false; +    if_packet_info.sid = std::rand(); +    if_packet_info.num_payload_words32 = 1111; +    pack_and_unpack(if_packet_info); +} + +BOOST_AUTO_TEST_CASE(test_with_cid){ +    vrt::if_packet_info_t if_packet_info; +    if_packet_info.packet_count = 2; +    if_packet_info.has_sid = false; +    if_packet_info.has_cid = true; +    if_packet_info.has_tsi = false; +    if_packet_info.has_tsf = false; +    if_packet_info.has_tlr = false; +    if_packet_info.cid = std::rand(); +    if_packet_info.num_payload_words32 = 2222; +    pack_and_unpack(if_packet_info);  } -BOOST_AUTO_TEST_CASE(test_with_time_spec){ -    uhd::tx_metadata_t metadata; -    metadata.has_time_spec = true; -    metadata.time_spec = uhd::time_spec_t(7, 0.2); -    pack_and_unpack(metadata, 500, 3); +BOOST_AUTO_TEST_CASE(test_with_time){ +    vrt::if_packet_info_t if_packet_info; +    if_packet_info.packet_count = 3; +    if_packet_info.has_sid = false; +    if_packet_info.has_cid = false; +    if_packet_info.has_tsi = true; +    if_packet_info.has_tsf = true; +    if_packet_info.has_tlr = false; +    if_packet_info.tsi = std::rand(); +    if_packet_info.tsf = std::rand(); +    if_packet_info.num_payload_words32 = 33333; +    pack_and_unpack(if_packet_info);  } -BOOST_AUTO_TEST_CASE(test_with_sid_and_time_spec){ -    uhd::tx_metadata_t metadata; -    metadata.has_stream_id = true; -    metadata.stream_id = 2; -    metadata.has_time_spec = true; -    metadata.time_spec = uhd::time_spec_t(5, 0.1); -    pack_and_unpack(metadata, 600, 4); +BOOST_AUTO_TEST_CASE(test_with_all){ +    vrt::if_packet_info_t if_packet_info; +    if_packet_info.packet_count = 4; +    if_packet_info.has_sid = true; +    if_packet_info.has_cid = true; +    if_packet_info.has_tsi = true; +    if_packet_info.has_tsf = true; +    if_packet_info.has_tlr = false; +    if_packet_info.sid = std::rand(); +    if_packet_info.cid = std::rand(); +    if_packet_info.tsi = std::rand(); +    if_packet_info.tsf = std::rand(); +    if_packet_info.num_payload_words32 = 44444; +    pack_and_unpack(if_packet_info);  } | 
