1//
2// Copyright 2020 Ettus Research, a National Instruments Brand
3//
4// SPDX-License-Identifier: GPL-3.0-or-later
5//
6
7#pragma once
8
9#include <uhd/exception.hpp>
10#include <uhd/types/endianness.hpp>
11
12namespace chdr_rfnoc = uhd::rfnoc::chdr;
13namespace uhd { namespace utils { namespace chdr {
14
15template <typename payload_t>
16chdr_packet::chdr_packet(uhd::rfnoc::chdr_w_t chdr_w,
17    chdr_rfnoc::chdr_header header,
18    payload_t payload,
19    boost::optional<uint64_t> timestamp,
20    std::vector<uint64_t> metadata)
21    : chdr_packet(chdr_w, header, std::vector<uint8_t>(), timestamp, std::move(metadata))
22{
23    set_payload(payload);
24}
25
26template <typename OutputIterator>
27void chdr_packet::serialize(
28    OutputIterator first, OutputIterator last, uhd::endianness_t endianness) const
29{
30    void* start = static_cast<void*>(&*first);
31    void* end   = static_cast<void*>(&*last);
32    serialize_ptr(endianness, start, end);
33}
34
35template <typename InputIterator>
36chdr_packet chdr_packet::deserialize(uhd::rfnoc::chdr_w_t chdr_w,
37    InputIterator first,
38    InputIterator last,
39    uhd::endianness_t endianness)
40{
41    void* start = static_cast<void*>(&*first);
42    void* end   = static_cast<void*>(&*last);
43    return deserialize_ptr(chdr_w, endianness, start, end);
44}
45
46template <typename payload_t>
47payload_t chdr_packet::get_payload(uhd::endianness_t endianness) const
48{
49    payload_t payload;
50    // Only Data Packets are allowed to have end on a incomplete CHDR_W length.
51    // This method is never called on a data packet. (They don't have a payload_t)
52    UHD_ASSERT_THROW(this->_payload.size() % sizeof(uint64_t) == 0)
53    auto conv_byte_order = [endianness](uint64_t x) -> uint64_t {
54        return (endianness == uhd::ENDIANNESS_BIG) ? uhd::htonx<uint64_t>(x)
55                                                   : uhd::htowx<uint64_t>(x);
56    };
57    payload.deserialize(reinterpret_cast<const uint64_t*>(this->_payload.data()),
58        this->_payload.size(),
59        conv_byte_order);
60    return payload;
61}
62
63template <typename payload_t>
64void chdr_packet::set_payload(payload_t payload, uhd::endianness_t endianness)
65{
66    _header.set_pkt_type(chdr_rfnoc::payload_to_packet_type<payload_t>());
67    // Meaning a 64 bit word (The basic unit of data for payloads)
68    size_t payload_len_words = payload.get_length();
69    this->_payload.resize(payload_len_words * sizeof(uint64_t), 0);
70    auto conv_byte_order = [endianness](uint64_t x) -> uint64_t {
71        return (endianness == uhd::ENDIANNESS_BIG) ? uhd::htonx<uint64_t>(x)
72                                                   : uhd::htowx<uint64_t>(x);
73    };
74    payload.serialize(reinterpret_cast<uint64_t*>(this->_payload.data()),
75        this->_payload.size(),
76        conv_byte_order);
77    set_header_lengths();
78}
79
80template <typename payload_t>
81const std::string chdr_packet::to_string_with_payload(
82    uhd::endianness_t endianness) const
83{
84    payload_t payload = this->get_payload<payload_t>(endianness);
85    return to_string() + payload.to_string();
86}
87
88template <>
89const std::string
90chdr_packet::to_string_with_payload<chdr_rfnoc::mgmt_payload>(
91    uhd::endianness_t endianness) const
92{
93    chdr_rfnoc::mgmt_payload payload =
94        this->get_payload<chdr_rfnoc::mgmt_payload>(endianness);
95    return to_string() + payload.to_string() + payload.hops_to_string();
96}
97
98}}}// namespace uhd::utils::chdr
99