aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp
blob: fc0d19a0a76ca8f373e3ec0a42c69d009346cf54 (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
324
325
326
327
328
329
330
331
332
//
// Copyright 2019 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: GPL-3.0-or-later
//

#include <uhd/rfnoc/defaults.hpp>
#include <uhd/rfnoc/radio_control.hpp>
#include <unordered_map>
#include <mutex>

#define RFNOC_RADIO_CONSTRUCTOR(CLASS_NAME) \
    CLASS_NAME##_impl(make_args_ptr make_args) : radio_control_impl(std::move(make_args))

namespace uhd { namespace rfnoc {

/*! Base class of radio controllers
 *
 * All radio control classes should derive from this class (e.g., the X300 radio
 * controller, etc.)
 *
 * Many of the radio_control API calls have virtual (default) implementations
 * here, but they can be overridden.
 */
class radio_control_impl : public radio_control
{
public:
    /**************************************************************************
     * Structors
     *************************************************************************/
    radio_control_impl(make_args_ptr make_args);

    virtual void deinit() {}

    virtual ~radio_control_impl() {}

    /**************************************************************************
     * Stream control API calls
     *************************************************************************/
    void issue_stream_cmd(const uhd::stream_cmd_t& stream_cmd, const size_t port);

    /**************************************************************************
     * Rate-Related API Calls
     *************************************************************************/
    virtual double set_rate(const double rate);
    virtual double get_rate() const;
    virtual meta_range_t get_rate_range() const;

    /**************************************************************************
     * RF-specific API calls
     *************************************************************************/
    // Setters
    virtual void set_tx_antenna(const std::string &ant, const size_t chan);
    virtual void set_rx_antenna(const std::string &ant, const size_t chan);
    virtual double set_tx_frequency(const double freq, const size_t chan);
    virtual double set_rx_frequency(const double freq, const size_t chan);
    virtual void set_tx_tune_args(const uhd::device_addr_t&, const size_t chan);
    virtual void set_rx_tune_args(const uhd::device_addr_t&, const size_t chan);
    virtual double set_tx_gain(const double gain, const size_t chan);
    virtual double set_tx_gain(const double gain, const std::string& name, const size_t chan);
    virtual double set_rx_gain(const double gain, const size_t chan);
    virtual double set_rx_gain(const double gain, const std::string& name, const size_t chan);
    virtual void set_rx_agc(const bool enable, const size_t chan);
    virtual double set_tx_bandwidth(const double bandwidth, const size_t chan);
    virtual double set_rx_bandwidth(const double bandwidth, const size_t chan);
    virtual void set_tx_gain_profile(const std::string& profile, const size_t chan);
    virtual void set_rx_gain_profile(const std::string& profile, const size_t chan);

    // Getters
    virtual std::string get_tx_antenna(const size_t chan) const;
    virtual std::string get_rx_antenna(const size_t chan) const;
    virtual std::vector<std::string> get_tx_antennas(const size_t chan) const;
    virtual std::vector<std::string> get_rx_antennas(const size_t chan) const;
    virtual double get_tx_frequency(const size_t);
    virtual double get_rx_frequency(const size_t);
    virtual uhd::freq_range_t get_tx_frequency_range(const size_t chan) const;
    virtual uhd::freq_range_t get_rx_frequency_range(const size_t chan) const;
    virtual std::vector<std::string> get_tx_gain_names(const size_t) const;
    virtual std::vector<std::string> get_rx_gain_names(const size_t) const;
    virtual double get_tx_gain(const size_t);
    virtual double get_tx_gain(const std::string&, size_t);
    virtual double get_rx_gain(const size_t);
    virtual double get_rx_gain(const std::string&, size_t);
    virtual uhd::gain_range_t get_tx_gain_range(const size_t) const;
    virtual uhd::gain_range_t get_tx_gain_range(const std::string&, const size_t) const;
    virtual uhd::gain_range_t get_rx_gain_range(const size_t) const;
    virtual uhd::gain_range_t get_rx_gain_range(const std::string&, const size_t) const;
    virtual std::vector<std::string> get_tx_gain_profile_names(const size_t chan) const;
    virtual std::vector<std::string> get_rx_gain_profile_names(const size_t chan) const;
    virtual std::string get_tx_gain_profile(const size_t chan) const;
    virtual std::string get_rx_gain_profile(const size_t chan) const;
    virtual double get_tx_bandwidth(const size_t);
    virtual double get_rx_bandwidth(const size_t);
    virtual meta_range_t get_tx_bandwidth_range(size_t chan) const;
    virtual meta_range_t get_rx_bandwidth_range(size_t chan) const;

    /**************************************************************************
     * LO Controls
     *************************************************************************/
    virtual std::vector<std::string> get_rx_lo_names(const size_t chan) const;
    virtual std::vector<std::string> get_rx_lo_sources(
        const std::string& name, const size_t chan) const;
    virtual freq_range_t get_rx_lo_freq_range(
        const std::string& name, const size_t chan) const;
    virtual void set_rx_lo_source(
        const std::string& src, const std::string& name, const size_t chan);
    virtual const std::string get_rx_lo_source(
        const std::string& name, const size_t chan);
    virtual void set_rx_lo_export_enabled(
        bool enabled, const std::string& name, const size_t chan);
    virtual bool get_rx_lo_export_enabled(
        const std::string& name, const size_t chan) const;
    virtual double set_rx_lo_freq(
        double freq, const std::string& name, const size_t chan);
    virtual double get_rx_lo_freq(const std::string& name, const size_t chan);
    virtual std::vector<std::string> get_tx_lo_names(const size_t chan) const;
    virtual std::vector<std::string> get_tx_lo_sources(
        const std::string& name, const size_t chan);
    virtual freq_range_t get_tx_lo_freq_range(
        const std::string& name, const size_t chan);
    virtual void set_tx_lo_source(
        const std::string& src, const std::string& name, const size_t chan);
    virtual const std::string get_tx_lo_source(
        const std::string& name, const size_t chan);
    virtual void set_tx_lo_export_enabled(
        const bool enabled, const std::string& name, const size_t chan);
    virtual bool get_tx_lo_export_enabled(const std::string& name, const size_t chan);
    virtual double set_tx_lo_freq(
        const double freq, const std::string& name, const size_t chan);
    virtual double get_tx_lo_freq(const std::string& name, const size_t chan);

    /**************************************************************************
     * Calibration-Related API Calls
     *************************************************************************/
    virtual void set_tx_dc_offset(const std::complex<double>& offset, size_t chan);
    virtual meta_range_t get_tx_dc_offset_range(size_t chan) const;
    virtual void set_tx_iq_balance(const std::complex<double>& correction, size_t chan);
    virtual void set_rx_dc_offset(const bool enb, size_t chan = ALL_CHANS);
    virtual void set_rx_dc_offset(const std::complex<double>& offset, size_t chan);
    virtual meta_range_t get_rx_dc_offset_range(size_t chan) const;
    virtual void set_rx_iq_balance(const bool enb, size_t chan);
    virtual void set_rx_iq_balance(const std::complex<double>& correction, size_t chan);

    /**************************************************************************
     * GPIO Controls
     *************************************************************************/
    virtual std::vector<std::string> get_gpio_banks() const;
    virtual void set_gpio_attr(const std::string& bank,
        const std::string& attr,
        const uint32_t value,
        const uint32_t mask);
    virtual uint32_t get_gpio_attr(const std::string& bank, const std::string& attr);

    /**************************************************************************
     * Sensor API
     *************************************************************************/
    virtual std::vector<std::string> get_rx_sensor_names(size_t chan) const;
    virtual uhd::sensor_value_t get_rx_sensor(const std::string& name, size_t chan);
    virtual std::vector<std::string> get_tx_sensor_names(size_t chan) const;
    virtual uhd::sensor_value_t get_tx_sensor(const std::string& name, size_t chan);

    /**************************************************************************
     * Identification API
     *************************************************************************/
    virtual std::string get_fe_name(
        const size_t chan, const uhd::direction_t direction) const
    {
        return get_dboard_fe_from_chan(chan, direction);
    }

    /**************************************************************************
     * EEPROM API
     *************************************************************************/
    virtual void set_db_eeprom(const uhd::eeprom_map_t& db_eeprom);
    virtual uhd::eeprom_map_t get_db_eeprom();

    /***********************************************************************
     * Reg Map
     **********************************************************************/
    static const uint16_t MAJOR_COMPAT;
    static const uint16_t MINOR_COMPAT;

    /*! Register map common to all radios
     *
     * See rfnoc_block_radio_regs.vh for details
     */
    struct regmap {
        static const uint32_t REG_COMPAT_NUM = 0x00;  // Compatibility number register offset
        static const uint32_t REG_RADIO_WIDTH   = 0x1000 + 0x04;   // Upper 16 bits is sample width, lower 16 bits is NSPC

        static const uint32_t RADIO_BASE_ADDR = 0x1000;
        static const uint32_t REG_CHAN_OFFSET = 128;
        static const uint32_t RADIO_ADDR_W     = 7;     // Address space size per radio

        // General Radio Registers
        static const uint32_t REG_LOOPBACK_EN   = 0x00;   // Loopback enable (connect Tx output to Rx input)

        // Note on the RX and TX Control Registers: These are per-channel,
        // which means the values here are offsets. The base address per
        // channel is RADIO_BASE_ADDR + i * REG_CHAN_OFFSET, where i is the
        // channel index.

        // RX Control Registers
        static const uint32_t REG_RX_STATUS            = 0x10; // Status of Rx radio
        static const uint32_t REG_RX_CMD               = 0x14; // The next radio command to execute
        static const uint32_t REG_RX_CMD_NUM_WORDS_LO  = 0x18; // Number of radio words for the next command (low word)
        static const uint32_t REG_RX_CMD_NUM_WORDS_HI  = 0x1C; // Number of radio words for the next command (high word)
        static const uint32_t REG_RX_CMD_TIME_LO       = 0x20; // Time for the next command (low word)
        static const uint32_t REG_RX_CMD_TIME_HI       = 0x24; // Time for the next command (high word)
        static const uint32_t REG_RX_MAX_WORDS_PER_PKT = 0x28; // Maximum packet length to build from Rx data
        static const uint32_t REG_RX_ERR_PORT          = 0x2C; // Port ID for error reporting
        static const uint32_t REG_RX_ERR_REM_PORT      = 0x30; // Remote port ID for error reporting
        static const uint32_t REG_RX_ERR_REM_EPID      = 0x34; // Remote EPID (endpoint ID) for error reporting
        static const uint32_t REG_RX_ERR_ADDR          = 0x38; // Offset to which to write error code (ADDR+0) and time (ADDR+8)
        static const uint32_t REG_RX_DATA = 0x3C;

        // TX Control Registers
        static const uint32_t REG_TX_IDLE_VALUE   = 0x40; // Value to output when transmitter is idle
        static const uint32_t REG_TX_ERROR_POLICY = 0x44; // Tx error policy
        static const uint32_t REG_TX_ERR_PORT     = 0x48; // Port ID for error reporting
        static const uint32_t REG_TX_ERR_REM_PORT = 0x4C; // Remote port ID for error reporting
        static const uint32_t REG_TX_ERR_REM_EPID = 0x50; // Remote EPID (endpoint ID) for error reporting
        static const uint32_t REG_TX_ERR_ADDR     = 0x54; // Offset to which to write error code (ADDR+0) and time (ADDR+8)

        static const uint32_t RX_CMD_STOP       = 0; // Stop acquiring at end of next packet
        static const uint32_t RX_CMD_FINITE     = 1; // Acquire NUM_SAMPS then stop
        static const uint32_t RX_CMD_CONTINUOUS = 2; // Acquire until stopped

        static const uint32_t RX_CMD_TIMED_POS = 31;

        static const uint32_t REG_SPI_W = 0x80000 + 168*8; // FIXME
        static const uint32_t REG_SPI_R = 0x80000 + 17*8; // FIXME

        static const uint32_t PERIPH_BASE = 0x80000;
        static const uint32_t PERIPH_REG_OFFSET = 8;

        static const uint32_t SWREG_TX_ERR      = 0x0000;
        static const uint32_t SWREG_RX_ERR      = 0x1000;
        static const uint32_t SWREG_CHAN_OFFSET = 64;
    };

    struct err_codes
    {
        //! Late command (stream command arrived after indicated time)
        static const uint32_t ERR_RX_LATE_CMD = 1;
        //! FIFO overflow
        static const uint32_t ERR_RX_OVERRUN = 2;
        // FIFO underrun (data not available when needed)
        static const uint32_t ERR_TX_UNDERRUN = 1;
        //! Late data (arrived after indicated time)
        static const uint32_t ERR_TX_LATE_DATA = 2;
        //! Acknowledge a TX burst with an EOB
        static const uint32_t EVENT_TX_BURST_ACK = 3;
    };

    //! Tree path to the dboard-specific properties
    static const uhd::fs_path DB_PATH;
    //! Tree path to the radio frontends' properties
    static const uhd::fs_path FE_PATH;

protected:
    /*! Helper function for property propagation: Like set_rate(), but called
     * during a different context.
     *
     * This function is called from the samp_rate property resolver. The
     * difference to set_rate() is that the latter is a user API, and may
     * trigger different kinds of warnings or errors.
     * If the radio supports changing its sampling rate at runtime, it is OK to
     * call set_rate() within this function.
     *
     * Default implementation is to simply return the current rate.
     */
    virtual double coerce_rate(const double /* rate */)
    {
        return _rate;
    }

    //! Properties for samp_rate (one per port)
    std::vector<property_t<double>> _samp_rate_in;
    //! Properties for samp_rate (one per port)
    std::vector<property_t<double>> _samp_rate_out;

private:
    //! Validator for the async messages
    //
    // We only know about overruns, underruns, and late commands/packets.
    bool async_message_validator(uint32_t addr, const std::vector<uint32_t>& data);

    //! Receiver for the async messages
    //
    // This block will receive all async messages. The following async messages
    // are expected to show up:
    // - Overrun info
    // - Underrun info
    // - Late data packets
    void async_message_handler(uint32_t addr,
        const std::vector<uint32_t>& data,
        boost::optional<uint64_t> timestamp);

    //! FPGA compat number
    const uint32_t _fpga_compat;

    //! Copy of the REG_RADIO_WIDTH register
    const uint32_t _radio_width;

    //! Sample width (total width, sc16 == 32 bits per complex sample)
    const uint32_t _samp_width;

    //! Samples per cycle
    const uint32_t _spc;

    std::vector<property_t<int>> _spp_prop;
    //! Properties for type_in (one per port)
    std::vector<property_t<io_type_t>> _type_in;
    //! Properties for type_out (one per port)
    std::vector<property_t<io_type_t>> _type_out;

    mutable std::mutex _cache_mutex;
    double _rate = 1.0;
    std::unordered_map<size_t, std::string> _tx_antenna;
    std::unordered_map<size_t, std::string> _rx_antenna;
    std::unordered_map<size_t, double> _tx_freq;
    std::unordered_map<size_t, double> _rx_freq;
    std::unordered_map<size_t, double> _tx_gain;
    std::unordered_map<size_t, double> _rx_gain;
    std::unordered_map<size_t, double> _tx_bandwidth;
    std::unordered_map<size_t, double> _rx_bandwidth;

    std::vector<uhd::stream_cmd_t> _last_stream_cmd;
};

}} // namespace uhd::rfnoc