1 //
2 // Copyright 2019 Ettus Research, a National Instruments Brand
3 //
4 // SPDX-License-Identifier: GPL-3.0-or-later
5 //
6
7 #include <uhd/exception.hpp>
8 #include <uhd/rfnoc/chdr_types.hpp>
9 #include <uhd/types/endianness.hpp>
10 #include <boost/format.hpp>
11 #include <cassert>
12 #include <sstream>
13
14 using namespace uhd;
15 using namespace uhd::rfnoc::chdr;
16
17 //----------------------------------------------------
18 // Utility Functions
19 //----------------------------------------------------
20
mask_u64(size_t width)21 static inline constexpr uint64_t mask_u64(size_t width)
22 {
23 return ((uint64_t(1) << width) - 1);
24 }
25
26 template <typename field_t>
get_field_u64(uint64_t flat_hdr,size_t offset,size_t width)27 static inline constexpr field_t get_field_u64(
28 uint64_t flat_hdr, size_t offset, size_t width)
29 {
30 return static_cast<field_t>((flat_hdr >> offset) & mask_u64(width));
31 }
32
33 //----------------------------------------------------
34 // CHDR Control Payload
35 //----------------------------------------------------
36
populate_header(chdr_header & header) const37 void ctrl_payload::populate_header(chdr_header& header) const
38 {
39 header.set_pkt_type(PKT_TYPE_CTRL);
40 header.set_eob(false);
41 header.set_eov(false);
42 header.set_num_mdata(0);
43 }
44
serialize(uint64_t * buff,size_t max_size_bytes,const std::function<uint64_t (uint64_t)> & conv_byte_order) const45 size_t ctrl_payload::serialize(uint64_t* buff,
46 size_t max_size_bytes,
47 const std::function<uint64_t(uint64_t)>& conv_byte_order) const
48 {
49 // Ctrl Packet Payload can't have more than 15 data -> 8 CHDR_W (RFNoC Spec.
50 // Section 2.2.3)
51 UHD_ASSERT_THROW((data_vtr.size() > 0 && data_vtr.size() < 16));
52 UHD_ASSERT_THROW(get_length() * sizeof(uint64_t) <= max_size_bytes);
53 size_t ptr = 0;
54
55 // Populate control header
56 buff[ptr++] = conv_byte_order(
57 ((static_cast<uint64_t>(dst_port) & mask_u64(DST_PORT_WIDTH)) << DST_PORT_OFFSET)
58 | ((static_cast<uint64_t>(src_port) & mask_u64(SRC_PORT_WIDTH))
59 << SRC_PORT_OFFSET)
60 | ((static_cast<uint64_t>(data_vtr.size()) & mask_u64(NUM_DATA_WIDTH))
61 << NUM_DATA_OFFSET)
62 | ((static_cast<uint64_t>(seq_num) & mask_u64(SEQ_NUM_WIDTH)) << SEQ_NUM_OFFSET)
63 | ((static_cast<uint64_t>(timestamp.is_initialized() ? 1 : 0)
64 & mask_u64(HAS_TIME_WIDTH))
65 << HAS_TIME_OFFSET)
66 | ((static_cast<uint64_t>(is_ack) & mask_u64(IS_ACK_WIDTH)) << IS_ACK_OFFSET)
67 | ((static_cast<uint64_t>(src_epid) & mask_u64(SRC_EPID_WIDTH))
68 << SRC_EPID_OFFSET));
69
70 // Populate optional timestamp
71 if (timestamp.is_initialized()) {
72 buff[ptr++] = conv_byte_order(timestamp.get());
73 }
74
75 // Populate control operation word
76 buff[ptr++] = conv_byte_order(
77 ((static_cast<uint64_t>(address) & mask_u64(ADDRESS_WIDTH)) << ADDRESS_OFFSET)
78 | ((static_cast<uint64_t>(byte_enable) & mask_u64(BYTE_ENABLE_WIDTH))
79 << BYTE_ENABLE_OFFSET)
80 | ((static_cast<uint64_t>(op_code) & mask_u64(OPCODE_WIDTH)) << OPCODE_OFFSET)
81 | ((static_cast<uint64_t>(status) & mask_u64(STATUS_WIDTH)) << STATUS_OFFSET)
82 | (static_cast<uint64_t>(data_vtr[0]) << HI_DATA_OFFSET));
83
84 // Populate the rest of the data
85 for (size_t i = 1; i < data_vtr.size(); i += 2) {
86 const uint32_t hi_data =
87 (((i + 2) >= data_vtr.size()) && (data_vtr.size() % 2 == 0))
88 ? 0
89 : data_vtr[i + 1];
90 buff[ptr++] =
91 conv_byte_order(static_cast<uint64_t>(hi_data) << HI_DATA_OFFSET
92 | static_cast<uint64_t>(data_vtr[i]) << LO_DATA_OFFSET);
93 }
94
95 // This really should be impossible but we'll leave it for safety's sake
96 UHD_ASSERT_THROW(ptr <= max_size_bytes);
97 // Return bytes written
98 return (ptr * sizeof(uint64_t));
99 }
100
deserialize(const uint64_t * buff,size_t max_size_bytes,const std::function<uint64_t (uint64_t)> & conv_byte_order)101 void ctrl_payload::deserialize(const uint64_t* buff,
102 size_t max_size_bytes,
103 const std::function<uint64_t(uint64_t)>& conv_byte_order)
104 {
105 // We assume that buff has room to hold the entire packet
106 size_t ptr = 0;
107
108 // Read control header
109 uint64_t ctrl_header = conv_byte_order(buff[ptr++]);
110 data_vtr.resize(get_field_u64<size_t>(ctrl_header, NUM_DATA_OFFSET, NUM_DATA_WIDTH));
111 UHD_ASSERT_THROW((data_vtr.size() > 0 && data_vtr.size() < 16));
112 dst_port = get_field_u64<uint16_t>(ctrl_header, DST_PORT_OFFSET, DST_PORT_WIDTH);
113 src_port = get_field_u64<uint16_t>(ctrl_header, SRC_PORT_OFFSET, SRC_PORT_WIDTH);
114 seq_num = get_field_u64<uint8_t>(ctrl_header, SEQ_NUM_OFFSET, SEQ_NUM_WIDTH);
115 is_ack = get_field_u64<bool>(ctrl_header, IS_ACK_OFFSET, IS_ACK_WIDTH);
116 src_epid = get_field_u64<uint16_t>(ctrl_header, SRC_EPID_OFFSET, SRC_EPID_WIDTH);
117
118 // Read optional timestamp
119 if (get_field_u64<bool>(ctrl_header, HAS_TIME_OFFSET, HAS_TIME_WIDTH)) {
120 timestamp = conv_byte_order(buff[ptr++]);
121 } else {
122 timestamp = boost::none;
123 }
124
125 // Read control operation word
126 uint64_t op_word = conv_byte_order(buff[ptr++]);
127 if (data_vtr.size() > 0) {
128 data_vtr[0] = get_field_u64<uint32_t>(op_word, HI_DATA_OFFSET, 32);
129 }
130 address = get_field_u64<uint32_t>(op_word, ADDRESS_OFFSET, ADDRESS_WIDTH);
131 byte_enable = get_field_u64<uint8_t>(op_word, BYTE_ENABLE_OFFSET, BYTE_ENABLE_WIDTH);
132 op_code = get_field_u64<ctrl_opcode_t>(op_word, OPCODE_OFFSET, OPCODE_WIDTH);
133 status = get_field_u64<ctrl_status_t>(op_word, STATUS_OFFSET, STATUS_WIDTH);
134
135 // Read the rest of the data
136 for (size_t i = 1; i < data_vtr.size(); i += 2) {
137 uint64_t data_word = conv_byte_order(buff[ptr++]);
138 if (((i + 2) < data_vtr.size()) || (data_vtr.size() % 2 != 0)) {
139 data_vtr[i + 1] = get_field_u64<uint32_t>(data_word, HI_DATA_OFFSET, 32);
140 }
141 data_vtr[i] = get_field_u64<uint32_t>(data_word, LO_DATA_OFFSET, 32);
142 }
143 UHD_ASSERT_THROW(ptr <= max_size_bytes);
144 }
145
get_length() const146 size_t ctrl_payload::get_length() const
147 {
148 size_t length = 1;
149 if (this->has_timestamp()) {
150 length += 1;
151 }
152 size_t operations = 1 + this->data_vtr.size();
153 length += operations / 2 + operations % 2;
154 return length;
155 }
156
operator ==(const ctrl_payload & rhs) const157 bool ctrl_payload::operator==(const ctrl_payload& rhs) const
158 {
159 return (dst_port == rhs.dst_port) && (src_port == rhs.src_port)
160 && (seq_num == rhs.seq_num)
161 && (timestamp.is_initialized() == rhs.timestamp.is_initialized())
162 && ((!timestamp.is_initialized()) || (timestamp.get() == rhs.timestamp.get()))
163 && (is_ack == rhs.is_ack) && (src_epid == rhs.src_epid)
164 && (address == rhs.address) && (data_vtr == rhs.data_vtr)
165 && (byte_enable == rhs.byte_enable) && (op_code == rhs.op_code)
166 && (status == rhs.status);
167 }
168
to_string() const169 const std::string ctrl_payload::to_string() const
170 {
171 return str(
172 boost::format("ctrl_payload{dst_port:%d, dst_port:%d, seq_num:%d, timestamp:%s, "
173 "is_ack:%s, src_epid:%d, address:0x%05x, byte_enable:0x%x, "
174 "op_code:%d, status:%d, data[0]:0x%08x}\n")
175 % dst_port % src_port % int(seq_num)
176 % (timestamp.is_initialized() ? str(boost::format("0x%016x") % timestamp.get())
177 : std::string("<not present>"))
178 % (is_ack ? "true" : "false") % src_epid % address % int(byte_enable) % op_code
179 % status % data_vtr[0]);
180 }
181
182 //----------------------------------------------------
183 // CHDR Stream Status Payload
184 //----------------------------------------------------
185
populate_header(chdr_header & header) const186 void strs_payload::populate_header(chdr_header& header) const
187 {
188 header.set_pkt_type(PKT_TYPE_STRS);
189 header.set_eob(false);
190 header.set_eov(false);
191 header.set_num_mdata(0);
192 }
193
serialize(uint64_t * buff,size_t max_size_bytes,const std::function<uint64_t (uint64_t)> & conv_byte_order) const194 size_t strs_payload::serialize(uint64_t* buff,
195 size_t max_size_bytes,
196 const std::function<uint64_t(uint64_t)>& conv_byte_order) const
197 {
198 UHD_ASSERT_THROW(max_size_bytes >= (4 * sizeof(uint64_t)));
199
200 // Populate first word
201 buff[0] = conv_byte_order(
202 ((static_cast<uint64_t>(src_epid) & mask_u64(SRC_EPID_WIDTH)) << SRC_EPID_OFFSET)
203 | ((static_cast<uint64_t>(status) & mask_u64(STATUS_WIDTH)) << STATUS_OFFSET)
204 | ((static_cast<uint64_t>(capacity_bytes) & mask_u64(CAPACITY_BYTES_WIDTH))
205 << CAPACITY_BYTES_OFFSET));
206
207 // Populate second word
208 buff[1] = conv_byte_order(
209 ((static_cast<uint64_t>(capacity_pkts) & mask_u64(CAPACITY_PKTS_WIDTH))
210 << CAPACITY_PKTS_OFFSET)
211 | ((static_cast<uint64_t>(xfer_count_pkts) & mask_u64(XFER_COUNT_PKTS_WIDTH))
212 << XFER_COUNT_PKTS_OFFSET));
213
214 // Populate third word
215 buff[2] = conv_byte_order(xfer_count_bytes);
216
217 // Populate fourth word
218 buff[3] = conv_byte_order(
219 ((static_cast<uint64_t>(buff_info) & mask_u64(BUFF_INFO_WIDTH))
220 << BUFF_INFO_OFFSET)
221 | ((static_cast<uint64_t>(status_info) & mask_u64(STATUS_INFO_WIDTH))
222 << STATUS_INFO_OFFSET));
223
224 // Return bytes written
225 return (4 * sizeof(uint64_t));
226 }
227
deserialize(const uint64_t * buff,size_t num_elems,const std::function<uint64_t (uint64_t)> & conv_byte_order)228 void strs_payload::deserialize(const uint64_t* buff,
229 size_t num_elems,
230 const std::function<uint64_t(uint64_t)>& conv_byte_order)
231 {
232 UHD_ASSERT_THROW(num_elems >= 4);
233
234 // Read first word
235 uint64_t word0 = conv_byte_order(buff[0]);
236 src_epid = get_field_u64<uint16_t>(word0, SRC_EPID_OFFSET, SRC_EPID_WIDTH);
237 status = get_field_u64<strs_status_t>(word0, STATUS_OFFSET, STATUS_WIDTH);
238 capacity_bytes =
239 get_field_u64<uint64_t>(word0, CAPACITY_BYTES_OFFSET, CAPACITY_BYTES_WIDTH);
240
241 // Read second word
242 uint64_t word1 = conv_byte_order(buff[1]);
243 capacity_pkts =
244 get_field_u64<uint32_t>(word1, CAPACITY_PKTS_OFFSET, CAPACITY_PKTS_WIDTH);
245 xfer_count_pkts =
246 get_field_u64<uint64_t>(word1, XFER_COUNT_PKTS_OFFSET, XFER_COUNT_PKTS_WIDTH);
247
248 // Read third word
249 xfer_count_bytes = conv_byte_order(buff[2]);
250
251 // Read fourth word
252 uint64_t word3 = conv_byte_order(buff[3]);
253 buff_info = get_field_u64<uint16_t>(word3, BUFF_INFO_OFFSET, BUFF_INFO_WIDTH);
254 status_info = get_field_u64<uint64_t>(word3, STATUS_INFO_OFFSET, STATUS_INFO_WIDTH);
255 }
256
get_length() const257 size_t strs_payload::get_length() const
258 {
259 return 4;
260 }
261
operator ==(const strs_payload & rhs) const262 bool strs_payload::operator==(const strs_payload& rhs) const
263 {
264 return (src_epid == rhs.src_epid) && (status == rhs.status)
265 && (capacity_bytes == rhs.capacity_bytes)
266 && (capacity_pkts == rhs.capacity_pkts)
267 && (xfer_count_pkts == rhs.xfer_count_pkts)
268 && (xfer_count_bytes == rhs.xfer_count_bytes) && (buff_info == rhs.buff_info)
269 && (status_info == rhs.status_info);
270 }
271
to_string() const272 const std::string strs_payload::to_string() const
273 {
274 return str(boost::format("strs_payload{src_epid:%lu, status:%d, capacity_bytes:%lu, "
275 "capacity_pkts:%lu, "
276 "xfer_count_pkts:%lu, xfer_count_bytes:%lu, "
277 "buff_info:0x%x, status_info:0x%x}\n")
278 % src_epid % int(status) % capacity_bytes % capacity_pkts % xfer_count_pkts
279 % xfer_count_bytes % buff_info % status_info);
280 }
281
282 //----------------------------------------------------
283 // CHDR Stream Command Payload
284 //----------------------------------------------------
285
populate_header(chdr_header & header) const286 void strc_payload::populate_header(chdr_header& header) const
287 {
288 header.set_pkt_type(PKT_TYPE_STRC);
289 header.set_eob(false);
290 header.set_eov(false);
291 header.set_num_mdata(0);
292 }
293
serialize(uint64_t * buff,size_t max_size_bytes,const std::function<uint64_t (uint64_t)> & conv_byte_order) const294 size_t strc_payload::serialize(uint64_t* buff,
295 size_t max_size_bytes,
296 const std::function<uint64_t(uint64_t)>& conv_byte_order) const
297 {
298 UHD_ASSERT_THROW(max_size_bytes >= (2 * sizeof(uint64_t)));
299
300 // Populate first word
301 buff[0] = conv_byte_order(
302 ((static_cast<uint64_t>(src_epid) & mask_u64(SRC_EPID_WIDTH)) << SRC_EPID_OFFSET)
303 | ((static_cast<uint64_t>(op_code) & mask_u64(OP_CODE_WIDTH)) << OP_CODE_OFFSET)
304 | ((static_cast<uint64_t>(op_data) & mask_u64(OP_DATA_WIDTH)) << OP_DATA_OFFSET)
305 | ((static_cast<uint64_t>(num_pkts) & mask_u64(NUM_PKTS_WIDTH))
306 << NUM_PKTS_OFFSET));
307
308 // Populate second word
309 buff[1] = conv_byte_order(num_bytes);
310
311 // Return bytes written
312 return (2 * sizeof(uint64_t));
313 }
314
deserialize(const uint64_t * buff,size_t num_elems,const std::function<uint64_t (uint64_t)> & conv_byte_order)315 void strc_payload::deserialize(const uint64_t* buff,
316 size_t num_elems,
317 const std::function<uint64_t(uint64_t)>& conv_byte_order)
318 {
319 UHD_ASSERT_THROW(num_elems >= 2);
320
321 // Read first word
322 uint64_t word0 = conv_byte_order(buff[0]);
323 src_epid = get_field_u64<uint16_t>(word0, SRC_EPID_OFFSET, SRC_EPID_WIDTH);
324 op_code = get_field_u64<strc_op_code_t>(word0, OP_CODE_OFFSET, OP_CODE_WIDTH);
325 op_data = get_field_u64<uint8_t>(word0, OP_DATA_OFFSET, OP_DATA_WIDTH);
326 num_pkts = get_field_u64<uint64_t>(word0, NUM_PKTS_OFFSET, NUM_PKTS_WIDTH);
327 // Read second word
328 num_bytes = conv_byte_order(buff[1]);
329 }
330
get_length() const331 size_t strc_payload::get_length() const
332 {
333 return 2;
334 }
335
operator ==(const strc_payload & rhs) const336 bool strc_payload::operator==(const strc_payload& rhs) const
337 {
338 return (src_epid == rhs.src_epid) && (op_code == rhs.op_code)
339 && (op_data == rhs.op_data) && (num_pkts == rhs.num_pkts)
340 && (num_bytes == rhs.num_bytes);
341 }
342
to_string() const343 const std::string strc_payload::to_string() const
344 {
345 return str(boost::format("strc_payload{src_epid:%lu, op_code:%d, op_data:0x%x, "
346 "num_pkts:%lu, num_bytes:%lu}\n")
347 % src_epid % int(op_code) % int(op_data) % num_pkts % num_bytes);
348 }
349
350 //----------------------------------------------------
351 // CHDR Management Payload
352 //----------------------------------------------------
353
to_string() const354 const std::string mgmt_op_t::to_string() const
355 {
356 std::stringstream stream;
357 switch (get_op_code()) {
358 case mgmt_op_t::MGMT_OP_NOP:
359 stream << "NOP";
360 break;
361 case mgmt_op_t::MGMT_OP_ADVERTISE:
362 stream << "ADVERTISE";
363 break;
364 case mgmt_op_t::MGMT_OP_SEL_DEST:
365 stream << "SEL_DEST";
366 break;
367 case mgmt_op_t::MGMT_OP_RETURN:
368 stream << "RETURN";
369 break;
370 case mgmt_op_t::MGMT_OP_INFO_REQ:
371 stream << "INFO_REQ";
372 break;
373 case mgmt_op_t::MGMT_OP_INFO_RESP:
374 stream << "INFO_RESP";
375 break;
376 case mgmt_op_t::MGMT_OP_CFG_WR_REQ:
377 stream << "CFG_WR_REQ";
378 break;
379 case mgmt_op_t::MGMT_OP_CFG_RD_REQ:
380 stream << "CFG_RD_REQ";
381 break;
382 case mgmt_op_t::MGMT_OP_CFG_RD_RESP:
383 stream << "CFG_RD_RESP";
384 break;
385 default:
386 UHD_THROW_INVALID_CODE_PATH();
387 }
388 stream << ": ";
389 switch (get_op_code()) {
390 case mgmt_op_t::MGMT_OP_SEL_DEST: {
391 mgmt_op_t::sel_dest_payload payload = static_cast<uint64_t>(get_op_payload());
392 stream << "dest:" << payload.dest;
393 break;
394 }
395 case mgmt_op_t::MGMT_OP_CFG_WR_REQ:
396 case mgmt_op_t::MGMT_OP_CFG_RD_REQ:
397 case mgmt_op_t::MGMT_OP_CFG_RD_RESP: {
398 mgmt_op_t::cfg_payload payload = static_cast<uint64_t>(get_op_payload());
399 stream << str(
400 boost::format("addr:0x%08x, data:0x%08x") % payload.addr % payload.data);
401 break;
402 }
403 case mgmt_op_t::MGMT_OP_INFO_REQ:
404 case mgmt_op_t::MGMT_OP_INFO_RESP: {
405 mgmt_op_t::node_info_payload payload =
406 static_cast<uint64_t>(get_op_payload());
407 stream << "device_id:" << payload.device_id
408 << ", node_type:" << payload.node_type
409 << ", node_inst:" << payload.node_inst
410 << ", ext_info:" << payload.ext_info;
411 break;
412 }
413 default: {
414 stream << "-";
415 break;
416 }
417 }
418 stream << "\n";
419 return stream.str();
420 }
421
422 //! Serialize this hop into a list of 64-bit words
serialize(std::vector<uint64_t> & target,const std::function<uint64_t (uint64_t)> & conv_byte_order,const size_t padding_size) const423 size_t mgmt_hop_t::serialize(std::vector<uint64_t>& target,
424 const std::function<uint64_t(uint64_t)>& conv_byte_order,
425 const size_t padding_size) const
426 {
427 for (size_t i = 0; i < get_num_ops(); i++) {
428 target.push_back(
429 conv_byte_order((static_cast<uint64_t>(_ops.at(i).get_op_payload()) << 16)
430 | (static_cast<uint64_t>(_ops.at(i).get_op_code()) << 8)
431 | (static_cast<uint64_t>(get_num_ops() - i - 1) << 0)));
432 for (size_t j = 0; j < padding_size; j++) {
433 target.push_back(uint64_t(0));
434 }
435 }
436 return get_num_ops();
437 }
438
439 //! Deserialize this hop into from list of 64-bit words
deserialize(std::list<uint64_t> & src,const std::function<uint64_t (uint64_t)> & conv_byte_order,const size_t padding_size)440 void mgmt_hop_t::deserialize(std::list<uint64_t>& src,
441 const std::function<uint64_t(uint64_t)>& conv_byte_order,
442 const size_t padding_size)
443 {
444 _ops.clear();
445 size_t ops_remaining = 0;
446 do {
447 // TODO: Change this to a legit exception
448 UHD_ASSERT_THROW(!src.empty());
449
450 uint64_t op_word = conv_byte_order(src.front());
451 ops_remaining = static_cast<size_t>(op_word & 0xFF);
452 mgmt_op_t op(static_cast<mgmt_op_t::op_code_t>((op_word >> 8) & 0xFF),
453 static_cast<uint64_t>((op_word >> 16)));
454 _ops.push_back(op);
455 src.pop_front();
456 for (size_t i = 0; i < padding_size; i++) {
457 src.pop_front();
458 }
459
460 } while (ops_remaining > 0);
461 }
462
to_string() const463 const std::string mgmt_hop_t::to_string() const
464 {
465 std::stringstream stream;
466 for (size_t op_index = 0; op_index < get_num_ops(); op_index++) {
467 if (op_index == 0) {
468 stream << " -> ";
469 } else {
470 stream << " ";
471 }
472 const mgmt_op_t& op = get_op(op_index);
473 stream << op.to_string();
474 }
475 return stream.str();
476 }
477
populate_header(chdr_header & header) const478 void mgmt_payload::populate_header(chdr_header& header) const
479 {
480 header.set_pkt_type(PKT_TYPE_MGMT);
481 header.set_eob(false);
482 header.set_eov(false);
483 header.set_num_mdata(0);
484 header.set_vc(0);
485 header.set_dst_epid(0);
486 }
487
serialize(uint64_t * buff,size_t max_size_bytes,const std::function<uint64_t (uint64_t)> & conv_byte_order) const488 size_t mgmt_payload::serialize(uint64_t* buff,
489 size_t max_size_bytes,
490 const std::function<uint64_t(uint64_t)>& conv_byte_order) const
491 {
492 std::vector<uint64_t> target;
493 // Insert header
494 target.push_back(conv_byte_order(
495 (static_cast<uint64_t>(_protover) << 48)
496 | (static_cast<uint64_t>(static_cast<uint8_t>(_chdr_w) & 0x7) << 45)
497 | (static_cast<uint64_t>(get_num_hops() & 0x3FF) << 16)
498 | (static_cast<uint64_t>(_src_epid) << 0)));
499 // According to the RFNoC specification section 2.2.6, the MSBs are 0 for
500 // all widths greater than 64. This logic adds the padding.
501 for (size_t i = 0; i < _padding_size; i++) {
502 target.push_back(uint64_t(0));
503 }
504
505 // Insert data from each hop
506 for (const auto& hop : _hops) {
507 hop.serialize(target, conv_byte_order, _padding_size);
508 }
509 UHD_ASSERT_THROW(target.size() <= max_size_bytes);
510
511 // We use a vector and copy just for ease of implementation
512 // These transactions are not performance critical
513 std::copy(target.begin(), target.end(), buff);
514 return (target.size() * sizeof(uint64_t));
515 }
516
deserialize(const uint64_t * buff,size_t num_elems,const std::function<uint64_t (uint64_t)> & conv_byte_order)517 void mgmt_payload::deserialize(const uint64_t* buff,
518 size_t num_elems,
519 const std::function<uint64_t(uint64_t)>& conv_byte_order)
520 {
521 UHD_ASSERT_THROW(num_elems > 1);
522
523 // We use a list and copy just for ease of implementation
524 // These transactions are not performance critical
525 std::list<uint64_t> src_list(buff, buff + (num_elems * (_padding_size + 1)));
526
527 _hops.clear();
528
529 // Deframe the header
530 uint64_t hdr = conv_byte_order(src_list.front());
531 _hops.resize(static_cast<size_t>((hdr >> 16) & 0x3FF));
532 _src_epid = static_cast<sep_id_t>(hdr & 0xFFFF);
533 _chdr_w = static_cast<chdr_w_t>((hdr >> 45) & 0x7);
534 _protover = static_cast<uint16_t>((hdr >> 48) & 0xFFFF);
535 _padding_size = (chdr_w_to_bits(_chdr_w) / 64) - 1;
536 src_list.pop_front();
537 // According to the RFNoC specification section 2.2.6, the MSBs are 0 for
538 // all widths greater than 64. This logic removes the padding.
539 for (size_t i = 0; i < _padding_size; i++) {
540 src_list.pop_front();
541 }
542
543 // Populate all hops
544 for (size_t i = 0; i < get_num_hops(); i++) {
545 _hops[i].deserialize(src_list, conv_byte_order, _padding_size);
546 }
547 }
548
get_length() const549 size_t mgmt_payload::get_length() const
550 {
551 size_t length = 1 + _padding_size; /* header */
552 for (const auto& hop : this->_hops) {
553 length += hop.get_num_ops() + _padding_size;
554 }
555 return length;
556 }
557
to_string() const558 const std::string mgmt_payload::to_string() const
559 {
560 return str(boost::format(
561 "mgmt_payload{src_epid:%lu, chdr_w:%d, protover:0x%x, num_hops:%lu}\n")
562 % _src_epid % int(_chdr_w) % _protover % _hops.size());
563 }
564
hops_to_string() const565 const std::string mgmt_payload::hops_to_string() const
566 {
567 std::stringstream stream;
568 for (size_t hop_index = 0; hop_index < get_num_hops(); hop_index++) {
569 const mgmt_hop_t& hop = get_hop(hop_index);
570 stream << hop.to_string();
571 }
572 return stream.str();
573 }
574
575
operator ==(const mgmt_payload & rhs) const576 bool mgmt_payload::operator==(const mgmt_payload& rhs) const
577 {
578 return (_src_epid == rhs._src_epid) && (_protover == rhs._protover)
579 && (_chdr_w == rhs._chdr_w) && (_hops == rhs._hops)
580 && (_padding_size == rhs._padding_size);
581 }
582