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
|
//
// Copyright 2014-2015 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// Declares the device3_impl class which is a layer between device3 and
// the different 3-rd gen device impls (e.g. x300_impl)
#ifndef INCLUDED_DEVICE3_IMPL_HPP
#define INCLUDED_DEVICE3_IMPL_HPP
#include <uhd/transport/bounded_buffer.hpp>
#include <uhd/transport/vrt_if_packet.hpp>
#include <uhd/transport/chdr.hpp>
#include <uhd/transport/zero_copy.hpp>
#include <uhd/types/sid.hpp>
#include <uhd/types/metadata.hpp>
#include <uhd/types/endianness.hpp>
#include <uhd/types/direction.hpp>
#include <uhd/utils/tasks.hpp>
#include <uhd/device3.hpp>
#include "../../transport/super_send_packet_handler.hpp"
#include "../../transport/super_recv_packet_handler.hpp"
#include <uhdlib/rfnoc/tx_stream_terminator.hpp>
#include <uhdlib/rfnoc/rx_stream_terminator.hpp>
#include <uhdlib/rfnoc/xports.hpp>
namespace uhd { namespace usrp {
/***********************************************************************
* Default settings (any device3 may override these)
**********************************************************************/
static const size_t DEVICE3_RX_FC_REQUEST_FREQ = 32; //per flow-control window
static const size_t DEVICE3_TX_FC_RESPONSE_FREQ = 8;
static const size_t DEVICE3_FC_PACKET_LEN_IN_WORDS32 = 2;
static const size_t DEVICE3_FC_PACKET_COUNT_OFFSET = 0;
static const size_t DEVICE3_FC_BYTE_COUNT_OFFSET = 1;
static const size_t DEVICE3_LINE_SIZE = 8;
static const size_t DEVICE3_TX_MAX_HDR_LEN = uhd::transport::vrt::chdr::max_if_hdr_words64 * sizeof(uint64_t); // Bytes
static const size_t DEVICE3_RX_MAX_HDR_LEN = uhd::transport::vrt::chdr::max_if_hdr_words64 * sizeof(uint64_t); // Bytes
// This class manages the lifetime of the TX async message handler task, transports, and terminator
class device3_send_packet_streamer : public uhd::transport::sph::send_packet_streamer
{
public:
device3_send_packet_streamer(
const size_t max_num_samps,
const uhd::rfnoc::tx_stream_terminator::sptr terminator,
const both_xports_t data_xport,
const both_xports_t async_msg_xport
) :
uhd::transport::sph::send_packet_streamer(max_num_samps),
_terminator(terminator),
_data_xport(data_xport),
_async_msg_xport(async_msg_xport)
{}
~device3_send_packet_streamer()
{
// Make sure the async task is destroyed before the transports
_tx_async_msg_tasks.clear();
}
uhd::rfnoc::tx_stream_terminator::sptr get_terminator()
{
return _terminator;
}
void add_async_msg_task(task::sptr task)
{
_tx_async_msg_tasks.push_back(task);
}
private:
uhd::rfnoc::tx_stream_terminator::sptr _terminator;
both_xports_t _data_xport;
both_xports_t _async_msg_xport;
std::vector<task::sptr> _tx_async_msg_tasks;
};
// This class manages the lifetime of the RX transports and terminator and provides access to both
class device3_recv_packet_streamer : public uhd::transport::sph::recv_packet_streamer
{
public:
device3_recv_packet_streamer(
const size_t max_num_samps,
const uhd::rfnoc::rx_stream_terminator::sptr terminator,
const both_xports_t xport
) :
uhd::transport::sph::recv_packet_streamer(max_num_samps),
_terminator(terminator),
_xport(xport) {}
~device3_recv_packet_streamer() {}
both_xports_t get_xport()
{
return _xport;
}
uhd::rfnoc::rx_stream_terminator::sptr get_terminator()
{
return _terminator;
}
private:
uhd::rfnoc::rx_stream_terminator::sptr _terminator;
both_xports_t _xport;
};
class device3_impl : public uhd::device3, public boost::enable_shared_from_this<device3_impl>
{
public:
/***********************************************************************
* device3-specific Types
**********************************************************************/
typedef uhd::transport::bounded_buffer<uhd::async_metadata_t> async_md_type;
//! The purpose of a transport
enum xport_type_t {
CTRL = 0,
ASYNC_MSG,
TX_DATA,
RX_DATA
};
enum xport_t {AXI, ETH, PCIE};
//! Stores all streaming-related options
struct stream_options_t
{
//! Max size of the header in bytes for TX
size_t tx_max_len_hdr;
//! Max size of the header in bytes for RX
size_t rx_max_len_hdr;
//! How often we send ACKs to the upstream block per one full FC window
size_t rx_fc_request_freq;
//! How often the downstream block should send ACKs per one full FC window
size_t tx_fc_response_freq;
stream_options_t(void)
: tx_max_len_hdr(DEVICE3_TX_MAX_HDR_LEN)
, rx_max_len_hdr(DEVICE3_RX_MAX_HDR_LEN)
, rx_fc_request_freq(DEVICE3_RX_FC_REQUEST_FREQ)
, tx_fc_response_freq(DEVICE3_TX_FC_RESPONSE_FREQ)
{}
};
/***********************************************************************
* I/O Interface
**********************************************************************/
uhd::tx_streamer::sptr get_tx_stream(const uhd::stream_args_t &);
uhd::rx_streamer::sptr get_rx_stream(const uhd::stream_args_t &);
bool recv_async_msg(uhd::async_metadata_t &async_metadata, double timeout);
/***********************************************************************
* Other public APIs
**********************************************************************/
rfnoc::graph::sptr create_graph(const std::string &name="");
protected:
/***********************************************************************
* Structors
**********************************************************************/
device3_impl();
virtual ~device3_impl() {}
/***********************************************************************
* Streaming-related
**********************************************************************/
// The 'rate' argument is so we can use these as subscribers to rate changes
public: // TODO make these protected again
void update_rx_streamers(double rate=-1.0);
void update_tx_streamers(double rate=-1.0);
protected:
/***********************************************************************
* Transport-related
**********************************************************************/
stream_options_t stream_options;
/*! \brief Create a transport to a given endpoint.
*
* \param address The endpoint address of the block we're creating a transport to.
* The source address in this value is not considered, only the
* destination address.
* \param xport_type Specify which kind of transport this is.
* \param args Additional arguments for the transport generation. See \ref page_transport
* for valid arguments.
*/
virtual uhd::both_xports_t make_transport(
const uhd::sid_t &address,
const xport_type_t xport_type,
const uhd::device_addr_t& args
) = 0;
virtual uhd::device_addr_t get_tx_hints(size_t) { return uhd::device_addr_t(); }
virtual uhd::device_addr_t get_rx_hints(size_t) { return uhd::device_addr_t(); }
//! Is called after a streamer is generated
virtual void post_streamer_hooks(uhd::direction_t) {}
/***********************************************************************
* Channel-related
**********************************************************************/
/*! Merge a list of channels into the existing channel definition.
*
* Intelligently merge the channels described in \p chan_ids
* into the current channel definition. If none of the channels in
* \p chan_ids is in the current definition, they simply get appended.
* Otherwise, they get overwritten in the order of \p chan_ids.
*
* \param chan_ids List of block IDs for the channels.
* \param chan_args New channel args. Must have same length as chan_ids.
*
*/
void merge_channel_defs(
const std::vector<rfnoc::block_id_t> &chan_ids,
const std::vector<uhd::device_addr_t> &chan_args,
const uhd::direction_t dir
);
/***********************************************************************
* RFNoC-Specific
**********************************************************************/
void enumerate_rfnoc_blocks(
size_t device_index,
size_t n_blocks,
size_t base_port,
const uhd::sid_t &base_sid,
uhd::device_addr_t transport_args
);
/***********************************************************************
* Members
**********************************************************************/
// TODO: Maybe move these to private
uhd::dict<std::string, boost::weak_ptr<uhd::rx_streamer> > _rx_streamers;
uhd::dict<std::string, boost::weak_ptr<uhd::tx_streamer> > _tx_streamers;
private:
/***********************************************************************
* Private Members
**********************************************************************/
//! Buffer for async metadata
boost::shared_ptr<async_md_type> _async_md;
//! This mutex locks the get_xx_stream() functions.
boost::mutex _transport_setup_mutex;
};
}} /* namespace uhd::usrp */
#endif /* INCLUDED_DEVICE3_IMPL_HPP */
|