Statistics
| Branch: | Tag: | Revision:

root / host / lib / usrp / usrp1 / io_impl.cpp @ 9449d057

History | View | Annotate | Download (10.8 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 "../../transport/vrt_packet_handler.hpp"
19
#include "usrp_commands.h"
20
#include "usrp1_impl.hpp"
21
#include <uhd/utils/thread_priority.hpp>
22
#include <uhd/transport/convert_types.hpp>
23
#include <uhd/transport/bounded_buffer.hpp>
24
#include <boost/bind.hpp>
25
#include <boost/format.hpp>
26
#include <boost/asio.hpp>
27
#include <boost/bind.hpp>
28
#include <boost/thread.hpp>
29
#include <iostream>
30

    
31
using namespace uhd;
32
using namespace uhd::usrp;
33
using namespace uhd::transport;
34
namespace asio = boost::asio;
35

    
36
static const float poll_interval = 0.1;  //100ms
37

    
38
struct usrp1_send_state {
39
    uhd::transport::managed_send_buffer::sptr send_buff;
40
    size_t bytes_written;
41
    size_t underrun_poll_samp_count;
42

    
43
    size_t bytes_free()
44
    {
45
        if (send_buff != NULL)
46
            return send_buff->size() - bytes_written;
47
        else
48
            return 0;
49
    }
50
};
51

    
52
struct usrp1_recv_state {
53
    uhd::transport::managed_recv_buffer::sptr recv_buff;
54
    size_t bytes_read;
55
    size_t overrun_poll_samp_count;
56

    
57
    size_t bytes_avail()
58
    {
59
        if (recv_buff != NULL)
60
            return recv_buff->size() - bytes_read;
61
        else
62
            return 0;
63
    }
64
};
65

    
66
/***********************************************************************
67
 * IO Implementation Details
68
 **********************************************************************/
69
struct usrp1_impl::io_impl {
70
    io_impl();
71
    ~io_impl(void);
72

    
73
    //state handling for buffer management 
74
    usrp1_recv_state recv_state;
75
    usrp1_send_state send_state;
76

    
77
    //send transport management 
78
    bool get_send_buffer(zero_copy_if::sptr zc_if);
79
    size_t copy_convert_send_samps(const void *buff, size_t num_samps,
80
                              size_t sample_offset, const io_type_t io_type,
81
                              otw_type_t otw_type);
82
    bool conditional_buff_commit(bool force);
83
    bool check_underrun(usrp_ctrl::sptr ctrl_if,
84
                        size_t poll_interval, bool force);
85

    
86
    //recv transport management 
87
    bool get_recv_buffer(zero_copy_if::sptr zc_if);
88
    size_t copy_convert_recv_samps(void *buff, size_t num_samps,
89
                              size_t sample_offset, const io_type_t io_type,
90
                              otw_type_t otw_type);
91
    bool check_overrun(usrp_ctrl::sptr ctrl_if,
92
                        size_t poll_interval, bool force);
93
};
94

    
95
usrp1_impl::io_impl::io_impl()
96
{
97
    send_state.send_buff = uhd::transport::managed_send_buffer::sptr();
98
    recv_state.recv_buff = uhd::transport::managed_recv_buffer::sptr();
99
}
100

    
101
usrp1_impl::io_impl::~io_impl(void)
102
{
103
   /* NOP */
104
}
105

    
106
void usrp1_impl::io_init(void)
107
{
108
    _rx_otw_type.width = 16;
109
    _rx_otw_type.shift = 0;
110
    _rx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN;
111

    
112
    _tx_otw_type.width = 16;
113
    _tx_otw_type.shift = 0;
114
    _tx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN;
115

    
116
    _io_impl = UHD_PIMPL_MAKE(io_impl, ());
117
}
118

    
119
/***********************************************************************
120
 * Data Send
121
 **********************************************************************/
122
bool usrp1_impl::io_impl::get_send_buffer(zero_copy_if::sptr zc_if)
123
{
124
    if (send_state.send_buff == NULL) {
125

    
126
        send_state.send_buff = zc_if->get_send_buff();
127
        if (send_state.send_buff == NULL)
128
            return false;
129

    
130
        send_state.bytes_written = 0;
131
    }
132

    
133
    return true;
134
}
135

    
136
size_t usrp1_impl::io_impl::copy_convert_send_samps(const void *buff,
137
                                                    size_t num_samps,
138
                                                    size_t sample_offset,
139
                                                    const io_type_t io_type,
140
                                                    otw_type_t otw_type)
141
{
142
    UHD_ASSERT_THROW(send_state.bytes_free() % otw_type.get_sample_size() == 0);
143

    
144
    size_t samps_free = send_state.bytes_free() / otw_type.get_sample_size();
145
    size_t copy_samps = std::min(num_samps - sample_offset, samps_free); 
146

    
147
    const boost::uint8_t *io_mem =
148
        reinterpret_cast<const boost::uint8_t *>(buff);
149

    
150
    boost::uint8_t *otw_mem = send_state.send_buff->cast<boost::uint8_t *>();
151

    
152
    convert_io_type_to_otw_type(io_mem + sample_offset * io_type.size,
153
                                io_type,
154
                                otw_mem + send_state.bytes_written,
155
                                otw_type,
156
                                copy_samps);
157

    
158
    send_state.bytes_written += copy_samps * otw_type.get_sample_size();
159
    send_state.underrun_poll_samp_count += copy_samps;
160

    
161
    return copy_samps;
162
}
163

    
164
bool usrp1_impl::io_impl::conditional_buff_commit(bool force)
165
{
166
    if (send_state.bytes_written % 512)
167
        return false;
168

    
169
    if (force || send_state.bytes_free() == 0) {
170
        send_state.send_buff->commit(send_state.bytes_written);
171
        send_state.send_buff = uhd::transport::managed_send_buffer::sptr();
172
        return true;
173
    }
174
    
175
    return false;
176
}
177

    
178
bool usrp1_impl::io_impl::check_underrun(usrp_ctrl::sptr ctrl_if,
179
                                         size_t poll_interval,
180
                                         bool force)
181
{
182
    unsigned char underrun = 0;
183

    
184
    bool ready_to_poll = send_state.underrun_poll_samp_count > poll_interval;
185

    
186
    if (force || ready_to_poll) {
187
        int ret = ctrl_if->usrp_control_read(VRQ_GET_STATUS,
188
                                             0,
189
                                             GS_TX_UNDERRUN,
190
                                             &underrun, sizeof(char));
191
        if (ret < 0)
192
            std::cerr << "USRP: underrun check failed" << std::endl;
193
        if (underrun)
194
            std::cerr << "U" << std::endl;
195

    
196
        send_state.underrun_poll_samp_count = 0;
197
    }
198

    
199
    return (bool) underrun;
200
}
201

    
202
size_t usrp1_impl::send(const std::vector<const void *> &buffs,
203
                        size_t num_samps,
204
                        const tx_metadata_t &,
205
                        const io_type_t &io_type,
206
                        send_mode_t)
207
{
208
    UHD_ASSERT_THROW(buffs.size() == 1);
209

    
210
    size_t total_samps_sent = 0;
211

    
212
    while (total_samps_sent < num_samps) {
213
        if (!_io_impl->get_send_buffer(_data_transport))
214
            return 0;
215

    
216
        total_samps_sent += _io_impl->copy_convert_send_samps(buffs[0],
217
                                                              num_samps,
218
                                                              total_samps_sent,
219
                                                              io_type,
220
                                                              _tx_otw_type);
221
        if (total_samps_sent == num_samps)
222
            _io_impl->conditional_buff_commit(true);
223
        else
224
            _io_impl->conditional_buff_commit(false);
225

    
226
        _io_impl->check_underrun(_ctrl_transport,
227
                                 _tx_samps_per_poll_interval, false);
228
    }
229

    
230
    return total_samps_sent;
231
}
232

    
233
/***********************************************************************
234
 * Data Recv
235
 **********************************************************************/
236
bool usrp1_impl::io_impl::get_recv_buffer(zero_copy_if::sptr zc_if)
237
{
238
    if ((recv_state.recv_buff == NULL) || (recv_state.bytes_avail() == 0)) {
239

    
240
        recv_state.recv_buff = zc_if->get_recv_buff();
241
        if (recv_state.recv_buff == NULL)
242
            return false;
243

    
244
        recv_state.bytes_read = 0;
245
    }
246

    
247
    return true;
248
}
249

    
250
size_t usrp1_impl::io_impl::copy_convert_recv_samps(void *buff,
251
                                                    size_t num_samps,
252
                                                    size_t sample_offset,
253
                                                    const io_type_t io_type,
254
                                                    otw_type_t otw_type)
255
{
256
    UHD_ASSERT_THROW(recv_state.bytes_avail() % otw_type.get_sample_size() == 0);
257

    
258
    size_t samps_avail = recv_state.bytes_avail() / otw_type.get_sample_size();
259
    size_t copy_samps = std::min(num_samps - sample_offset, samps_avail); 
260

    
261
    const boost::uint8_t *otw_mem =
262
        recv_state.recv_buff->cast<const boost::uint8_t *>();
263

    
264
    boost::uint8_t *io_mem = reinterpret_cast<boost::uint8_t *>(buff);
265

    
266
    convert_otw_type_to_io_type(otw_mem + recv_state.bytes_read,
267
                                otw_type,
268
                                io_mem + sample_offset * io_type.size,
269
                                io_type,
270
                                copy_samps);
271

    
272
    recv_state.bytes_read += copy_samps * otw_type.get_sample_size();
273
    recv_state.overrun_poll_samp_count += copy_samps;
274

    
275
    return copy_samps;
276
}
277

    
278
bool usrp1_impl::io_impl::check_overrun(usrp_ctrl::sptr ctrl_if,
279
                                        size_t poll_interval,
280
                                        bool force)
281
{
282
    unsigned char overrun = 0;
283

    
284
    bool ready_to_poll = recv_state.overrun_poll_samp_count > poll_interval;
285

    
286
    if (force || ready_to_poll) {
287
        int ret = ctrl_if->usrp_control_read(VRQ_GET_STATUS,
288
                                             0,
289
                                             GS_RX_OVERRUN,
290
                                             &overrun, sizeof(char));
291
        if (ret < 0)
292
            std::cerr << "USRP: overrrun check failed" << std::endl;
293
        if (overrun)
294
            std::cerr << "O" << std::endl;
295

    
296
        recv_state.overrun_poll_samp_count = 0;
297
    }
298

    
299
    return (bool) overrun;
300
}
301

    
302
size_t usrp1_impl::recv(const std::vector<void *> &buffs,
303
                        size_t num_samps,
304
                        rx_metadata_t &,
305
                        const io_type_t &io_type,
306
                        recv_mode_t,
307
                        size_t)
308
{
309
    UHD_ASSERT_THROW(buffs.size() == 1);
310

    
311
    size_t total_samps_recv = 0;
312

    
313
    while (total_samps_recv < num_samps) {
314

    
315
        if (!_io_impl->get_recv_buffer(_data_transport))
316
            return 0;
317

    
318
        total_samps_recv += _io_impl->copy_convert_recv_samps(buffs[0],
319
                                                              num_samps,
320
                                                              total_samps_recv,
321
                                                              io_type,
322
                                                              _rx_otw_type);
323
        _io_impl->check_overrun(_ctrl_transport,
324
                                _rx_samps_per_poll_interval, false);
325
    }
326

    
327
    return total_samps_recv; 
328
}