aboutsummaryrefslogtreecommitdiffstats
path: root/host/include/uhd/rfnoc/node_ctrl_base.hpp
blob: c94507173af48618cda2dfa0408ffe9fa16c4537 (plain) (blame)
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
//
// Copyright 2014-2016 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
// Copyright 2019 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: GPL-3.0-or-later
//

#ifndef INCLUDED_LIBUHD_NODE_CTRL_BASE_HPP
#define INCLUDED_LIBUHD_NODE_CTRL_BASE_HPP

#include <uhd/rfnoc/constants.hpp>
#include <uhd/types/device_addr.hpp>
#include <uhd/utils/log.hpp>
#include <uhd/utils/noncopyable.hpp>
#include <stdint.h>
#include <boost/enable_shared_from_this.hpp>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
#include <map>
#include <set>

namespace uhd { namespace usrp {
// Forward declaration for friend clause
class device3_impl;
}} // namespace uhd::usrp

namespace uhd { namespace rfnoc {

#define UHD_RFNOC_BLOCK_TRACE() UHD_LOGGER_TRACE("RFNOC")

/*! \brief Abstract base class for streaming nodes.
 *
 */
class UHD_RFNOC_API node_ctrl_base;
class node_ctrl_base : uhd::noncopyable,
                       public boost::enable_shared_from_this<node_ctrl_base>
{
public:
    /***********************************************************************
     * Types
     **********************************************************************/
    typedef boost::shared_ptr<node_ctrl_base> sptr;
    typedef boost::weak_ptr<node_ctrl_base> wptr;
    typedef std::map<size_t, wptr> node_map_t;
    typedef std::pair<size_t, wptr> node_map_pair_t;
    typedef boost::function<void(void)> graph_update_cb_t;

    /***********************************************************************
     * Node control
     **********************************************************************/
    //! Returns a unique string that identifies this block.
    virtual std::string unique_id() const;

    /***********************************************************************
     * Connections
     **********************************************************************/
    /*! Clears the list of connected nodes.
     */
    virtual void clear();

    node_map_t list_downstream_nodes()
    {
        return _downstream_nodes;
    };
    node_map_t list_upstream_nodes()
    {
        return _upstream_nodes;
    };

    /*! Disconnect this node from all neighbouring nodes.
     */
    void disconnect();

    /*! Identify \p output_port as unconnected
     */
    void disconnect_output_port(const size_t output_port);

    /*! Identify \p input_port as unconnected
     */
    void disconnect_input_port(const size_t input_port);

    // TODO we need a more atomic connect procedure, this is too error-prone.

    /*! For an existing connection, store the remote port number.
     *
     * \throws uhd::value_error if \p this_port is not connected.
     */
    void set_downstream_port(const size_t this_port, const size_t remote_port);

    /*! Return the remote port of a connection on a given port.
     *
     * \throws uhd::value_error if \p this_port is not connected.
     */
    size_t get_downstream_port(const size_t this_port);

    /*! For an existing connection, store the remote port number.
     *
     * \throws uhd::value_error if \p this_port is not connected.
     */
    void set_upstream_port(const size_t this_port, const size_t remote_port);

    /*! Return the remote port of a connection on a given port.
     *
     * \throws uhd::value_error if \p this_port is not connected.
     */
    size_t get_upstream_port(const size_t this_port);

    /*! Find nodes downstream that match a predicate.
     *
     * Uses a non-recursive breadth-first search algorithm.
     * On every branch, the search stops if a block matches.
     * See this example:
     * <pre>
     * A -> B -> C -> C
     * </pre>
     * Say node A searches for nodes of type C. It will only find the
     * first 'C' block, not the second.
     *
     * Returns blocks that are of type T.
     *
     * Search only goes downstream.
     */
    template <typename T>
    UHD_INLINE std::vector<boost::shared_ptr<T> > find_downstream_node(
        bool active_only = false)
    {
        return _find_child_node<T, true>(active_only);
    }

    /*! Same as find_downstream_node(), but only search upstream.
     */
    template <typename T>
    UHD_INLINE std::vector<boost::shared_ptr<T> > find_upstream_node(
        bool active_only = false)
    {
        return _find_child_node<T, false>(active_only);
    }

    /*! Checks if downstream nodes share a common, unique property.
     *
     * This will use find_downstream_node() to find all nodes downstream of
     * this that are of type T. Then it will use \p get_property to return a
     * property from all of them. If all these properties are identical, it will
     * return that property. Otherwise, it will throw a uhd::runtime_error.
     *
     * \p get_property A functor to return the property from a node
     * \p null_value If \p get_property returns this value, that node is skipped.
     * \p explored_nodes A list of nodes to exclude from the search. This is typically
     *                   to avoid recursion loops.
     */
    template <typename T, typename value_type>
    UHD_INLINE value_type find_downstream_unique_property(
        boost::function<value_type(boost::shared_ptr<T> node, size_t port)> get_property,
        value_type null_value,
        const std::set<boost::shared_ptr<T> >& exclude_nodes =
            std::set<boost::shared_ptr<T> >())
    {
        return _find_unique_property<T, value_type, true>(
            get_property, null_value, exclude_nodes);
    }

    /*! Like find_downstream_unique_property(), but searches upstream.
     */
    template <typename T, typename value_type>
    UHD_INLINE value_type find_upstream_unique_property(
        boost::function<value_type(boost::shared_ptr<T> node, size_t port)> get_property,
        value_type null_value,
        const std::set<boost::shared_ptr<T> >& exclude_nodes =
            std::set<boost::shared_ptr<T> >())
    {
        return _find_unique_property<T, value_type, false>(
            get_property, null_value, exclude_nodes);
    }

protected:
    /***********************************************************************
     * Structors
     **********************************************************************/
    node_ctrl_base(void) : _num_input_ports(0), _num_output_ports(0) {}
    virtual ~node_ctrl_base()
    {
        disconnect();
    }

    /***********************************************************************
     * Protected members
     **********************************************************************/

    //! Stores default arguments
    uhd::device_addr_t _args;

    // TODO make these private

    //! List of upstream nodes
    node_map_t _upstream_nodes;

    //! List of downstream nodes
    node_map_t _downstream_nodes;

    /*! Number of input ports
     */
    size_t _num_input_ports;

    /*! Number of output ports
     */
    size_t _num_output_ports;

    /*! For every output port, store rx streamer activity.
     *
     * If _rx_streamer_active[0] == true, this means that an active rx
     * streamer is operating on port 0. If it is false, or if the entry
     * does not exist, there is no streamer.
     * Values are toggled by set_rx_streamer().
     */
    std::map<size_t, bool> _rx_streamer_active;

    /*! For every input port, store tx streamer activity.
     *
     * If _tx_streamer_active[0] == true, this means that an active tx
     * streamer is operating on port 0. If it is false, or if the entry
     * does not exist, there is no streamer.
     * Values are toggled by set_tx_streamer().
     */
    std::map<size_t, bool> _tx_streamer_active;

    /***********************************************************************
     * Connections
     **********************************************************************/
    /*! Registers another node as downstream of this node, connected to a given port.
     *
     * This implies that this node is a source node, and the downstream node is
     * a sink node.
     * See also uhd::rfnoc::source_node_ctrl::_register_downstream_node().
     */
    virtual void _register_downstream_node(
        node_ctrl_base::sptr downstream_node, size_t port);

    /*! Registers another node as upstream of this node, connected to a given port.
     *
     * This implies that this node is a sink node, and the upstream node is
     * a source node.
     * See also uhd::rfnoc::sink_node_ctrl::_register_upstream_node().
     */
    virtual void _register_upstream_node(node_ctrl_base::sptr upstream_node, size_t port);

    /*! Initiate the update graph callback
     *
     * Call this from your block when you've changed one of these:
     * - sampling rate
     * - scaling
     * - tick rate
     */
    void update_graph()
    {
        _graph_update_cb();
    }

private:
    friend class uhd::usrp::device3_impl;

    /*! Implements the search algorithm for find_downstream_node() and
     * find_upstream_node().
     *
     * Depending on \p downstream, "child nodes" are either defined as
     * nodes connected downstream or upstream.
     *
     * \param downstream Set to true if search goes downstream, false for upstream.
     */
    template <typename T, bool downstream>
    std::vector<boost::shared_ptr<T> > _find_child_node(bool active_only = false);

    /*! Implements the search algorithm for find_downstream_unique_property() and
     * find_upstream_unique_property().
     *
     * Depending on \p downstream, "child nodes" are either defined as
     * nodes connected downstream or upstream.
     *
     * \param downstream Set to true if search goes downstream, false for upstream.
     */
    template <typename T, typename value_type, bool downstream>
    value_type _find_unique_property(
        boost::function<value_type(boost::shared_ptr<T>, size_t)> get_property,
        value_type NULL_VALUE,
        const std::set<boost::shared_ptr<T> >& exclude_nodes);

    void set_graph_update_cb(graph_update_cb_t graph_update_cb)
    {
        _graph_update_cb = graph_update_cb;
    }

    /*! Stores the remote port number of a downstream connection.
     */
    std::map<size_t, size_t> _upstream_ports;

    /*! Stores the remote port number of a downstream connection.
     */
    std::map<size_t, size_t> _downstream_ports;

    graph_update_cb_t _graph_update_cb;

}; /* class node_ctrl_base */

}} /* namespace uhd::rfnoc */

#include <uhd/rfnoc/node_ctrl_base.ipp>

#endif /* INCLUDED_LIBUHD_NODE_CTRL_BASE_HPP */