Statistics
| Branch: | Tag: | Revision:

root / host / lib / usrp / usrp2 / mboard_impl.cpp @ 258d9bb4

History | View | Annotate | Download (12.2 KB)

1
//
2
// Copyright 2010 Ettus Research LLC
3
//
4
// This program is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
//
17

    
18
#include "usrp2_impl.hpp"
19
#include "usrp2_regs.hpp"
20
#include <uhd/usrp/misc_utils.hpp>
21
#include <uhd/usrp/dsp_utils.hpp>
22
#include <uhd/usrp/mboard_props.hpp>
23
#include <uhd/utils/assert.hpp>
24
#include <uhd/utils/algorithm.hpp>
25
#include <boost/bind.hpp>
26
#include <iostream>
27
#include <boost/date_time/posix_time/posix_time.hpp>
28

    
29
using namespace uhd;
30
using namespace uhd::usrp;
31
using namespace boost::posix_time;
32

    
33
/***********************************************************************
34
 * Structors
35
 **********************************************************************/
36
usrp2_mboard_impl::usrp2_mboard_impl(
37
    size_t index,
38
    transport::udp_simple::sptr ctrl_transport,
39
    size_t recv_frame_size
40
):
41
    _index(index),
42
    _recv_frame_size(recv_frame_size),
43
    _iface(usrp2_iface::make(ctrl_transport))
44
{
45
    //contruct the interfaces to mboard perifs
46
    _clock_ctrl = usrp2_clock_ctrl::make(_iface);
47
    _codec_ctrl = usrp2_codec_ctrl::make(_iface);
48
    _serdes_ctrl = usrp2_serdes_ctrl::make(_iface);
49
    //_gps_ctrl = usrp2_gps_ctrl::make(_iface);
50

    
51
    //if(_gps_ctrl->gps_detected()) std::cout << "GPS time: " << _gps_ctrl->get_time() << std::endl;
52

    
53
    //TODO move to dsp impl...
54
    //load the allowed decim/interp rates
55
    //_USRP2_RATES = range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4)
56
    _allowed_decim_and_interp_rates.clear();
57
    for (size_t i = 4; i <= 128; i+=1){
58
        _allowed_decim_and_interp_rates.push_back(i);
59
    }
60
    for (size_t i = 130; i <= 256; i+=2){
61
        _allowed_decim_and_interp_rates.push_back(i);
62
    }
63
    for (size_t i = 260; i <= 512; i+=4){
64
        _allowed_decim_and_interp_rates.push_back(i);
65
    }
66

    
67
    //Issue a stop streaming command (in case it was left running).
68
    //Since this command is issued before the networking is setup,
69
    //most if not all junk packets will never make it to the socket.
70
    this->issue_ddc_stream_cmd(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
71

    
72
    //setup the vrt rx registers
73
    _iface->poke32(_iface->regs.rx_ctrl_nsamps_per_pkt, _recv_frame_size);
74
    _iface->poke32(_iface->regs.rx_ctrl_nchannels, 1);
75
    _iface->poke32(_iface->regs.rx_ctrl_clear_overrun, 1); //reset
76
    _iface->poke32(_iface->regs.rx_ctrl_vrt_header, 0
77
        | (0x1 << 28) //if data with stream id
78
        | (0x1 << 26) //has trailer
79
        | (0x3 << 22) //integer time other
80
        | (0x1 << 20) //fractional time sample count
81
    );
82
    _iface->poke32(_iface->regs.rx_ctrl_vrt_stream_id, 0);
83
    _iface->poke32(_iface->regs.rx_ctrl_vrt_trailer, 0);
84
    _iface->poke32(_iface->regs.time64_tps, size_t(get_master_clock_freq()));
85

    
86
    //init the tx control registers
87
    _iface->poke32(_iface->regs.tx_ctrl_num_chan, 0);    //1 channel
88
    _iface->poke32(_iface->regs.tx_ctrl_clear_state, 1); //reset
89
    _iface->poke32(_iface->regs.tx_ctrl_report_sid, 1);  //sid 1 (different from rx)
90
    _iface->poke32(_iface->regs.tx_ctrl_policy, U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET);
91

    
92
    //init the ddc
93
    init_ddc_config();
94

    
95
    //init the duc
96
    init_duc_config();
97

    
98
    //initialize the clock configuration
99
    init_clock_config();
100

    
101
    //init the codec before the dboard
102
    codec_init();
103

    
104
    //init the tx and rx dboards (do last)
105
    dboard_init();
106

    
107
    //set default subdev specs
108
    (*this)[MBOARD_PROP_RX_SUBDEV_SPEC] = subdev_spec_t();
109
    (*this)[MBOARD_PROP_TX_SUBDEV_SPEC] = subdev_spec_t();
110
}
111

    
112
usrp2_mboard_impl::~usrp2_mboard_impl(void){
113
    /* NOP */
114
}
115

    
116
/***********************************************************************
117
 * Helper Methods
118
 **********************************************************************/
119
void usrp2_mboard_impl::init_clock_config(void){
120
    //setup the clock configuration settings
121
    _clock_config.ref_source = clock_config_t::REF_INT;
122
    _clock_config.pps_source = clock_config_t::PPS_SMA;
123
    _clock_config.pps_polarity = clock_config_t::PPS_NEG;
124

    
125
    //update the clock config (sends a control packet)
126
    update_clock_config();
127
}
128

    
129
void usrp2_mboard_impl::update_clock_config(void){
130
    boost::uint32_t pps_flags = 0;
131

    
132
    //translate pps source enums
133
    switch(_clock_config.pps_source){
134
    case clock_config_t::PPS_SMA:  pps_flags |= U2_FLAG_TIME64_PPS_SMA;  break;
135
    case clock_config_t::PPS_MIMO: pps_flags |= U2_FLAG_TIME64_PPS_MIMO; break;
136
    default: throw std::runtime_error("unhandled clock configuration pps source");
137
    }
138

    
139
    //translate pps polarity enums
140
    switch(_clock_config.pps_polarity){
141
    case clock_config_t::PPS_POS: pps_flags |= U2_FLAG_TIME64_PPS_POSEDGE; break;
142
    case clock_config_t::PPS_NEG: pps_flags |= U2_FLAG_TIME64_PPS_NEGEDGE; break;
143
    default: throw std::runtime_error("unhandled clock configuration pps polarity");
144
    }
145

    
146
    //set the pps flags
147
    _iface->poke32(_iface->regs.time64_flags, pps_flags);
148

    
149
    //clock source ref 10mhz
150
    switch(_iface->get_rev()){
151
    case usrp2_iface::USRP_N200:
152
    case usrp2_iface::USRP_N210:
153
        switch(_clock_config.ref_source){
154
        case clock_config_t::REF_INT : _iface->poke32(_iface->regs.misc_ctrl_clock, 0x12); break;
155
        case clock_config_t::REF_SMA : _iface->poke32(_iface->regs.misc_ctrl_clock, 0x1C); break;
156
        case clock_config_t::REF_MIMO: _iface->poke32(_iface->regs.misc_ctrl_clock, 0x15); break;
157
        default: throw std::runtime_error("unhandled clock configuration reference source");
158
        }
159
        _clock_ctrl->enable_external_ref(true); //USRP2P has an internal 10MHz TCXO
160
        break;
161

    
162
    case usrp2_iface::USRP2_REV3:
163
    case usrp2_iface::USRP2_REV4:
164
        switch(_clock_config.ref_source){
165
        case clock_config_t::REF_INT : _iface->poke32(_iface->regs.misc_ctrl_clock, 0x10); break;
166
        case clock_config_t::REF_SMA : _iface->poke32(_iface->regs.misc_ctrl_clock, 0x1C); break;
167
        case clock_config_t::REF_MIMO: _iface->poke32(_iface->regs.misc_ctrl_clock, 0x15); break;
168
        default: throw std::runtime_error("unhandled clock configuration reference source");
169
        }
170
        _clock_ctrl->enable_external_ref(_clock_config.ref_source != clock_config_t::REF_INT);
171
        break;
172

    
173
    case usrp2_iface::USRP_NXXX: break;
174
    }
175
}
176

    
177
void usrp2_mboard_impl::set_time_spec(const time_spec_t &time_spec, bool now){
178
    //set the ticks
179
    _iface->poke32(_iface->regs.time64_ticks, time_spec.get_tick_count(get_master_clock_freq()));
180

    
181
    //set the flags register
182
    boost::uint32_t imm_flags = (now)? U2_FLAG_TIME64_LATCH_NOW : U2_FLAG_TIME64_LATCH_NEXT_PPS;
183
    _iface->poke32(_iface->regs.time64_imm, imm_flags);
184

    
185
    //set the seconds (latches in all 3 registers)
186
    _iface->poke32(_iface->regs.time64_secs, boost::uint32_t(time_spec.get_full_secs()));
187
}
188

    
189
void usrp2_mboard_impl::handle_overflow(void){
190
    _iface->poke32(_iface->regs.rx_ctrl_clear_overrun, 1);
191
    if (_continuous_streaming){ //re-issue the stream command if already continuous
192
        this->issue_ddc_stream_cmd(stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
193
    }
194
}
195

    
196
void usrp2_mboard_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){
197
    _continuous_streaming = stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS;
198
    _iface->poke32(_iface->regs.rx_ctrl_stream_cmd, dsp_type1::calc_stream_cmd_word(
199
        stream_cmd, _recv_frame_size
200
    ));
201
    _iface->poke32(_iface->regs.rx_ctrl_time_secs,  boost::uint32_t(stream_cmd.time_spec.get_full_secs()));
202
    _iface->poke32(_iface->regs.rx_ctrl_time_ticks, stream_cmd.time_spec.get_tick_count(get_master_clock_freq()));
203
}
204

    
205
/***********************************************************************
206
 * MBoard Get Properties
207
 **********************************************************************/
208
static const std::string dboard_name = "0";
209

    
210
void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){
211
    named_prop_t key = named_prop_t::extract(key_);
212
    //handle the get request conditioned on the key
213
    switch(key.as<mboard_prop_t>()){
214
    case MBOARD_PROP_NAME:
215
        val = _iface->get_cname() + " mboard";
216
        return;
217

    
218
    case MBOARD_PROP_OTHERS:
219
        val = prop_names_t();
220
        return;
221

    
222
    case MBOARD_PROP_RX_DBOARD:
223
        UHD_ASSERT_THROW(key.name == dboard_name);
224
        val = _rx_dboard_proxy->get_link();
225
        return;
226

    
227
    case MBOARD_PROP_RX_DBOARD_NAMES:
228
        val = prop_names_t(1, dboard_name);
229
        return;
230

    
231
    case MBOARD_PROP_TX_DBOARD:
232
        UHD_ASSERT_THROW(key.name == dboard_name);
233
        val = _tx_dboard_proxy->get_link();
234
        return;
235

    
236
    case MBOARD_PROP_TX_DBOARD_NAMES:
237
        val = prop_names_t(1, dboard_name);
238
        return;
239

    
240
    case MBOARD_PROP_RX_DSP:
241
        UHD_ASSERT_THROW(key.name == "");
242
        val = _rx_dsp_proxy->get_link();
243
        return;
244

    
245
    case MBOARD_PROP_RX_DSP_NAMES:
246
        val = prop_names_t(1, "");
247
        return;
248

    
249
    case MBOARD_PROP_TX_DSP:
250
        UHD_ASSERT_THROW(key.name == "");
251
        val = _tx_dsp_proxy->get_link();
252
        return;
253

    
254
    case MBOARD_PROP_TX_DSP_NAMES:
255
        val = prop_names_t(1, "");
256
        return;
257

    
258
    case MBOARD_PROP_CLOCK_CONFIG:
259
        val = _clock_config;
260
        return;
261

    
262
    case MBOARD_PROP_TIME_NOW:{
263
            usrp2_iface::pair64 time64(
264
                _iface->peek64(_iface->regs.time64_secs_rb, _iface->regs.time64_ticks_rb)
265
            );
266
            val = time_spec_t(
267
                time64.first, time64.second, get_master_clock_freq()
268
            );
269
        }
270
        return;
271

    
272
    case MBOARD_PROP_RX_SUBDEV_SPEC:
273
        val = _rx_subdev_spec;
274
        return;
275

    
276
    case MBOARD_PROP_TX_SUBDEV_SPEC:
277
        val = _tx_subdev_spec;
278
        return;
279

    
280
    case MBOARD_PROP_EEPROM_MAP:
281
        val = _iface->mb_eeprom;
282
        return;
283

    
284
    default: UHD_THROW_PROP_GET_ERROR();
285
    }
286
}
287

    
288
/***********************************************************************
289
 * MBoard Set Properties
290
 **********************************************************************/
291
void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){
292
    //handle the set request conditioned on the key
293
    switch(key.as<mboard_prop_t>()){
294

    
295
    case MBOARD_PROP_CLOCK_CONFIG:
296
        _clock_config = val.as<clock_config_t>();
297
        update_clock_config();
298
        return;
299

    
300
    case MBOARD_PROP_TIME_NOW:
301
        set_time_spec(val.as<time_spec_t>(), true);
302
        return;
303

    
304
    case MBOARD_PROP_TIME_NEXT_PPS:
305
        set_time_spec(val.as<time_spec_t>(), false);
306
        return;
307

    
308
    case MBOARD_PROP_STREAM_CMD:
309
        issue_ddc_stream_cmd(val.as<stream_cmd_t>());
310
        return;
311

    
312
    case MBOARD_PROP_RX_SUBDEV_SPEC:
313
        _rx_subdev_spec = val.as<subdev_spec_t>();
314
        verify_rx_subdev_spec(_rx_subdev_spec, this->get_link());
315
        //sanity check
316
        UHD_ASSERT_THROW(_rx_subdev_spec.size() == 1);
317
        //set the mux
318
        _iface->poke32(_iface->regs.dsp_rx_mux, dsp_type1::calc_rx_mux_word(
319
            _dboard_manager->get_rx_subdev(_rx_subdev_spec.front().sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()
320
        ));
321
        return;
322

    
323
    case MBOARD_PROP_TX_SUBDEV_SPEC:
324
        _tx_subdev_spec = val.as<subdev_spec_t>();
325
        verify_tx_subdev_spec(_tx_subdev_spec, this->get_link());
326
        //sanity check
327
        UHD_ASSERT_THROW(_tx_subdev_spec.size() == 1);
328
        //set the mux
329
        _iface->poke32(_iface->regs.dsp_tx_mux, dsp_type1::calc_tx_mux_word(
330
            _dboard_manager->get_tx_subdev(_tx_subdev_spec.front().sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()
331
        ));
332
        return;
333

    
334
    case MBOARD_PROP_EEPROM_MAP:
335
        // Step1: commit the map, writing only those values set.
336
        // Step2: readback the entire eeprom map into the iface.
337
        val.as<mboard_eeprom_t>().commit(*_iface, mboard_eeprom_t::MAP_N100);
338
        _iface->mb_eeprom = mboard_eeprom_t(*_iface, mboard_eeprom_t::MAP_N100);
339
        return;
340

    
341
    default: UHD_THROW_PROP_SET_ERROR();
342
    }
343
}