Statistics
| Branch: | Tag: | Revision:

root / host / lib / usrp / usrp1 / io_impl.cpp @ c9cd9b60

History | View | Annotate | Download (10.7 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
struct usrp1_send_state {
37
    uhd::transport::managed_send_buffer::sptr send_buff;
38
    size_t bytes_written;
39
    size_t underrun_poll_samp_count;
40

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

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

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

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

    
71
    //state handling for buffer management 
72
    usrp1_recv_state recv_state;
73
    usrp1_send_state send_state;
74

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

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

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

    
99
usrp1_impl::io_impl::~io_impl(void)
100
{
101
   /* NOP */
102
}
103

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

    
110
    _tx_otw_type.width = 16;
111
    _tx_otw_type.shift = 0;
112
    _tx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN;
113

    
114
    _io_impl = UHD_PIMPL_MAKE(io_impl, ());
115
}
116

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

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

    
128
        send_state.bytes_written = 0;
129
    }
130

    
131
    return true;
132
}
133

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

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

    
145
    const boost::uint8_t *io_mem =
146
        reinterpret_cast<const boost::uint8_t *>(buff);
147

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

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

    
156
    send_state.bytes_written += copy_samps * otw_type.get_sample_size();
157
    send_state.underrun_poll_samp_count += copy_samps;
158

    
159
    return copy_samps;
160
}
161

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

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

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

    
182
    bool ready_to_poll = send_state.underrun_poll_samp_count > poll_interval;
183

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

    
194
        send_state.underrun_poll_samp_count = 0;
195
    }
196

    
197
    return (bool) underrun;
198
}
199

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

    
208
    size_t total_samps_sent = 0;
209

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

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

    
224
        _io_impl->check_underrun(_ctrl_transport,
225
                                 _tx_samps_per_poll_interval, false);
226
    }
227

    
228
    return total_samps_sent;
229
}
230

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

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

    
242
        recv_state.bytes_read = 0;
243
    }
244

    
245
    return true;
246
}
247

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

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

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

    
262
    boost::uint8_t *io_mem = reinterpret_cast<boost::uint8_t *>(buff);
263

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

    
270
    recv_state.bytes_read += copy_samps * otw_type.get_sample_size();
271
    recv_state.overrun_poll_samp_count += copy_samps;
272

    
273
    return copy_samps;
274
}
275

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

    
282
    bool ready_to_poll = recv_state.overrun_poll_samp_count > poll_interval;
283

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

    
294
        recv_state.overrun_poll_samp_count = 0;
295
    }
296

    
297
    return (bool) overrun;
298
}
299

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

    
309
    size_t total_samps_recv = 0;
310

    
311
    while (total_samps_recv < num_samps) {
312

    
313
        if (!_io_impl->get_recv_buffer(_data_transport))
314
            return 0;
315

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

    
325
    return total_samps_recv; 
326
}