aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/x300/x300_impl.hpp
blob: 37f8cc4689f30ce770dd33680763a50fc8a64044 (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
//
// Copyright 2013-2014 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#ifndef INCLUDED_X300_IMPL_HPP
#define INCLUDED_X300_IMPL_HPP

#include <uhd/property_tree.hpp>
#include <uhd/device.hpp>
#include <uhd/usrp/mboard_eeprom.hpp>
#include <uhd/usrp/dboard_manager.hpp>
#include <uhd/usrp/dboard_eeprom.hpp>
#include <uhd/usrp/subdev_spec.hpp>
#include <uhd/types/sensors.hpp>
#include "x300_clock_ctrl.hpp"
#include "x300_fw_common.h"
#include <uhd/transport/udp_simple.hpp> //mtu
#include <uhd/utils/tasks.hpp>
#include "spi_core_3000.hpp"
#include "x300_adc_ctrl.hpp"
#include "x300_dac_ctrl.hpp"
#include "rx_vita_core_3000.hpp"
#include "tx_vita_core_3000.hpp"
#include "time_core_3000.hpp"
#include "rx_dsp_core_3000.hpp"
#include "tx_dsp_core_3000.hpp"
#include "i2c_core_100_wb32.hpp"
#include "radio_ctrl_core_3000.hpp"
#include "rx_frontend_core_200.hpp"
#include "tx_frontend_core_200.hpp"
#include "gpio_core_200.hpp"
#include <boost/weak_ptr.hpp>
#include <uhd/usrp/gps_ctrl.hpp>
#include <uhd/usrp/mboard_eeprom.hpp>
#include <uhd/transport/bounded_buffer.hpp>
#include <uhd/transport/nirio/niusrprio_session.h>
#include <uhd/transport/vrt_if_packet.hpp>
#include "recv_packet_demuxer_3000.hpp"

static const std::string X300_FW_FILE_NAME  = "usrp_x300_fw.bin";

static const double X300_DEFAULT_TICK_RATE      = 200e6;        //Hz
static const double X300_BUS_CLOCK_RATE         = 175e6;        //Hz

static const size_t X300_TX_HW_BUFF_SIZE        = 0x90000;      //576KiB
static const size_t X300_TX_FC_RESPONSE_FREQ    = 8;            //per flow-control window

static const size_t X300_RX_SW_BUFF_SIZE_ETH        = 0x2000000; //32MiB    For an ~8k MTU any size >32MiB is just wasted buffer space
static const size_t X300_RX_SW_BUFF_SIZE_ETH_MACOS  = 0x100000;  //1Mib
static const double X300_RX_SW_BUFF_FULL_FACTOR     = 0.90;      //Buffer should ideally be 90% full.
static const size_t X300_RX_FC_REQUEST_FREQ         = 32;        //per flow-control window

static const size_t X300_PCIE_DATA_FRAME_SIZE   = 8192;          //bytes
static const size_t X300_PCIE_DATA_NUM_FRAMES   = 2048;
static const size_t X300_PCIE_MSG_FRAME_SIZE    = 256;           //bytes
static const size_t X300_PCIE_MSG_NUM_FRAMES    = 32;

static const size_t X300_ETH_DATA_FRAME_SIZE    = 8000;                             //bytes
static const size_t X300_ETH_DATA_NUM_FRAMES    = 32;
static const size_t X300_ETH_MSG_FRAME_SIZE     = uhd::transport::udp_simple::mtu;  //bytes
static const size_t X300_ETH_MSG_NUM_FRAMES     = 32;
static const double X300_DEFAULT_SYSREF_RATE    = 10e6;

#define X300_RADIO_DEST_PREFIX_TX 0
#define X300_RADIO_DEST_PREFIX_CTRL 1
#define X300_RADIO_DEST_PREFIX_RX 2

#define X300_XB_DST_E0 0
#define X300_XB_DST_E1 1
#define X300_XB_DST_R0 2
#define X300_XB_DST_R1 3
#define X300_XB_DST_CE0 4
#define X300_XB_DST_CE1 5
#define X300_XB_DST_CE2 5
#define X300_XB_DST_PCI 7

#define X300_DEVICE_THERE 2
#define X300_DEVICE_HERE 0

//eeprom addrs for various boards
enum
{
    X300_DB0_RX_EEPROM = 0x5,
    X300_DB0_TX_EEPROM = 0x4,
    X300_DB0_GDB_EEPROM = 0x1,
    X300_DB1_RX_EEPROM = 0x7,
    X300_DB1_TX_EEPROM = 0x6,
    X300_DB1_GDB_EEPROM = 0x3,
};

struct x300_dboard_iface_config_t
{
    gpio_core_200::sptr gpio;
    spi_core_3000::sptr spi;
    size_t rx_spi_slaveno;
    size_t tx_spi_slaveno;
    i2c_core_100_wb32::sptr i2c;
    x300_clock_ctrl::sptr clock;
    x300_clock_which_t which_rx_clk;
    x300_clock_which_t which_tx_clk;
    boost::uint8_t dboard_slot;
};

uhd::usrp::dboard_iface::sptr x300_make_dboard_iface(const x300_dboard_iface_config_t &);
uhd::uart_iface::sptr x300_make_uart_iface(uhd::wb_iface::sptr iface);

uhd::wb_iface::sptr x300_make_ctrl_iface_enet(uhd::transport::udp_simple::sptr udp);
uhd::wb_iface::sptr x300_make_ctrl_iface_pcie(uhd::niusrprio::niriok_proxy& drv_proxy);

class x300_impl : public uhd::device
{
public:
    typedef uhd::transport::bounded_buffer<uhd::async_metadata_t> async_md_type;

    x300_impl(const uhd::device_addr_t &);
    void setup_mb(const size_t which, const uhd::device_addr_t &);
    ~x300_impl(void);

    //the io interface
    uhd::rx_streamer::sptr get_rx_stream(const uhd::stream_args_t &);
    uhd::tx_streamer::sptr get_tx_stream(const uhd::stream_args_t &);

    //support old async call
    bool recv_async_msg(uhd::async_metadata_t &, double);

    // used by x300_find_with_addr to find X300 devices.
    static bool is_claimed(uhd::wb_iface::sptr);

    enum x300_mboard_t {
        USRP_X300_MB, USRP_X310_MB, UNKNOWN
    };
    static x300_mboard_t get_mb_type_from_pcie(const std::string& resource, const std::string& rpc_port);
    static x300_mboard_t get_mb_type_from_eeprom(const uhd::usrp::mboard_eeprom_t& mb_eeprom);

private:
    boost::shared_ptr<async_md_type> _async_md;

    //perifs in the radio core
    struct radio_perifs_t
    {
        radio_ctrl_core_3000::sptr ctrl;
        spi_core_3000::sptr spi;
        x300_adc_ctrl::sptr adc;
        x300_dac_ctrl::sptr dac;
        time_core_3000::sptr time64;
        rx_vita_core_3000::sptr framer;
        rx_dsp_core_3000::sptr ddc;
        tx_vita_core_3000::sptr deframer;
        tx_dsp_core_3000::sptr duc;
        gpio_core_200_32wo::sptr leds;
        rx_frontend_core_200::sptr rx_fe;
        tx_frontend_core_200::sptr tx_fe;
    };

    //overflow recovery impl
    void handle_overflow(radio_perifs_t &perif, boost::weak_ptr<uhd::rx_streamer> streamer);

    //vector of member objects per motherboard
    struct mboard_members_t
    {
        uhd::dict<size_t, boost::weak_ptr<uhd::rx_streamer> > rx_streamers;
        uhd::dict<size_t, boost::weak_ptr<uhd::tx_streamer> > tx_streamers;

        uhd::task::sptr claimer_task;
        std::string addr;
        std::string xport_path;
        int router_dst_here;
        uhd::device_addr_t send_args;
        uhd::device_addr_t recv_args;
        bool if_pkt_is_big_endian;
        uhd::niusrprio::niusrprio_session::sptr  rio_fpga_interface;

        //perifs in the zpu
        uhd::wb_iface::sptr zpu_ctrl;
        spi_core_3000::sptr zpu_spi;
        i2c_core_100_wb32::sptr zpu_i2c;

        //perifs in each radio
        radio_perifs_t radio_perifs[2];
        uhd::usrp::dboard_eeprom_t db_eeproms[8];

        //per mboard frontend mapping
        uhd::usrp::subdev_spec_t rx_fe_map;
        uhd::usrp::subdev_spec_t tx_fe_map;

        //other perifs on mboard
        x300_clock_ctrl::sptr clock;
        uhd::gps_ctrl::sptr gps;
        gpio_core_200::sptr fp_gpio;

        //clock control register bits
        int clock_control_regs__clock_source;
        int clock_control_regs__pps_select;
        int clock_control_regs__pps_out_enb;
        int clock_control_regs__tcxo_enb;
        int clock_control_regs__gpsdo_pwr;
    };
    std::vector<mboard_members_t> _mb;

    //task for periodically reclaiming the device from others
    void claimer_loop(uhd::wb_iface::sptr);

    boost::mutex _transport_setup_mutex;

    void register_loopback_self_test(uhd::wb_iface::sptr iface);

    void setup_radio(const size_t, const size_t which_radio, const std::string &db_name);

    size_t _sid_framer;
    struct sid_config_t
    {
        boost::uint8_t router_addr_there;
        boost::uint8_t dst_prefix; //2bits
        boost::uint8_t router_dst_there;
        boost::uint8_t router_dst_here;
    };
    boost::uint32_t allocate_sid(mboard_members_t &mb, const sid_config_t &config);

    struct both_xports_t
    {
        uhd::transport::zero_copy_if::sptr recv;
        uhd::transport::zero_copy_if::sptr send;
        size_t recv_buff_size;
        size_t send_buff_size;
    };
    both_xports_t make_transport(
        const size_t mb_index,
        const uint8_t& destination,
        const uint8_t& prefix,
        const uhd::device_addr_t& args,
        boost::uint32_t& sid);

    struct mtu_result_t
    {
        size_t recv_mtu;
        size_t send_mtu;
    };

    mtu_result_t determine_mtu(const std::string &addr, const mtu_result_t &user_mtu);

    ////////////////////////////////////////////////////////////////////
    //
    //Caching for transport interface re-use -- like sharing a DMA.
    //The cache is optionally used by make_transport by use-case.
    //The cache maps an ID string to a transport-ish object.
    //The ID string identifies a purpose for the transport.
    //
    //For recv, there is a demux cache, which maps a ID string
    //to a recv demux object. When a demux is used, the underlying transport
    //must never be used outside of the demux. Use demux->make_proxy(sid).
    //
    uhd::dict<std::string, uhd::usrp::recv_packet_demuxer_3000::sptr> _demux_cache;
    //
    //For send, there is a shared send xport, which maps an ID string
    //to a transport capable of sending buffers. Send transports
    //can be shared amongst multiple callers, unlike recv.
    //
    uhd::dict<std::string, uhd::transport::zero_copy_if::sptr> _send_cache;
    //
    ////////////////////////////////////////////////////////////////////

    uhd::dict<std::string, uhd::usrp::dboard_manager::sptr> _dboard_managers;
    uhd::dict<std::string, uhd::usrp::dboard_iface::sptr> _dboard_ifaces;

    void set_rx_fe_corrections(const uhd::fs_path &mb_path, const std::string &fe_name, const double lo_freq);

    void update_rx_subdev_spec(const size_t, const uhd::usrp::subdev_spec_t &spec);
    void update_tx_subdev_spec(const size_t, const uhd::usrp::subdev_spec_t &spec);

    void set_tick_rate(mboard_members_t &, const double);
    void update_tick_rate(mboard_members_t &, const double);
    void update_rx_samp_rate(mboard_members_t&, const size_t, const double);
    void update_tx_samp_rate(mboard_members_t&, const size_t, const double);

    void update_clock_control(mboard_members_t&);
    void set_time_source_out(mboard_members_t&, const bool);
    void update_clock_source(mboard_members_t&, const std::string &);
    void update_time_source(mboard_members_t&, const std::string &);

    uhd::sensor_value_t get_ref_locked(uhd::wb_iface::sptr);

    void set_db_eeprom(uhd::i2c_iface::sptr i2c, const size_t, const uhd::usrp::dboard_eeprom_t &);
    void set_mb_eeprom(uhd::i2c_iface::sptr i2c, const uhd::usrp::mboard_eeprom_t &);

    void check_fw_compat(const uhd::fs_path &mb_path, uhd::wb_iface::sptr iface);
    void check_fpga_compat(const uhd::fs_path &mb_path, uhd::wb_iface::sptr iface);

    void update_atr_leds(gpio_core_200_32wo::sptr, const std::string &ant);
    boost::uint32_t get_fp_gpio(gpio_core_200::sptr, const std::string &);
    void set_fp_gpio(gpio_core_200::sptr, const std::string &, const boost::uint32_t);
};

#endif /* INCLUDED_X300_IMPL_HPP */