aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/docs/uhd.dox1
-rw-r--r--host/docs/vrt_chdr.dox83
-rw-r--r--host/include/uhd/transport/CMakeLists.txt4
-rw-r--r--host/include/uhd/transport/chdr.hpp113
-rw-r--r--host/include/uhd/transport/vrt_if_packet.hpp74
-rw-r--r--host/lib/transport/CMakeLists.txt1
-rw-r--r--host/lib/transport/chdr.cpp182
-rw-r--r--host/tests/CMakeLists.txt3
-rw-r--r--host/tests/chdr_test.cpp141
9 files changed, 598 insertions, 4 deletions
diff --git a/host/docs/uhd.dox b/host/docs/uhd.dox
index 5b0738969..5cbe51a90 100644
--- a/host/docs/uhd.dox
+++ b/host/docs/uhd.dox
@@ -11,6 +11,7 @@ Some additional pages on developing UHD are also available here:
\li \subpage page_coding
\li \subpage page_stream
+\li \subpage page_rtp
*/
// vim:ft=doxygen:
diff --git a/host/docs/vrt_chdr.dox b/host/docs/vrt_chdr.dox
new file mode 100644
index 000000000..8ab177b21
--- /dev/null
+++ b/host/docs/vrt_chdr.dox
@@ -0,0 +1,83 @@
+/*! \page page_rtp Radio Transport Protocols
+
+\tableofcontents
+
+Radio transport protocols are used to exchange samples (or other items) between host and devices.
+If one were to sniff Ethernet traffic between a USRP and a PC, the packets would conform to a
+radio transport protocol.
+
+For USRP devices, two radio transport protocols are relevent: VRT (the VITA Radio Transport protocol)
+and CVITA (compressed VITA), also known as CHDR. Generation-3 devices and the B200 use CHDR, the rest
+use VRT.
+
+\section rtp_vrt VRT
+
+VRT is an open protocol defined by the VITA-49 standard. It was designed for interoperability,
+and to allow different device types to work with different software stacks.
+
+VRT is a very verbose standard, and only a subset is implemented in UHD/USRPs.
+The full standard is available from the VITA website: http://www.vita.com .
+
+
+\section rtp_chdr CVITA (CHDR)
+
+For the third generation of Ettus devices, a new type transport protocol was designed.
+It reduces the complexity of the original standard and uses a fixed-length 64-Bit header
+for everything except the timestamp. Because this is a "compressed" form of VITA, it
+was dubbed "Compressed VITA" (CVITA). The compressed header is called CHDR, which is why
+the protocol is often called CHDR itself (pronounced like the cheese "cheddar").
+
+By compressing all information into a 64-bit line, the header can efficiently be parsed
+in newer FPGAs, where the common streaming protocol is 64-Bit AXI. The first line in a
+packet already provides all necessary information to proceed.
+
+Some CHDR-specific functions can be found in: uhd::transport::vrt::chdr.
+
+The form of a CVITA packet is the following:
+
+Address (Bytes) | Length (Bytes) | Payload
+----------------|----------------|----------------------------
+0 | 8 | Compressed Header (CHDR)
+8 | 8 | Fractional Time (Optional!)
+8/16 | - | Data
+
+If there is no timestamp present, the data starts at address 8, otherwise, it starts at 16.
+
+The 64 Bits in the compressed header have the following meaning:
+
+Bits | Meaning
+-------|--------------------------------------------------
+63:62 | Packet Type
+61 | Has fractional time stamp (1: Yes)
+60 | End-of-burst or error flag
+59:48 | 12-bit sequence number
+47:32 | Total packet length in Bytes
+31:0 | Stream ID (SID)
+
+
+The packet type is determined mainly by the first two bits, although
+the EOB or error flag are also taken into consideration:
+
+Bit 63 | Bit 62 | Bit 60 | Packet Type
+-------|--------|--------|--------------
+0 | 0 | 0 | Data
+0 | 0 | 1 | Data (End-of-burst)
+0 | 1 | 0 | Flow Control
+1 | 0 | 0 | Command Packet
+1 | 1 | 0 | Command Response
+1 | 1 | 1 | Command Response (Error)
+
+\section vrt_tools Tools
+
+For CHDR, we provide a Wireshark dissector under tools/chdr_dissector. It can be used
+for Ethernet links as well as USB (e.g., for the B210).
+
+\section vrt_code Code
+
+Relevent code sections for the radio transport layer are:
+* uhd::transport::vrt - Namespace for radio transport protocol related functions and definitions
+* uhd::transport::vrt::chdr - Sub-namespace specifically for CVITA/CHDR
+* uhd::sid_t - Datatype to represent SIDs
+
+*/
+// vim:ft=doxygen:
diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt
index 2118674c6..623c179e9 100644
--- a/host/include/uhd/transport/CMakeLists.txt
+++ b/host/include/uhd/transport/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2010-2013 Ettus Research LLC
+# Copyright 2010-2014 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
@@ -15,11 +15,11 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-
UHD_INSTALL(FILES
bounded_buffer.hpp
bounded_buffer.ipp
buffer_pool.hpp
+ chdr.hpp
if_addrs.hpp
udp_constants.hpp
udp_simple.hpp
diff --git a/host/include/uhd/transport/chdr.hpp b/host/include/uhd/transport/chdr.hpp
new file mode 100644
index 000000000..5e8cd58a9
--- /dev/null
+++ b/host/include/uhd/transport/chdr.hpp
@@ -0,0 +1,113 @@
+//
+// Copyright 2014 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_UHD_TRANSPORT_CHDR_HPP
+#define INCLUDED_UHD_TRANSPORT_CHDR_HPP
+
+#include <uhd/transport/vrt_if_packet.hpp>
+
+namespace uhd{ namespace transport{ namespace vrt{
+
+/*! \brief CVITA/CHDR related function
+ *
+ * See \ref rtp_chdr for details on the CVITA/CHDR protocol.
+ *
+ * All packers take the host format into account. Choose the _le functions
+ * if the transport uses little endian format (e.g. PCIe) and the _be
+ * functions if the transport uses big endian format (e.g. Ethernet).
+ *
+ * Note 1: All packers assume there to be enough space at the address
+ * provided by \p packet_buff. See also \ref vrt_pack_contract.
+ *
+ * Note 2: All these packers assume the following options without checking them:
+ * - `if_packet_info.link_type == LINK_TYPE_CHDR`
+ * - `if_packet_info.has_cid == false`
+ * - `if_packet_info.has_sid == true`
+ * - `if_packet_info.has_tsi == false`
+ * - `if_packet_info.has_tlr == false`
+ * This relaxes some of \ref vrt_pack_contract, but adds the additional
+ * constraint that the input data must be CHDR.
+ *
+ * In the unpacker, these values will be set accordingly.
+ */
+namespace chdr{
+
+ //! The maximum number of 64-bit words in a CVITA header
+ static const size_t max_if_hdr_words64 = 2; // CHDR + tsf (fractional timestamp)
+
+ /*!
+ * Pack a CHDR header from metadata (big endian format).
+ *
+ * See \ref vrt_pack_contract, but `link_type` is assumed to be
+ * `LINK_TYPE_CHDR`.
+ *
+ * \param packet_buff memory to write the packed vrt header
+ * \param if_packet_info the if packet info (read/write)
+ */
+ UHD_API void if_hdr_pack_be(
+ boost::uint32_t *packet_buff,
+ if_packet_info_t &if_packet_info
+ );
+
+ /*!
+ * Unpack a CHDR header to metadata (big endian format).
+ *
+ * See \ref vrt_unpack_contract, but `link_type` is assumed to be
+ * `LINK_TYPE_CHDR`.
+ *
+ * \param packet_buff memory to read the packed vrt header
+ * \param if_packet_info the if packet info (read/write)
+ */
+ UHD_API void if_hdr_unpack_be(
+ const boost::uint32_t *packet_buff,
+ if_packet_info_t &if_packet_info
+ );
+
+ /*!
+ * Pack a CHDR header from metadata (little endian format).
+ *
+ * See \ref vrt_pack_contract, but `link_type` is assumed to be
+ * `LINK_TYPE_CHDR`.
+ *
+ * \param packet_buff memory to write the packed vrt header
+ * \param if_packet_info the if packet info (read/write)
+ */
+ UHD_API void if_hdr_pack_le(
+ boost::uint32_t *packet_buff,
+ if_packet_info_t &if_packet_info
+ );
+
+ /*!
+ * Unpack a CHDR header to metadata (little endian format).
+ *
+ * See \ref vrt_unpack_contract, but `link_type` is assumed to be
+ * `LINK_TYPE_CHDR`.
+ *
+ * \param packet_buff memory to read the packed vrt header
+ * \param if_packet_info the if packet info (read/write)
+ */
+ UHD_API void if_hdr_unpack_le(
+ const boost::uint32_t *packet_buff,
+ if_packet_info_t &if_packet_info
+ );
+
+} //namespace chdr
+
+}}} //namespace uhd::transport::vrt
+
+#endif /* INCLUDED_UHD_TRANSPORT_CHDR_HPP */
+
diff --git a/host/include/uhd/transport/vrt_if_packet.hpp b/host/include/uhd/transport/vrt_if_packet.hpp
index d16892281..8bc65cdf1 100644
--- a/host/include/uhd/transport/vrt_if_packet.hpp
+++ b/host/include/uhd/transport/vrt_if_packet.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2013 Ettus Research LLC
+// Copyright 2010-2014 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
@@ -52,9 +52,18 @@ namespace vrt{
//packet type
enum packet_type_t
{
+ // VRT language:
PACKET_TYPE_DATA = 0x0,
PACKET_TYPE_IF_EXT = 0x1,
PACKET_TYPE_CONTEXT = 0x2, //extension context: has_sid = true
+
+ // CVITA language:
+ //PACKET_TYPE_DATA = 0x0, // Data
+ PACKET_TYPE_FC = 0x1, // Flow control
+ PACKET_TYPE_ACK = 0x1, // Flow control (ack)
+ PACKET_TYPE_CMD = 0x2, // Command
+ PACKET_TYPE_RESP = 0x3, // Command response
+ PACKET_TYPE_ERROR = 0x3, // Command response: Error (the EOB bit is raised in this case)
} packet_type;
//size fields
@@ -65,18 +74,46 @@ namespace vrt{
//header fields
size_t packet_count;
+ //! Asserted for start- or end-of-burst
bool sob, eob;
+ //! This is asserted for command responses that are errors (CHDR only)
+ bool error;
//optional fields
+ //! Stream ID (SID). See uhd::sid_t
bool has_sid; boost::uint32_t sid;
+ //! Class ID.
bool has_cid; boost::uint64_t cid;
+ //! Integer timestamp
bool has_tsi; boost::uint32_t tsi;
+ //! Fractional timestamp
bool has_tsf; boost::uint64_t tsf;
+ //! Trailer
bool has_tlr; boost::uint32_t tlr;
};
/*!
* Pack a vrt header from metadata (big endian format).
+ *
+ * \section vrt_pack_contract Packing contract
+ *
+ * \subsection Requirements:
+ * - packet_buff points to a valid address space with enough space to write
+ * the entire buffer, regardless of its length. At the very least, it must
+ * be able to hold an entire header.
+ * - `if_packet_info` has the following members set to correct values:
+ * - `has_*` members all set accordingly
+ * - For every true `has_*` member, the corresponding variable holds a valid
+ * value (e.g. if `has_sid` is true, `sid` contains a valid SID)
+ * - `num_payload_bytes` and `num_payload_words32` are both set to the correct values
+ *
+ * \subsection Result:
+ * - `packet_buff` now points to a valid header that can be sent over the transport
+ * without further modification
+ * - The following members on `if_packet_info` are set:
+ * - `num_header_words32`
+ * - `num_packet_words32`
+ *
* \param packet_buff memory to write the packed vrt header
* \param if_packet_info the if packet info (read/write)
*/
@@ -87,6 +124,34 @@ namespace vrt{
/*!
* Unpack a vrt header to metadata (big endian format).
+ *
+ * \section vrt_unpack_contract Unpacking contract
+ *
+ * \subsection Requirements
+ * - `packet_buff` points to a readable address space with a
+ * CHDR packet, starting at the header. `packet_buff[0]` *must* always
+ * point to a valid first word of the header. This implies that num_packet_words32
+ * must be at least 1.
+ * - `if_packet_info` has the following members set to correct values:
+ * - `num_packet_words32`. This means all values `packet_buff[0]`
+ * through `packet_buff[if_packet_info.num_packet_words32-1]` are
+ * readable words from this packet.
+ * - `link_type`
+ *
+ * \subsection Result
+ * - `if_packet_info` now has the following values set to correct values:
+ * - `packet_type`
+ * - `num_payload_bytes`
+ * - `num_payload_words32`
+ * - `num_header_words32`
+ * - `has_*`
+ * - `sob`, `eob`, `error`, `cid`, `sid` (if applicable)
+ * - `tsf`, `tsi` (if applicable)
+ *
+ * \subsection Exceptions
+ * - If the header is invalid, but the requirements are still met,
+ * will throw a uhd::value_error.
+ *
* \param packet_buff memory to read the packed vrt header
* \param if_packet_info the if packet info (read/write)
*/
@@ -97,6 +162,9 @@ namespace vrt{
/*!
* Pack a vrt header from metadata (little endian format).
+ *
+ * See \ref vrt_pack_contract.
+ *
* \param packet_buff memory to write the packed vrt header
* \param if_packet_info the if packet info (read/write)
*/
@@ -107,6 +175,9 @@ namespace vrt{
/*!
* Unpack a vrt header to metadata (little endian format).
+ *
+ * See \ref vrt_unpack_contract.
+ *
* \param packet_buff memory to read the packed vrt header
* \param if_packet_info the if packet info (read/write)
*/
@@ -124,6 +195,7 @@ namespace vrt{
num_packet_words32(0),
packet_count(0),
sob(false), eob(false),
+ error(false),
has_sid(false), sid(0),
has_cid(false), cid(0),
has_tsi(false), tsi(0),
diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt
index 5920f3d78..9ec8a5c0b 100644
--- a/host/lib/transport/CMakeLists.txt
+++ b/host/lib/transport/CMakeLists.txt
@@ -129,6 +129,7 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/if_addrs.cpp
${CMAKE_CURRENT_SOURCE_DIR}/udp_simple.cpp
${CMAKE_CURRENT_SOURCE_DIR}/nirio_zero_copy.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/chdr.cpp
)
# Verbose Debug output for send/recv
diff --git a/host/lib/transport/chdr.cpp b/host/lib/transport/chdr.cpp
new file mode 100644
index 000000000..47ac961b9
--- /dev/null
+++ b/host/lib/transport/chdr.cpp
@@ -0,0 +1,182 @@
+//
+// Copyright 2014 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/transport/chdr.hpp>
+#include <uhd/utils/byteswap.hpp>
+#include <uhd/exception.hpp>
+
+//define the endian macros to convert integers
+#ifdef BOOST_BIG_ENDIAN
+ #define BE_MACRO(x) (x)
+ #define LE_MACRO(x) uhd::byteswap(x)
+#else
+ #define BE_MACRO(x) uhd::byteswap(x)
+ #define LE_MACRO(x) (x)
+#endif
+
+using namespace uhd::transport::vrt;
+
+static const boost::uint32_t HDR_FLAG_TSF = (1 << 29);
+static const boost::uint32_t HDR_FLAG_EOB = (1 << 28);
+static const boost::uint32_t HDR_FLAG_ERROR = (1 << 28);
+
+/***************************************************************************/
+/* Packing */
+/***************************************************************************/
+/*! Translate the contents of \p if_packet_info into a 32-Bit word and return it.
+ */
+UHD_INLINE boost::uint32_t _hdr_pack_chdr(
+ if_packet_info_t &if_packet_info
+) {
+ // Set fields in if_packet_info
+ if_packet_info.num_header_words32 = 2 + (if_packet_info.has_tsf ? 2 : 0);
+ if_packet_info.num_packet_words32 =
+ if_packet_info.num_header_words32 +
+ if_packet_info.num_payload_words32;
+
+ boost::uint16_t pkt_length =
+ if_packet_info.num_payload_bytes + (4 * if_packet_info.num_header_words32);
+ boost::uint32_t chdr = 0
+ // 2 Bits: Packet type
+ | (if_packet_info.packet_type << 30)
+ // 1 Bit: Has time
+ | (if_packet_info.has_tsf ? HDR_FLAG_TSF : 0)
+ // 1 Bit: EOB or Error
+ | ((if_packet_info.eob or if_packet_info.error) ? HDR_FLAG_EOB : 0)
+ // 12 Bits: Sequence number
+ | ((if_packet_info.packet_count & 0xFFF) << 16)
+ // 16 Bits: Total packet length
+ | pkt_length;
+ return chdr;
+}
+
+void chdr::if_hdr_pack_be(
+ boost::uint32_t *packet_buff,
+ if_packet_info_t &if_packet_info
+) {
+ // Write header and update if_packet_info
+ packet_buff[0] = BE_MACRO(_hdr_pack_chdr(if_packet_info));
+
+ // Write SID
+ packet_buff[1] = BE_MACRO(if_packet_info.sid);
+
+ // Write time
+ if (if_packet_info.has_tsf) {
+ packet_buff[2] = BE_MACRO(boost::uint32_t(if_packet_info.tsf >> 32));
+ packet_buff[3] = BE_MACRO(boost::uint32_t(if_packet_info.tsf >> 0));
+ }
+}
+
+void chdr::if_hdr_pack_le(
+ boost::uint32_t *packet_buff,
+ if_packet_info_t &if_packet_info
+) {
+ // Write header and update if_packet_info
+ packet_buff[0] = LE_MACRO(_hdr_pack_chdr(if_packet_info));
+
+ // Write SID
+ packet_buff[1] = LE_MACRO(if_packet_info.sid);
+
+ // Write time
+ if (if_packet_info.has_tsf) {
+ packet_buff[2] = LE_MACRO(boost::uint32_t(if_packet_info.tsf >> 32));
+ packet_buff[3] = LE_MACRO(boost::uint32_t(if_packet_info.tsf >> 0));
+ }
+}
+
+
+/***************************************************************************/
+/* Unpacking */
+/***************************************************************************/
+UHD_INLINE void _hdr_unpack_chdr(
+ const boost::uint32_t chdr,
+ if_packet_info_t &if_packet_info
+) {
+ // Set constant members
+ if_packet_info.link_type = if_packet_info_t::LINK_TYPE_CHDR;
+ if_packet_info.has_cid = false;
+ if_packet_info.has_sid = true;
+ if_packet_info.has_tsi = false;
+ if_packet_info.has_tlr = false;
+ if_packet_info.sob = false;
+
+ // Set configurable members
+ if_packet_info.has_tsf = bool(chdr & HDR_FLAG_TSF);
+ if_packet_info.packet_type = if_packet_info_t::packet_type_t((chdr >> 30) & 0x3);
+ if_packet_info.eob = (if_packet_info.packet_type == if_packet_info_t::PACKET_TYPE_DATA)
+ && bool(chdr & HDR_FLAG_EOB);
+ if_packet_info.error = (if_packet_info.packet_type == if_packet_info_t::PACKET_TYPE_RESP)
+ && bool(chdr & HDR_FLAG_ERROR);
+ if_packet_info.packet_count = (chdr >> 16) & 0xFFF;
+
+ // Set packet length variables
+ if (if_packet_info.has_tsf) {
+ if_packet_info.num_header_words32 = 4;
+ } else {
+ if_packet_info.num_header_words32 = 2;
+ }
+ size_t pkt_size_bytes = (chdr & 0xFFFF);
+ size_t pkt_size_word32 = (pkt_size_bytes / 4) + ((pkt_size_bytes % 4) ? 1 : 0);
+ // Check lengths match:
+ if (pkt_size_word32 < if_packet_info.num_header_words32) {
+ throw uhd::value_error("Bad CHDR or invalid packet length");
+ }
+ if (if_packet_info.num_packet_words32 < pkt_size_word32) {
+ throw uhd::value_error("Bad CHDR or packet fragment");
+ }
+ if_packet_info.num_payload_bytes = pkt_size_bytes - (4 * if_packet_info.num_header_words32);
+ if_packet_info.num_payload_words32 = pkt_size_word32 - if_packet_info.num_header_words32;
+}
+
+void chdr::if_hdr_unpack_be(
+ const boost::uint32_t *packet_buff,
+ if_packet_info_t &if_packet_info
+) {
+ // Read header and update if_packet_info
+ boost::uint32_t chdr = BE_MACRO(packet_buff[0]);
+ _hdr_unpack_chdr(chdr, if_packet_info);
+
+ // Read SID
+ if_packet_info.sid = BE_MACRO(packet_buff[1]);
+
+ // Read time (has_tsf was updated earlier)
+ if (if_packet_info.has_tsf) {
+ if_packet_info.tsf = 0
+ | boost::uint64_t(BE_MACRO(packet_buff[2])) << 32
+ | BE_MACRO(packet_buff[3]);
+ }
+}
+
+void chdr::if_hdr_unpack_le(
+ const boost::uint32_t *packet_buff,
+ if_packet_info_t &if_packet_info
+) {
+ // Read header and update if_packet_info
+ boost::uint32_t chdr = LE_MACRO(packet_buff[0]);
+ _hdr_unpack_chdr(chdr, if_packet_info);
+
+ // Read SID
+ if_packet_info.sid = LE_MACRO(packet_buff[1]);
+
+ // Read time (has_tsf was updated earlier)
+ if (if_packet_info.has_tsf) {
+ if_packet_info.tsf = 0
+ | boost::uint64_t(LE_MACRO(packet_buff[2])) << 32
+ | LE_MACRO(packet_buff[3]);
+ }
+}
+
diff --git a/host/tests/CMakeLists.txt b/host/tests/CMakeLists.txt
index 579fd46ca..829fb8e94 100644
--- a/host/tests/CMakeLists.txt
+++ b/host/tests/CMakeLists.txt
@@ -27,8 +27,9 @@ SET(test_sources
addr_test.cpp
buffer_test.cpp
byteswap_test.cpp
- convert_test.cpp
cast_test.cpp
+ chdr_test.cpp
+ convert_test.cpp
dict_test.cpp
error_test.cpp
fp_compare_delta_test.cpp
diff --git a/host/tests/chdr_test.cpp b/host/tests/chdr_test.cpp
new file mode 100644
index 000000000..8893e12e5
--- /dev/null
+++ b/host/tests/chdr_test.cpp
@@ -0,0 +1,141 @@
+//
+// Copyright 2014 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/transport/chdr.hpp>
+#include <uhd/utils/byteswap.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/format.hpp>
+#include <cstdlib>
+#include <iostream>
+
+using namespace uhd::transport::vrt;
+
+static void pack_and_unpack(
+ if_packet_info_t &if_packet_info_in
+){
+ // Temp buffer for packed packet
+ boost::uint32_t packet_buff[2048] = {0};
+
+ // Check input (must not be lazy)
+ BOOST_REQUIRE(
+ (if_packet_info_in.num_payload_words32 == 0 and if_packet_info_in.num_payload_bytes == 0)
+ or
+ (if_packet_info_in.num_payload_words32 != 0 and if_packet_info_in.num_payload_bytes != 0)
+ );
+ if (if_packet_info_in.num_payload_words32) {
+ BOOST_REQUIRE(if_packet_info_in.num_payload_bytes <= 4 * if_packet_info_in.num_payload_words32);
+ BOOST_REQUIRE(if_packet_info_in.num_payload_bytes > 4*(if_packet_info_in.num_payload_words32-1));
+ }
+
+ //pack metadata into a vrt header
+ chdr::if_hdr_pack_be(
+ packet_buff, if_packet_info_in
+ );
+ std::cout << std::endl;
+ boost::uint32_t header_bits = (uhd::ntohx(packet_buff[0]) >> 28);
+ std::cout << boost::format("header bits = 0b%d%d%d%d") % bool(header_bits & 8) % bool(header_bits & 4) % bool(header_bits & 2) % bool(header_bits & 1) << std::endl;
+ for (size_t i = 0; i < 5; i++)
+ {
+ std::cout << boost::format("packet_buff[%u] = 0x%08x") % i % uhd::ntohx(packet_buff[i]) << std::endl;
+ }
+
+ if_packet_info_t if_packet_info_out;
+ // Must be set a-priori as per contract
+ if_packet_info_out.num_packet_words32 = if_packet_info_in.num_packet_words32;
+
+ //unpack the vrt header back into metadata
+ chdr::if_hdr_unpack_be(
+ packet_buff, if_packet_info_out
+ );
+
+ //check the the unpacked metadata is the same
+ 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(if_packet_info_out.has_sid);
+ BOOST_CHECK_EQUAL(if_packet_info_in.sid, if_packet_info_out.sid);
+ BOOST_CHECK(if_packet_info_out.has_sid);
+ 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_AUTO_TEST_CASE(test_with_chdr){
+ if_packet_info_t if_packet_info;
+ if_packet_info.packet_type = if_packet_info_t::PACKET_TYPE_DATA;
+ if_packet_info.eob = false;
+ if_packet_info.packet_count = 7;
+ if_packet_info.has_tsf = true;
+ if_packet_info.tsf = 0x1234567890ABCDEF;
+ if_packet_info.sid = 0xAABBCCDD;
+ if_packet_info.num_payload_words32 = 24;
+ if_packet_info.num_payload_bytes = 95;
+ pack_and_unpack(if_packet_info);
+}
+
+BOOST_AUTO_TEST_CASE(test_with_chdr_fc){
+ if_packet_info_t if_packet_info;
+ if_packet_info.packet_type = if_packet_info_t::PACKET_TYPE_FC;
+ if_packet_info.eob = false;
+ if_packet_info.packet_count = 19;
+ if_packet_info.has_tsf = false;
+ if_packet_info.tsf = 0x1234567890ABCDEF;
+ if_packet_info.sid = 0xAABBCCDD;
+ if_packet_info.num_payload_words32 = 4;
+ if_packet_info.num_payload_bytes = 16;
+ pack_and_unpack(if_packet_info);
+}
+
+BOOST_AUTO_TEST_CASE(test_with_chdr_cmd){
+ if_packet_info_t if_packet_info;
+ if_packet_info.packet_type = if_packet_info_t::PACKET_TYPE_CMD;
+ if_packet_info.packet_count = 19;
+ if_packet_info.has_tsf = true;
+ if_packet_info.tsf = 0x1234567890ABCDEF;
+ if_packet_info.sid = 0xAABBCCDD;
+ if_packet_info.num_payload_words32 = 4;
+ if_packet_info.num_payload_bytes = 16;
+ pack_and_unpack(if_packet_info);
+}
+
+BOOST_AUTO_TEST_CASE(test_with_chdr_resp){
+ if_packet_info_t if_packet_info;
+ if_packet_info.packet_type = if_packet_info_t::PACKET_TYPE_RESP;
+ if_packet_info.packet_count = 123;
+ if_packet_info.has_tsf = false;
+ if_packet_info.tsf = 0x1234567890ABCDEF;
+ if_packet_info.sid = 0xAABBCCDD;
+ if_packet_info.num_payload_words32 = 4;
+ if_packet_info.num_payload_bytes = 16;
+ pack_and_unpack(if_packet_info);
+}
+
+BOOST_AUTO_TEST_CASE(test_with_chdr_err){
+ if_packet_info_t if_packet_info;
+ if_packet_info.packet_type = if_packet_info_t::PACKET_TYPE_ERROR;
+ if_packet_info.packet_count = 1928;
+ if_packet_info.eob = false;
+ if_packet_info.error = false; // Needs to be set explicitly
+ if_packet_info.has_tsf = false;
+ if_packet_info.tsf = 0x1234567890ABCDEF;
+ if_packet_info.sid = 0xAABBCCDD;
+ if_packet_info.num_payload_words32 = 4;
+ if_packet_info.num_payload_bytes = 16;
+ pack_and_unpack(if_packet_info);
+}
+