aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/include/uhdlib/rfnoc/chdr_packet.hpp
blob: cc729de6c5fcf8503aca38c1336c7e940ebd5b10 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
//
// Copyright 2019 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: GPL-3.0-or-later
//

#ifndef INCLUDED_RFNOC_CHDR_PACKET_HPP
#define INCLUDED_RFNOC_CHDR_PACKET_HPP

#include <uhd/types/endianness.hpp>
#include <uhd/utils/byteswap.hpp>
#include <uhdlib/rfnoc/chdr_types.hpp>
#include <limits>

namespace uhd { namespace rfnoc { namespace chdr {

//----------------------------------------------------
// Generic CHDR Packet Container
//----------------------------------------------------

//! A container class that wraps a generic buffer that contains a CHDR packet. The
//  container provides a high level API to read and write the header, metadata and payload
//  of the packet. The payload can be accessed as a generic buffer using this interface.
//
class chdr_packet
{
public:
    //! A unique pointer to a const chdr_packet. Useful as a read-only interface.
    typedef std::unique_ptr<const chdr_packet> cuptr;
    //! A unique pointer to a non-const chdr_packet. Useful as a read-write interface.
    typedef std::unique_ptr<chdr_packet> uptr;

    virtual ~chdr_packet() = 0;

    /*! Updates the underlying storage of this packet. This is a const method and is
     *  only useful for read-only (RX) access.
     *
     * \param pkt_buff Pointer to a buffer that contains the RX packet
     */
    virtual void refresh(const void* pkt_buff) const = 0;

    /*! Updates the underlying storage of this packet, and populates it with the specified
     *  arguments. This is a non-const method and is useful for read-write (TX) access.
     *
     * \param pkt_buff Pointer to a buffer that should be populated with the TX packet
     * \param header The CHDR header to fill into the TX packet
     * \param timestamp The timestamp to fill into the TX packet (if requested)
     */
    virtual void refresh(void* pkt_buff, chdr_header& header, uint64_t timestamp = 0) = 0;

    /*! Updates the CHDR header with the written payload size
     *
     * \param payload_size_bytes The payload size in bytes
     */
    virtual void update_payload_size(size_t payload_size_bytes) = 0;

    /*! Returns a class that represents the contents of the CHDR header
     *
     * \return The CHDR header
     */
    virtual chdr_header get_chdr_header() const = 0;

    /*! Returns the timestamp in the packet as an optional value
     *
     * \return A boost::optional which if initialized has the timestamp
     */
    virtual boost::optional<uint64_t> get_timestamp() const = 0;

    /*! Returns the endianness of the metadata and payload buffers
     *
     * \return The byte order as a uhd::endianness_t
     */
    virtual endianness_t get_byte_order() const = 0;

    /*! Returns the maximum transfer unit in bytes
     *
     * \return The maximum transfer unit in bytes
     */
    virtual size_t get_mtu_bytes() const = 0;

    /*! Returns the metadata size in bytes
     *
     * \return The size in bytes
     */
    virtual size_t get_mdata_size() const = 0;

    /*! Returns a const void pointer to the metadata section in the packet
     *
     * \return A pointer to the metadata
     */
    virtual const void* get_mdata_const_ptr() const = 0;

    /*! Returns a non-const void pointer to the metadata section in the packet
     *
     * \return A pointer to the metadata
     */
    virtual void* get_mdata_ptr() = 0;

    /*! Returns the payload size in bytes
     *
     * \return The size in bytes
     */
    virtual size_t get_payload_size() const = 0;

    /*! Returns a const void pointer to the payload section in the packet
     *
     * \return A pointer to the payload
     */
    virtual const void* get_payload_const_ptr() const = 0;

    /*! Returns a non-const void pointer to the payload section in the packet
     *
     * \return A pointer to the payload
     */
    virtual void* get_payload_ptr() = 0;

    /*! Return the payload offset in bytes for a given type and num_mdata
     *
     * \param pkt_type The packet type for calculation
     * \param num_mdata The number of metadata words for calculation
     * \return The offset of the payload in a packet with the given params
     */
    virtual size_t calculate_payload_offset(const packet_type_t pkt_type,
        const uint8_t num_mdata = 0) const = 0;

    //! Shortcut to return the const metadata pointer cast as a specific type
    template <typename data_t>
    inline const data_t* get_mdata_const_ptr_as() const
    {
        return reinterpret_cast<const data_t*>(get_mdata_const_ptr());
    }

    //! Shortcut to return the non-const metadata pointer cast as a specific type
    template <typename data_t>
    inline data_t* get_mdata_ptr_as()
    {
        return reinterpret_cast<data_t*>(get_mdata_ptr());
    }

    //! Shortcut to return the const payload pointer cast as a specific type
    template <typename data_t>
    inline const data_t* get_payload_const_ptr_as() const
    {
        return reinterpret_cast<const data_t*>(get_payload_const_ptr());
    }

    //! Shortcut to return the non-const payload pointer cast as a specific type
    template <typename data_t>
    inline data_t* get_payload_ptr_as()
    {
        return reinterpret_cast<data_t*>(get_payload_ptr());
    }

    //! Return a function to convert a word of type data_t to host order
    template <typename data_t>
    const std::function<data_t(data_t)> conv_to_host() const
    {
        return (get_byte_order() == uhd::ENDIANNESS_BIG) ? uhd::ntohx<data_t>
                                                         : uhd::wtohx<data_t>;
    }

    //! Return a function to convert a word of type data_t from host order
    template <typename data_t>
    const std::function<data_t(data_t)> conv_from_host() const
    {
        return (get_byte_order() == uhd::ENDIANNESS_BIG) ? uhd::htonx<data_t>
                                                         : uhd::htowx<data_t>;
    }
};

//----------------------------------------------------
// Container for specific CHDR Packets
//----------------------------------------------------

//! A container class that wraps a generic buffer that contains a CHDR packet. The
//  container provides a high level API to read and write the header, metadata and payload
//  of the packet. The payload can be accessed as a specific type that will be serialized
//  and deserialized appropriately.
//
template <typename payload_t>
class chdr_packet_specific
{
public:
    //! A unique pointer to a const chdr_packet. Useful as a read-only interface.
    typedef std::unique_ptr<const chdr_packet_specific<payload_t>> cuptr;
    //! A unique pointer to a non-const chdr_packet. Useful as a read-write interface.
    typedef std::unique_ptr<chdr_packet_specific<payload_t>> uptr;

    chdr_packet_specific(chdr_packet::uptr chdr_pkt) : _chdr_pkt(std::move(chdr_pkt)) {}
    ~chdr_packet_specific() = default;

    //! Updates the underlying storage of this packet. This is a const method and is
    //  only useful for read-only access.
    inline void refresh(const void* pkt_buff) const
    {
        _chdr_pkt->refresh(pkt_buff);
    }

    //! Updates the underlying storage of this packet, and populates it with the specified
    //  arguments. This is a non-const method and is useful for read-write access.
    inline void refresh(void* pkt_buff, chdr_header& header, const payload_t& payload)
    {
        payload.populate_header(header);
        _chdr_pkt->refresh(pkt_buff, header);
        size_t bytes_copied = payload.serialize(_chdr_pkt->get_payload_ptr_as<uint64_t>(),
            _chdr_pkt->get_mtu_bytes(),
            _chdr_pkt->conv_from_host<uint64_t>());
        _chdr_pkt->update_payload_size(bytes_copied);
        header = _chdr_pkt->get_chdr_header();
    }

    //! Returns a class that represents the contents of the CHDR header
    inline chdr_header get_chdr_header() const
    {
        return std::move(_chdr_pkt->get_chdr_header());
    }

    //! Returns a class that represents the contents of the CHDR payload
    inline payload_t get_payload() const
    {
        payload_t payload;
        payload.deserialize(_chdr_pkt->get_payload_const_ptr_as<uint64_t>(),
            _chdr_pkt->get_payload_size() / sizeof(uint64_t),
            _chdr_pkt->conv_to_host<uint64_t>());
        return payload;
    }

    //! Fills the CHDR payload into the specified parameter
    inline void fill_payload(payload_t& payload) const
    {
        payload.deserialize(_chdr_pkt->get_payload_const_ptr_as<uint64_t>(),
            _chdr_pkt->get_payload_size() / sizeof(uint64_t),
            _chdr_pkt->conv_to_host<uint64_t>());
    }

private:
    chdr_packet::uptr _chdr_pkt;
};

//----------------------------------------------------
// Specific CHDR packet types
//----------------------------------------------------

//! CHDR control packet
typedef chdr_packet_specific<ctrl_payload> chdr_ctrl_packet;

//! CHDR stream status packet
typedef chdr_packet_specific<strs_payload> chdr_strs_packet;

//! CHDR stream command packet
typedef chdr_packet_specific<strc_payload> chdr_strc_packet;

//! CHDR management packet
typedef chdr_packet_specific<mgmt_payload> chdr_mgmt_packet;

//----------------------------------------------------
// CHDR packet factory
//----------------------------------------------------

//! A copyable and movable factory class that is capable of generating generic and
//! specific CHDR packet containers.
//
class chdr_packet_factory
{
public:
    //! A parametrized ctor that takes in all the info required to generate a CHDR packet
    //
    // \param chdr_w The CHDR width of the remote device
    // \param endianness The endianness of the link being used (e.g., Ethernet
    //                   typically uses big-endian, PCIe typically uses
    //                   little-endian). Note: The host endianness is
    //                   automatically derived.
    chdr_packet_factory(chdr_w_t chdr_w, endianness_t endianness);
    chdr_packet_factory()                               = delete;
    chdr_packet_factory(const chdr_packet_factory& rhs) = default;
    chdr_packet_factory(chdr_packet_factory&& rhs)      = default;

    //! Makes a generic CHDR packet and transfers ownership to the client
    chdr_packet::uptr make_generic(
        size_t mtu_bytes = std::numeric_limits<size_t>::max()) const;

    //! Makes a CHDR control packet and transfers ownership to the client
    chdr_ctrl_packet::uptr make_ctrl(
        size_t mtu_bytes = std::numeric_limits<size_t>::max()) const;

    //! Makes a CHDR stream status packet and transfers ownership to the client
    chdr_strs_packet::uptr make_strs(
        size_t mtu_bytes = std::numeric_limits<size_t>::max()) const;

    //! Makes a CHDR stream cmd packet and transfers ownership to the client
    chdr_strc_packet::uptr make_strc(
        size_t mtu_bytes = std::numeric_limits<size_t>::max()) const;

    //! Makes a CHDR management packet and transfers ownership to the client
    chdr_mgmt_packet::uptr make_mgmt(
        size_t mtu_bytes = std::numeric_limits<size_t>::max()) const;

    //! Get the CHDR width
    inline chdr_w_t get_chdr_w() const
    {
        return _chdr_w;
    }

    //! Get the link endianness
    inline endianness_t get_endianness() const
    {
        return _endianness;
    }

    //! Get the protocol version for RFNoC and the CHDR format
    inline uint16_t get_protover() const
    {
        return RFNOC_PROTO_VER;
    }

private:
    const chdr_w_t _chdr_w;
    const endianness_t _endianness;
};

}}} // namespace uhd::rfnoc::chdr

#endif /* INCLUDED_RFNOC_CHDR_PACKET_HPP */