Statistics
| Branch: | Tag: | Revision:

root / host / lib / usrp / usrp1 / io_impl.cpp @ 9cb9e7d5

History | View | Annotate | Download (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
/*
37
 * The FX2 firmware bursts data to the FPGA in 512 byte chunks so
38
 * maintain send state to make sure that happens.
39
 */
40
struct usrp1_send_state {
41
    uhd::transport::managed_send_buffer::sptr send_buff;
42
    size_t bytes_used;
43
    size_t bytes_free;
44
};
45

    
46
/***********************************************************************
47
 * IO Implementation Details
48
 **********************************************************************/
49
struct usrp1_impl::io_impl {
50
    io_impl(zero_copy_if::sptr zc_if);
51
    ~io_impl(void);
52

    
53
    bool get_recv_buff(managed_recv_buffer::sptr buff); 
54

    
55
    //state management for the vrt packet handler code
56
    vrt_packet_handler::recv_state packet_handler_recv_state;
57
    usrp1_send_state send_state;
58

    
59
    zero_copy_if::sptr data_transport;
60
    unsigned int count;
61
};
62

    
63
usrp1_impl::io_impl::io_impl(zero_copy_if::sptr zc_if)
64
 : packet_handler_recv_state(1), data_transport(zc_if), count(0)
65
{
66
    /* NOP */
67
}
68

    
69
usrp1_impl::io_impl::~io_impl(void)
70
{
71
   /* NOP */
72
}
73

    
74
void usrp1_impl::io_init(void)
75
{
76
    _rx_otw_type.width = 16;
77
    _rx_otw_type.shift = 0;
78
    _rx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN;
79

    
80
    _tx_otw_type.width = 16;
81
    _tx_otw_type.shift = 0;
82
    _tx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN;
83

    
84
    _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport));
85
}
86

    
87
/***********************************************************************
88
 * Data Send
89
 **********************************************************************/
90
size_t usrp1_impl::send(const std::vector<const void *> &buffs,
91
                        size_t num_samps,
92
                        const tx_metadata_t &,
93
                        const io_type_t &io_type,
94
                        send_mode_t)
95
{
96
    UHD_ASSERT_THROW(buffs.size() == 1);
97

    
98
    size_t total_samps_sent = 0;
99

    
100
    while (total_samps_sent < num_samps) {
101

    
102
        if (_io_impl->send_state.send_buff == NULL) {
103
            _io_impl->send_state.send_buff = _data_transport->get_send_buff();
104
            if (_io_impl->send_state.send_buff == NULL) {
105
                return 0;
106
            }
107
            _io_impl->send_state.bytes_used = 0;
108
            _io_impl->send_state.bytes_free = _io_impl->send_state.send_buff->size();
109
        }
110

    
111
        size_t copy_samps =
112
               std::min(num_samps - total_samps_sent, _io_impl->send_state.bytes_free / _tx_otw_type.get_sample_size());
113

    
114
        const boost::uint8_t *io_mem =
115
                             reinterpret_cast<const boost::uint8_t *>(buffs[0]);
116

    
117
        boost::uint8_t *otw_mem = _io_impl->send_state.send_buff->cast<boost::uint8_t *>();
118

    
119
        // Type conversion and copy 
120
        convert_io_type_to_otw_type(
121
                     io_mem + total_samps_sent * io_type.size,
122
                     io_type,
123
                     otw_mem + _io_impl->send_state.bytes_used,
124
                     _tx_otw_type,
125
                     copy_samps);
126
 
127
        _io_impl->send_state.bytes_used += copy_samps * _tx_otw_type.get_sample_size();
128
        _io_impl->send_state.bytes_free -= copy_samps * _tx_otw_type.get_sample_size();
129

    
130
        if (_io_impl->send_state.bytes_free == 0) {
131
            _io_impl->send_state.send_buff->commit(_io_impl->send_state.bytes_used);
132
            _io_impl->send_state.send_buff = uhd::transport::managed_send_buffer::sptr();
133
        }
134

    
135
        total_samps_sent += copy_samps; 
136
 
137
        //check for underruns
138
        if (!(_io_impl->count++ % 1000)) {
139
            unsigned char underrun;
140
            int ret = _ctrl_transport->usrp_control_read(VRQ_GET_STATUS,
141
                                                         0,
142
                                                         GS_TX_UNDERRUN,
143
                                                         &underrun, sizeof(char));
144
            if (ret < 0)
145
                std::cerr << "error: underrun check failed" << std::endl;
146
            if (underrun)
147
                std::cerr << "U" << std::endl;
148
        }
149
    }
150

    
151
    return total_samps_sent;
152
}
153

    
154
/***********************************************************************
155
 * Data Recv
156
 **********************************************************************/
157
void _recv_helper(vrt_packet_handler::recv_state &state)
158
{
159
    size_t num_packet_words32 =
160
                       state.managed_buffs[0]->size() / sizeof(boost::uint32_t);
161

    
162
    const boost::uint32_t *data =
163
                        state.managed_buffs[0]->cast<const boost::uint32_t *>();
164

    
165
    state.copy_buffs[0] = reinterpret_cast<const boost::uint8_t *>(data);
166
    size_t num_payload_bytes = num_packet_words32 * sizeof(boost::uint32_t);
167
    state.size_of_copy_buffs = num_payload_bytes;
168
}
169

    
170
size_t usrp1_impl::recv(const std::vector<void *> &buffs,
171
                        size_t num_samps,
172
                        rx_metadata_t &,
173
                        const io_type_t &io_type,
174
                        recv_mode_t,
175
                        size_t)
176
{
177
    UHD_ASSERT_THROW(_io_impl->packet_handler_recv_state.width == 1);
178
    UHD_ASSERT_THROW(buffs.size() == 1);
179

    
180
    size_t sent_samps = 0;
181
    size_t nsamps_to_copy = 0;; 
182

    
183
    while (sent_samps < num_samps) {
184
        if (_io_impl->packet_handler_recv_state.size_of_copy_buffs == 0) {
185
            _io_impl->packet_handler_recv_state.fragment_offset_in_samps = 0;
186
            _io_impl->packet_handler_recv_state.managed_buffs[0] =
187
                                          _io_impl->data_transport->get_recv_buff();
188
 
189
            //timeout or something bad returns zero
190
            if (!_io_impl->packet_handler_recv_state.managed_buffs[0].get())
191
                return 0;
192
 
193
            _recv_helper(_io_impl->packet_handler_recv_state);
194
        }
195

    
196
        size_t bytes_per_item = _rx_otw_type.get_sample_size();
197
        size_t nsamps_available =
198
            _io_impl->packet_handler_recv_state.size_of_copy_buffs / bytes_per_item;
199
        nsamps_to_copy = std::min(num_samps, nsamps_available);
200
        size_t bytes_to_copy = nsamps_to_copy * bytes_per_item;
201

    
202
        convert_otw_type_to_io_type(
203
              _io_impl->packet_handler_recv_state.copy_buffs[0],
204
              _rx_otw_type,
205
              reinterpret_cast<boost::uint8_t *>(buffs[0]) + sent_samps * io_type.size,
206
              io_type,
207
              nsamps_to_copy);
208
 
209
        _io_impl->packet_handler_recv_state.copy_buffs[0] += bytes_to_copy; 
210
        _io_impl->packet_handler_recv_state.size_of_copy_buffs -= bytes_to_copy;
211

    
212
        sent_samps += nsamps_to_copy;
213

    
214
        //check for overruns
215
        if (!(_io_impl->count++ % 10000)) {
216
            unsigned char overrun;
217
            int ret = _ctrl_transport->usrp_control_read(
218
                                   VRQ_GET_STATUS,
219
                                   0,
220
                                   GS_RX_OVERRUN,
221
                                   &overrun, sizeof(char));
222
            if (ret < 0)
223
                std::cerr << "error: overrun check failed" << std::endl;
224
            if (overrun)
225
                std::cerr << "O" << std::endl;
226
        }
227
    }
228
    return sent_samps; 
229
}