1 //
2 // Copyright 2020 Ettus Research, a National Instruments Brand
3 //
4 // SPDX-License-Identifier: GPL-3.0-or-later
5 //
6
7 #include <uhd/utils/chdr/chdr_packet.hpp>
8 #include <uhdlib/rfnoc/chdr_packet_writer.hpp>
9 #include <boost/format.hpp>
10
11 namespace chdr_rfnoc = uhd::rfnoc::chdr;
12 namespace chdr_util = uhd::utils::chdr;
13 using namespace uhd;
14
chdr_packet(uhd::rfnoc::chdr_w_t chdr_w,chdr_rfnoc::chdr_header header,std::vector<uint8_t> payload,boost::optional<uint64_t> timestamp,std::vector<uint64_t> mdata)15 chdr_util::chdr_packet::chdr_packet(uhd::rfnoc::chdr_w_t chdr_w,
16 chdr_rfnoc::chdr_header header,
17 std::vector<uint8_t> payload,
18 boost::optional<uint64_t> timestamp,
19 std::vector<uint64_t> mdata)
20 : _chdr_w(chdr_w)
21 , _header(header)
22 , _payload(std::move(payload))
23 , _timestamp(timestamp)
24 , _mdata(std::move(mdata))
25 {
26 set_header_lengths();
27 }
28
u64_to_host(uhd::endianness_t endianness,uint64_t word)29 inline static uint64_t u64_to_host(uhd::endianness_t endianness, uint64_t word)
30 {
31 return (endianness == ENDIANNESS_BIG) ? uhd::ntohx<uint64_t>(word)
32 : uhd::wtohx<uint64_t>(word);
33 }
34
u64_from_host(uhd::endianness_t endianness,uint64_t word)35 inline static uint64_t u64_from_host(uhd::endianness_t endianness, uint64_t word)
36 {
37 return (endianness == ENDIANNESS_BIG) ? uhd::htonx<uint64_t>(word)
38 : uhd::htowx<uint64_t>(word);
39 }
40
get_header() const41 chdr_rfnoc::chdr_header chdr_util::chdr_packet::get_header() const
42 {
43 return this->_header;
44 }
45
set_header(chdr_rfnoc::chdr_header header)46 void chdr_util::chdr_packet::set_header(chdr_rfnoc::chdr_header header)
47 {
48 _header = header;
49 set_header_lengths();
50 }
51
get_timestamp() const52 boost::optional<uint64_t> chdr_util::chdr_packet::get_timestamp() const
53 {
54 return this->_timestamp;
55 }
56
set_timestamp(boost::optional<uint64_t> timestamp)57 void chdr_util::chdr_packet::set_timestamp(boost::optional<uint64_t> timestamp)
58 {
59 _timestamp = timestamp;
60 set_header_lengths();
61 }
62
serialize_to_byte_vector(endianness_t endianness) const63 std::vector<uint8_t> chdr_util::chdr_packet::serialize_to_byte_vector(
64 endianness_t endianness) const
65 {
66 std::vector<uint8_t> buffer(get_packet_len(), 0);
67 serialize(buffer.begin(), buffer.end(), endianness);
68 return buffer;
69 }
70
serialize_ptr(endianness_t endianness,void * start,void * end) const71 void chdr_util::chdr_packet::serialize_ptr(
72 endianness_t endianness, void* start, void* end) const
73 {
74 size_t len = static_cast<uint8_t*>(end) - static_cast<uint8_t*>(start);
75 UHD_ASSERT_THROW(get_packet_len() <= len);
76 chdr_rfnoc::chdr_packet_factory factory(_chdr_w, endianness);
77 chdr_rfnoc::chdr_packet_writer::uptr packet_writer =
78 factory.make_generic(std::numeric_limits<size_t>::max());
79 chdr_rfnoc::chdr_header header = _header;
80 packet_writer->refresh(start, header, (_timestamp ? *_timestamp : 0));
81
82 uint64_t* mdata_ptr = static_cast<uint64_t*>(packet_writer->get_mdata_ptr());
83 auto mdata_src_begin = this->_mdata.begin();
84 auto mdata_src_end = this->_mdata.end();
85 std::transform(
86 mdata_src_begin, mdata_src_end, mdata_ptr, [endianness](uint64_t value) {
87 return u64_from_host(endianness, value);
88 });
89
90 uint8_t* payload_ptr = static_cast<uint8_t*>(packet_writer->get_payload_ptr());
91 std::copy(_payload.begin(), _payload.end(), payload_ptr);
92 }
93
deserialize_ptr(uhd::rfnoc::chdr_w_t chdr_w,endianness_t endianness,const void * start,const void * end)94 chdr_util::chdr_packet chdr_util::chdr_packet::deserialize_ptr(
95 uhd::rfnoc::chdr_w_t chdr_w,
96 endianness_t endianness,
97 const void* start,
98 const void* end)
99 {
100 chdr_rfnoc::chdr_packet_factory factory(chdr_w, endianness);
101 chdr_rfnoc::chdr_packet_writer::uptr packet_writer =
102 factory.make_generic(std::numeric_limits<size_t>::max());
103 packet_writer->refresh(start);
104
105 chdr_rfnoc::chdr_header header = packet_writer->get_chdr_header();
106 boost::optional<uint64_t> timestamp = packet_writer->get_timestamp();
107
108 const size_t mdata_size_words = packet_writer->get_mdata_size() / 8;
109 const uint64_t* mdata_src_begin =
110 static_cast<const uint64_t*>(packet_writer->get_mdata_const_ptr());
111 const uint64_t* mdata_src_end = mdata_src_begin + mdata_size_words;
112 std::vector<uint64_t> mdata(mdata_size_words, 0);
113 uint64_t* mdata_ptr = mdata.data();
114 UHD_ASSERT_THROW(mdata_src_end < static_cast<const uint64_t*>(end));
115 std::transform(
116 mdata_src_begin, mdata_src_end, mdata_ptr, [endianness](uint64_t value) {
117 return u64_from_host(endianness, value);
118 });
119
120 size_t payload_size = packet_writer->get_payload_size();
121 const uint8_t* payload_begin =
122 static_cast<const uint8_t*>(packet_writer->get_payload_const_ptr());
123 const uint8_t* payload_end = payload_begin + payload_size;
124 std::vector<uint8_t> payload(payload_size, 0);
125 UHD_ASSERT_THROW(payload_end <= static_cast<const uint8_t*>(end));
126 std::copy(payload_begin, payload_end, payload.begin());
127
128 return chdr_util::chdr_packet(chdr_w, header, payload, timestamp, mdata);
129 }
130
set_metadata(std::vector<uint64_t> metadata)131 void chdr_util::chdr_packet::set_metadata(std::vector<uint64_t> metadata)
132 {
133 _mdata = std::move(metadata);
134 set_header_lengths();
135 }
136
get_metadata() const137 const std::vector<uint64_t>& chdr_util::chdr_packet::get_metadata() const
138 {
139 return _mdata;
140 }
141
get_packet_len() const142 size_t chdr_util::chdr_packet::get_packet_len() const
143 {
144 size_t chdr_w_bytes = uhd::rfnoc::chdr_w_to_bits(_chdr_w) / 8;
145 // The timestamp and header take up 2 chdr_w lengths only when CHDR_W = 64 bits and
146 // there is a timestamp (RFNoC Specifcation section 2.2.1)
147 return _payload.size() * sizeof(uint8_t) + _mdata.size() * sizeof(uint64_t)
148 + ((_timestamp != boost::none && _chdr_w == uhd::rfnoc::CHDR_W_64) ? 2 : 1)
149 * chdr_w_bytes;
150 }
151
get_payload_bytes() const152 const std::vector<uint8_t>& chdr_util::chdr_packet::get_payload_bytes() const
153 {
154 return _payload;
155 }
156
set_payload_bytes(std::vector<uint8_t> bytes)157 void chdr_util::chdr_packet::set_payload_bytes(std::vector<uint8_t> bytes)
158 {
159 this->_payload = std::move(bytes);
160 set_header_lengths();
161 }
162
163 //! Return a string representation of this object
to_string() const164 const std::string chdr_util::chdr_packet::to_string() const
165 {
166 return str(boost::format("chdr_packet{chdr_w:%u}\n%s")
167 % uhd::rfnoc::chdr_w_to_bits(_chdr_w) % _header.to_string());
168 }
169