Statistics
| Branch: | Tag: | Revision:

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

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 bytes_free;
42
    size_t underrun_poll_samp_count;
43
};
44

    
45
struct usrp1_recv_state {
46
    uhd::transport::managed_recv_buffer::sptr recv_buff;
47
    size_t bytes_read;
48
    size_t bytes_avail;
49
    size_t overrun_poll_samp_count;
50
};
51

    
52
/***********************************************************************
53
 * IO Implementation Details
54
 **********************************************************************/
55
struct usrp1_impl::io_impl {
56
    io_impl();
57
    ~io_impl(void);
58

    
59
    //state handling for buffer management 
60
    usrp1_recv_state recv_state;
61
    usrp1_send_state send_state;
62

    
63
    //send transport management 
64
    bool get_send_buffer(zero_copy_if::sptr zc_if);
65
    size_t copy_convert_send_samps(const void *buff, size_t num_samps,
66
                              size_t sample_offset, const io_type_t io_type,
67
                              otw_type_t otw_type);
68
    bool conditional_buff_commit(bool force);
69
    bool check_underrun(usrp_ctrl::sptr ctrl_if,
70
                        size_t poll_interval, bool force);
71

    
72
    //recv transport management 
73
    bool get_recv_buffer(zero_copy_if::sptr zc_if);
74
    size_t copy_convert_recv_samps(void *buff, size_t num_samps,
75
                              size_t sample_offset, const io_type_t io_type,
76
                              otw_type_t otw_type);
77
    bool check_overrun(usrp_ctrl::sptr ctrl_if,
78
                        size_t poll_interval, bool force);
79
};
80

    
81
usrp1_impl::io_impl::io_impl()
82
{
83
    send_state.send_buff = uhd::transport::managed_send_buffer::sptr();
84
    recv_state.recv_buff = uhd::transport::managed_recv_buffer::sptr();
85
}
86

    
87
usrp1_impl::io_impl::~io_impl(void)
88
{
89
   /* NOP */
90
}
91

    
92
void usrp1_impl::io_init(void)
93
{
94
    _rx_otw_type.width = 16;
95
    _rx_otw_type.shift = 0;
96
    _rx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN;
97

    
98
    _tx_otw_type.width = 16;
99
    _tx_otw_type.shift = 0;
100
    _tx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN;
101

    
102
    _io_impl = UHD_PIMPL_MAKE(io_impl, ());
103
}
104

    
105
/***********************************************************************
106
 * Data Send
107
 **********************************************************************/
108
bool usrp1_impl::io_impl::get_send_buffer(zero_copy_if::sptr zc_if)
109
{
110
    if (send_state.send_buff == NULL) {
111

    
112
        send_state.send_buff = zc_if->get_send_buff();
113
        if (send_state.send_buff == NULL)
114
            return false;
115

    
116
        send_state.bytes_free = send_state.send_buff->size();
117
        send_state.bytes_written = 0;
118
    }
119

    
120
    return true;
121
}
122

    
123
size_t usrp1_impl::io_impl::copy_convert_send_samps(const void *buff,
124
                                                    size_t num_samps,
125
                                                    size_t sample_offset,
126
                                                    const io_type_t io_type,
127
                                                    otw_type_t otw_type)
128
{
129
    UHD_ASSERT_THROW(send_state.bytes_free % otw_type.get_sample_size() == 0);
130

    
131
    size_t samps_free = send_state.bytes_free / otw_type.get_sample_size();
132
    size_t copy_samps = std::min(num_samps - sample_offset, samps_free); 
133

    
134
    const boost::uint8_t *io_mem =
135
        reinterpret_cast<const boost::uint8_t *>(buff);
136

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

    
139
    convert_io_type_to_otw_type(io_mem + sample_offset * io_type.size,
140
                                io_type,
141
                                otw_mem + send_state.bytes_written,
142
                                otw_type,
143
                                copy_samps);
144

    
145
    send_state.bytes_written += copy_samps * otw_type.get_sample_size();
146
    send_state.bytes_free -= copy_samps * otw_type.get_sample_size();
147
    send_state.underrun_poll_samp_count += copy_samps;
148

    
149
    return copy_samps;
150
}
151

    
152
bool usrp1_impl::io_impl::conditional_buff_commit(bool force)
153
{
154
    if (send_state.bytes_written % 512)
155
        return false;
156

    
157
    if (force || send_state.bytes_free == 0) {
158
        send_state.send_buff->commit(send_state.bytes_written);
159
        send_state.send_buff = uhd::transport::managed_send_buffer::sptr();
160
        return true;
161
    }
162
    
163
    return false;
164
}
165

    
166
bool usrp1_impl::io_impl::check_underrun(usrp_ctrl::sptr ctrl_if,
167
                                         size_t poll_interval,
168
                                         bool force)
169
{
170
    unsigned char underrun = 0;
171

    
172
    bool ready_to_poll = send_state.underrun_poll_samp_count > poll_interval;
173

    
174
    if (force || ready_to_poll) {
175
        int ret = ctrl_if->usrp_control_read(VRQ_GET_STATUS,
176
                                             0,
177
                                             GS_TX_UNDERRUN,
178
                                             &underrun, sizeof(char));
179
        if (ret < 0)
180
            std::cerr << "USRP: underrun check failed" << std::endl;
181
        if (underrun)
182
            std::cerr << "U" << std::endl;
183

    
184
        send_state.underrun_poll_samp_count = 0;
185
    }
186

    
187
    return (bool) underrun;
188
}
189

    
190
size_t usrp1_impl::send(const std::vector<const void *> &buffs,
191
                        size_t num_samps,
192
                        const tx_metadata_t &,
193
                        const io_type_t &io_type,
194
                        send_mode_t)
195
{
196
    UHD_ASSERT_THROW(buffs.size() == 1);
197

    
198
    size_t total_samps_sent = 0;
199

    
200
    while (total_samps_sent < num_samps) {
201
        if (!_io_impl->get_send_buffer(_data_transport))
202
            return 0;
203

    
204
        total_samps_sent += _io_impl->copy_convert_send_samps(buffs[0],
205
                                                              num_samps,
206
                                                              total_samps_sent,
207
                                                              io_type,
208
                                                              _tx_otw_type);
209
        if (total_samps_sent == num_samps)
210
            _io_impl->conditional_buff_commit(true);
211
        else
212
            _io_impl->conditional_buff_commit(false);
213

    
214
        _io_impl->check_underrun(_ctrl_transport,
215
                                 _tx_samps_per_poll_interval, false);
216
    }
217

    
218
    return total_samps_sent;
219
}
220

    
221
/***********************************************************************
222
 * Data Recv
223
 **********************************************************************/
224
bool usrp1_impl::io_impl::get_recv_buffer(zero_copy_if::sptr zc_if)
225
{
226
    if ((recv_state.recv_buff == NULL) || (recv_state.bytes_avail == 0)) {
227

    
228
        recv_state.recv_buff = zc_if->get_recv_buff();
229
        if (recv_state.recv_buff == NULL)
230
            return false;
231

    
232
        recv_state.bytes_read = 0;
233
        recv_state.bytes_avail = recv_state.recv_buff->size();
234
    }
235

    
236
    return true;
237
}
238

    
239
size_t usrp1_impl::io_impl::copy_convert_recv_samps(void *buff,
240
                                                    size_t num_samps,
241
                                                    size_t sample_offset,
242
                                                    const io_type_t io_type,
243
                                                    otw_type_t otw_type)
244
{
245
    UHD_ASSERT_THROW(recv_state.bytes_avail % otw_type.get_sample_size() == 0);
246

    
247
    size_t samps_avail = recv_state.bytes_avail / otw_type.get_sample_size();
248
    size_t copy_samps = std::min(num_samps - sample_offset, samps_avail); 
249

    
250
    const boost::uint8_t *otw_mem =
251
        recv_state.recv_buff->cast<const boost::uint8_t *>();
252

    
253
    boost::uint8_t *io_mem = reinterpret_cast<boost::uint8_t *>(buff);
254

    
255
    convert_otw_type_to_io_type(otw_mem + recv_state.bytes_read,
256
                                otw_type,
257
                                io_mem + sample_offset * io_type.size,
258
                                io_type,
259
                                copy_samps);
260

    
261
    recv_state.bytes_read += copy_samps * otw_type.get_sample_size();
262
    recv_state.bytes_avail -= copy_samps * otw_type.get_sample_size();
263
    recv_state.overrun_poll_samp_count += copy_samps;
264

    
265
    return copy_samps;
266
}
267

    
268
bool usrp1_impl::io_impl::check_overrun(usrp_ctrl::sptr ctrl_if,
269
                                        size_t poll_interval,
270
                                        bool force)
271
{
272
    unsigned char overrun = 0;
273

    
274
    bool ready_to_poll = recv_state.overrun_poll_samp_count > poll_interval;
275

    
276
    if (force || ready_to_poll) {
277
        int ret = ctrl_if->usrp_control_read(VRQ_GET_STATUS,
278
                                             0,
279
                                             GS_RX_OVERRUN,
280
                                             &overrun, sizeof(char));
281
        if (ret < 0)
282
            std::cerr << "USRP: overrrun check failed" << std::endl;
283
        if (overrun)
284
            std::cerr << "O" << std::endl;
285

    
286
        recv_state.overrun_poll_samp_count = 0;
287
    }
288

    
289
    return (bool) overrun;
290
}
291

    
292
size_t usrp1_impl::recv(const std::vector<void *> &buffs,
293
                        size_t num_samps,
294
                        rx_metadata_t &,
295
                        const io_type_t &io_type,
296
                        recv_mode_t,
297
                        size_t)
298
{
299
    UHD_ASSERT_THROW(buffs.size() == 1);
300

    
301
    size_t total_samps_recv = 0;
302

    
303
    while (total_samps_recv < num_samps) {
304

    
305
        if (!_io_impl->get_recv_buffer(_data_transport))
306
            return 0;
307

    
308
        total_samps_recv += _io_impl->copy_convert_recv_samps(buffs[0],
309
                                                              num_samps,
310
                                                              total_samps_recv,
311
                                                              io_type,
312
                                                              _rx_otw_type);
313
        _io_impl->check_overrun(_ctrl_transport,
314
                                _rx_samps_per_poll_interval, false);
315
    }
316

    
317
    return total_samps_recv; 
318
}